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

File fix-ipv6-literals-udp.6.patch, 8.9 KB (added by marto1_, 15 months 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        """