Ticket #3014: ipv6.2.patch

File ipv6.2.patch, 56.1 KB (added by dripton, 9 years ago)

Version 3 of the ipv6 patch

  • twisted/internet/abstract.py

    diff --git a/twisted/internet/abstract.py b/twisted/internet/abstract.py
    index 4419d61..eea676a 100644
    a b  
    11# -*- test-case-name: twisted.test.test_abstract -*-
    2 # Copyright (c) 2001-2007 Twisted Matrix Laboratories.
     2# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
    33# See LICENSE for details.
    44
    55
    API Stability: stable 
    1010Maintainer: U{Itamar Shtull-Trauring<mailto:twisted@itamarst.org>}
    1111"""
    1212
     13import socket
     14
    1315from zope.interface import implements
    1416
    1517# Twisted Imports
    def isIPAddress(addr): 
    366368    return False
    367369
    368370
     371def isIPv6Address(ip):
     372    """
     373    Return True iff ip is a valid bare IPv6 address.
     374
     375    Return False for 'enhanced' IPv6 addresses like '::1%lo' and '::1/128'
     376    """
     377    try:
     378        socket.inet_pton(socket.AF_INET6, ip)
     379    except (ValueError, socket.error):
     380        return False
     381    return True
     382
     383
    369384__all__ = ["FileDescriptor"]
  • twisted/internet/address.py

    diff --git a/twisted/internet/address.py b/twisted/internet/address.py
    index b349080..3f25770 100644
    a b class IPv4Address(object): 
    2121    # _bwHack is given to old users who think we are a tuple. They expected
    2222    # addr[0] to define the socket type rather than the address family, so
    2323    # the value comes from a different namespace than the new .type value:
    24    
     24
    2525    #  type = map[_bwHack]
    2626    # map = { 'SSL': 'TCP', 'INET': 'TCP', 'INET_UDP': 'UDP' }
    2727
    2828    implements(IAddress)
    29    
     29
    3030    def __init__(self, type, host, port, _bwHack = None):
    31         assert type in ('TCP', 'UDP')
     31        if type not in ('TCP', 'UDP'):
     32            raise ValueError, "illegal transport type"
    3233        self.type = type
    3334        self.host = host
    3435        self.port = port
    class IPv4Address(object): 
    5657    def __str__(self):
    5758        return 'IPv4Address(%s, %r, %d)' % (self.type, self.host, self.port)
    5859
     60class IPv6Address(object):
     61    """
     62    Object representing an IPv6 socket endpoint.
     63
     64    @ivar type: A string describing the type of transport, either 'TCP' or 'UDP'.
     65    @ivar host: A string containing the coloned-oct IP address.
     66    @ivar port: An integer representing the port number.
     67    @ivar flowinfo: An integer representing the sockaddr-in6 flowinfo
     68    @ivar scopeid: An integer representing the sockaddr-in6 scopeid
     69    """
     70
     71    implements(IAddress)
     72
     73    def __init__(self, type, host, port, flowinfo=0, scopeid=0):
     74        if type not in ('TCP', 'UDP'):
     75            raise ValueError, "illegal transport type"
     76        self.type = type
     77        self.host = host
     78        self.port = port
     79        self.flowinfo = flowinfo
     80        self.scopeid = scopeid
     81
     82    def __eq__(self, other):
     83        if isinstance(other, tuple):
     84            return tuple(self) == other
     85        elif isinstance(other, IPv6Address):
     86            a = (self.type, self.host, self.port, self.flowinfo, self.scopeid)
     87            b = (other.type, other.host, other.port, other.flowinfo, other.scopeid)
     88            return a == b
     89        return False
     90
     91    def __str__(self):
     92        return 'IPv6Address(%s, %r, %d, %s, %s, %s)' % (self.type, self.host,
     93          self.port, self.flowinfo, self.scopeid)
    5994
    6095class UNIXAddress(object):
    6196    """
    class UNIXAddress(object): 
    66101    """
    67102
    68103    implements(IAddress)
    69    
     104
    70105    def __init__(self, name, _bwHack='UNIX'):
    71106        self.name = name
    72107        self._bwHack = _bwHack
    73    
     108
    74109    def __getitem__(self, index):
    75110        warnings.warn("UNIXAddress.__getitem__ is deprecated.  Use attributes instead.",
    76111                      category=DeprecationWarning, stacklevel=2)
    class UNIXAddress(object): 
    100135
    101136class _ServerFactoryIPv4Address(IPv4Address):
    102137    """Backwards compatability hack. Just like IPv4Address in practice."""
    103    
     138
    104139    def __eq__(self, other):
    105140        if isinstance(other, tuple):
    106141            warnings.warn("IPv4Address.__getitem__ is deprecated.  Use attributes instead.",
  • twisted/internet/base.py

    diff --git a/twisted/internet/base.py b/twisted/internet/base.py
    index 3337fca..8f7e16c 100644
    a b class DelayedCall(styles.Ephemeral): 
    194194        return "".join(L)
    195195
    196196
     197def getHostByName(name):
     198    """
     199    Call socket.getaddrinfo, using the args and return value type of
     200    socket.gethostbyname
     201    """
     202    lst = socket.getaddrinfo(name, None)
     203    res = lst[0]
     204    (family, socktype, proto, canonname, sockaddr) = res
     205    address = sockaddr[0]
     206    return address
     207
     208
    197209class ThreadedResolver:
    198210    implements(IResolverSimple)
    199211
    class ThreadedResolver: 
    224236            else:
    225237                userDeferred.callback(result)
    226238
     239
     240
    227241    def getHostByName(self, name, timeout = (1, 3, 11, 45)):
    228242        if timeout:
    229243            timeoutDelay = reduce(operator.add, timeout)
    230244        else:
    231245            timeoutDelay = 60
    232246        userDeferred = defer.Deferred()
    233         lookupDeferred = threads.deferToThread(socket.gethostbyname, name)
     247        lookupDeferred = threads.deferToThread(getHostByName, name)
    234248        cancelCall = self.reactor.callLater(
    235249            timeoutDelay, self._cleanup, name, lookupDeferred)
    236250        self._runningQueries[lookupDeferred] = (userDeferred, cancelCall)
    class BlockingResolver: 
    242256
    243257    def getHostByName(self, name, timeout = (1, 3, 11, 45)):
    244258        try:
    245             address = socket.gethostbyname(name)
     259            address = getHostByName(name)
    246260        except socket.error:
    247261            msg = "address %r not found" % (name,)
    248262            err = error.DNSLookupError(msg)
  • twisted/internet/interfaces.py

    diff --git a/twisted/internet/interfaces.py b/twisted/internet/interfaces.py
    index d9c2744..3d1b45a 100644
    a b class IReactorTCP(Interface): 
    209209                 docs for details.
    210210        """
    211211
     212class IReactorTCP6(Interface):
     213
     214    def listenTCP6(port, factory, backlog=50, interface=''):
     215        """
     216        Connects a given protocol factory to the given numeric TCP/IPv6 port.
     217
     218        @param port: a port number on which to listen
     219
     220        @param factory: a L{twisted.internet.protocol.ServerFactory} instance
     221
     222        @param backlog: size of the listen queue
     223
     224        @param interface: the hostname to bind to, defaults to '' (all)
     225
     226        @return: an object that provides L{IListeningPort}.
     227
     228        @raise CannotListenError: as defined here
     229                                  L{twisted.internet.error.CannotListenError},
     230                                  if it cannot listen on this port (e.g., it
     231                                  cannot bind to the required port number)
     232        """
     233
     234    def connectTCP6(host, port, factory, timeout=30, bindAddress=None):
     235        """
     236        Connect a TCPv6 client.
     237
     238        @param host: a host name
     239
     240        @param port: a port number
     241
     242        @param factory: a L{twisted.internet.protocol.ClientFactory} instance
     243
     244        @param timeout: number of seconds to wait before assuming the
     245                        connection has failed.
     246
     247        @param bindAddress: a (host, port) tuple of local address to bind
     248                            to, or None.
     249
     250        @return: An object which provides L{IConnector}. This connector will
     251                 call various callbacks on the factory when a connection is
     252                 made, failed, or lost - see
     253                 L{ClientFactory<twisted.internet.protocol.ClientFactory>}
     254                 docs for details.
     255        """
     256
    212257class IReactorSSL(Interface):
    213258
    214259    def connectSSL(host, port, factory, contextFactory, timeout=30, bindAddress=None):
  • twisted/internet/posixbase.py

    diff --git a/twisted/internet/posixbase.py b/twisted/internet/posixbase.py
    index ab2d9b5..691f265 100644
    a b  
    11# -*- test-case-name: twisted.test.test_internet -*-
    22#
    3 # Copyright (c) 2001-2007 Twisted Matrix Laboratories.
     3# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
    44# See LICENSE for details.
    55
    66
    from zope.interface import implements, classImplements 
    2222
    2323from twisted.internet.interfaces import IReactorUNIX, IReactorUNIXDatagram
    2424from twisted.internet.interfaces import IReactorTCP, IReactorUDP, IReactorSSL, IReactorArbitrary
     25from twisted.internet.interfaces import IReactorTCP6
    2526from twisted.internet.interfaces import IReactorProcess, IReactorMulticast
    2627from twisted.internet.interfaces import IHalfCloseableDescriptor
    2728from twisted.internet import error
    class PosixReactorBase(ReactorBase): 
    167168    """
    168169    A basis for reactors that use file descriptors.
    169170    """
    170     implements(IReactorArbitrary, IReactorTCP, IReactorUDP, IReactorMulticast)
     171    implements(IReactorArbitrary, IReactorTCP, IReactorTCP6, IReactorUDP,
     172               IReactorMulticast)
    171173
    172174    def __init__(self):
    173175        ReactorBase.__init__(self)
    class PosixReactorBase(ReactorBase): 
    481483        c.connect()
    482484        return c
    483485
     486    # IReactorTCP6
     487
     488    def listenTCP6(self, port, factory, backlog=50, interface=''):
     489        """
     490        @see: twisted.internet.interfaces.IReactorTCP.listenTCP6
     491        """
     492        p = tcp.Port6(port, factory, backlog, interface, self)
     493        p.startListening()
     494        return p
     495
     496    def connectTCP6(self, host, port, factory, timeout=30, bindAddress=None,
     497                    flowinfo=0, scopeid=0):
     498        """
     499        @see: twisted.internet.interfaces.IReactorTCP.connectTCP6
     500        """
     501        c = tcp.Connector6(host, port, factory, timeout, bindAddress, self,
     502                           flowinfo, scopeid)
     503        c.connect()
     504        return c
     505
    484506    # IReactorSSL (sometimes, not implemented)
    485507
    486508    def connectSSL(self, host, port, factory, contextFactory, timeout=30, bindAddress=None):
  • twisted/internet/protocol.py

    diff --git a/twisted/internet/protocol.py b/twisted/internet/protocol.py
    index 15e344c..5909d09 100644
    a b  
    11# -*- test-case-name: twisted.test.test_factories -*-
    22#
    3 # Copyright (c) 2001-2004 Twisted Matrix Laboratories.
     3# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
    44# See LICENSE for details.
    55
    66
    class _InstanceFactory(ClientFactory): 
    137137    """Factory used by ClientCreator."""
    138138
    139139    noisy = False
    140    
     140
    141141    def __init__(self, reactor, instance, deferred):
    142142        self.reactor = reactor
    143143        self.instance = instance
    class _InstanceFactory(ClientFactory): 
    145145
    146146    def __repr__(self):
    147147        return "<ClientCreator factory: %r>" % (self.instance, )
    148    
     148
    149149    def buildProtocol(self, addr):
    150150        self.reactor.callLater(0, self.deferred.callback, self.instance)
    151151        del self.deferred
    class ClientCreator: 
    162162    The various connect* methods create a protocol instance using the given
    163163    protocol class and arguments, and connect it, returning a Deferred of the
    164164    resulting protocol instance.
    165    
     165
    166166    Useful for cases when we don't really need a factory.  Mainly this
    167167    is when there is no shared state between protocol instances, and no need
    168168    to reconnect.
    class ClientCreator: 
    181181        self.reactor.connectTCP(host, port, f, timeout=timeout, bindAddress=bindAddress)
    182182        return d
    183183
     184    def connectTCP6(self, host, port, timeout=30, bindAddress=None):
     185        """
     186        Connect to remote host, return Deferred of resulting protocol instance.
     187        @see twisted.internet.interfaces.IReactorTCP6.connectTCP6
     188        """
     189        d = defer.Deferred()
     190        f = _InstanceFactory(self.reactor, self.protocolClass(*self.args,
     191                                                    **self.kwargs), d)
     192        self.reactor.connectTCP6(host, port, f, timeout=timeout,
     193                                 bindAddress=bindAddress)
     194        return d
     195
    184196    def connectUNIX(self, address, timeout = 30, checkPID=0):
    185197        """Connect to Unix socket, return Deferred of resulting protocol instance."""
    186198        d = defer.Deferred()
    187199        f = _InstanceFactory(self.reactor, self.protocolClass(*self.args, **self.kwargs), d)
    188200        self.reactor.connectUNIX(address, f, timeout = timeout, checkPID=checkPID)
    189201        return d
    190    
     202
    191203    def connectSSL(self, host, port, contextFactory, timeout=30, bindAddress=None):
    192204        """Connect to SSL server, return Deferred of resulting protocol instance."""
    193205        d = defer.Deferred()
    class FileWrapper: 
    630642    def pauseProducing(self):
    631643        # Never sends data anyways
    632644        pass
    633    
     645
    634646    def stopProducing(self):
    635647        self.loseConnection()
    636        
    637648
    638 __all__ = ["Factory", "ClientFactory", "ReconnectingClientFactory", "connectionDone",
     649
     650__all__ = ["Factory", "ClientFactory", "ReconnectingClientFactory", "connectionDone",
    639651           "Protocol", "ProcessProtocol", "FileWrapper", "ServerFactory",
    640652           "AbstractDatagramProtocol", "DatagramProtocol", "ConnectedDatagramProtocol",
    641653           "ClientCreator"]
  • twisted/internet/tcp.py

    diff --git a/twisted/internet/tcp.py b/twisted/internet/tcp.py
    index bbb7029..2a567eb 100644
    a b if platformType == 'win32': 
    5252    ENOMEM = object()
    5353    EAGAIN = EWOULDBLOCK
    5454    from errno import WSAECONNRESET as ECONNABORTED
    55    
    56     from twisted.python.win32 import formatError as strerror   
     55
     56    from twisted.python.win32 import formatError as strerror
    5757else:
    5858    from errno import EPERM
    5959    from errno import EINVAL
    else: 
    7070    from errno import ENOMEM
    7171    from errno import EAGAIN
    7272    from errno import ECONNABORTED
    73    
     73
    7474    from os import strerror
    7575
    7676from errno import errorcode
    class Connector(base.BaseConnector): 
    892892
    893893    def getDestination(self):
    894894        return address.IPv4Address('TCP', self.host, self.port, 'INET')
     895
     896
     897class Client6(Client):
     898    """
     899    A TCP6 client.
     900    """
     901    addressFamily = socket.AF_INET6
     902
     903    def __init__(self, host, port, bindAddress, connector, reactor=None,
     904                 flowinfo=0, scopeid=0):
     905        Client.__init__(self, host, port, bindAddress, connector, reactor)
     906        self.addr = (host, port, flowinfo, scopeid)
     907
     908    def resolveAddress(self):
     909        """
     910        Lookup the IPv6 address for self.addr[0] if necessary, then set
     911        self.realAddress to that IPv6 address.
     912        """
     913        if abstract.isIPv6Address(self.addr[0]):
     914            self._setRealAddress(self.addr[0])
     915        else:
     916            d = self.reactor.resolve(self.addr[0])
     917            d.addCallbacks(self._setRealAddress, self.failIfNotConnected)
     918
     919    def _setRealAddress(self, address):
     920        """
     921        Set self.realAddress[0] to address.  Set the remaining parts of
     922        self.realAddress to the corresponding parts of self.addr.
     923        """
     924        self.realAddress = (address, self.addr[1], self.addr[2], self.addr[3])
     925        self.doConnect()
     926
     927    def getHost(self):
     928        """
     929        Returns an IPv6Address.
     930
     931        This indicates the address from which I am connecting.
     932        """
     933        return address.IPv6Address('TCP', *(self.socket.getsockname()))
     934
     935    def getPeer(self):
     936        """
     937        Returns an IPv6Address.
     938
     939        This indicates the address that I am connected to.
     940        """
     941        return address.IPv6Address('TCP', *(self.addr))
     942
     943    def __repr__(self):
     944        s = '<%s to %s at %x>' % (self.__class__, self.addr, unsignedID(self))
     945        return s
     946
     947
     948class Server6(Server):
     949    """
     950    IPv6 serverside socket-stream connection class.
     951
     952    This is a serverside network connection transport; a socket which came from
     953    an accept() on a server.
     954    """
     955    def getHost(self):
     956        """
     957        Returns an IPv6Address.
     958
     959        This indicates the server's address.
     960        """
     961        return address.IPv6Address('TCP', *(self.socket.getsockname()))
     962
     963    def getPeer(self):
     964        """
     965        Returns an IPv6Address.
     966
     967        This indicates the client's address.
     968        """
     969        return address.IPv6Address('TCP', *(self.client))
     970
     971
     972class Connector6(base.BaseConnector):
     973    """
     974    IPv6 implementation of connector
     975
     976    @ivar flowinfo An integer representing the sockaddr-in6 flowinfo
     977    @ivar scopeid An integer representing the sockaddr-in6 scopeid
     978    """
     979
     980    def __init__(self, host, port, factory, timeout, bindAddress,
     981                 reactor=None, flowinfo=0, scopeid=0):
     982        self.host = host
     983        if isinstance(port, types.StringTypes):
     984            try:
     985                port = socket.getservbyname(port, 'tcp')
     986            except socket.error, e:
     987                raise error.ServiceNameUnknownError(string="%s (%r)" % (e, port))
     988        self.port = port
     989        self.bindAddress = bindAddress
     990        self.flowinfo = flowinfo
     991        self.scopeid = scopeid
     992        base.BaseConnector.__init__(self, factory, timeout, reactor)
     993
     994    def _makeTransport(self):
     995        """
     996        Build and return a TCP6 client for the connector's transport.
     997        """
     998        return Client6(self.host, self.port, self.bindAddress, self,
     999                      self.reactor, self.flowinfo, self.scopeid)
     1000
     1001    def getDestination(self):
     1002        """
     1003        @see twisted.internet.interfaces.IConnector.getDestination
     1004        """
     1005        return address.IPv6Address('TCP', self.host, self.port, self.flowinfo,
     1006                                   self.scopeid)
     1007
     1008
     1009class Port6(Port):
     1010    """
     1011    I am a TCP server port, listening for connections.
     1012
     1013    When a connection is accepted, I will call my factory's buildProtocol with
     1014    the incoming connection as an argument, according to the specification
     1015    described in twisted.internet.interfaces.IProtocolFactory.
     1016
     1017    If you wish to change the sort of transport that will be used, my
     1018    `transport' attribute will be called with the signature expected for
     1019    Server.__init__, so it can be replaced.
     1020    """
     1021    addressFamily = socket.AF_INET6
     1022    transport = Server6
     1023
     1024    def _buildAddr(self, (host, port, flowinfo, scopeid)):
     1025        """
     1026        Build and return an IPv6Address from the passed sockaddr-in6 tuple.
     1027        """
     1028        return address.IPv6Address('TCP', host, port, flowinfo, scopeid)
     1029
     1030    def getHost(self):
     1031        """
     1032        Returns an IPv6Address.
     1033
     1034        This indicates the server's address.
     1035        """
     1036        return address.IPv6Address('TCP', *(self.socket.getsockname()))
  • twisted/test/test_abstract.py

    diff --git a/twisted/test/test_abstract.py b/twisted/test/test_abstract.py
    index 44b4646..294a69e 100644
    a b  
    1 # Copyright (c) 2007 Twisted Matrix Laboratories.
     1# Copyright (c) 2007-2008 Twisted Matrix Laboratories.
    22# See LICENSE for details.
    33
    44"""
    Tests for generic file descriptor based reactor support code. 
    88from twisted.trial.unittest import TestCase
    99
    1010from twisted.internet.abstract import isIPAddress
     11from twisted.internet.abstract import isIPv6Address
    1112
    1213
    1314class AddressTests(TestCase):
    class AddressTests(TestCase): 
    8182        self.assertFalse(isIPAddress('0.0.256.0'))
    8283        self.assertFalse(isIPAddress('0.0.0.256'))
    8384        self.assertFalse(isIPAddress('256.256.256.256'))
     85
     86
     87class IPv6AddressTests(TestCase):
     88    """
     89    Tests for IPv6 addresses.
     90    """
     91    def test_hexadecimalColoned(self):
     92        """
     93        L{isIPv6Address} should return C{True} for any valid colon-separated
     94        hexadecimal representation of an IPv6 address.
     95        """
     96        self.assertTrue(isIPv6Address('::1'))
     97        self.assertTrue(isIPv6Address('fe80::215:cbfe:feac:8888'))
     98        self.assertTrue(isIPv6Address('fe80::215:cbfe:feac:8888'))
     99        self.assertTrue(isIPv6Address('fe80:5:5:5:215:cbfe:feac:8888'))
     100
     101    def test_illegalHexadecimalColoned(self):
     102        """
     103        L{isIPv6Address} should return C{False} for any invalid colon-separated
     104        hexadecimal representation of an IPv6 address.
     105        """
     106        self.assertFalse(isIPv6Address(':1::2'))
     107        self.assertFalse(isIPv6Address('fe80:5:5:5:215:cbfe:feac:8888:5'))
     108        self.assertFalse(isIPv6Address('g::h'))
  • twisted/test/test_tcp.py

    diff --git a/twisted/test/test_tcp.py b/twisted/test/test_tcp.py
    index ac7b8b9..d3cf433 100644
    a b from twisted.trial import unittest 
    1414from twisted.python.log import msg
    1515from twisted.internet import protocol, reactor, defer, interfaces
    1616from twisted.internet import error
    17 from twisted.internet.address import IPv4Address
     17from twisted.internet.address import IPv4Address, IPv6Address
    1818from twisted.internet.interfaces import IHalfCloseableProtocol, IPullProducer
    1919from twisted.protocols import policies
    2020
    class PortCleanerUpper(unittest.TestCase): 
    179179
    180180
    181181class ListeningTestCase(PortCleanerUpper):
     182    """
     183    Tests for listening on a port.
     184
     185    @ivar listenMethod Method used to listen
     186    @ivar connectMethod Method used to connect
     187    @ivar loopback Loopback interface to use for testing
     188    """
     189
     190    listenMethod = reactor.listenTCP
     191    connectMethod = reactor.connectTCP
     192    loopback = "127.0.0.1"
    182193
    183194    def testListen(self):
    184195        f = MyServerFactory()
    185         p1 = reactor.listenTCP(0, f, interface="127.0.0.1")
     196        p1 = self.listenMethod(0, f, interface=self.loopback)
    186197        self.failUnless(interfaces.IListeningPort.providedBy(p1))
    187198        return p1.stopListening()
    188199
    189200    def testStopListening(self):
    190201        f = MyServerFactory()
    191         port = reactor.listenTCP(0, f, interface="127.0.0.1")
     202        port = self.listenMethod(0, f, interface=self.loopback)
    192203        n = port.getHost().port
    193204        self.ports.append(port)
    194205
    195206        def cbStopListening(ignored):
    196207            # Make sure we can rebind the port right away
    197             port = reactor.listenTCP(n, f, interface="127.0.0.1")
     208            port = self.listenMethod(n, f, interface=self.loopback)
    198209            self.ports.append(port)
    199210
    200211        d = defer.maybeDeferred(port.stopListening)
    class ListeningTestCase(PortCleanerUpper): 
    204215    def testNumberedInterface(self):
    205216        f = MyServerFactory()
    206217        # listen only on the loopback interface
    207         p1 = reactor.listenTCP(0, f, interface='127.0.0.1')
     218        p1 = self.listenMethod(0, f, interface=self.loopback)
    208219        return p1.stopListening()
    209220
    210221    def testPortRepr(self):
    211222        f = MyServerFactory()
    212         p = reactor.listenTCP(0, f)
     223        p = self.listenMethod(0, f)
    213224        portNo = str(p.getHost().port)
    214225        self.failIf(repr(p).find(portNo) == -1)
    215226        def stoppedListening(ign):
    class ListeningTestCase(PortCleanerUpper): 
    225236        """
    226237        server = MyServerFactory()
    227238        serverConnMade = server.protocolConnectionMade = defer.Deferred()
    228         port = reactor.listenTCP(0, server)
     239        port = self.listenMethod(0, server)
    229240        self.addCleanup(port.stopListening)
    230241
    231242        client = MyClientFactory()
    232243        clientConnMade = client.protocolConnectionMade = defer.Deferred()
    233         connector = reactor.connectTCP("127.0.0.1",
    234                                        port.getHost().port, client)
     244        connector = self.connectMethod(self.loopback, port.getHost().port,
     245                                       client)
    235246        self.addCleanup(connector.disconnect)
    236247        def check((serverProto, clientProto)):
    237248            portNumber = port.getHost().port
    class ListeningTestCase(PortCleanerUpper): 
    242253        return defer.gatherResults([serverConnMade, clientConnMade]
    243254            ).addCallback(check)
    244255
     256class ListeningIPv6TestCase(ListeningTestCase):
     257    """
     258    Tests for listening on a port using IPv6.
     259
     260    @ivar listenMethod Method used to listen
     261    @ivar connectMethod Method used to connect
     262    @ivar loopback Loopback interface to use for testing
     263    """
     264    listenMethod = reactor.listenTCP6
     265    connectMethod = reactor.connectTCP6
     266    loopback = "::1"
    245267
    246268
    247269def callWithSpew(f):
    def callWithSpew(f): 
    254276        sys.settrace(None)
    255277
    256278class LoopbackTestCase(PortCleanerUpper):
    257     """Test loopback connections."""
     279    """
     280    Test loopback connections.
    258281
    259     n = 10081
     282    @ivar listenMethod Method used to listen
     283    @ivar connectMethod Method used to connect
     284    @ivar loopback Loopback interface to use for testing
     285    @ivar addressFamily Socket address family to use
     286    """
    260287
     288    listenMethod = reactor.listenTCP
     289    connectMethod = reactor.connectTCP
     290    creatorConnectMethod = protocol.ClientCreator.connectTCP
     291    loopback = "127.0.0.1"
     292    addressFamily = socket.AF_INET
     293    n = 10081
    261294
    262295    def testClosePortInProtocolFactory(self):
    263296        f = ClosingFactory()
    264         port = reactor.listenTCP(0, f, interface="127.0.0.1")
     297        port = self.listenMethod(0, f, interface=self.loopback)
    265298        self.n = port.getHost().port
    266299        self.ports.append(port)
    267300        f.port = port
    268301        clientF = MyClientFactory()
    269         reactor.connectTCP("127.0.0.1", self.n, clientF)
     302        self.connectMethod(self.loopback, self.n, clientF)
    270303        def check(x):
    271304            self.assert_(clientF.protocol.made)
    272305            self.assert_(port.disconnected)
    class LoopbackTestCase(PortCleanerUpper): 
    278311
    279312    def testTcpNoDelay(self):
    280313        f = MyServerFactory()
    281         port = reactor.listenTCP(0, f, interface="127.0.0.1")
     314        port = self.listenMethod(0, f, interface=self.loopback)
    282315
    283316        self.n = port.getHost().port
    284317        self.ports.append(port)
    285318        clientF = MyClientFactory()
    286         reactor.connectTCP("127.0.0.1", self.n, clientF)
     319        self.connectMethod(self.loopback, self.n, clientF)
    287320
    288321        d = loopUntil(lambda: (f.called > 0 and
    289322                               getattr(clientF, 'protocol', None) is not None))
    class LoopbackTestCase(PortCleanerUpper): 
    301334
    302335    def testTcpKeepAlive(self):
    303336        f = MyServerFactory()
    304         port = reactor.listenTCP(0, f, interface="127.0.0.1")
     337        port = self.listenMethod(0, f, interface=self.loopback)
    305338        self.n = port.getHost().port
    306339        self.ports.append(port)
    307340        clientF = MyClientFactory()
    308         reactor.connectTCP("127.0.0.1", self.n, clientF)
     341        self.connectMethod(self.loopback, self.n, clientF)
    309342
    310343        d = loopUntil(lambda :(f.called > 0 and
    311344                               getattr(clientF, 'protocol', None) is not None))
    class LoopbackTestCase(PortCleanerUpper): 
    324357    def testFailing(self):
    325358        clientF = MyClientFactory()
    326359        # XXX we assume no one is listening on TCP port 69
    327         reactor.connectTCP("127.0.0.1", 69, clientF, timeout=5)
     360        self.connectMethod(self.loopback, 69, clientF, timeout=5)
    328361        def check(ignored):
    329362            clientF.reason.trap(error.ConnectionRefusedError)
    330363        return clientF.failDeferred.addCallback(check)
    class LoopbackTestCase(PortCleanerUpper): 
    357390
    358391        serverSockets = []
    359392        for i in xrange(10):
    360             serverSocket = socket.socket()
    361             serverSocket.bind(('127.0.0.1', 0))
     393            serverSocket = socket.socket(self.addressFamily)
     394            serverSocket.bind((self.loopback, 0))
    362395            serverSocket.listen(1)
    363396            serverSockets.append(serverSocket)
    364397        random.shuffle(serverSockets)
    class LoopbackTestCase(PortCleanerUpper): 
    376409                self.fail("Could not fail to connect - could not test errno for that case.")
    377410
    378411            serverSocket = serverSockets.pop()
    379             serverHost, serverPort = serverSocket.getsockname()
     412            serverHost, serverPort = serverSocket.getsockname()[:2]
    380413            serverSocket.close()
    381414
    382             connectDeferred = clientCreator.connectTCP(serverHost, serverPort)
     415            connectDeferred = self.creatorConnectMethod(clientCreator,
     416                                                        serverHost, serverPort)
    383417            connectDeferred.addCallback(connected)
    384418            return connectDeferred
    385419
    class LoopbackTestCase(PortCleanerUpper): 
    398432
    399433    def testConnectByServiceFail(self):
    400434        try:
    401             reactor.connectTCP("127.0.0.1", "thisbetternotexist",
     435            self.connectMethod(self.loopback, "thisbetternotexist",
    402436                               MyClientFactory())
    403437        except error.ServiceNameUnknownError:
    404438            return
    class LoopbackTestCase(PortCleanerUpper): 
    409443        d = defer.succeed(None)
    410444        try:
    411445            s = MyServerFactory()
    412             port = reactor.listenTCP(0, s, interface="127.0.0.1")
     446            port = self.listenMethod(0, s, interface=self.loopback)
    413447            self.n = port.getHost().port
    414448            socket.getservbyname = (lambda s, p,n=self.n:
    415449                                    s == 'http' and p == 'tcp' and n or 10)
    416450            self.ports.append(port)
    417451            cf = MyClientFactory()
    418452            try:
    419                 c = reactor.connectTCP('127.0.0.1', 'http', cf)
     453                c = self.connectMethod(self.loopback, 'http', cf)
    420454            except:
    421455                socket.getservbyname = serv
    422456                raise
    class LoopbackTestCase(PortCleanerUpper): 
    432466                                              '%s was not called' % (s,)))
    433467        return d
    434468
     469class LoopbackIPv6TestCase(LoopbackTestCase):
     470    """
     471    Test IPv6 loopback connections.
     472    """
     473    listenMethod = reactor.listenTCP6
     474    connectMethod = reactor.connectTCP6
     475    creatorConnectMethod = protocol.ClientCreator.connectTCP6
     476    loopback = "::1"
     477    addressFamily = socket.AF_INET6
     478
    435479
    436480class StartStopFactory(protocol.Factory):
    437481
    class ClientStartStopFactory(MyClientFactory): 
    466510
    467511
    468512class FactoryTestCase(PortCleanerUpper):
    469     """Tests for factories."""
     513    """
     514    Tests for factories.
     515
     516    @ivar listenMethod Method used to listen
     517    @ivar loopback Loopback interface to use for testing
     518    """
     519    listenMethod = reactor.listenTCP
     520    loopback = "127.0.0.1"
    470521
    471522    def testServerStartStop(self):
    472523        f = StartStopFactory()
    473524
    474525        # listen on port
    475         p1 = reactor.listenTCP(0, f, interface='127.0.0.1')
     526        p1 = self.listenMethod(0, f, interface=self.loopback)
    476527        self.n1 = p1.getHost().port
    477528        self.ports.append(p1)
    478529
    class FactoryTestCase(PortCleanerUpper): 
    482533    def _testServerStartStop(self, ignored, f, p1):
    483534        self.assertEquals((f.started, f.stopped), (1,0))
    484535        # listen on two more ports
    485         p2 = reactor.listenTCP(0, f, interface='127.0.0.1')
     536        p2 = self.listenMethod(0, f, interface=self.loopback)
    486537        self.n2 = p2.getHost().port
    487538        self.ports.append(p2)
    488         p3 = reactor.listenTCP(0, f, interface='127.0.0.1')
     539        p3 = self.listenMethod(0, f, interface=self.loopback)
    489540        self.n3 = p3.getHost().port
    490541        self.ports.append(p3)
    491542        d = loopUntil(lambda :(p2.connected == 1 and p3.connected == 1))
    class FactoryTestCase(PortCleanerUpper): 
    513564
    514565    def testClientStartStop(self):
    515566        f = ClosingFactory()
    516         p = reactor.listenTCP(0, f, interface="127.0.0.1")
     567        p = self.listenMethod(0, f, interface=self.loopback)
    517568        self.n = p.getHost().port
    518569        self.ports.append(p)
    519570        f.port = p
    class FactoryTestCase(PortCleanerUpper): 
    521572        d = loopUntil(lambda :p.connected)
    522573        def check(ignored):
    523574            factory = ClientStartStopFactory()
    524             reactor.connectTCP("127.0.0.1", self.n, factory)
     575            self.connectMethod(self.loopback, self.n, factory)
    525576            self.assert_(factory.started)
    526577            return loopUntil(lambda :factory.stopped)
    527578        d.addCallback(check)
    528579        d.addBoth(lambda _: self.cleanPorts(*self.ports))
    529580        return d
    530581
     582class FactoryIPv6TestCase(FactoryTestCase):
     583    """
     584    IPv6 Tests for factories.
     585
     586    @ivar listenMethod Method used to listen
     587    @ivar loopback Loopback interface to use for testing
     588    """
     589    listenMethod = reactor.listenTCP6
     590    loopback = "::1"
     591
    531592
    532593class ConnectorTestCase(PortCleanerUpper):
     594    """
     595    Tests for connectors.
     596
     597    @ivar listenMethod Method used to listen
     598    @ivar connectMethod Method used to connect
     599    @ivar loopback Loopback interface to use for testing
     600    """
     601    listenMethod = reactor.listenTCP
     602    connectMethod = reactor.connectTCP
     603    loopback = "127.0.0.1"
    533604
    534605    def testConnectorIdentity(self):
    535606        f = ClosingFactory()
    536         p = reactor.listenTCP(0, f, interface="127.0.0.1")
     607        p = self.listenMethod(0, f, interface=self.loopback)
    537608        n = p.getHost().port
    538609        self.ports.append(p)
    539610        f.port = p
    class ConnectorTestCase(PortCleanerUpper): 
    547618            factory.clientConnectionLost = lambda c, r: (l.append(c),
    548619                                                         m.append(r))
    549620            factory.startedConnecting = lambda c: l.append(c)
    550             connector = reactor.connectTCP("127.0.0.1", n, factory)
     621            connector = self.connectMethod(self.loopback, n, factory)
    551622            self.failUnless(interfaces.IConnector.providedBy(connector))
    552623            dest = connector.getDestination()
    553624            self.assertEquals(dest.type, "TCP")
    554             self.assertEquals(dest.host, "127.0.0.1")
     625            self.assertEquals(dest.host, self.loopback)
    555626            self.assertEquals(dest.port, n)
    556627
    557628            d = loopUntil(lambda :factory.stopped)
    class ConnectorTestCase(PortCleanerUpper): 
    564635
    565636    def testUserFail(self):
    566637        f = MyServerFactory()
    567         p = reactor.listenTCP(0, f, interface="127.0.0.1")
     638        p = self.listenMethod(0, f, interface=self.loopback)
    568639        n = p.getHost().port
    569640        self.ports.append(p)
    570641
    class ConnectorTestCase(PortCleanerUpper): 
    573644
    574645        factory = ClientStartStopFactory()
    575646        factory.startedConnecting = startedConnecting
    576         reactor.connectTCP("127.0.0.1", n, factory)
     647        self.connectMethod(self.loopback, n, factory)
    577648
    578649        d = loopUntil(lambda :factory.stopped)
    579650        def check(ignored):
    class ConnectorTestCase(PortCleanerUpper): 
    585656
    586657    def testReconnect(self):
    587658        f = ClosingFactory()
    588         p = reactor.listenTCP(0, f, interface="127.0.0.1")
     659        p = self.listenMethod(0, f, interface=self.loopback)
    589660        n = p.getHost().port
    590661        self.ports.append(p)
    591662        f.port = p
    class ConnectorTestCase(PortCleanerUpper): 
    596667            def clientConnectionLost(c, reason):
    597668                c.connect()
    598669            factory.clientConnectionLost = clientConnectionLost
    599             reactor.connectTCP("127.0.0.1", n, factory)
     670            self.connectMethod(self.loopback, n, factory)
    600671            return loopUntil(lambda :factory.failed)
    601672
    602673        def step2(ignored):
    class ConnectorTestCase(PortCleanerUpper): 
    609680        return d.addCallback(step1).addCallback(step2)
    610681
    611682
     683class ConnectorIPv6TestCase(ConnectorTestCase):
     684    """
     685    Tests for IPv6 connectors.
     686    """
     687    listenMethod = reactor.listenTCP6
     688    connectMethod = reactor.connectTCP6
     689    loopback = "::1"
     690
     691
    612692class CannotBindTestCase(PortCleanerUpper):
    613     """Tests for correct behavior when a reactor cannot bind to the required
    614     TCP port."""
     693    """
     694    Tests for correct behavior when a reactor cannot bind to the required
     695    TCP port.
     696
     697    @ivar listenMethod Method used to listen
     698    @ivar connectMethod Method used to connect
     699    @ivar loopback Loopback interface to use for testing
     700    """
     701
     702    listenMethod = reactor.listenTCP
     703    connectMethod = reactor.connectTCP
     704    loopback = "127.0.0.1"
    615705
    616706    def testCannotBind(self):
    617707        f = MyServerFactory()
    618708
    619         p1 = reactor.listenTCP(0, f, interface='127.0.0.1')
     709        p1 = self.listenMethod(0, f, interface=self.loopback)
    620710        n = p1.getHost().port
    621711        self.ports.append(p1)
    622712        dest = p1.getHost()
    623713        self.assertEquals(dest.type, "TCP")
    624         self.assertEquals(dest.host, "127.0.0.1")
     714        self.assertEquals(dest.host, self.loopback)
    625715        self.assertEquals(dest.port, n)
    626716
    627717        # make sure new listen raises error
    628718        self.assertRaises(error.CannotListenError,
    629                           reactor.listenTCP, n, f, interface='127.0.0.1')
     719                          reactor.listenTCP, n, f, interface=self.loopback)
    630720
    631721        return self.cleanPorts(*self.ports)
    632722
    class CannotBindTestCase(PortCleanerUpper): 
    644734        theDeferred = defer.Deferred()
    645735        sf = MyServerFactory()
    646736        sf.startFactory = self._fireWhenDoneFunc(theDeferred, sf.startFactory)
    647         p = reactor.listenTCP(0, sf, interface="127.0.0.1")
     737        p = self.listenMethod(0, sf, interface=self.loopback)
    648738        self.ports.append(p)
    649739
    650740        def _connect1(results):
    651741            d = defer.Deferred()
    652742            cf1 = MyClientFactory()
    653743            cf1.buildProtocol = self._fireWhenDoneFunc(d, cf1.buildProtocol)
    654             reactor.connectTCP("127.0.0.1", p.getHost().port, cf1,
    655                                bindAddress=("127.0.0.1", 0))
     744            self.connectMethod(self.loopback, p.getHost().port, cf1,
     745                               bindAddress=(self.loopback, 0))
    656746            d.addCallback(_conmade, cf1)
    657747            return d
    658748
    class CannotBindTestCase(PortCleanerUpper): 
    673763            cf2.clientConnectionFailed = self._fireWhenDoneFunc(
    674764                d1, cf2.clientConnectionFailed)
    675765            cf2.stopFactory = self._fireWhenDoneFunc(d2, cf2.stopFactory)
    676             reactor.connectTCP("127.0.0.1", p.getHost().port, cf2,
    677                                bindAddress=("127.0.0.1", port))
     766            self.connectMethod(self.loopback, p.getHost().port, cf2,
     767                               bindAddress=(self.loopback, port))
    678768            d1.addCallback(_check2failed, cf1, cf2)
    679769            d2.addCallback(_check2stopped, cf1, cf2)
    680770            dl = defer.DeferredList([d1, d2])
    class CannotBindTestCase(PortCleanerUpper): 
    705795        theDeferred.addCallback(_connect1)
    706796        return theDeferred
    707797
     798
     799class CannotBindIPv6TestCase(CannotBindTestCase):
     800    """
     801    Tests for correct behavior when a reactor cannot bind to the required
     802    TCPv6 port.
     803    """
     804    listenMethod = reactor.listenTCP6
     805    connectMethod = reactor.connectTCP6
     806    loopback = "::1"
     807
     808
    708809class MyOtherClientFactory(protocol.ClientFactory):
    709810    def buildProtocol(self, address):
    710811        self.address = address
    class MyOtherClientFactory(protocol.ClientFactory): 
    714815
    715816
    716817class LocalRemoteAddressTestCase(PortCleanerUpper):
    717     """Tests for correct getHost/getPeer values and that the correct address
     818    """
     819    Tests for correct getHost/getPeer values and that the correct address
    718820    is passed to buildProtocol.
     821
     822    @ivar listenMethod Method used to listen
     823    @ivar connectMethod Method used to connect
     824    @ivar loopback Loopback interface to use for testing
    719825    """
     826
     827    listenMethod = reactor.listenTCP
     828    connectMethod = reactor.connectTCP
     829    loopback = "127.0.0.1"
     830
    720831    def testHostAddress(self):
    721832        f1 = MyServerFactory()
    722         p1 = reactor.listenTCP(0, f1, interface='127.0.0.1')
     833        p1 = self.listenMethod(0, f1, interface=self.loopback)
    723834        n = p1.getHost().port
    724835        self.ports.append(p1)
    725836
    726837        f2 = MyOtherClientFactory()
    727         p2 = reactor.connectTCP('127.0.0.1', n, f2)
     838        p2 = self.connectMethod(self.loopback, n, f2)
    728839
    729840        d = loopUntil(lambda :p2.state == "connected")
    730841        def check(ignored):
    class LocalRemoteAddressTestCase(PortCleanerUpper): 
    737848        return d.addCallback(check).addCallback(cleanup)
    738849
    739850
     851class LocalRemoteAddressIPv6TestCase(LocalRemoteAddressTestCase):
     852    """
     853    IPv6 tests for correct getHost/getPeer values and that the correct address
     854    is passed to buildProtocol.
     855    """
     856    listenMethod = reactor.listenTCP6
     857    connectMethod = reactor.connectTCP6
     858    loopback = "::1"
     859
     860
    740861class WriterProtocol(protocol.Protocol):
    741862    def connectionMade(self):
    742863        # use everything ITransport claims to provide. If something here
    class WriterClientFactory(protocol.ClientFactory): 
    778899class WriteDataTestCase(PortCleanerUpper):
    779900    """Test that connected TCP sockets can actually write data. Try to
    780901    exercise the entire ITransport interface.
     902
     903    @ivar listenMethod Method used to listen
     904    @ivar connectMethod Method used to connect
     905    @ivar loopback Loopback interface to use for testing
    781906    """
     907    listenMethod = reactor.listenTCP
     908    connectMethod = reactor.connectTCP
     909    loopback = "127.0.0.1"
    782910
    783911    def testWriter(self):
    784912        f = protocol.Factory()
    class WriteDataTestCase(PortCleanerUpper): 
    786914        f.done = 0
    787915        f.problem = 0
    788916        wrappedF = WiredFactory(f)
    789         p = reactor.listenTCP(0, wrappedF, interface="127.0.0.1")
     917        p = self.listenMethod(0, wrappedF, interface=self.loopback)
    790918        n = p.getHost().port
    791919        self.ports.append(p)
    792920        clientF = WriterClientFactory()
    793921        wrappedClientF = WiredFactory(clientF)
    794         reactor.connectTCP("127.0.0.1", n, wrappedClientF)
     922        self.connectMethod(self.loopback, n, wrappedClientF)
    795923
    796924        def check(ignored):
    797925            self.failUnless(f.done, "writer didn't finish, it probably died")
    class WriteDataTestCase(PortCleanerUpper): 
    820948        # Gtk reactor cannot pass this test, though, because it fails to
    821949        # implement IReactorTCP entirely correctly.  Gtk is quite old at
    822950        # this point, so it's more likely that gtkreactor will be deprecated
    823         # and removed rather than fixed to handle this case correctly. 
     951        # and removed rather than fixed to handle this case correctly.
    824952        # Since this is a pre-existing (and very long-standing) issue with
    825953        # the Gtk reactor, there's no reason for it to prevent this test
    826954        # being added to exercise the other reactors, for which the behavior
    class WriteDataTestCase(PortCleanerUpper): 
    8721000        # Create the server port to which a connection will be made.
    8731001        server = protocol.ServerFactory()
    8741002        server.protocol = Disconnecter
    875         port = reactor.listenTCP(0, server, interface='127.0.0.1')
     1003        port = self.listenMethod(0, server, interface=self.loopback)
    8761004        self.addCleanup(port.stopListening)
    8771005        addr = port.getHost()
    8781006
    class WriteDataTestCase(PortCleanerUpper): 
    9421070            return client.lostReason
    9431071        clientConnectionLost.addCallback(cbClientLost)
    9441072        msg('Connecting to %s:%s' % (addr.host, addr.port))
    945         connector = reactor.connectTCP(addr.host, addr.port, client)
     1073        connector = self.connectMethod(addr.host, addr.port, client)
    9461074
    9471075        # By the end of the test, the client should have received notification
    9481076        # of unclean disconnection.
    9491077        msg('Returning Deferred')
    9501078        return self.assertFailure(clientConnectionLost, error.ConnectionLost)
    9511079
     1080class WriteDataIPv6TestCase(WriteDataTestCase):
     1081    """
     1082    Test that connected TCPv6 sockets can actually write data. Try to
     1083    exercise the entire ITransport interface.
     1084    """
     1085    listenMethod = reactor.listenTCP6
     1086    connectMethod = reactor.connectTCP6
     1087    loopback = "::1"
     1088
    9521089
    9531090
    9541091class ConnectionLosingProtocol(protocol.Protocol):
    class ProperlyCloseFilesMixin: 
    10531190        serverFactory = protocol.ServerFactory()
    10541191        serverFactory.protocol = lambda: ConnectionLostNotifyingProtocol(
    10551192            onServerConnectionLost)
    1056         serverPort = self.createServer('127.0.0.1', 0, serverFactory)
     1193        serverPort = self.createServer(self.loopback, 0, serverFactory)
    10571194
    10581195        onClientConnectionLost = defer.Deferred()
    10591196        serverAddr = serverPort.getHost()
    class ProperlyCloseFilesMixin: 
    10981235
    10991236
    11001237class ProperlyCloseFilesTestCase(unittest.TestCase, ProperlyCloseFilesMixin):
    1101     def createServer(self, address, portNumber, factory):
    1102         return reactor.listenTCP(portNumber, factory, interface=address)
     1238    """
     1239    Test that we properly close files.
    11031240
     1241    @ivar listenMethod Method used to listen
     1242    @ivar connectMethod Method used to connect
     1243    @ivar loopback Loopback interface to use for testing
     1244    """
    11041245
    1105     def connectClient(self, address, portNumber, clientCreator):
    1106         return clientCreator.connectTCP(address, portNumber)
     1246    listenMethod = reactor.listenTCP
     1247    creatorConnectMethod = protocol.ClientCreator.connectTCP
     1248    loopback = "127.0.0.1"
    11071249
     1250    def createServer(self, address, portNumber, factory):
     1251        return self.listenMethod(portNumber, factory, interface=address)
     1252
     1253    def connectClient(self, address, portNumber, clientCreator):
     1254        return self.creatorConnectMethod(clientCreator, address, portNumber)
    11081255
    11091256    def getHandleExceptionType(self):
    11101257        return socket.error
    11111258
     1259class ProperlyCloseFilesIPv6TestCase(ProperlyCloseFilesTestCase):
     1260    """
     1261    Test that we properly close files using IPv6
     1262    """
     1263    listenMethod = reactor.listenTCP6
     1264    creatorConnectMethod = protocol.ClientCreator.connectTCP6
     1265    loopback = "::1"
    11121266
    11131267
    11141268class WiredForDeferreds(policies.ProtocolWrapper):
    class WiredFactory(policies.WrappingFactory): 
    11381292class AddressTestCase(unittest.TestCase):
    11391293    """
    11401294    Tests for address-related interactions with client and server protocols.
     1295
     1296    @ivar listenMethod Method used to listen
     1297    @ivar connectMethod Method used to connect
     1298    @ivar loopback Loopback interface to use for testing
     1299    @ivar addrType Type of address we expect to see
    11411300    """
     1301
     1302    listenMethod = reactor.listenTCP
     1303    connectMethod = reactor.connectTCP
     1304    loopback = "127.0.0.1"
     1305    addrtype = IPv4Address
     1306
    11421307    def setUp(self):
    11431308        """
    11441309        Create a port and connected client/server pair which can be used
    class AddressTestCase(unittest.TestCase): 
    11891354        self.clientConnLost = self.client.protocolConnectionLost = defer.Deferred()
    11901355        self.clientWrapper = RememberingWrapper(self.client)
    11911356
    1192         self.port = reactor.listenTCP(0, self.serverWrapper, interface='127.0.0.1')
    1193         self.connector = reactor.connectTCP(
     1357        self.port = self.listenMethod(0, self.serverWrapper, interface=self.loopback)
     1358        self.connector = self.connectMethod(
    11941359            self.port.getHost().host, self.port.getHost().port, self.clientWrapper)
    11951360
    11961361        return defer.gatherResults([self.serverConnMade, self.clientConnMade])
    class AddressTestCase(unittest.TestCase): 
    12201385
    12211386        self.assertEqual(
    12221387            self.clientWrapper.addresses,
    1223             [IPv4Address('TCP', serverHost.host, serverHost.port)])
     1388            [self.addrtype('TCP', serverHost.host, serverHost.port)])
    12241389        self.assertEqual(
    12251390            self.clientWrapper.addresses,
    1226             [IPv4Address('TCP', clientPeer.host, clientPeer.port)])
     1391            [self.addrtype('TCP', clientPeer.host, clientPeer.port)])
    12271392
    12281393
    12291394    def test_buildProtocolServer(self):
    class AddressTestCase(unittest.TestCase): 
    12391404
    12401405        self.assertEqual(
    12411406            self.serverWrapper.addresses,
    1242             [IPv4Address('TCP', serverPeer.host, serverPeer.port)])
     1407            [self.addrtype('TCP', serverPeer.host, serverPeer.port)])
    12431408        self.assertEqual(
    12441409            self.serverWrapper.addresses,
    1245             [IPv4Address('TCP', clientHost.host, clientHost.port)])
     1410            [self.addrtype('TCP', clientHost.host, clientHost.port)])
    12461411
    12471412
     1413class AddressIPv6TestCase(AddressTestCase):
     1414    """
     1415    Tests for address-related interactions with client and server IPv6
     1416    protocols.
     1417    """
     1418    listenMethod = reactor.listenTCP6
     1419    connectMethod = reactor.connectTCP6
     1420    loopback = "::1"
     1421    addrtype = IPv6Address
     1422
    12481423
    12491424class LargeBufferWriterProtocol(protocol.Protocol):
    12501425
    class FireOnCloseFactory(policies.WrappingFactory): 
    12921467
    12931468
    12941469class LargeBufferTestCase(PortCleanerUpper):
    1295     """Test that buffering large amounts of data works.
    12961470    """
     1471    Test that buffering large amounts of data works.
     1472
     1473    @ivar listenMethod Method used to listen
     1474    @ivar connectMethod Method used to connect
     1475    @ivar loopback Loopback interface to use for testing
     1476    """
     1477    listenMethod = reactor.listenTCP
     1478    connectMethod = reactor.connectTCP
     1479    loopback = "127.0.0.1"
    12971480
    12981481    datalen = 60*1024*1024
    12991482    def testWriter(self):
    class LargeBufferTestCase(PortCleanerUpper): 
    13031486        f.problem = 0
    13041487        f.len = self.datalen
    13051488        wrappedF = FireOnCloseFactory(f)
    1306         p = reactor.listenTCP(0, wrappedF, interface="127.0.0.1")
     1489        p = self.listenMethod(0, wrappedF, interface=self.loopback)
    13071490        n = p.getHost().port
    13081491        self.ports.append(p)
    13091492        clientF = LargeBufferReaderClientFactory()
    13101493        wrappedClientF = FireOnCloseFactory(clientF)
    1311         reactor.connectTCP("127.0.0.1", n, wrappedClientF)
     1494        self.connectMethod(self.loopback, n, wrappedClientF)
    13121495
    13131496        d = defer.gatherResults([wrappedF.deferred, wrappedClientF.deferred])
    13141497        def check(ignored):
    class LargeBufferTestCase(PortCleanerUpper): 
    13201503                            "client didn't see connection dropped")
    13211504        return d.addCallback(check)
    13221505
     1506class LargeBufferIPv6TestCase(LargeBufferTestCase):
     1507    """
     1508    Test that buffering large amounts of data works over IPv6
     1509    """
     1510    listenMethod = reactor.listenTCP6
     1511    connectMethod = reactor.connectTCP6
     1512    loopback = "::1"
     1513
    13231514
    13241515class MyHCProtocol(MyProtocol):
    13251516
    class MyHCFactory(protocol.ServerFactory): 
    13551546
    13561547
    13571548class HalfCloseTestCase(PortCleanerUpper):
    1358     """Test half-closing connections."""
     1549    """
     1550    Test half-closing connections.
     1551
     1552    @ivar listenMethod Method used to listen
     1553    @ivar connectMethod Method used to connect
     1554    @ivar creatorConnectMethod Method used to connect with a ClientCreator
     1555    @ivar loopback Loopback interface to use for testing
     1556    """
     1557    listenMethod = reactor.listenTCP
     1558    connectMethod = reactor.connectTCP
     1559    creatorConnectMethod = protocol.ClientCreator.connectTCP
     1560    loopback = "127.0.0.1"
    13591561
    13601562    def setUp(self):
    13611563        PortCleanerUpper.setUp(self)
    13621564        self.f = f = MyHCFactory()
    1363         self.p = p = reactor.listenTCP(0, f, interface="127.0.0.1")
     1565        self.p = p = self.listenMethod(0, f, interface=self.loopback)
    13641566        self.ports.append(p)
    13651567        d = loopUntil(lambda :p.connected)
    13661568
    13671569        self.cf = protocol.ClientCreator(reactor, MyHCProtocol)
    13681570
    1369         d.addCallback(lambda _: self.cf.connectTCP(p.getHost().host,
    1370                                                    p.getHost().port))
     1571        d.addCallback(lambda _: self.creatorConnectMethod(self.cf,
     1572                                                          p.getHost().host,
     1573                                                          p.getHost().port))
    13711574        d.addCallback(self._setUp)
    13721575        return d
    13731576
    class HalfCloseTestCase(PortCleanerUpper): 
    14361639            f.protocol.readHalfClosed, False))
    14371640        return d
    14381641
     1642class HalfCloseIPv6TestCase(HalfCloseTestCase):
     1643    """
     1644    Test half-closing IPv6 connections.
     1645    """
     1646    listenMethod = reactor.listenTCP6
     1647    connectMethod = reactor.connectTCP6
     1648    creatorConnectMethod = protocol.ClientCreator.connectTCP6
     1649    loopback = "::1"
     1650
    14391651
    14401652class HalfClose2TestCase(unittest.TestCase):
     1653    """
     1654    Test half-closing connections.
     1655
     1656    @ivar listenMethod Method used to listen
     1657    @ivar creatorConnectMethod Method used to connect with a ClientCreator
     1658    @ivar loopback Loopback interface to use for testing
     1659    """
     1660    listenMethod = reactor.listenTCP
     1661    creatorConnectMethod = protocol.ClientCreator.connectTCP
     1662    loopback = "127.0.0.1"
    14411663
    14421664    def setUp(self):
    14431665        self.f = f = MyServerFactory()
    14441666        self.f.protocolConnectionMade = defer.Deferred()
    1445         self.p = p = reactor.listenTCP(0, f, interface="127.0.0.1")
     1667        self.p = p = self.listenMethod(0, f, interface=self.loopback)
    14461668
    14471669        # XXX we don't test server side yet since we don't do it yet
    1448         d = protocol.ClientCreator(reactor, MyProtocol).connectTCP(
    1449             p.getHost().host, p.getHost().port)
     1670        creator = protocol.ClientCreator(reactor, MyProtocol)
     1671        d = self.creatorConnectMethod(creator, p.getHost().host,
     1672                                      p.getHost().port)
    14501673        d.addCallback(self._gotClient)
    14511674        return d
    14521675
    class HalfClose2TestCase(unittest.TestCase): 
    14911714                      self.failUnlessEqual(self.f.protocol.closed, True))
    14921715        return defer.gatherResults([d, d2])
    14931716
     1717class HalfClose2IPv6TestCase(HalfClose2TestCase):
     1718    """
     1719    Test half-closing IPv6 connections.
     1720    """
     1721    listenMethod = reactor.listenTCP6
     1722    creatorConnectMethod = protocol.ClientCreator.connectTCP6
     1723    loopback = "::1"
    14941724
    14951725class HalfCloseBuggyApplicationTests(unittest.TestCase):
    14961726    """
    14971727    Test half-closing connections where notification code has bugs.
     1728
     1729    @ivar listenMethod Method used to listen
     1730    @ivar creatorConnectMethod Method used to connect with a ClientCreator
     1731    @ivar loopback Loopback interface to use for testing
    14981732    """
     1733    listenMethod = reactor.listenTCP
     1734    creatorConnectMethod = protocol.ClientCreator.connectTCP
     1735    loopback = "127.0.0.1"
    14991736
    15001737    def setUp(self):
    15011738        """
    class HalfCloseBuggyApplicationTests(unittest.TestCase): 
    15041741        """
    15051742        self.serverFactory = MyHCFactory()
    15061743        self.serverFactory.protocolConnectionMade = defer.Deferred()
    1507         self.port = reactor.listenTCP(
    1508             0, self.serverFactory, interface="127.0.0.1")
     1744        self.port = self.listenMethod(
     1745            0, self.serverFactory, interface=self.loopback)
    15091746        self.addCleanup(self.port.stopListening)
    15101747        addr = self.port.getHost()
    15111748        creator = protocol.ClientCreator(reactor, MyHCProtocol)
    1512         clientDeferred = creator.connectTCP(addr.host, addr.port)
     1749        clientDeferred = self.creatorConnectMethod(creator, addr.host, addr.port)
    15131750        def setClient(clientProtocol):
    15141751            self.clientProtocol = clientProtocol
    15151752        clientDeferred.addCallback(setClient)
    class HalfCloseBuggyApplicationTests(unittest.TestCase): 
    15591796        self.clientProtocol.writeConnectionLost = self.aBug
    15601797        return self._notificationRaisesTest()
    15611798
     1799class HalfCloseBuggyApplicationIPv6Tests(HalfCloseBuggyApplicationTests):
     1800    """
     1801    Test half-closing IPv6 connections where notification code has bugs.
     1802    """
     1803    listenMethod = reactor.listenTCP6
     1804    creatorConnectMethod = protocol.ClientCreator.connectTCP6
     1805    loopback = "::1"
    15621806
    15631807
    15641808class LogTestCase(unittest.TestCase):
    15651809    """
    15661810    Test logging facility of TCP base classes.
     1811
     1812    @ivar listenMethod Method used to listen
     1813    @ivar connectMethod Method used to connect
     1814    @ivar loopback Loopback interface to use for testing
    15671815    """
     1816    listenMethod = reactor.listenTCP
     1817    connectMethod = reactor.connectTCP
     1818    loopback = "127.0.0.1"
    15681819
    15691820    def test_logstrClientSetup(self):
    15701821        """
    class LogTestCase(unittest.TestCase): 
    15761827        client = MyClientFactory()
    15771828        client.protocolConnectionMade = defer.Deferred()
    15781829
    1579         port = reactor.listenTCP(0, server, interface='127.0.0.1')
     1830        port = self.listenMethod(0, server, interface=self.loopback)
    15801831        self.addCleanup(port.stopListening)
    15811832
    1582         connector = reactor.connectTCP(
     1833        connector = self.connectMethod(
    15831834            port.getHost().host, port.getHost().port, client)
    15841835        self.addCleanup(connector.disconnect)
    15851836
    class LogTestCase(unittest.TestCase): 
    15931844        client.protocolConnectionMade.addCallback(cb)
    15941845        return client.protocolConnectionMade
    15951846
     1847class LogIPv6TestCase(LogTestCase):
     1848    """
     1849    Test logging facility of TCPv6 base classes.
     1850    """
     1851    listenMethod = reactor.listenTCP6
     1852    connectMethod = reactor.connectTCP6
     1853    loopback = "::1"
    15961854
    15971855
    15981856try:
    except ImportError: 
    16021860else:
    16031861    numRounds = resource.getrlimit(resource.RLIMIT_NOFILE)[0] + 10
    16041862    ProperlyCloseFilesTestCase.numberRounds = numRounds
     1863
     1864try:
     1865    s = socket.socket(socket.AF_INET6)
     1866except socket.error:
     1867    for klass in [
     1868        "ListeningIPv6TestCase",
     1869        "LoopbackIPv6TestCase",
     1870        "FactoryIPv6TestCase",
     1871        "ConnectorIPv6TestCase",
     1872        "CannotBindIPv6TestCase",
     1873        "LocalRemoteAddressIPv6TestCase",
     1874        "WriteDataIPv6TestCase",
     1875        "ProperlyCloseFilesIPv6TestCase",
     1876        "AddressIPv6TestCase",
     1877        "LargeBufferIPv6TestCase",
     1878        "HalfCloseIPv6TestCase",
     1879        "HalfClose2IPv6TestCase",
     1880        "HalfCloseBuggyApplicationIPv6Tests",
     1881        "LogIPv6TestCase",
     1882    ]:
     1883        klass.skip = "IPv6 is not enabled"
     1884