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

File fix-ipv6-literals-udp.7.patch, 25.7 KB (added by marto1_, 16 months ago)
  • twisted/test/test_udp.py

     
    168168 
    169169        return d.addCallback(cbStarted, p) 
    170170 
     171    def test_bindToIPv6Interface(self): 
     172        """ 
     173        Bind to ipv6 interface. 
     174        """ 
     175        server = Server() 
     176        p = reactor.listenUDP(0, server, interface="::1") 
     177        self.assertEqual(p.getHost().host, "::1") 
    171178 
     179        return p.stopListening() 
     180 
     181    def cbServerStarted(self, ignored, client, interface, d): 
     182        self.port2 = reactor.listenUDP(0, client, interface=interface) 
     183        return d 
     184 
     185    def cbClientStarted(self, ignored, client, server, interface): 
     186        client.transport.connect(interface, 
     187                                 server.transport.getHost().port) 
     188        cAddr = client.transport.getHost() 
     189        sAddr = server.transport.getHost() 
     190 
     191        serverSend = client.packetReceived = defer.Deferred() 
     192        server.transport.write(b"hello", (cAddr.host, cAddr.port)) 
     193 
     194        clientWrites = [ 
     195            (b"a",), 
     196            (b"b", None), 
     197            (b"c", (sAddr.host, sAddr.port))] 
     198 
     199        def cbClientSend(ignored): 
     200            if clientWrites: 
     201                nextClientWrite = server.packetReceived = defer.Deferred() 
     202                nextClientWrite.addCallback(cbClientSend) 
     203                client.transport.write(*clientWrites.pop(0)) 
     204                return nextClientWrite 
     205 
     206        # No one will ever call .errback on either of these Deferreds, 
     207        # but there is a non-trivial amount of test code which might 
     208        # cause them to fail somehow.  So fireOnOneErrback=True. 
     209        return defer.DeferredList([ 
     210                cbClientSend(None), 
     211                serverSend], fireOnOneErrback=True) 
     212 
     213 
     214    def cbSendsFinished(self, ignored, client, server, addressAddition=()): 
     215        cAddr = client.transport.getHost() 
     216        sAddr = server.transport.getHost() 
     217        clientAddr = (cAddr.host, cAddr.port) + addressAddition 
     218        serverAddr = (sAddr.host, sAddr.port) + addressAddition 
     219        self.assertEqual( 
     220            client.packets, 
     221            [(b"hello", serverAddr)]) 
     222        self.assertEqual( 
     223            server.packets, 
     224            [(b"a", clientAddr), 
     225             (b"b", clientAddr), 
     226             (b"c", clientAddr)]) 
     227 
     228 
     229    def cbFinished(self, ignored, port1, port2): 
     230        return defer.DeferredList([ 
     231            defer.maybeDeferred(port1.stopListening), 
     232            defer.maybeDeferred(port2.stopListening)], 
     233            fireOnOneErrback=True) 
     234 
     235 
     236 
    172237    def test_bindError(self): 
    173238        """ 
    174239        A L{CannotListenError} exception is raised when attempting to bind a 
     
    192257        d.addCallback(cbFinished) 
    193258        return d 
    194259 
    195  
    196     def test_sendPackets(self): 
     260    def performTransferServerClient(self, interface, addressAddition=()): 
    197261        """ 
    198         Datagrams can be sent with the transport's C{write} method and 
    199         received via the C{datagramReceived} callback method. 
     262        Helper method that creates UDP server and client, 
     263        connects the client to the server, sends some packets 
     264        and asserts addresses. 
    200265        """ 
    201266        server = Server() 
    202267        serverStarted = server.startedDeferred = defer.Deferred() 
    203         port1 = reactor.listenUDP(0, server, interface="127.0.0.1") 
     268        port1 = reactor.listenUDP(0, server, interface=interface) 
    204269 
    205270        client = GoodClient() 
    206271        clientStarted = client.startedDeferred = defer.Deferred() 
    207272 
    208         def cbServerStarted(ignored): 
    209             self.port2 = reactor.listenUDP(0, client, interface="127.0.0.1") 
    210             return clientStarted 
     273        d = serverStarted.addCallback(self.cbServerStarted, client, interface, 
     274                                      clientStarted) 
     275        d.addCallback(self.cbClientStarted, client, server, interface) 
     276        d.addCallback(self.cbSendsFinished, client, server, addressAddition) 
     277        d.addCallback(self.cbFinished, port1, self.port2) 
    211278 
    212         d = serverStarted.addCallback(cbServerStarted) 
     279        return d 
    213280 
    214         def cbClientStarted(ignored): 
    215             client.transport.connect("127.0.0.1", 
    216                                      server.transport.getHost().port) 
    217             cAddr = client.transport.getHost() 
    218             sAddr = server.transport.getHost() 
     281    def test_writeToIPv6Interface(self): 
     282        """ 
     283        Send packets to ipv6 address. 
     284        """ 
     285        return self.performTransferServerClient("::1", (0, 0)) 
    219286 
    220             serverSend = client.packetReceived = defer.Deferred() 
    221             server.transport.write(b"hello", (cAddr.host, cAddr.port)) 
    222287 
    223             clientWrites = [ 
    224                 (b"a",), 
    225                 (b"b", None), 
    226                 (b"c", (sAddr.host, sAddr.port))] 
     288    def test_sendPackets(self): 
     289        """ 
     290        Datagrams can be sent with the transport's C{write} method and 
     291        received via the C{datagramReceived} callback method. 
     292        """ 
     293        return self.performTransferServerClient("127.0.0.1") 
    227294 
    228             def cbClientSend(ignored): 
    229                 if clientWrites: 
    230                     nextClientWrite = server.packetReceived = defer.Deferred() 
    231                     nextClientWrite.addCallback(cbClientSend) 
    232                     client.transport.write(*clientWrites.pop(0)) 
    233                     return nextClientWrite 
    234295 
    235             # No one will ever call .errback on either of these Deferreds, 
    236             # but there is a non-trivial amount of test code which might 
    237             # cause them to fail somehow.  So fireOnOneErrback=True. 
    238             return defer.DeferredList([ 
    239                 cbClientSend(None), 
    240                 serverSend], 
    241                 fireOnOneErrback=True) 
    242  
    243         d.addCallback(cbClientStarted) 
    244  
    245         def cbSendsFinished(ignored): 
    246             cAddr = client.transport.getHost() 
    247             sAddr = server.transport.getHost() 
    248             self.assertEqual( 
    249                 client.packets, 
    250                 [(b"hello", (sAddr.host, sAddr.port))]) 
    251             clientAddr = (cAddr.host, cAddr.port) 
    252             self.assertEqual( 
    253                 server.packets, 
    254                 [(b"a", clientAddr), 
    255                  (b"b", clientAddr), 
    256                  (b"c", clientAddr)]) 
    257  
    258         d.addCallback(cbSendsFinished) 
    259  
    260         def cbFinished(ignored): 
    261             return defer.DeferredList([ 
    262                 defer.maybeDeferred(port1.stopListening), 
    263                 defer.maybeDeferred(self.port2.stopListening)], 
    264                 fireOnOneErrback=True) 
    265  
    266         d.addCallback(cbFinished) 
    267         return d 
    268  
    269  
    270296    def test_connectionRefused(self): 
    271297        """ 
    272298        A L{ConnectionRefusedError} exception is raised when a connection 
     
    500526 
    501527class MulticastTestCase(unittest.TestCase): 
    502528 
     529    localhost = "127.0.0.1" 
     530    multicast = "225.0.0.250" 
     531    all = "0.0.0.0" 
     532 
    503533    def setUp(self): 
    504534        self.server = Server() 
    505535        self.client = Client() 
     
    530560        """ 
    531561        self.assertEqual(self.server.transport.getLoopbackMode(), 1) 
    532562        addr = self.server.transport.getHost() 
    533         joined = self.server.transport.joinGroup("225.0.0.250") 
     563        joined = self.server.transport.joinGroup(self.multicast, 
     564                                                 self.all) 
    534565 
    535566        def cbJoined(ignored): 
    536567            d = self.server.packetReceived = Deferred() 
    537             self.server.transport.write(b"hello", ("225.0.0.250", addr.port)) 
     568            self.server.transport.write(b"hello", (self.multicast, addr.port)) 
    538569            return d 
    539570        joined.addCallback(cbJoined) 
    540571 
     
    542573            self.assertEqual(len(self.server.packets), 1) 
    543574            self.server.transport.setLoopbackMode(0) 
    544575            self.assertEqual(self.server.transport.getLoopbackMode(), 0) 
    545             self.server.transport.write(b"hello", ("225.0.0.250", addr.port)) 
     576            self.server.transport.write(b"hello", (self.multicast, addr.port)) 
    546577 
    547578            # This is fairly lame. 
    548579            d = Deferred() 
     
    562593        Test C{getOutgoingInterface} and C{setOutgoingInterface}. 
    563594        """ 
    564595        self.assertEqual( 
    565             self.client.transport.getOutgoingInterface(), "0.0.0.0") 
     596            self.client.transport.getOutgoingInterface(), self.all) 
    566597        self.assertEqual( 
    567             self.server.transport.getOutgoingInterface(), "0.0.0.0") 
     598            self.server.transport.getOutgoingInterface(), self.all) 
    568599 
    569         d1 = self.client.transport.setOutgoingInterface("127.0.0.1") 
    570         d2 = self.server.transport.setOutgoingInterface("127.0.0.1") 
     600        d1 = self.client.transport.setOutgoingInterface(self.localhost) 
     601        d2 = self.server.transport.setOutgoingInterface(self.localhost) 
    571602        result = gatherResults([d1, d2]) 
    572603 
    573604        def cbInterfaces(ignored): 
    574605            self.assertEqual( 
    575                 self.client.transport.getOutgoingInterface(), "127.0.0.1") 
     606                self.client.transport.getOutgoingInterface(), self.localhost) 
    576607            self.assertEqual( 
    577                 self.server.transport.getOutgoingInterface(), "127.0.0.1") 
     608                self.server.transport.getOutgoingInterface(), self.localhost) 
    578609        result.addCallback(cbInterfaces) 
    579610        return result 
    580611 
     
    583614        """ 
    584615        Test that multicast a group can be joined and left. 
    585616        """ 
    586         d = self.client.transport.joinGroup("225.0.0.250") 
     617        d = self.client.transport.joinGroup(self.multicast, self.all) 
    587618 
    588619        def clientJoined(ignored): 
    589             return self.client.transport.leaveGroup("225.0.0.250") 
     620            return self.client.transport.leaveGroup(self.multicast, self.all) 
    590621        d.addCallback(clientJoined) 
    591622 
    592623        def clientLeft(ignored): 
    593             return self.server.transport.joinGroup("225.0.0.250") 
     624            return self.server.transport.joinGroup(self.multicast, self.all) 
    594625        d.addCallback(clientLeft) 
    595626 
    596627        def serverJoined(ignored): 
    597             return self.server.transport.leaveGroup("225.0.0.250") 
     628            return self.server.transport.leaveGroup(self.multicast, self.all) 
    598629        d.addCallback(serverJoined) 
    599630 
    600631        return d 
     
    607638        """ 
    608639        # 127.0.0.1 is not a multicast address, so joining it should fail. 
    609640        return self.assertFailure( 
    610             self.client.transport.joinGroup("127.0.0.1"), 
     641            self.client.transport.joinGroup(self.localhost, self.all), 
    611642            error.MulticastJoinError) 
    612643    if runtime.platform.isWindows() and not runtime.platform.isVista(): 
    613644        test_joinFailure.todo = "Windows' multicast is wonky" 
     
    619650        received from it. 
    620651        """ 
    621652        c = Server() 
    622         p = reactor.listenMulticast(0, c) 
     653        p = reactor.listenMulticast(0, c, interface=self.all) 
    623654        addr = self.server.transport.getHost() 
    624655 
    625         joined = self.server.transport.joinGroup("225.0.0.250") 
     656        joined = self.server.transport.joinGroup(self.multicast, self.all) 
    626657 
    627658        def cbJoined(ignored): 
    628659            d = self.server.packetReceived = Deferred() 
    629             c.transport.write(b"hello world", ("225.0.0.250", addr.port)) 
     660            c.transport.write(b"hello world", (self.multicast, addr.port)) 
    630661            return d 
    631662        joined.addCallback(cbJoined) 
    632663 
     
    650681        """ 
    651682        firstClient = Server() 
    652683        firstPort = reactor.listenMulticast( 
    653             0, firstClient, listenMultiple=True) 
     684            0, firstClient, listenMultiple=True, interface=self.all) 
    654685 
    655686        portno = firstPort.getHost().port 
    656687 
    657688        secondClient = Server() 
    658689        secondPort = reactor.listenMulticast( 
    659             portno, secondClient, listenMultiple=True) 
     690            portno, secondClient, listenMultiple=True, interface=self.all) 
    660691 
    661         theGroup = "225.0.0.250" 
    662         joined = gatherResults([self.server.transport.joinGroup(theGroup), 
    663                                 firstPort.joinGroup(theGroup), 
    664                                 secondPort.joinGroup(theGroup)]) 
     692        theGroup = self.multicast 
     693        joined = gatherResults([self.server.transport.joinGroup(theGroup, 
     694                                                                self.all), 
     695                                firstPort.joinGroup(theGroup, self.all), 
     696                                secondPort.joinGroup(theGroup, self.all)]) 
    665697 
    666698 
    667699        def serverJoined(ignored): 
     
    689721                                 "processes can listen, but not multiple sockets " 
    690722                                 "in same process?") 
    691723 
     724class IPv6MulticastTestCase(MulticastTestCase): 
    692725 
     726    localhost = "::1" 
     727    multicast = "ffb1::" 
     728    all = "::" 
     729 
     730    def setUp(self): 
     731        self.server = Server() 
     732        self.client = Client() 
     733        self.port1 = reactor.listenMulticast(0, self.server, interface="::") 
     734        self.port2 = reactor.listenMulticast(0, self.client, interface="::") 
     735        self.client.transport.connect( 
     736            "::1", self.server.transport.getHost().port) 
     737 
     738    def test_interface(self): 
     739        """ 
     740        Test C{getOutgoingInterface} and C{setOutgoingInterface}. 
     741        """ 
     742        self.assertEqual( 
     743            self.client.transport.getOutgoingInterface(), self.all) 
     744        self.assertEqual( 
     745            self.server.transport.getOutgoingInterface(), self.all) 
     746 
     747        d1 = self.client.transport.setOutgoingInterface(self.localhost) 
     748        d2 = self.server.transport.setOutgoingInterface(self.localhost) 
     749        result = gatherResults([d1, d2]) 
     750 
     751        def cbInterfaces(ignored): 
     752            self.assertEqual( 
     753                self.client.transport.getOutgoingInterface(), self.all) 
     754            self.assertEqual( 
     755                self.server.transport.getOutgoingInterface(), self.all) 
     756        result.addCallback(cbInterfaces) 
     757        return result 
     758 
     759 
     760     
    693761if not interfaces.IReactorUDP(reactor, None): 
    694762    UDPTestCase.skip = "This reactor does not support UDP" 
    695763    ReactorShutdownInteraction.skip = "This reactor does not support UDP" 
  • twisted/internet/test/test_address.py

     
    199199        """ 
    200200        return IPv6Address("TCP", "::2", 0) 
    201201 
     202    def buildWholeAddress(self): 
     203        """ 
     204        Like L{buldAddress}, but assigns all fields specific to 
     205        ipv6 (including flow info and scope id) 
     206        """ 
     207        return IPv6Address("TCP", "FE80::", 1, 1, None) 
    202208 
     209    def test_specificFields(self): 
     210        """ 
     211        Simply check if ipv6 specific fields exist. 
     212        """ 
     213        addr = self.buildWholeAddress() 
     214        self.assertTrue(hasattr(addr, "flowInfo")) 
     215        self.assertTrue(hasattr(addr, "scopeId")) 
    203216 
     217 
     218 
    204219class UNIXAddressTestCase(unittest.SynchronousTestCase, AddressTestCaseMixin): 
    205220    addressArgSpec = (("name", "%r"),) 
    206221 
  • 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, 
     
    4848        """ 
    4949        return "(UDP Port %s Closed)" % (port.getHost().port,) 
    5050 
     51    def getIPv6ListeningPort(self, reactor, protocol): 
     52        """ 
     53        Get a UDP port binded to ipv6 interface. 
     54        """ 
     55        return reactor.listenUDP(0, protocol, "::1") 
    5156 
    5257 
     58 
    5359class DatagramTransportTestsMixin(LogObserverMixin): 
    5460    """ 
    5561    Mixin defining tests which apply to any port/datagram based transport. 
     
    162168        self.assertEqual( 
    163169            port.getHost(), IPv4Address('UDP', host, portNumber)) 
    164170 
     171    def test_getHostIPv6(self): 
     172        """ 
     173        L{IListeningPort.getHost} returns an L{IPv6Address} giving a 
     174        IPv6 address, the port number that the protocol is listening on 
     175        and the port number. 
     176        """ 
     177        reactor = self.buildReactor() 
     178        port = self.getIPv6ListeningPort(reactor, DatagramProtocol()) 
     179        addr = port.getHost() 
     180        self.assertEqual(addr.host, "::1") 
     181        self.assertEqual(addr.flowInfo, 0) 
     182        self.assertEqual(addr.scopeId, 0) 
    165183 
     184 
     185 
    166186    def test_logPrefix(self): 
    167187        """ 
    168188        Datagram transports implement L{ILoggingContext.logPrefix} to return a 
  • twisted/internet/abstract.py

     
    99from __future__ import division, absolute_import 
    1010 
    1111from socket import AF_INET6, inet_pton, error 
     12from struct import unpack 
    1213 
     14 
    1315from zope.interface import implementer 
    1416 
    1517# Twisted Imports 
     
    526528        return False 
    527529    return True 
    528530 
     531#Look: 
     532#http://stackoverflow.com/questions/10558441/inet-aton-similar-function-for-ipv6 
     533def covertIPv6ToInteger(address): 
     534    """Convert ipv6 address to integer""" 
     535    address = inet_pton(AF_INET6, address) 
     536    a, b = unpack(">QQ", address) 
     537    return (a << 64) | b 
    529538 
    530 __all__ = ["FileDescriptor", "isIPAddress", "isIPv6Address"] 
     539__all__ = ["FileDescriptor", "isIPAddress", "isIPv6Address", 
     540           "covertIPv6ToInteger"] 
  • twisted/internet/base.py

     
    564564        if not name: 
    565565            # XXX - This is *less than* '::', and will screw up IPv6 servers 
    566566            return defer.succeed('0.0.0.0') 
    567         if abstract.isIPAddress(name): 
     567        if abstract.isIPAddress(name) or abstract.isIPv6Address(name): 
    568568            return defer.succeed(name) 
    569569        return self.resolver.getHostByName(name, timeout) 
    570570 
  • twisted/internet/address.py

     
    7777        IPv6 address; for example, "::1". 
    7878    @type host: C{str} 
    7979    """ 
     80    def __init__(self, type, host, port, flowInfo=0, scopeId=0, _bwHack=None): 
     81        _IPAddress.__init__(self, type, host, port) 
     82        self.flowInfo = flowInfo 
     83        self.scopeId = scopeId 
     84        if _bwHack is not None: 
     85            warnings.warn("twisted.internet.address.IPv4Address._bwHack " 
     86                          "is deprecated since Twisted 11.0", 
     87                          DeprecationWarning, stacklevel=2) 
    8088 
    8189 
    8290 
  • 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            if not socket.has_ipv6: 
     262                raise RuntimeError("IPV6 is not supported, "+\ 
     263                                       "compile with ipv6 support") 
     264            self.addressFamily = socket.AF_INET6 
     265        elif abstract.isIPAddress(self.interface): 
     266            self.addressFamily = socket.AF_INET 
     267         
    255268 
     269 
    256270    def logPrefix(self): 
    257271        """ 
    258272        Return the prefix to log with. 
     
    262276 
    263277    def getHost(self): 
    264278        """ 
    265         Returns an IPv4Address. 
     279        Returns an IPv4Address or IPv6Address. 
    266280 
    267281        This indicates the address from which I am connecting. 
    268282        """ 
    269         return address.IPv4Address('UDP', *self.socket.getsockname()) 
     283        if self.addressFamily == socket.AF_INET: 
     284            return address.IPv4Address('UDP', *self.socket.getsockname()) 
     285        elif self.addressFamily == socket.AF_INET6: 
     286            return address.IPv6Address('UDP', *self.socket.getsockname()) 
    270287 
    271288 
    272289 
     
    276293    """ 
    277294 
    278295    def getOutgoingInterface(self): 
    279         i = self.socket.getsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF) 
    280         return socket.inet_ntoa(struct.pack("@i", i)) 
     296        i = self.socket.getsockopt(self.IPLayer, self.multicastOUT) 
     297        #FIXME This might be a bug. 
     298        if self.IPLayer == socket.IPPROTO_IPV6: 
     299            addr = struct.pack("@i", i) 
     300            addr = addr.ljust(16, '\x00') 
     301        else: 
     302            addr = struct.pack("@i", i) 
     303        return socket.inet_ntop(self.addressFamily, addr) 
    281304 
    282305    def setOutgoingInterface(self, addr): 
    283306        """Returns Deferred of success.""" 
    284307        return self.reactor.resolve(addr).addCallback(self._setInterface) 
    285308 
    286309    def _setInterface(self, addr): 
    287         i = socket.inet_aton(addr) 
    288         self.socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, i) 
     310        i = socket.inet_pton(self.addressFamily, addr) 
     311        self.socket.setsockopt(self.IPLayer, self.multicastOUT, i) 
    289312        return 1 
    290313 
    291314    def getLoopbackMode(self): 
    292         return self.socket.getsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP) 
     315        return self.socket.getsockopt(self.IPLayer, self.multicastLoop) 
    293316 
    294317    def setLoopbackMode(self, mode): 
    295         mode = struct.pack("b", operator.truth(mode)) 
    296         self.socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, mode) 
     318        if self.IPLayer != socket.IPPROTO_IPV6: 
     319            mode = struct.pack("b", operator.truth(mode)) 
     320        self.socket.setsockopt(self.IPLayer, self.multicastLoop, mode) 
    297321 
    298322    def getTTL(self): 
    299         return self.socket.getsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL) 
     323        return self.socket.getsockopt(self.IPLayer, self.multicastHops) 
    300324 
    301325    def setTTL(self, ttl): 
    302         ttl = struct.pack("B", ttl) 
    303         self.socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl) 
     326        if self.IPLayer != socket.IPPROTO_IPV6: 
     327            ttl = struct.pack("B", ttl) 
     328        self.socket.setsockopt(self.IPLayer, self.multicastHops, ttl) 
    304329 
     330    def _checkIPVersions(self, addr1, addr2): 
     331        """Check if address versions match""" 
     332        addrIsIPv6 = abstract.isIPv6Address(addr1) 
     333        interfaceIsIPv6 = abstract.isIPv6Address(addr2) 
     334        if addrIsIPv6 and interfaceIsIPv6: 
     335            pass 
     336        elif not addrIsIPv6 and not addrIsIPv6: 
     337            pass 
     338        else: 
     339            raise RuntimeError("IP version mismatch") 
     340 
    305341    def joinGroup(self, addr, interface=""): 
    306342        """Join a multicast group. Returns Deferred of success.""" 
     343        self._checkIPVersions(addr, interface) 
    307344        return self.reactor.resolve(addr).addCallback(self._joinAddr1, interface, 1) 
    308345 
    309346    def _joinAddr1(self, addr, interface, join): 
    310347        return self.reactor.resolve(interface).addCallback(self._joinAddr2, addr, join) 
    311348 
    312349    def _joinAddr2(self, interface, addr, join): 
    313         addr = socket.inet_aton(addr) 
    314         interface = socket.inet_aton(interface) 
     350 
     351        addr = socket.inet_pton(self.addressFamily, addr) 
     352        interface = socket.inet_pton(self.addressFamily, interface) 
    315353        if join: 
    316             cmd = socket.IP_ADD_MEMBERSHIP 
     354            cmd = self.multicastJoin 
    317355        else: 
    318             cmd = socket.IP_DROP_MEMBERSHIP 
     356            cmd = self.multicastLeave 
    319357        try: 
    320             self.socket.setsockopt(socket.IPPROTO_IP, cmd, addr + interface) 
     358            self.socket.setsockopt(self.IPLayer, cmd, addr + interface) 
    321359        except socket.error as e: 
    322             return failure.Failure(error.MulticastJoinError(addr, interface, *e.args)) 
     360            return failure.Failure(error.MulticastJoinError( 
     361                    addr, interface, *e.args)) 
    323362 
    324363    def leaveGroup(self, addr, interface=""): 
    325364        """Leave multicast group, return Deferred of success.""" 
     365        self._checkIPVersions(addr, interface) 
    326366        return self.reactor.resolve(addr).addCallback(self._joinAddr1, interface, 0) 
    327367 
    328368 
     
    331371    """ 
    332372    UDP Port that supports multicasting. 
    333373    """ 
     374    IPLayer = socket.IPPROTO_IP 
     375    multicastJoin = socket.IP_ADD_MEMBERSHIP 
     376    multicastLeave = socket.IP_DROP_MEMBERSHIP 
     377    multicastOUT = socket.IP_MULTICAST_IF 
     378    multicastLoop = socket.IP_MULTICAST_LOOP 
     379    multicastHops = socket.IP_MULTICAST_TTL 
    334380 
    335381    def __init__(self, port, proto, interface='', maxPacketSize=8192, reactor=None, listenMultiple=False): 
    336382        """ 
    337383        @see: L{twisted.internet.interfaces.IReactorMulticast.listenMulticast} 
    338384        """ 
    339385        Port.__init__(self, port, proto, interface, maxPacketSize, reactor) 
     386        if abstract.isIPv6Address(interface): 
     387            self.IPLayer = socket.IPPROTO_IPV6 
     388            self.multicastJoin = socket.IPV6_JOIN_GROUP 
     389            self.multicastLeave = socket.IPV6_LEAVE_GROUP 
     390            self.multicastOUT = socket.IPV6_MULTICAST_IF 
     391            self.multicastLoop = socket.IPV6_MULTICAST_LOOP 
     392            self.multicastHops = socket.IPV6_MULTICAST_HOPS 
     393 
    340394        self.listenMultiple = listenMultiple 
    341395 
    342396    def createInternetSocket(self):