Ticket #5085: twisted-tcp6_v2.patch

File twisted-tcp6_v2.patch, 20.6 KB (added by chjurk, 3 years ago)
  • twisted/internet/address.py

    diff -ru ../listentcp-ipv6-5084-3/twisted/internet/address.py ./twisted/internet/address.py
    old new  
    1919 
    2020    @ivar type: A string describing the type of transport, either 'TCP' or 
    2121        'UDP'. 
    22     @ivar host: A string containing the dotted-quad IP address. 
     22    @ivar host: A string containing the native IP address. 
    2323    @ivar port: An integer representing the port number. 
    2424    """ 
    2525 
     
    4747class IPv4Address(_IPAddress): 
    4848    """ 
    4949    Object representing an IPv4 socket endpoint. 
     50     
     51    @ivar type: A string describing the type of transport, either 'TCP' or 
     52        'UDP'. 
     53    @ivar host: A string containing the dotted-quad IP address. 
     54    @ivar port: An integer representing the port number. 
    5055    """ 
    5156    def __init__(self, type, host, port, _bwHack=None): 
    5257        _IPAddress.__init__(self, type, host, port) 
     
    5560                    DeprecationWarning, stacklevel=2) 
    5661 
    5762 
     63    def __str__(self): 
     64        """ 
     65        Returns human-readable IP address version. 
     66         
     67        @return: A string containing the word "IPv6". 
     68        """ 
     69        return "IPv4" 
     70 
     71 
    5872 
    5973class IPv6Address(_IPAddress): 
    6074    """ 
    6175    Object representing an IPv6 socket endpoint. 
     76 
     77    @ivar type: A string describing the type of transport, either 'TCP' or 
     78        'UDP'. 
     79    @ivar host: A string containing the hexadecimal formatted IP address. 
     80    @ivar port: An integer representing the port number. 
     81    @ivar flow_info: An integer specifying IPv6 flow info flags. 
     82    @ivar scope_id: A string containing the address scope identifier. 
    6283    """ 
     84    def __init__(self, type, host, port, flow_info=0, scope_id=0): 
     85        self.flow_info = flow_info 
     86        self.scope_id = scope_id 
     87        _IPAddress.__init__(self, type, host, port) 
     88 
     89 
     90    def __hash__(self): 
     91        return hash((self.type, self.host, self.port, self.flow_info, self.scope_id)) 
     92 
     93 
     94    def __str__(self): 
     95        """ 
     96        Returns human-readable IP address version. 
     97         
     98        @return: A string containing the word "IPv6". 
     99        """ 
     100        return "IPv6" 
    63101 
    64102 
    65103 
  • twisted/internet/endpoints.py

    diff -ru ../listentcp-ipv6-5084-3/twisted/internet/endpoints.py ./twisted/internet/endpoints.py
    old new  
    2525 
    2626__all__ = ["clientFromString", "serverFromString", 
    2727           "TCP4ServerEndpoint", "TCP4ClientEndpoint", 
     28           "TCP6ServerEndpoint", "TCP6ClientEndpoint", 
    2829           "UNIXServerEndpoint", "UNIXClientEndpoint", 
    2930           "SSL4ServerEndpoint", "SSL4ClientEndpoint"] 
    3031 
     
    145146 
    146147 
    147148 
    148 class TCP4ServerEndpoint(object): 
     149class _TCPServerEndpoint(object): 
    149150    """ 
    150     TCP server endpoint with an IPv4 configuration 
     151    TCP server endpoint with an generic IP configuration 
    151152 
    152153    @ivar _reactor: An L{IReactorTCP} provider. 
    153154 
     
    188189 
    189190 
    190191 
    191 class TCP4ClientEndpoint(object): 
     192class TCP4ServerEndpoint(_TCPServerEndpoint): 
    192193    """ 
    193     TCP client endpoint with an IPv4 configuration. 
     194    TCP server endpoint with an IPv4 configuration 
     195 
     196    @ivar _reactor: An L{IReactorTCP} provider. 
     197 
     198    @type _port: int 
     199    @ivar _port: The port number on which to listen for incoming connections. 
     200 
     201    @type _backlog: int 
     202    @ivar _backlog: size of the listen queue 
     203 
     204    @type _interface: str 
     205    @ivar _interface: the hostname to bind to, defaults to '' (all) 
     206    """ 
     207    pass 
     208 
     209 
     210 
     211class TCP6ServerEndpoint(_TCPServerEndpoint): 
     212    """ 
     213    TCP server endpoint with an IPv6 configuration 
     214 
     215    @ivar _reactor: An L{IReactorTCP} provider. 
     216 
     217    @type _port: int 
     218    @ivar _port: The port number on which to listen for incoming connections. 
     219 
     220    @type _backlog: int 
     221    @ivar _backlog: size of the listen queue 
     222 
     223    @type _interface: str 
     224    @ivar _interface: the hostname to bind to, defaults to '::' (all) 
     225    """ 
     226    def __init__(self, reactor, port, backlog=50, interface='::'): 
     227        _TCPServerEndpoint.__init__(self, reactor, port, backlog, interface) 
     228 
     229 
     230 
     231class _TCPClientEndpoint(object): 
     232    """ 
     233    TCP client endpoint with an generic IP configuration. 
    194234 
    195235    @ivar _reactor: An L{IReactorTCP} provider. 
    196236 
     
    247287 
    248288 
    249289 
    250 class SSL4ServerEndpoint(object): 
     290class TCP4ClientEndpoint(_TCPClientEndpoint): 
    251291    """ 
    252     SSL secured TCP server endpoint with an IPv4 configuration. 
     292    TCP client endpoint with an IPv4 configuration. 
     293 
     294    @ivar _reactor: An L{IReactorTCP} provider. 
     295 
     296    @type _host: str 
     297    @ivar _host: The hostname to connect to as a C{str} 
     298 
     299    @type _port: int 
     300    @ivar _port: The port to connect to as C{int} 
     301 
     302    @type _timeout: int 
     303    @ivar _timeout: number of seconds to wait before assuming the 
     304        connection has failed. 
     305 
     306    @type _bindAddress: tuple 
     307    @type _bindAddress: a (host, port) tuple of local address to bind 
     308        to, or None. 
     309    """ 
     310    pass 
     311 
     312 
     313 
     314class TCP6ClientEndpoint(_TCPClientEndpoint): 
     315    """ 
     316    TCP client endpoint with an IPv6 configuration. 
     317 
     318    @ivar _reactor: An L{IReactorTCP} provider. 
     319 
     320    @type _host: str 
     321    @ivar _host: The hostname to connect to as a C{str} 
     322 
     323    @type _port: int 
     324    @ivar _port: The port to connect to as C{int} 
     325 
     326    @type _timeout: int 
     327    @ivar _timeout: number of seconds to wait before assuming the 
     328        connection has failed. 
     329 
     330    @type _bindAddress: tuple 
     331    @type _bindAddress: a (host, port) tuple of local address to bind 
     332        to, or None. 
     333    """ 
     334    pass 
     335 
     336 
     337 
     338class _SSLServerEndpoint(object): 
     339    """ 
     340    SSL secured TCP server endpoint with an generic IP configuration. 
    253341 
    254342    @ivar _reactor: An L{IReactorSSL} provider. 
    255343 
     
    303391 
    304392 
    305393 
    306 class SSL4ClientEndpoint(object): 
     394class SSL4ServerEndpoint(_SSLServerEndpoint): 
    307395    """ 
    308     SSL secured TCP client endpoint with an IPv4 configuration 
     396    SSL secured TCP server endpoint with an IPv4 configuration. 
     397 
     398    @ivar _reactor: An L{IReactorSSL} provider. 
     399 
     400    @type _host: str 
     401    @ivar _host: The hostname to connect to as a C{str} 
     402 
     403    @type _port: int 
     404    @ivar _port: The port to connect to as C{int} 
     405 
     406    @type _sslContextFactory: L{OpenSSLCertificateOptions} 
     407    @var _sslContextFactory: SSL Configuration information as an 
     408        L{OpenSSLCertificateOptions} 
     409 
     410    @type _backlog: int 
     411    @ivar _backlog: size of the listen queue 
     412 
     413    @type _interface: str 
     414    @ivar _interface: the hostname to bind to, defaults to '' (all) 
     415    """ 
     416    pass 
     417 
     418 
     419 
     420class SSL6ServerEndpoint(_SSLServerEndpoint): 
     421    """ 
     422    SSL secured TCP server endpoint with an IPv6 configuration. 
     423 
     424    @ivar _reactor: An L{IReactorSSL} provider. 
     425 
     426    @type _host: str 
     427    @ivar _host: The hostname to connect to as a C{str} 
     428 
     429    @type _port: int 
     430    @ivar _port: The port to connect to as C{int} 
     431 
     432    @type _sslContextFactory: L{OpenSSLCertificateOptions} 
     433    @var _sslContextFactory: SSL Configuration information as an 
     434        L{OpenSSLCertificateOptions} 
     435 
     436    @type _backlog: int 
     437    @ivar _backlog: size of the listen queue 
     438 
     439    @type _interface: str 
     440    @ivar _interface: the hostname to bind to, defaults to '::' (all) 
     441    """ 
     442    pass 
     443 
     444 
     445 
     446 
     447class _SSLClientEndpoint(object): 
     448    """ 
     449    SSL secured TCP client endpoint with an generic IP configuration 
    309450 
    310451    @ivar _reactor: An L{IReactorSSL} provider. 
    311452 
     
    368509            return wf._onConnection 
    369510        except: 
    370511            return defer.fail() 
     512 
     513 
     514 
     515class SSL4ClientEndpoint(_SSLClientEndpoint): 
     516    """ 
     517    SSL secured TCP client endpoint with an IPv4 configuration 
     518 
     519    @ivar _reactor: An L{IReactorSSL} provider. 
     520 
     521    @type _host: str 
     522    @ivar _host: The hostname to connect to as a C{str} 
     523 
     524    @type _port: int 
     525    @ivar _port: The port to connect to as C{int} 
     526 
     527    @type _sslContextFactory: L{OpenSSLCertificateOptions} 
     528    @var _sslContextFactory: SSL Configuration information as an 
     529        L{OpenSSLCertificateOptions} 
     530 
     531    @type _timeout: int 
     532    @ivar _timeout: number of seconds to wait before assuming the 
     533        connection has failed. 
     534 
     535    @type _bindAddress: tuple 
     536    @ivar _bindAddress: a (host, port) tuple of local address to bind 
     537        to, or None. 
     538    """ 
     539    pass 
     540 
     541 
     542 
     543class SSL6ClientEndpoint(_SSLClientEndpoint): 
     544    """ 
     545    SSL secured TCP client endpoint with an IPv6 configuration 
     546 
     547    @ivar _reactor: An L{IReactorSSL} provider. 
     548 
     549    @type _host: str 
     550    @ivar _host: The hostname to connect to as a C{str} 
     551 
     552    @type _port: int 
     553    @ivar _port: The port to connect to as C{int} 
     554 
     555    @type _sslContextFactory: L{OpenSSLCertificateOptions} 
     556    @var _sslContextFactory: SSL Configuration information as an 
     557        L{OpenSSLCertificateOptions} 
     558 
     559    @type _timeout: int 
     560    @ivar _timeout: number of seconds to wait before assuming the 
     561        connection has failed. 
     562 
     563    @type _bindAddress: tuple 
     564    @ivar _bindAddress: a (host, port) tuple of local address to bind 
     565        to, or None. 
     566    """ 
     567    pass 
    371568 
    372569 
    373570 
  • twisted/internet/tcp.py

    diff -ru ../listentcp-ipv6-5084-3/twisted/internet/tcp.py ./twisted/internet/tcp.py
    old new  
    258258    A base class for client TCP (and similiar) sockets. 
    259259    """ 
    260260    _base = Connection 
     261    _addressType = address.IPv4Address 
    261262 
    262263    addressFamily = socket.AF_INET 
    263264    socketType = socket.SOCK_STREAM 
     
    270271            Connection.__init__(self, skt, None, reactor) 
    271272            self.doWrite = self.doConnect 
    272273            self.doRead = self.doConnect 
    273             reactor.callLater(0, whenDone) 
     274            self.doConnect() 
    274275        else: 
    275276            reactor.callLater(0, self.failIfNotConnected, error) 
    276277 
     
    312313        return s 
    313314 
    314315    def resolveAddress(self): 
    315         if abstract.isIPAddress(self.addr[0]): 
     316        if abstract.isIPAddress(self.addr[0]) or abstract.isIPv6Address(self.addr[0]): 
    316317            self._setRealAddress(self.addr[0]) 
    317318        else: 
    318319            d = self.reactor.resolve(self.addr[0]) 
    319320            d.addCallbacks(self._setRealAddress, self.failIfNotConnected) 
    320321 
    321     def _setRealAddress(self, address): 
    322         self.realAddress = (address, self.addr[1]) 
    323         self.doConnect() 
     322    def _setRealAddress(self, addr): 
     323        """ 
     324        Set the real IP address for this client. 
     325        Once the IP address is set, the socket is created using the correct 
     326        address family. 
     327        """ 
     328        if abstract.isIPv6Address(addr): 
     329            self.addressFamily = socket.AF_INET6 
     330            self._addressType = address.IPv6Address 
     331        self.realAddress = (addr, self.addr[1]) 
     332 
     333        # create the socket and wait finish init after that 
     334        self.initConnection() 
     335 
     336    def initConnection(self): 
     337        """ 
     338        Initialize connection by creating the appropriate socket. 
     339        """ 
     340        err = None 
     341        skt = None 
     342        result = True 
     343 
     344        try: 
     345            skt = self.createInternetSocket() 
     346        except socket.error, se: 
     347            err = error.ConnectBindError(se[0], se[1]) 
     348            result = None 
     349        if result and self.bindAddress is not None: 
     350            try: 
     351                skt.bind(self.bindAddress) 
     352            except socket.error, se: 
     353                err = error.ConnectBindError(se[0], se[1]) 
     354                result = None 
     355        self._finishInit(result, skt, err, self.reactor) 
    324356 
    325357    def doConnect(self): 
    326358        """I connect the socket. 
     
    394426        # BaseClient.__init__ is invoked later 
    395427        self.connector = connector 
    396428        self.addr = (host, port) 
     429        self.bindAddress = bindAddress 
     430        self.reactor = reactor 
    397431 
    398         whenDone = self.resolveAddress 
    399         err = None 
    400         skt = None 
    401  
    402         try: 
    403             skt = self.createInternetSocket() 
    404         except socket.error, se: 
    405             err = error.ConnectBindError(se[0], se[1]) 
    406             whenDone = None 
    407         if whenDone and bindAddress is not None: 
    408             try: 
    409                 skt.bind(bindAddress) 
    410             except socket.error, se: 
    411                 err = error.ConnectBindError(se[0], se[1]) 
    412                 whenDone = None 
    413         self._finishInit(whenDone, skt, err, reactor) 
     432        # Do outstanding initialization when real address is resolved 
     433        self.resolveAddress() 
    414434 
    415435    def getHost(self): 
    416         """Returns an IPv4Address. 
     436        """ 
     437        Returns an L{IPv4Address} or L{IPv6Address}. 
    417438 
    418439        This indicates the address from which I am connecting. 
    419440        """ 
    420         return address.IPv4Address('TCP', *self.socket.getsockname()) 
     441        return self._addressType('TCP', *self.socket.getsockname()) 
    421442 
    422443    def getPeer(self): 
    423         """Returns an IPv4Address. 
     444        """ 
     445        Returns an L{IPv4Address} or L{IPv6Address}. 
    424446 
    425447        This indicates the address that I am connected to. 
    426448        """ 
    427         return address.IPv4Address('TCP', *self.realAddress) 
     449        return self._addressType('TCP', *self.realAddress) 
    428450 
    429451    def __repr__(self): 
    430452        s = '<%s to %s at %x>' % (self.__class__, self.addr, unsignedID(self)) 
     
    556578 
    557579    def __repr__(self): 
    558580        if self._realPortNumber is not None: 
    559             return "<%s of %s on %s>" % (self.__class__, self.factory.__class__, 
    560                                          self._realPortNumber) 
     581            return "<%s of %s on %s (%s)>" % (self.__class__, self.factory.__class__, 
     582                                         self._realPortNumber, self._addressType) 
    561583        else: 
    562584            return "<%s of %s (not listening)>" % (self.__class__, self.factory.__class__) 
    563585 
     586 
    564587    def createInternetSocket(self): 
    565588        s = base.BasePort.createInternetSocket(self) 
    566589        if platformType == "posix" and sys.platform != "cygwin": 
     
    588611        # reflect what the OS actually assigned us. 
    589612        self._realPortNumber = skt.getsockname()[1] 
    590613 
    591         log.msg("%s starting on %s" % (self.factory.__class__, self._realPortNumber)) 
     614        log.msg("%s starting on %s (%s)" % (self.factory.__class__, self._realPortNumber, 
     615                                            self._addressType)) 
    592616 
    593617        # The order of the next 6 lines is kind of bizarre.  If no one 
    594618        # can explain it, perhaps we should re-arrange them. 
     
    739763 
    740764 
    741765class Connector(base.BaseConnector): 
     766    _addressType = address.IPv4Address 
     767 
    742768    def __init__(self, host, port, factory, timeout, bindAddress, reactor=None): 
    743         self.host = host 
    744769        if isinstance(port, types.StringTypes): 
    745770            try: 
    746771                port = socket.getservbyname(port, 'tcp') 
    747772            except socket.error, e: 
    748773                raise error.ServiceNameUnknownError(string="%s (%r)" % (e, port)) 
     774         
     775        self.host, self.port = host, port 
     776         
     777        if abstract.isIPv6Address(host): 
     778            self._addressType = address.IPv6Address 
     779        elif not abstract.isIPAddress(host): 
     780            # do a host lookup to make sure we have the correct address family 
     781            try: 
     782                addressInfo = socket.getaddrinfo(host, port) 
     783            except socket.gaierror: 
     784                raise error.DNSLookupError(host) 
     785            else: 
     786                assert len(addressInfo) > 0 
     787 
     788                # Sort addressInfo. IPv4 addresses should be preferred over  
     789                # IPv6 addresses to keep legacy applications working. 
     790                addressInfo = sorted(addressInfo, key=lambda fields: fields[0]) 
     791              
     792                if addressInfo[0][0] == socket.AF_INET6: 
     793                    self._addressType = address.IPv6Address 
     794 
     795                host, port = addressInfo[0][4][:2] 
     796         
     797        self.host = host 
    749798        self.port = port 
    750799        self.bindAddress = bindAddress 
    751800        base.BaseConnector.__init__(self, factory, timeout, reactor) 
     
    754803        return Client(self.host, self.port, self.bindAddress, self, self.reactor) 
    755804 
    756805    def getDestination(self): 
    757         return address.IPv4Address('TCP', self.host, self.port) 
     806        return self._addressType('TCP', self.host, self.port) 
  • twisted/internet/test/test_tcp.py

    diff -ru ../listentcp-ipv6-5084-3/twisted/internet/test/test_tcp.py ./twisted/internet/test/test_tcp.py
    old new  
    2020    IResolverSimple, IConnector, IReactorFDSet) 
    2121from twisted.internet.address import IPv4Address, IPv6Address 
    2222from twisted.internet.defer import Deferred, DeferredList, succeed, fail, maybeDeferred 
    23 from twisted.internet.endpoints import TCP4ServerEndpoint, TCP4ClientEndpoint 
     23from twisted.internet.endpoints import TCP4ServerEndpoint, TCP4ClientEndpoint, TCP6ServerEndpoint, TCP6ClientEndpoint 
    2424from twisted.internet.protocol import ServerFactory, ClientFactory, Protocol 
    2525from twisted.python.failure import Failure 
    2626from twisted.python import log 
     
    114114    """ 
    115115    def __init__(self, reactor): 
    116116        self.reactor = reactor 
    117  
    118  
     117     
     118     
    119119    def clientConnectionFailed(self, connector, reason): 
    120120        self.reactor.stop() 
    121121 
     
    605605 
    606606 
    607607 
     608class TCP6ClientTestsBuilder(ReactorBuilder, ConnectionTestsMixin): 
     609    """ 
     610    Builder defining tests relating to L{IReactorTCP.connectTCP}, IPv6 version. 
     611    """ 
     612    def serverEndpoint(self, reactor): 
     613        """ 
     614        Create a L{TCP6ServerEndpoint} listening on localhost on a 
     615        TCP/IP-selected port. 
     616        """ 
     617        return TCP6ServerEndpoint(reactor, 0, interface='::1') 
     618 
     619 
     620    def clientEndpoint(self, reactor, serverAddress): 
     621        """ 
     622        Create a L{TCP6ClientEndpoint} which will connect to localhost 
     623        on the port given by C{serverAddress}. 
     624 
     625        @type serverAddress: L{IPv6Address} 
     626        """ 
     627        return TCP6ClientEndpoint(reactor, '::1', serverAddress.port) 
     628 
     629 
     630    def test_interface(self): 
     631        """ 
     632        L{IReactorTCP.connectTCP} returns an object providing L{IConnector}. 
     633        """ 
     634        reactor = self.buildReactor() 
     635        connector = reactor.connectTCP("::1", 1234, ClientFactory()) 
     636        self.assertTrue(verifyObject(IConnector, connector)) 
     637 
     638 
     639    def test_clientConnectionFailedStopsReactor(self): 
     640        """ 
     641        The reactor can be stopped by a client factory's 
     642        C{clientConnectionFailed} method. 
     643        """ 
     644        host, port = findFreePort("::1", socket.AF_INET6)[:2] 
     645        reactor = self.buildReactor() 
     646        reactor.connectTCP(host, port, Stop(reactor)) 
     647        self.runReactor(reactor) 
     648 
     649 
     650    def test_addresses(self): 
     651        """ 
     652        A client's transport's C{getHost} and C{getPeer} return L{IPv6Address} 
     653        instances which give the hexadecimal formatted string form of the local 
     654        and remote endpoints of the connection respectively. 
     655        """ 
     656        host, port = findFreePort("::1", socket.AF_INET6)[:2] 
     657        reactor = self.buildReactor() 
     658 
     659        server = reactor.listenTCP( 
     660            0, serverFactoryFor(Protocol), interface=host) 
     661        serverAddress = server.getHost() 
     662 
     663        addresses = {'host': None, 'peer': None} 
     664        class CheckAddress(Protocol): 
     665            def makeConnection(self, transport): 
     666                addresses['host'] = transport.getHost() 
     667                addresses['peer'] = transport.getPeer() 
     668                reactor.stop() 
     669 
     670        clientFactory = Stop(reactor) 
     671        clientFactory.protocol = CheckAddress 
     672        reactor.connectTCP( 
     673            '::1', server.getHost().port, clientFactory, 
     674            bindAddress=('::1', port)) 
     675 
     676        self.runReactor(reactor) 
     677 
     678        self.assertEqual( 
     679            addresses['host'], 
     680            IPv6Address('TCP', '::1', port)) 
     681        self.assertEqual( 
     682            addresses['peer'], 
     683            IPv6Address('TCP', '::1', serverAddress.port)) 
     684 
     685 
     686 
    608687class StreamTransportTestsMixin: 
    609688    """ 
    610689    Mixin defining tests which apply to any port/connection based transport. 
     
    10241103 
    10251104 
    10261105globals().update(TCPClientTestsBuilder.makeTestCaseClasses()) 
     1106globals().update(TCP6ClientTestsBuilder.makeTestCaseClasses()) 
    10271107globals().update(TCPPortTestsBuilder.makeTestCaseClasses()) 
    10281108globals().update(TCPConnectionTestsBuilder.makeTestCaseClasses())