Ticket #5086: fix-ipv6-literals-udp.6.patch

File fix-ipv6-literals-udp.6.patch, 8.9 KB (added by marto1_, 3 years ago)

With the exception of the two FIXMEs this should work

  • twisted/topfiles/5086.feature

     
     1IReactorUDP.listenUDP, IUDPTransport.write and IUDPTransport.connect now accept ipv6 address literals.
     2 No newline at end of file
  • twisted/internet/test/test_udp.py

     
    2020from twisted.internet.defer import Deferred, maybeDeferred
    2121from twisted.internet.interfaces import (
    2222    ILoggingContext, IListeningPort, IReactorUDP)
    23 from twisted.internet.address import IPv4Address
     23from twisted.internet.address import IPv4Address, IPv6Address
    2424from twisted.internet.protocol import DatagramProtocol
    2525
    2626from twisted.internet.test.connectionmixins import (LogObserverMixin,
    2727                                                    findFreePort)
     28from twisted.internet import protocol, error, defer, interfaces, udp
     29from twisted.test.test_udp import Server, GoodClient
    2830
    2931
    3032class UDPPortMixin(object):
     
    4850        """
    4951        return "(UDP Port %s Closed)" % (port.getHost().port,)
    5052
     53    def getIPv6ListeningPort(self, reactor, protocol):
     54        """
     55        Get a UDP port binded to ipv6 interface.
     56        """
     57        return reactor.listenUDP(0, protocol, "::1")
    5158
    5259
     60
    5361class DatagramTransportTestsMixin(LogObserverMixin):
    5462    """
    5563    Mixin defining tests which apply to any port/datagram based transport.
     
    162170        self.assertEqual(
    163171            port.getHost(), IPv4Address('UDP', host, portNumber))
    164172
     173    def test_getHostIPv6(self):
     174        """
     175        L{IListeningPort.getHost} returns an L{IPv6Address} giving a
     176        IPv6 address, the port number that the protocol is listening on
     177        and the port number.
     178        """
     179        reactor = self.buildReactor()
     180        port = self.getIPv6ListeningPort(reactor, DatagramProtocol())
     181        addr = port.getHost()
     182        self.assertEqual(addr.host, "::1")
    165183
     184
    166185    def test_logPrefix(self):
    167186        """
    168187        Datagram transports implement L{ILoggingContext.logPrefix} to return a
     
    215234        port = reactor.listenUDP(0, DatagramProtocol())
    216235        self.assertIn(repr(port.getHost().port), str(port))
    217236
     237    def test_bindToIPv6Interface(self):
     238        """
     239        Binds to ipv6 interface.
     240        """
     241        reactor = self.buildReactor()
     242        server = Server()
     243        p = reactor.listenUDP(0, server, interface="::1")
     244        self.assertEqual(p.getHost().host, "::1")
     245
     246        return p.stopListening()
     247
     248    def performTransferServerClient(self, reactor, interface,
     249                                    cbServerStarted,
     250                                    cbClientStarted,
     251                                    cbSendsFinished,
     252                                    cbFinished):
     253        """
     254        Creates UDP server and client.
     255        @param cbServerStarted: execute when server starts.
     256        @param cbClientStarted: execute when client starts.
     257        @param cbSendsFinished: execute when packets are send.
     258        @param cbFinished: execute tear down.
     259        """
     260        server = Server()
     261        serverStarted = server.startedDeferred = defer.Deferred()
     262        port1 = reactor.listenUDP(0, server, interface=interface)
     263
     264        client = GoodClient()
     265        clientStarted = client.startedDeferred = defer.Deferred()
     266
     267        d = serverStarted.addCallback(cbServerStarted, reactor, client,
     268                                      interface, cbClientStarted)
     269        d.addCallback(cbClientStarted, client, server, interface)
     270        #FIXME the following two do not seem to execute
     271        d.addCallback(cbSendsFinished, client, server)
     272        d.addCallback(cbFinished, port1, self.port2)
     273
     274
     275        return d
     276
     277    #FIXME (almost) code duplication with twisted.test.test_udp
     278    def cbServerStarted(self, ignored, reactor, client, interface, d):
     279        self.port2 = reactor.listenUDP(0, client, interface=interface)
     280        return d
     281
     282    def cbClientStarted(self, ignored, client, server, interface):
     283        client.transport.connect(interface,
     284                                 server.transport.getHost().port)
     285        cAddr = client.transport.getHost()
     286        sAddr = server.transport.getHost()
     287
     288        serverSend = client.packetReceived = defer.Deferred()
     289        server.transport.write(b"hello", (cAddr.host, cAddr.port))
     290       
     291        clientWrites = [
     292            (b"a",),
     293            (b"b", None),
     294            (b"c", (sAddr.host, sAddr.port))]
     295
     296        def cbClientSend(ignored):
     297            if clientWrites:
     298                nextClientWrite = server.packetReceived = defer.Deferred()
     299                nextClientWrite.addCallback(cbClientSend)
     300                client.transport.write(*clientWrites.pop(0))
     301                return nextClientWrite
     302
     303        # No one will ever call .errback on either of these Deferreds,
     304        # but there is a non-trivial amount of test code which might
     305        # cause them to fail somehow.  So fireOnOneErrback=True.
     306        return defer.DeferredList([
     307                cbClientSend(None),
     308                serverSend], fireOnOneErrback=True)
     309
     310
     311    def cbSendsFinished(self, ignored, client, server):
     312        cAddr = client.transport.getHost()
     313        sAddr = server.transport.getHost()
     314        clientAddr = cAddr.host, cAddr.port
     315        serverAddr = sAddr.host, sAddr.port
     316
     317       
     318        self.assertEqual(
     319            client.packets,
     320            [(b"hello", serverAddr)])
     321        self.assertEqual(
     322            server.packets,
     323            [(b"a", clientAddr),
     324             (b"b", clientAddr),
     325             (b"c", clientAddr)])
     326
     327
     328    def cbFinished(self, ignored, port1, port2):
     329        return defer.DeferredList([
     330                defer.maybeDeferred(port1.stopListening),
     331                defer.maybeDeferred(port2.stopListening)],
     332                                  fireOnOneErrback=True)
     333
     334
     335    def test_connectAndWriteToIPv6Interface(self):
     336        """
     337        Connects and writes to ipv6 address.
     338        """
     339        reactor = self.buildReactor()
     340        return self.performTransferServerClient(reactor, "::1",
     341                                                self.cbServerStarted,
     342                                                self.cbClientStarted,
     343                                                self.cbSendsFinished,
     344                                                self.cbFinished)
     345
     346
    218347globals().update(UDPServerTestsBuilder.makeTestCaseClasses())
  • twisted/internet/udp.py

     
    8080        self.interface = interface
    8181        self.setLogStr()
    8282        self._connectedAddr = None
     83        self._setAddressFamily()
    8384
    8485    def __repr__(self):
    8586        if self._realPortNumber is not None:
     
    207208        """
    208209        if self._connectedAddr:
    209210            raise RuntimeError("already connected, reconnecting is not currently supported")
    210         if not abstract.isIPAddress(host):
     211        if not abstract.isIPAddress(host) and not abstract.isIPv6Address(host):
    211212            raise ValueError("please pass only IP addresses, not domain names")
    212213        self._connectedAddr = (host, port)
    213214        self.socket.connect((host, port))
     
    252253        logPrefix = self._getLogPrefix(self.protocol)
    253254        self.logstr = "%s (UDP)" % logPrefix
    254255
     256    def _setAddressFamily(self):
     257        """
     258        Resolve address family for the socket.
     259        """
     260        if abstract.isIPv6Address(self.interface):
     261            self.addressFamily = socket.AF_INET6
     262        elif abstract.isIPAddress(self.interface):
     263            self.addressFamily = socket.AF_INET
     264       
    255265
     266
    256267    def logPrefix(self):
    257268        """
    258269        Return the prefix to log with.
     
    262273
    263274    def getHost(self):
    264275        """
    265         Returns an IPv4Address.
     276        Returns an IPv4Address or IPv6Address.
    266277
    267278        This indicates the address from which I am connecting.
    268279        """
    269         return address.IPv4Address('UDP', *self.socket.getsockname())
     280        addr = self.socket.getsockname()
     281        if self.addressFamily == socket.AF_INET:
     282            return address.IPv4Address('UDP', *addr)
     283        elif self.addressFamily == socket.AF_INET6:
     284            return address.IPv6Address('UDP', *(addr[:2]))
    270285
    271286
    272287
     
    332347    UDP Port that supports multicasting.
    333348    """
    334349
    335     def __init__(self, port, proto, interface='', maxPacketSize=8192, reactor=None, listenMultiple=False):
     350    def __init__(self, port, proto, interface='', maxPacketSize=8192,
     351                 reactor=None, listenMultiple=False):
    336352        """
    337353        @see: L{twisted.internet.interfaces.IReactorMulticast.listenMulticast}
    338354        """