<s> import socket <EOL> from errno import EWOULDBLOCK , ECONNREFUSED , EHOSTUNREACH <EOL> try : <EOL> from select import poll , error , POLLIN , POLLOUT , POLLERR , POLLHUP <EOL> timemult = <NUM_LIT:1000> <EOL> except ImportError : <EOL> from selectpoll import poll , error , POLLIN , POLLOUT , POLLERR , POLLHUP <EOL> timemult = <NUM_LIT:1> <EOL> from time import sleep <EOL> from clock import clock <EOL> import sys <EOL> from random import shuffle , randrange <EOL> from natpunch import UPnP_open_port , UPnP_close_port <EOL> try : <EOL> True <EOL> except : <EOL> True = <NUM_LIT:1> <EOL> False = <NUM_LIT:0> <EOL> all = POLLIN | POLLOUT <EOL> UPnP_ERROR = "<STR_LIT>" <EOL> class SingleSocket : <EOL> def __init__ ( self , socket_handler , sock , handler , ip = None ) : <EOL> self . socket_handler = socket_handler <EOL> self . socket = sock <EOL> self . handler = handler <EOL> self . buffer = [ ] <EOL> self . last_hit = clock ( ) <EOL> self . fileno = sock . fileno ( ) <EOL> self . connected = False <EOL> self . skipped = <NUM_LIT:0> <EOL> try : <EOL> self . ip = self . socket . getpeername ( ) [ <NUM_LIT:0> ] <EOL> except : <EOL> if ip is None : <EOL> self . ip = '<STR_LIT>' <EOL> else : <EOL> self . ip = ip <EOL> def get_ip ( self , real = False ) : <EOL> if real : <EOL> try : <EOL> self . ip = self . socket . getpeername ( ) [ <NUM_LIT:0> ] <EOL> except : <EOL> pass <EOL> return self . ip <EOL> def close ( self ) : <EOL> '''<STR_LIT>''' <EOL> assert self . socket <EOL> self . connected = False <EOL> sock = self . socket <EOL> self . socket = None <EOL> self . buffer = [ ] <EOL> del self . socket_handler . single_sockets [ self . fileno ] <EOL> self . socket_handler . poll . unregister ( sock ) <EOL> sock . close ( ) <EOL> def shutdown ( self , val ) : <EOL> self . socket . shutdown ( val ) <EOL> def is_flushed ( self ) : <EOL> return not self . buffer <EOL> def write ( self , s ) : <EOL> assert self . socket is not None <EOL> self . buffer . append ( s ) <EOL> if len ( self . buffer ) == <NUM_LIT:1> : <EOL> self . try_write ( ) <EOL> def try_write ( self ) : <EOL> if self . connected : <EOL> dead = False <EOL> try : <EOL> while self . buffer : <EOL> buf = self . buffer [ <NUM_LIT:0> ] <EOL> amount = self . socket . send ( buf ) <EOL> if amount == <NUM_LIT:0> : <EOL> self . skipped += <NUM_LIT:1> <EOL> break <EOL> self . skipped = <NUM_LIT:0> <EOL> if amount != len ( buf ) : <EOL> self . buffer [ <NUM_LIT:0> ] = buf [ amount : ] <EOL> break <EOL> del self . buffer [ <NUM_LIT:0> ] <EOL> except socket . error , e : <EOL> try : <EOL> dead = e [ <NUM_LIT:0> ] != EWOULDBLOCK <EOL> except : <EOL> dead = True <EOL> self . skipped += <NUM_LIT:1> <EOL> if self . skipped >= <NUM_LIT:3> : <EOL> dead = True <EOL> if dead : <EOL> self . socket_handler . dead_from_write . append ( self ) <EOL> return <EOL> if self . buffer : <EOL> self . socket_handler . poll . register ( self . socket , all ) <EOL> else : <EOL> self . socket_handler . poll . register ( self . socket , POLLIN ) <EOL> def set_handler ( self , handler ) : <EOL> self . handler = handler <EOL> class SocketHandler : <EOL> def __init__ ( self , timeout , ipv6_enable , readsize = <NUM_LIT> ) : <EOL> self . timeout = timeout <EOL> self . ipv6_enable = ipv6_enable <EOL> self . readsize = readsize <EOL> self . poll = poll ( ) <EOL> self . single_sockets = { } <EOL> self . dead_from_write = [ ] <EOL> self . max_connects = <NUM_LIT:1000> <EOL> self . port_forwarded = None <EOL> self . servers = { } <EOL> def scan_for_timeouts ( self ) : <EOL> t = clock ( ) - self . timeout <EOL> tokill = [ ] <EOL> for s in self . single_sockets . values ( ) : <EOL> if s . last_hit < t : <EOL> tokill . append ( s ) <EOL> for k in tokill : <EOL> if k . socket is not None : <EOL> self . _close_socket ( k ) <EOL> def bind ( self , port , bind = '<STR_LIT>' , reuse = False , ipv6_socket_style = <NUM_LIT:1> , upnp = <NUM_LIT:0> ) : <EOL> port = int ( port ) <EOL> addrinfos = [ ] <EOL> self . servers = { } <EOL> self . interfaces = [ ] <EOL> if bind : <EOL> if self . ipv6_enable : <EOL> socktype = socket . AF_UNSPEC <EOL> else : <EOL> socktype = socket . AF_INET <EOL> bind = bind . split ( '<STR_LIT:U+002C>' ) <EOL> for addr in bind : <EOL> if sys . version_info < ( <NUM_LIT:2> , <NUM_LIT:2> ) : <EOL> addrinfos . append ( ( socket . AF_INET , None , None , None , ( addr , port ) ) ) <EOL> else : <EOL> addrinfos . extend ( socket . getaddrinfo ( addr , port , <EOL> socktype , socket . SOCK_STREAM ) ) <EOL> else : <EOL> if self . ipv6_enable : <EOL> addrinfos . append ( [ socket . AF_INET6 , None , None , None , ( '<STR_LIT>' , port ) ] ) <EOL> if not addrinfos or ipv6_socket_style != <NUM_LIT:0> : <EOL> addrinfos . append ( [ socket . AF_INET , None , None , None , ( '<STR_LIT>' , port ) ] ) <EOL> for addrinfo in addrinfos : <EOL> try : <EOL> server = socket . socket ( addrinfo [ <NUM_LIT:0> ] , socket . SOCK_STREAM ) <EOL> if reuse : <EOL> server . setsockopt ( socket . SOL_SOCKET , socket . SO_REUSEADDR , <NUM_LIT:1> ) <EOL> server . setblocking ( <NUM_LIT:0> ) <EOL> server . bind ( addrinfo [ <NUM_LIT:4> ] ) <EOL> self . servers [ server . fileno ( ) ] = server <EOL> if bind : <EOL> self . interfaces . append ( server . getsockname ( ) [ <NUM_LIT:0> ] ) <EOL> server . listen ( <NUM_LIT:64> ) <EOL> self . poll . register ( server , POLLIN ) <EOL> except socket . error , e : <EOL> for server in self . servers . values ( ) : <EOL> try : <EOL> server . close ( ) <EOL> except : <EOL> pass <EOL> if self . ipv6_enable and ipv6_socket_style == <NUM_LIT:0> and self . servers : <EOL> raise socket . error ( '<STR_LIT>' ) <EOL> raise socket . error ( str ( e ) ) <EOL> if not self . servers : <EOL> raise socket . error ( '<STR_LIT>' ) <EOL> if upnp : <EOL> if not UPnP_open_port ( port ) : <EOL> for server in self . servers . values ( ) : <EOL> try : <EOL> server . close ( ) <EOL> except : <EOL> pass <EOL> self . servers = None <EOL> self . interfaces = None <EOL> raise socket . error ( UPnP_ERROR ) <EOL> self . port_forwarded = port <EOL> self . port = port <EOL> def find_and_bind ( self , minport , maxport , bind = '<STR_LIT>' , reuse = False , <EOL> ipv6_socket_style = <NUM_LIT:1> , upnp = <NUM_LIT:0> , randomizer = False ) : <EOL> e = '<STR_LIT>' <EOL> if maxport - minport < <NUM_LIT:50> or not randomizer : <EOL> portrange = range ( minport , maxport + <NUM_LIT:1> ) <EOL> if randomizer : <EOL> shuffle ( portrange ) <EOL> portrange = portrange [ : <NUM_LIT:20> ] <EOL> else : <EOL> portrange = [ ] <EOL> while len ( portrange ) < <NUM_LIT:20> : <EOL> listen_port = randrange ( minport , maxport + <NUM_LIT:1> ) <EOL> if not listen_port in portrange : <EOL> portrange . append ( listen_port ) <EOL> for listen_port in portrange : <EOL> try : <EOL> self . bind ( listen_port , bind , <EOL> ipv6_socket_style = ipv6_socket_style , upnp = upnp ) <EOL> return listen_port <EOL> except socket . error , e : <EOL> pass <EOL> raise socket . error ( str ( e ) ) <EOL> def set_handler ( self , handler ) : <EOL> self . handler = handler <EOL> def start_connection_raw ( self , dns , socktype = socket . AF_INET , handler = None ) : <EOL> if handler is None : <EOL> handler = self . handler <EOL> sock = socket . socket ( socktype , socket . SOCK_STREAM ) <EOL> sock . setblocking ( <NUM_LIT:0> ) <EOL> try : <EOL> sock . connect_ex ( dns ) <EOL> except socket . error : <EOL> raise <EOL> except Exception , e : <EOL> raise socket . error ( str ( e ) ) <EOL> self . poll . register ( sock , POLLIN ) <EOL> s = SingleSocket ( self , sock , handler , dns [ <NUM_LIT:0> ] ) <EOL> self . single_sockets [ sock . fileno ( ) ] = s <EOL> return s <EOL> def start_connection ( self , dns , handler = None , randomize = False ) : <EOL> if handler is None : <EOL> handler = self . handler <EOL> if sys . version_info < ( <NUM_LIT:2> , <NUM_LIT:2> ) : <EOL> s = self . start_connection_raw ( dns , socket . AF_INET , handler ) <EOL> else : <EOL> if self . ipv6_enable : <EOL> socktype = socket . AF_UNSPEC <EOL> else : <EOL> socktype = socket . AF_INET <EOL> try : <EOL> addrinfos = socket . getaddrinfo ( dns [ <NUM_LIT:0> ] , int ( dns [ <NUM_LIT:1> ] ) , <EOL> socktype , socket . SOCK_STREAM ) <EOL> except socket . error , e : <EOL> raise <EOL> except Exception , e : <EOL> raise socket . error ( str ( e ) ) <EOL> if randomize : <EOL> shuffle ( addrinfos ) <EOL> for addrinfo in addrinfos : <EOL> try : <EOL> s = self . start_connection_raw ( addrinfo [ <NUM_LIT:4> ] , addrinfo [ <NUM_LIT:0> ] , handler ) <EOL> break <EOL> except : <EOL> pass <EOL> else : <EOL> raise socket . error ( '<STR_LIT>' ) <EOL> return s <EOL> def _sleep ( self ) : <EOL> sleep ( <NUM_LIT:1> ) <EOL> def handle_events ( self , events ) : <EOL> for sock , event in events : <EOL> s = self . servers . get ( sock ) <EOL> if s : <EOL> if event & ( POLLHUP | POLLERR ) != <NUM_LIT:0> : <EOL> self . poll . unregister ( s ) <EOL> s . close ( ) <EOL> del self . servers [ sock ] <EOL> print "<STR_LIT>" <EOL> elif len ( self . single_sockets ) < self . max_connects : <EOL> try : <EOL> newsock , addr = s . accept ( ) <EOL> newsock . setblocking ( <NUM_LIT:0> ) <EOL> nss = SingleSocket ( self , newsock , self . handler ) <EOL> self . single_sockets [ newsock . fileno ( ) ] = nss <EOL> self . poll . register ( newsock , POLLIN ) <EOL> self . handler . external_connection_made ( nss ) <EOL> except socket . error : <EOL> self . _sleep ( ) <EOL> else : <EOL> s = self . single_sockets . get ( sock ) <EOL> if not s : <EOL> continue <EOL> s . connected = True <EOL> if ( event & ( POLLHUP | POLLERR ) ) : <EOL> self . _close_socket ( s ) <EOL> continue <EOL> if ( event & POLLIN ) : <EOL> try : <EOL> s . last_hit = clock ( ) <EOL> data = s . socket . recv ( self . readsize ) <EOL> if not data : <EOL> self . _close_socket ( s ) <EOL> else : <EOL> s . handler . data_came_in ( s , data ) <EOL> except socket . error , e : <EOL> code , msg = e <EOL> if code != EWOULDBLOCK : <EOL> self . _close_socket ( s ) <EOL> continue <EOL> if ( event & POLLOUT ) and s . socket and not s . is_flushed ( ) : <EOL> s . try_write ( ) <EOL> if s . is_flushed ( ) : <EOL> s . handler . connection_flushed ( s ) <EOL> def close_dead ( self ) : <EOL> while self . dead_from_write : <EOL> old = self . dead_from_write <EOL> self . dead_from_write = [ ] <EOL> for s in old : <EOL> if s . socket : <EOL> self . _close_socket ( s ) <EOL> def _close_socket ( self , s ) : <EOL> s . close ( ) <EOL> s . handler . connection_lost ( s ) <EOL> def do_poll ( self , t ) : <EOL> r = self . poll . poll ( t * timemult ) <EOL> if r is None : <EOL> connects = len ( self . single_sockets ) <EOL> to_close = int ( connects * <NUM_LIT> ) + <NUM_LIT:1> <EOL> self . max_connects = connects - to_close <EOL> closelist = self . single_sockets . values ( ) <EOL> shuffle ( closelist ) <EOL> closelist = closelist [ : to_close ] <EOL> for sock in closelist : <EOL> self . _close_socket ( sock ) <EOL> return [ ] <EOL> return r <EOL> def get_stats ( self ) : <EOL> return { '<STR_LIT>' : self . interfaces , <EOL> '<STR_LIT:port>' : self . port , <EOL> '<STR_LIT>' : self . port_forwarded is not None } <EOL> def shutdown ( self ) : <EOL> for ss in self . single_sockets . values ( ) : <EOL> try : <EOL> ss . close ( ) <EOL> except : <EOL> pass <EOL> for server in self . servers . values ( ) : <EOL> try : <EOL> server . close ( ) <EOL> except : <EOL> pass <EOL> if self . port_forwarded is not None : <EOL> UPnP_close_port ( self . port_forwarded ) </s>
