Ticket #3014: Twisted-11.0.0-ipv6.chjurk.diff

File Twisted-11.0.0-ipv6.chjurk.diff, 17.3 KB (added by chjurk, 4 years ago)

IPv6 patch for Twisted 11.0.0

  • twisted/internet/abstract.py

    diff -ru ../Twisted-11.0.0/twisted/internet/abstract.py ./twisted/internet/abstract.py
    old new  
    99Maintainer: Itamar Shtull-Trauring
    1010"""
    1111
     12import socket
     13
    1214from zope.interface import implements
    1315
    1416# Twisted Imports
     
    412414        return -1
    413415
    414416
    415 def isIPAddress(addr):
     417def isIPv6Address(addr):
     418    """
     419    Determine whether the given string represents an IPv6 address.
     420
     421        @param addr: A string which may or may not be the hexadecimal
     422        representation of an IPv6 address.
     423
     424        @rtype: C{bool}
     425        @return: C{True} if C{addr} represents an IPv6 address, C{False}
     426    otherwise.
     427    """
     428    if addr.find(":") != 1:
     429        try:
     430            socket.getaddrinfo(addr, 0, socket.AF_INET6, 0, 0, socket.AI_NUMERICHOST)
     431        except socket.gaierror:
     432            pass
     433        else:
     434            return True
     435    return False
     436
     437def isIPv4Address(addr):
    416438    """
    417439    Determine whether the given string represents an IPv4 address.
    418440
     
    437459        return True
    438460    return False
    439461
     462def isIPAddress(addr):
     463    """
     464    Determine whether the given string represents an IPv4 or IPv6 address.
     465   
     466    @type addr: C{str}
     467    @param addr: A string which may or may not be the decimal dotted
     468    representation of an IPv4 address.
     469
     470    @rtype: C{bool}
     471    @return: C{True} if C{addr} represents an IPv4 address, C{False}
     472    """
     473    return isIPv4Address(addr) or isIPv6Address(addr)
    440474
    441475__all__ = ["FileDescriptor"]
  • twisted/internet/address.py

    diff -ru ../Twisted-11.0.0/twisted/internet/address.py ./twisted/internet/address.py
    old new  
    55Address objects for network connections.
    66"""
    77
    8 import warnings, os
     8import warnings, os, socket
    99
    1010from zope.interface import implements
    1111
     
    1313from twisted.python import util
    1414
    1515
    16 class IPv4Address(object, util.FancyEqMixin):
     16class IPAddress(object, util.FancyEqMixin):
    1717    """
    18     Object representing an IPv4 socket endpoint.
     18    Object representing an IP socket endpoint.
    1919
    2020    @ivar type: A string describing the type of transport, either 'TCP' or
    2121        'UDP'.
     
    2525
    2626    implements(IAddress)
    2727
    28     compareAttributes = ('type', 'host', 'port')
     28    compareAttributes = ('type', 'family', 'host', 'port')
    2929
    30     def __init__(self, type, host, port, _bwHack = None):
     30    def __init__(self, type, family, host, port, _bwHack = None):
    3131        assert type in ('TCP', 'UDP')
    3232        self.type = type
     33        self.family = family
    3334        self.host = host
    3435        self.port = port
    3536        if _bwHack is not None:
     
    3738                    DeprecationWarning, stacklevel=2)
    3839
    3940    def __repr__(self):
    40         return 'IPv4Address(%s, %r, %d)' % (self.type, self.host, self.port)
     41        family_str = "IPv4" if self.family == socket.AF_INET else "IPv6"
     42        return 'IPAddress(%s, %s, %r, %d)' % (self.type, family_str, self.host, self.port)
    4143
    4244
    4345    def __hash__(self):
    44         return hash((self.type, self.host, self.port))
    45 
     46        return hash((self.type, self.family, self.host, self.port))
    4647
     48class IPv4Address(IPAddress):
     49    """
     50    Generic version of IPv4Address.
     51    """
     52    def __init(self, type, host, port):
     53        IPAddress.__init__(type, socket.AF_INET, host, port, None)       
    4754
    4855class UNIXAddress(object, util.FancyEqMixin):
    4956    """
     
    9299
    93100
    94101
     102class _ServerFactoryIPAddress(IPAddress):
     103    def __eq__(self, other):
     104        if isinstance(other, IPAddress):
     105            a = (self.type, self.family, self.host, self.port)
     106            b = (other.type, other.family, other.host, other.port)
     107            return a == b
     108        return False
     109
    95110# These are for buildFactory backwards compatability due to
    96111# stupidity-induced inconsistency.
    97112
  • twisted/internet/base.py

    diff -ru ../Twisted-11.0.0/twisted/internet/base.py ./twisted/internet/base.py
    old new  
    249249            else:
    250250                userDeferred.callback(result)
    251251
     252    def _lookup(self, name):
     253        """
     254        Replacement for gethostbyname.
     255        """
     256        ai = socket.getaddrinfo(name, 0)
     257        assert len(ai) > 0 and len(ai[0]) >= 5
     258       
     259        # Sort the result. IPv4 addresses should be preferred over
     260        # IPv6 addresses to keep legacy applications working.
     261        ai = sorted(ai, key=lambda fields: fields[0])
     262       
     263        return ai[0][4][0]
    252264
    253265    def getHostByName(self, name, timeout = (1, 3, 11, 45)):
    254266        """
     
    265277        userDeferred = defer.Deferred()
    266278        lookupDeferred = threads.deferToThreadPool(
    267279            self.reactor, self.reactor.getThreadPool(),
    268             socket.gethostbyname, name)
     280            self._lookup, name)
    269281        cancelCall = self.reactor.callLater(
    270282            timeoutDelay, self._cleanup, name, lookupDeferred)
    271283        self._runningQueries[lookupDeferred] = (userDeferred, cancelCall)
  • twisted/internet/endpoints.py

    diff -ru ../Twisted-11.0.0/twisted/internet/endpoints.py ./twisted/internet/endpoints.py
    old new  
    145145
    146146
    147147
    148 class TCP4ServerEndpoint(object):
     148class TCPServerEndpoint(object):
    149149    """
    150     TCP server endpoint with an IPv4 configuration
     150    TCP server endpoint with an IP configuration
    151151
    152152    @ivar _reactor: An L{IReactorTCP} provider.
    153153
     
    186186                             backlog=self._backlog,
    187187                             interface=self._interface)
    188188
     189""" Legacy: TCP4ServerEndpoint """
     190class TCP4ServerEndpoint(TCPServerEndpoint):
     191    pass
    189192
    190 
    191 class TCP4ClientEndpoint(object):
     193class TCPClientEndpoint(object):
    192194    """
    193     TCP client endpoint with an IPv4 configuration.
     195    TCP client endpoint with an IP configuration.
    194196
    195197    @ivar _reactor: An L{IReactorTCP} provider.
    196198
     
    245247        except:
    246248            return defer.fail()
    247249
     250""" Legacy: TCP4ClientEndpoint """
     251class TCP4ClientEndpoint(TCPClientEndpoint):
     252    pass
    248253
    249 
    250 class SSL4ServerEndpoint(object):
     254class SSLServerEndpoint(object):
    251255    """
    252     SSL secured TCP server endpoint with an IPv4 configuration.
     256    SSL secured TCP server endpoint with an IP configuration.
    253257
    254258    @ivar _reactor: An L{IReactorSSL} provider.
    255259
     
    301305                             backlog=self._backlog,
    302306                             interface=self._interface)
    303307
     308""" Legacy: SSL4ServerEndpoint """
     309class SSL4ServerEndpoint(SSLServerEndpoint):
     310    pass
    304311
    305 
    306 class SSL4ClientEndpoint(object):
     312class SSLClientEndpoint(object):
    307313    """
    308     SSL secured TCP client endpoint with an IPv4 configuration
     314    SSL secured TCP client endpoint with an IP configuration
    309315
    310316    @ivar _reactor: An L{IReactorSSL} provider.
    311317
     
    369375        except:
    370376            return defer.fail()
    371377
    372 
     378""" Legacy: SSL4ClientEndpoint """
     379class SSL4ClientEndpoint(SSLClientEndpoint):
     380    pass
    373381
    374382class UNIXServerEndpoint(object):
    375383    """
     
    652660
    653661# Mappings from description "names" to endpoint constructors.
    654662_endpointServerFactories = {
    655     'TCP': TCP4ServerEndpoint,
    656     'SSL': SSL4ServerEndpoint,
     663    'TCP': TCPServerEndpoint,
     664    'SSL': SSLServerEndpoint,
    657665    'UNIX': UNIXServerEndpoint,
    658666    }
    659667
    660668_endpointClientFactories = {
    661     'TCP': TCP4ClientEndpoint,
    662     'SSL': SSL4ClientEndpoint,
     669    'TCP': TCPClientEndpoint,
     670    'SSL': SSLClientEndpoint,
    663671    'UNIX': UNIXClientEndpoint,
    664672    }
    665673
  • twisted/internet/iocpreactor/tcp.py

    diff -ru ../Twisted-11.0.0/twisted/internet/iocpreactor/tcp.py ./twisted/internet/iocpreactor/tcp.py
    old new  
    261261    def __init__(self, host, port, bindAddress, connector, reactor):
    262262        self.connector = connector
    263263        self.addr = (host, port)
     264        self.addressFamily = connector.family
    264265        self.reactor = reactor
    265266        # ConnectEx documentation says socket _has_ to be bound
    266267        if bindAddress is None:
     
    352353
    353354    def getHost(self):
    354355        """
    355         Returns an IPv4Address.
     356        Returns an IPAddress.
    356357
    357358        This indicates the address from which I am connecting.
    358359        """
    359         return address.IPv4Address('TCP', *self.socket.getsockname())
     360        return address.IPAddress('TCP', self.socket.family, *self.socket.getsockname())
    360361
    361362
    362363    def getPeer(self):
    363364        """
    364         Returns an IPv4Address.
     365        Returns an IPAddress.
    365366
    366367        This indicates the address that I am connected to.
    367368        """
    368         return address.IPv4Address('TCP', *self.realAddress)
     369        return address.IPv4Address('TCP', self.addressFamily, *self.realAddress)
    369370
    370371
    371372    def __repr__(self):
     
    423424
    424425    def getHost(self):
    425426        """
    426         Returns an IPv4Address.
     427        Returns an IPAddress.
    427428
    428429        This indicates the server's address.
    429430        """
     
    432433
    433434    def getPeer(self):
    434435        """
    435         Returns an IPv4Address.
     436        Returns an IPAddress.
    436437
    437438        This indicates the client's address.
    438439        """
     
    482483
    483484
    484485    def startListening(self):
     486        # Get the correct address family by using getaddrinfo() on the interface address
     487        ai = socket.getaddrinfo(self.interface, self.port)
     488        self.addressFamily = ai[0][0]
     489       
    485490        try:
    486491            skt = self.reactor.createSocket(self.addressFamily,
    487492                                            self.socketType)
     
    574579
    575580    def getHost(self):
    576581        """
    577         Returns an IPv4Address.
     582        Returns an IPAddress.
    578583
    579584        This indicates the server's address.
    580585        """
    581         return address.IPv4Address('TCP', *self.socket.getsockname())
     586        return address.IPAddress('TCP', self.socket.family, *self.socket.getsockname())
    582587
    583588
    584589    def cbAccept(self, rc, bytes, evt):
     
    605610            assert family == self.addressFamily
    606611
    607612            protocol = self.factory.buildProtocol(
    608                 address._ServerFactoryIPv4Address('TCP', rAddr[0], rAddr[1]))
     613                address._ServerFactoryIPAddress('TCP', family, rAddr[0], rAddr[1]))
    609614            if protocol is None:
    610615                evt.newskt.close()
    611616            else:
    612617                s = self.sessionno
    613618                self.sessionno = s+1
    614619                transport = Server(evt.newskt, protocol,
    615                         address.IPv4Address('TCP', rAddr[0], rAddr[1]),
    616                         address.IPv4Address('TCP', lAddr[0], lAddr[1]),
     620                        address.IPAddress('TCP', family, rAddr[0], rAddr[1]),
     621                        address.IPAddress('TCP', family, lAddr[0], lAddr[1]),
    617622                        s, self.reactor)
    618623                protocol.makeConnection(transport)
    619624            return True
  • twisted/internet/iocpreactor/udp.py

    diff -ru ../Twisted-11.0.0/twisted/internet/iocpreactor/udp.py ./twisted/internet/iocpreactor/udp.py
    old new  
    5151
    5252        abstract.FileHandle.__init__(self, reactor)
    5353
     54        # Get the correct address family by using getaddrinfo() on the interface address
     55        ai = socket.getaddrinfo(self.interface, self.port)
     56        self.addressFamily = ai[0][0]
     57       
    5458        skt = socket.socket(self.addressFamily, self.socketType)
    5559        addrLen = _iocp.maxAddrLen(skt.fileno())
    5660        self.addressBuffer = _iocp.AllocateReadBuffer(addrLen)
     
    269273
    270274    def getHost(self):
    271275        """
    272         Returns an IPv4Address.
     276        Returns an IPAddress.
    273277
    274278        This indicates the address from which I am connecting.
    275279        """
    276         return address.IPv4Address('UDP', *self.socket.getsockname())
     280        return address.IPAddress('UDP', self.socket.family, *self.socket.getsockname())
    277281
    278282
    279283
  • twisted/internet/tcp.py

    diff -ru ../Twisted-11.0.0/twisted/internet/tcp.py ./twisted/internet/tcp.py
    old new  
    695695        # BaseClient.__init__ is invoked later
    696696        self.connector = connector
    697697        self.addr = (host, port)
    698 
     698        self.addressFamily = connector.family
     699       
    699700        whenDone = self.resolveAddress
    700701        err = None
    701702        skt = None
     
    714715        self._finishInit(whenDone, skt, err, reactor)
    715716
    716717    def getHost(self):
    717         """Returns an IPv4Address.
     718        """Returns an IPAddress.
    718719
    719720        This indicates the address from which I am connecting.
    720721        """
    721         return address.IPv4Address('TCP', *self.socket.getsockname())
     722        return address.IPAddress('TCP', self.socket.family, *self.socket.getsockname())
    722723
    723724    def getPeer(self):
    724         """Returns an IPv4Address.
     725        """Returns an IPAddress.
    725726
    726727        This indicates the address that I am connected to.
    727728        """
    728         return address.IPv4Address('TCP', *self.realAddress)
     729        return address.IPAddress('TCP', self.addressFamily, *self.realAddress)
    729730
    730731    def __repr__(self):
    731732        s = '<%s to %s at %x>' % (self.__class__, self.addr, unsignedID(self))
     
    776777
    777778
    778779    def getHost(self):
    779         """Returns an IPv4Address.
     780        """Returns an IPAddress.
    780781
    781782        This indicates the server's address.
    782783        """
    783         return address.IPv4Address('TCP', *self.socket.getsockname())
     784        return address.IPAddress('TCP', self.socket.family, *self.socket.getsockname())
    784785
    785786    def getPeer(self):
    786         """Returns an IPv4Address.
     787        """Returns an IPAddress.
    787788
    788789        This indicates the client's address.
    789790        """
    790         return address.IPv4Address('TCP', *self.client)
     791        return address.IPAddress('TCP', self.socket.family, *self.client)
    791792
    792793
    793794
     
    848849            return "<%s of %s (not listening)>" % (self.__class__, self.factory.__class__)
    849850
    850851    def createInternetSocket(self):
     852        # Get the correct address family by using getaddrinfo() on the interface address
     853        ai = socket.getaddrinfo(self.interface, self.port)
     854        self.addressFamily = ai[0][0]
    851855        s = base.BasePort.createInternetSocket(self)
    852856        if platformType == "posix" and sys.platform != "cygwin":
    853857            s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
     
    863867        try:
    864868            skt = self.createInternetSocket()
    865869            skt.bind((self.interface, self.port))
     870            pass
    866871        except socket.error, le:
    867872            raise CannotListenError, (self.interface, self.port, le)
    868873
     
    885890
    886891
    887892    def _buildAddr(self, (host, port)):
    888         return address._ServerFactoryIPv4Address('TCP', host, port)
     893        return address._ServerFactoryIPAddress('TCP', self.addressFamily, host, port)
    889894
    890895
    891896    def doRead(self):
     
    939944                    raise
    940945
    941946                fdesc._setCloseOnExec(skt.fileno())
     947               
     948                # IPv6 addresses have usually more than two fields, reduce them.
     949                if len(addr) > 2:
     950                    addr = addr[0:2]
     951               
    942952                protocol = self.factory.buildProtocol(self._buildAddr(addr))
    943953                if protocol is None:
    944954                    skt.close()
     
    10091019        return reflect.qual(self.factory.__class__)
    10101020
    10111021    def getHost(self):
    1012         """Returns an IPv4Address.
     1022        """Returns an IPAddress.
    10131023
    10141024        This indicates the server's address.
    10151025        """
    1016         return address.IPv4Address('TCP', *self.socket.getsockname())
     1026        return address.IPAddress('TCP', self.socket.family, *self.socket.getsockname())
    10171027
    10181028class Connector(base.BaseConnector):
    10191029    def __init__(self, host, port, factory, timeout, bindAddress, reactor=None):
     1030        ai = socket.getaddrinfo(host, port)
     1031        self.family = ai[0][0]
    10201032        self.host = host
    10211033        if isinstance(port, types.StringTypes):
    10221034            try:
     
    10311043        return Client(self.host, self.port, self.bindAddress, self, self.reactor)
    10321044
    10331045    def getDestination(self):
    1034         return address.IPv4Address('TCP', self.host, self.port)
     1046        return address.IPAddress('TCP', self.family, self.host, self.port)
  • twisted/internet/udp.py

    diff -ru ../Twisted-11.0.0/twisted/internet/udp.py ./twisted/internet/udp.py
    old new  
    8686        self._connectToProtocol()
    8787
    8888    def _bindSocket(self):
     89        # Get the correct address family by using getaddrinfo() on the interface address
     90        ai = socket.getaddrinfo(self.interface, self.port)
     91        self.addressFamily = ai[0][0]
     92       
    8993        try:
    9094            skt = self.createInternetSocket()
    9195            skt.bind((self.interface, self.port))
     
    238242
    239243    def getHost(self):
    240244        """
    241         Returns an IPv4Address.
     245        Returns an IPAddress.
    242246
    243247        This indicates the address from which I am connecting.
    244248        """
    245         return address.IPv4Address('UDP', *self.socket.getsockname())
     249        return address.IPAddress('UDP', self.socket.family, *self.socket.getsockname())
    246250
    247251
    248252