<s> """<STR_LIT>""" <EOL> from __future__ import division <EOL> import os <EOL> import time <EOL> import errno <EOL> import select <EOL> import socket <EOL> from . . import ( conf , drivers , log , utils , world ) <EOL> from . . utils import minisix <EOL> from . . utils . str import decode_raw_line <EOL> try : <EOL> import ssl <EOL> SSLError = ssl . SSLError <EOL> except : <EOL> drivers . log . debug ( '<STR_LIT>' <EOL> '<STR_LIT>' ) <EOL> class SSLError ( Exception ) : <EOL> pass <EOL> class SocketDriver ( drivers . IrcDriver , drivers . ServersMixin ) : <EOL> _instances = [ ] <EOL> _selecting = [ False ] <EOL> def __init__ ( self , irc ) : <EOL> self . _instances . append ( self ) <EOL> assert irc is not None <EOL> self . irc = irc <EOL> drivers . IrcDriver . __init__ ( self , irc ) <EOL> drivers . ServersMixin . __init__ ( self , irc ) <EOL> self . conn = None <EOL> self . _attempt = - <NUM_LIT:1> <EOL> self . servers = ( ) <EOL> self . eagains = <NUM_LIT:0> <EOL> self . inbuffer = b'<STR_LIT>' <EOL> self . outbuffer = '<STR_LIT>' <EOL> self . zombie = False <EOL> self . connected = False <EOL> self . writeCheckTime = None <EOL> self . nextReconnectTime = None <EOL> self . resetDelay ( ) <EOL> if self . networkGroup . get ( '<STR_LIT>' ) . value and '<STR_LIT>' not in globals ( ) : <EOL> drivers . log . error ( '<STR_LIT>' <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' ) <EOL> self . ssl = False <EOL> else : <EOL> self . ssl = self . networkGroup . get ( '<STR_LIT>' ) . value <EOL> self . connect ( ) <EOL> def getDelay ( self ) : <EOL> ret = self . currentDelay <EOL> self . currentDelay = min ( self . currentDelay * <NUM_LIT:2> , <EOL> conf . supybot . drivers . maxReconnectWait ( ) ) <EOL> return ret <EOL> def resetDelay ( self ) : <EOL> self . currentDelay = <NUM_LIT> <EOL> def _getNextServer ( self ) : <EOL> oldServer = getattr ( self , '<STR_LIT>' , None ) <EOL> server = drivers . ServersMixin . _getNextServer ( self ) <EOL> if self . currentServer != oldServer : <EOL> self . resetDelay ( ) <EOL> return server <EOL> def _handleSocketError ( self , e ) : <EOL> if e . args [ <NUM_LIT:0> ] != <NUM_LIT:11> or self . eagains > <NUM_LIT> : <EOL> drivers . log . disconnect ( self . currentServer , e ) <EOL> if self in self . _instances : <EOL> self . _instances . remove ( self ) <EOL> try : <EOL> self . conn . close ( ) <EOL> except : <EOL> pass <EOL> self . connected = False <EOL> self . scheduleReconnect ( ) <EOL> else : <EOL> log . debug ( '<STR_LIT>' , self . eagains ) <EOL> self . eagains += <NUM_LIT:1> <EOL> def _sendIfMsgs ( self ) : <EOL> if not self . connected : <EOL> return <EOL> if not self . zombie : <EOL> msgs = [ self . irc . takeMsg ( ) ] <EOL> while msgs [ - <NUM_LIT:1> ] is not None : <EOL> msgs . append ( self . irc . takeMsg ( ) ) <EOL> del msgs [ - <NUM_LIT:1> ] <EOL> self . outbuffer += '<STR_LIT>' . join ( map ( str , msgs ) ) <EOL> if self . outbuffer : <EOL> try : <EOL> if minisix . PY2 : <EOL> sent = self . conn . send ( self . outbuffer ) <EOL> else : <EOL> sent = self . conn . send ( self . outbuffer . encode ( ) ) <EOL> self . outbuffer = self . outbuffer [ sent : ] <EOL> self . eagains = <NUM_LIT:0> <EOL> except socket . error as e : <EOL> self . _handleSocketError ( e ) <EOL> if self . zombie and not self . outbuffer : <EOL> self . _reallyDie ( ) <EOL> @ classmethod <EOL> def _select ( cls ) : <EOL> if cls . _selecting [ <NUM_LIT:0> ] : <EOL> return <EOL> try : <EOL> cls . _selecting [ <NUM_LIT:0> ] = True <EOL> for inst in cls . _instances : <EOL> if not inst . connected or ( minisix . PY3 and inst . conn . _closed ) or ( minisix . PY2 and <EOL> inst . conn . _sock . __class__ is socket . _closedsocket ) : <EOL> cls . _instances . remove ( inst ) <EOL> elif inst . conn . fileno ( ) == - <NUM_LIT:1> : <EOL> inst . reconnect ( ) <EOL> if not cls . _instances : <EOL> return <EOL> rlist , wlist , xlist = select . select ( [ x . conn for x in cls . _instances ] , <EOL> [ ] , [ ] , conf . supybot . drivers . poll ( ) ) <EOL> for instance in cls . _instances : <EOL> if instance . conn in rlist : <EOL> instance . _read ( ) <EOL> except select . error as e : <EOL> if e . args [ <NUM_LIT:0> ] != errno . EINTR : <EOL> raise <EOL> finally : <EOL> cls . _selecting [ <NUM_LIT:0> ] = False <EOL> for instance in cls . _instances : <EOL> if instance . irc and not instance . irc . zombie : <EOL> instance . _sendIfMsgs ( ) <EOL> def run ( self ) : <EOL> now = time . time ( ) <EOL> if self . nextReconnectTime is not None and now > self . nextReconnectTime : <EOL> self . reconnect ( ) <EOL> elif self . writeCheckTime is not None and now > self . writeCheckTime : <EOL> self . _checkAndWriteOrReconnect ( ) <EOL> if not self . connected : <EOL> time . sleep ( conf . supybot . drivers . poll ( ) ) <EOL> return <EOL> self . _sendIfMsgs ( ) <EOL> self . _select ( ) <EOL> def _read ( self ) : <EOL> """<STR_LIT>""" <EOL> try : <EOL> self . inbuffer += self . conn . recv ( <NUM_LIT> ) <EOL> self . eagains = <NUM_LIT:0> <EOL> lines = self . inbuffer . split ( b'<STR_LIT:\n>' ) <EOL> self . inbuffer = lines . pop ( ) <EOL> for line in lines : <EOL> line = decode_raw_line ( line ) <EOL> msg = drivers . parseMsg ( line ) <EOL> if msg is not None and self . irc is not None : <EOL> self . irc . feedMsg ( msg ) <EOL> except socket . timeout : <EOL> pass <EOL> except SSLError as e : <EOL> if e . args [ <NUM_LIT:0> ] == '<STR_LIT>' : <EOL> pass <EOL> else : <EOL> self . _handleSocketError ( e ) <EOL> return <EOL> except socket . error as e : <EOL> self . _handleSocketError ( e ) <EOL> return <EOL> if self . irc and not self . irc . zombie : <EOL> self . _sendIfMsgs ( ) <EOL> def connect ( self , ** kwargs ) : <EOL> self . reconnect ( reset = False , ** kwargs ) <EOL> def reconnect ( self , wait = False , reset = True ) : <EOL> self . _attempt += <NUM_LIT:1> <EOL> self . nextReconnectTime = None <EOL> if self . connected : <EOL> drivers . log . reconnect ( self . irc . network ) <EOL> if self in self . _instances : <EOL> self . _instances . remove ( self ) <EOL> try : <EOL> self . conn . shutdown ( socket . SHUT_RDWR ) <EOL> except : <EOL> pass <EOL> self . conn . close ( ) <EOL> self . connected = False <EOL> if reset : <EOL> drivers . log . debug ( '<STR_LIT>' , self . irc ) <EOL> self . irc . reset ( ) <EOL> else : <EOL> drivers . log . debug ( '<STR_LIT>' , self . irc ) <EOL> if wait : <EOL> self . scheduleReconnect ( ) <EOL> return <EOL> self . server = self . _getNextServer ( ) <EOL> network_config = getattr ( conf . supybot . networks , self . irc . network ) <EOL> socks_proxy = network_config . socksproxy ( ) <EOL> try : <EOL> if socks_proxy : <EOL> import socks <EOL> except ImportError : <EOL> log . error ( '<STR_LIT>' <EOL> '<STR_LIT>' ) <EOL> socks_proxy = '<STR_LIT>' <EOL> if socks_proxy : <EOL> address = self . server [ <NUM_LIT:0> ] <EOL> else : <EOL> try : <EOL> address = utils . net . getAddressFromHostname ( self . server [ <NUM_LIT:0> ] , <EOL> attempt = self . _attempt ) <EOL> except ( socket . gaierror , socket . error ) as e : <EOL> drivers . log . connectError ( self . currentServer , e ) <EOL> self . scheduleReconnect ( ) <EOL> return <EOL> port = self . server [ <NUM_LIT:1> ] <EOL> drivers . log . connect ( self . currentServer ) <EOL> try : <EOL> self . conn = utils . net . getSocket ( address , port = port , <EOL> socks_proxy = socks_proxy , <EOL> vhost = conf . supybot . protocols . irc . vhost ( ) , <EOL> vhostv6 = conf . supybot . protocols . irc . vhostv6 ( ) , <EOL> ) <EOL> except socket . error as e : <EOL> drivers . log . connectError ( self . currentServer , e ) <EOL> self . scheduleReconnect ( ) <EOL> return <EOL> self . conn . settimeout ( max ( <NUM_LIT:10> , conf . supybot . drivers . poll ( ) * <NUM_LIT:10> ) ) <EOL> try : <EOL> self . conn . connect ( ( address , port ) ) <EOL> if network_config . ssl ( ) : <EOL> self . starttls ( ) <EOL> elif not network_config . requireStarttls ( ) : <EOL> drivers . log . warning ( ( '<STR_LIT>' <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' ) <EOL> % self . irc . network ) <EOL> def setTimeout ( ) : <EOL> self . conn . settimeout ( conf . supybot . drivers . poll ( ) ) <EOL> conf . supybot . drivers . poll . addCallback ( setTimeout ) <EOL> setTimeout ( ) <EOL> self . connected = True <EOL> self . resetDelay ( ) <EOL> except socket . error as e : <EOL> if e . args [ <NUM_LIT:0> ] == <NUM_LIT> : <EOL> now = time . time ( ) <EOL> when = now + <NUM_LIT> <EOL> whenS = log . timestamp ( when ) <EOL> drivers . log . debug ( '<STR_LIT>' <EOL> '<STR_LIT>' , whenS ) <EOL> self . writeCheckTime = when <EOL> else : <EOL> drivers . log . connectError ( self . currentServer , e ) <EOL> self . scheduleReconnect ( ) <EOL> return <EOL> self . _instances . append ( self ) <EOL> def _checkAndWriteOrReconnect ( self ) : <EOL> self . writeCheckTime = None <EOL> drivers . log . debug ( '<STR_LIT>' ) <EOL> ( _ , w , _ ) = select . select ( [ ] , [ self . conn ] , [ ] , <NUM_LIT:0> ) <EOL> if w : <EOL> drivers . log . debug ( '<STR_LIT>' ) <EOL> self . connected = True <EOL> self . resetDelay ( ) <EOL> else : <EOL> drivers . log . connectError ( self . currentServer , '<STR_LIT>' ) <EOL> self . reconnect ( ) <EOL> def scheduleReconnect ( self ) : <EOL> when = time . time ( ) + self . getDelay ( ) <EOL> if not world . dying : <EOL> drivers . log . reconnect ( self . irc . network , when ) <EOL> if self . nextReconnectTime : <EOL> drivers . log . error ( '<STR_LIT>' <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' ) <EOL> self . nextReconnectTime = when <EOL> def die ( self ) : <EOL> if self in self . _instances : <EOL> self . _instances . remove ( self ) <EOL> self . zombie = True <EOL> if self . nextReconnectTime is not None : <EOL> self . nextReconnectTime = None <EOL> if self . writeCheckTime is not None : <EOL> self . writeCheckTime = None <EOL> drivers . log . die ( self . irc ) <EOL> def _reallyDie ( self ) : <EOL> if self . conn is not None : <EOL> self . conn . close ( ) <EOL> drivers . IrcDriver . die ( self ) <EOL> def name ( self ) : <EOL> return '<STR_LIT>' % ( self . __class__ . __name__ , self . irc ) <EOL> def starttls ( self ) : <EOL> assert '<STR_LIT>' in globals ( ) <EOL> network_config = getattr ( conf . supybot . networks , self . irc . network ) <EOL> certfile = network_config . certfile ( ) <EOL> if not certfile : <EOL> certfile = conf . supybot . protocols . irc . certfile ( ) <EOL> if not certfile : <EOL> certfile = None <EOL> elif not os . path . isfile ( certfile ) : <EOL> drivers . log . warning ( '<STR_LIT>' % <EOL> certfile ) <EOL> certfile = None <EOL> verifyCertificates = conf . supybot . protocols . ssl . verifyCertificates ( ) <EOL> if not verifyCertificates : <EOL> drivers . log . warning ( '<STR_LIT>' <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' ) <EOL> try : <EOL> self . conn = utils . net . ssl_wrap_socket ( self . conn , <EOL> logger = drivers . log , hostname = self . server [ <NUM_LIT:0> ] , <EOL> certfile = certfile , <EOL> verify = verifyCertificates , <EOL> trusted_fingerprints = network_config . ssl . serverFingerprints ( ) , <EOL> ca_file = network_config . ssl . authorityCertificate ( ) , <EOL> ) <EOL> except getattr ( ssl , '<STR_LIT>' , None ) as e : <EOL> drivers . log . error ( ( '<STR_LIT>' <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' ) <EOL> % ( self . irc . network , e . args [ <NUM_LIT:0> ] ) ) <EOL> raise ssl . SSLError ( '<STR_LIT>' <EOL> '<STR_LIT>' ) <EOL> except ssl . SSLError as e : <EOL> drivers . log . error ( ( '<STR_LIT>' <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' ) <EOL> % ( self . irc . network , e . args [ <NUM_LIT:1> ] ) ) <EOL> raise ssl . SSLError ( '<STR_LIT>' <EOL> '<STR_LIT>' ) <EOL> Driver = SocketDriver </s>
