Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
  • 4 commits
  • 7 files changed
  • 0 comments
  • 1 contributor
Jun 17, 2013
Branching to 'udp-port-from-fd-5574-2'
git-svn-id: svn://svn.twistedmatrix.com/svn/Twisted/branches/udp-port-from-fd-5574-2@38845 bbbe8e31-12d6-0310-92fd-ac37d47ddeeb
941d00d
merge forward
git-svn-id: svn://svn.twistedmatrix.com/svn/Twisted/branches/udp-port-from-fd-5574-2@38846 bbbe8e31-12d6-0310-92fd-ac37d47ddeeb
515a8b5
Jun 18, 2013
address code review points
git-svn-id: svn://svn.twistedmatrix.com/svn/Twisted/branches/udp-port-from-fd-5574-2@38848 bbbe8e31-12d6-0310-92fd-ac37d47ddeeb
ef5fa7c
Pass the correct address type to FakePort
git-svn-id: svn://svn.twistedmatrix.com/svn/Twisted/branches/udp-port-from-fd-5574-2@38849 bbbe8e31-12d6-0310-92fd-ac37d47ddeeb
ee618a3
64  twisted/internet/interfaces.py
@@ -837,7 +837,21 @@ class IReactorUDP(Interface):
837 837
 
838 838
     def listenUDP(port, protocol, interface='', maxPacketSize=8192):
839 839
         """
840  
-        Connects a given DatagramProtocol to the given numeric UDP port.
  840
+        Connects a given L{DatagramProtocol} to the given numeric UDP port.
  841
+
  842
+        @param port: A port number on which to listen.
  843
+        @type port: C{int}
  844
+
  845
+        @param protocol: A L{DatagramProtocol} instance which will be
  846
+            connected to the given C{port}.
  847
+        @type protocol: L{DatagramProtocol}
  848
+
  849
+        @param interface: The local IPv4 or IPv6 address to which to bind;
  850
+            defaults to '', ie all IPv4 addresses.
  851
+        @type interface: C{str}
  852
+
  853
+        @param maxPacketSize: The maximum packet size to accept.
  854
+        @type maxPacketSize: C{int}
841 855
 
842 856
         @return: object which provides L{IListeningPort}.
843 857
         """
@@ -905,7 +919,6 @@ class IReactorSocket(Interface):
905 919
 
906 920
         - U{http://twistedmatrix.com/trac/ticket/5570}: established connections
907 921
         - U{http://twistedmatrix.com/trac/ticket/5573}: AF_UNIX ports
908  
-        - U{http://twistedmatrix.com/trac/ticket/5574}: SOCK_DGRAM sockets
909 922
     """
910 923
 
911 924
     def adoptStreamPort(fileDescriptor, addressFamily, factory):
@@ -929,12 +942,13 @@ def adoptStreamPort(fileDescriptor, addressFamily, factory):
929 942
 
930 943
         @return: An object providing L{IListeningPort}.
931 944
 
932  
-        @raise UnsupportedAddressFamily: If the given address family is not
933  
-            supported by this reactor, or not supported with the given socket
934  
-            type.
  945
+        @raise twisted.internet.error.UnsupportedAddressFamily: If the
  946
+            given address family is not supported by this reactor, or
  947
+            not supported with the given socket type.
935 948
 
936  
-        @raise UnsupportedSocketType: If the given socket type is not supported
937  
-            by this reactor, or not supported with the given socket type.
  949
+        @raise twisted.internet.error.UnsupportedSocketType: If the
  950
+            given socket type is not supported by this reactor, or not
  951
+            supported with the given socket type.
938 952
         """
939 953
 
940 954
 
@@ -970,6 +984,42 @@ def adoptStreamConnection(fileDescriptor, addressFamily, factory):
970 984
         """
971 985
 
972 986
 
  987
+    def adoptDatagramPort(fileDescriptor, addressFamily, protocol,
  988
+                          maxPacketSize=8192):
  989
+        """
  990
+        Add an existing listening I{SOCK_DGRAM} socket to the reactor to
  991
+        monitor for read and write readiness.
  992
+
  993
+        @param fileDescriptor: A file descriptor associated with a socket which
  994
+            is already bound to an address and marked as listening.  The socket
  995
+            must be set non-blocking.  Any additional flags (for example,
  996
+            close-on-exec) must also be set by application code.  Application
  997
+            code is responsible for closing the file descriptor, which may be
  998
+            done as soon as C{adoptDatagramPort} returns.
  999
+        @type fileDescriptor: C{int}
  1000
+
  1001
+        @param addressFamily: The address family (or I{domain}) of the socket.
  1002
+            For example, L{socket.AF_INET6}.
  1003
+        @type addressFamily: C{int}
  1004
+
  1005
+        @param protocol: A L{DatagramProtocol} instance to connect to
  1006
+            a UDP transport.
  1007
+        @type protocol: L{DatagramProtocol}
  1008
+
  1009
+        @param maxPacketSize: The maximum packet size to accept.
  1010
+        @type maxPacketSize: C{int}
  1011
+
  1012
+        @return: An object providing L{IListeningPort}.
  1013
+
  1014
+        @raise L{UnsupportedAddressFamily}: If the given address family is not
  1015
+            supported by this reactor, or not supported with the given socket
  1016
+            type.
  1017
+
  1018
+        @raise UnsupportedSocketType: If the given socket type is not supported
  1019
+            by this reactor, or not supported with the given socket type.
  1020
+        """
  1021
+
  1022
+
973 1023
 
974 1024
 class IReactorProcess(Interface):
975 1025
 
15  twisted/internet/posixbase.py
@@ -475,6 +475,19 @@ def adoptStreamConnection(self, fileDescriptor, addressFamily, factory):
475 475
             fileDescriptor, addressFamily, factory, self)
476 476
 
477 477
 
  478
+    def adoptDatagramPort(self, fileDescriptor, addressFamily, protocol,
  479
+                          maxPacketSize=8192):
  480
+        if addressFamily not in (socket.AF_INET, socket.AF_INET6):
  481
+            raise error.UnsupportedAddressFamily(addressFamily)
  482
+
  483
+        p = udp.Port._fromListeningDescriptor(
  484
+            self, fileDescriptor, addressFamily, protocol,
  485
+            maxPacketSize=maxPacketSize)
  486
+        p.startListening()
  487
+        return p
  488
+
  489
+
  490
+
478 491
     # IReactorTCP
479 492
 
480 493
     def listenTCP(self, port, factory, backlog=50, interface=''):
@@ -581,7 +594,7 @@ def _doReadOrWrite(self, selectable, fd, event):
581 594
             # Any non-disconnect event turns into a doRead or a doWrite.
582 595
             try:
583 596
                 # First check to see if the descriptor is still valid.  This
584  
-                # gives fileno() a chance to raise an exception, too. 
  597
+                # gives fileno() a chance to raise an exception, too.
585 598
                 # Ideally, disconnection would always be indicated by the
586 599
                 # return value of doRead or doWrite (or an exception from
587 600
                 # one of those methods), but calling fileno here helps make
108  twisted/internet/test/test_socket.py
... ...
@@ -1,10 +1,21 @@
  1
+# Copyright (c) Twisted Matrix Laboratories.
  2
+# See LICENSE for details.
  3
+
  4
+"""
  5
+Tests for implementations of L{IReactorSocket}.
  6
+
  7
+Generally only tests for failure cases are found here.  Success cases for
  8
+this interface are tested elsewhere.  For example, the success case for
  9
+I{AF_INET} is in L{twisted.internet.test.test_tcp}, since that case should
  10
+behave exactly the same as L{IReactorTCP.listenTCP}.
  11
+"""
1 12
 
2 13
 import errno, socket
3 14
 
4 15
 from twisted.python.log import err
5 16
 from twisted.internet.interfaces import IReactorSocket
6 17
 from twisted.internet.error import UnsupportedAddressFamily
7  
-from twisted.internet.protocol import ServerFactory
  18
+from twisted.internet.protocol import DatagramProtocol, ServerFactory
8 19
 from twisted.internet.test.reactormixins import (
9 20
     ReactorBuilder, needsRunningReactor)
10 21
 
@@ -59,10 +70,11 @@ def test_invalidAddressFamily(self):
59 70
 
60 71
     def test_stopOnlyCloses(self):
61 72
         """
62  
-        When the L{IListeningPort} returned by L{IReactorSocket.adoptStreamPort}
63  
-        is stopped using C{stopListening}, the underlying socket is closed but
64  
-        not shutdown.  This allows another process which still has a reference
65  
-        to it to continue accepting connections over it.
  73
+        When the L{IListeningPort} returned by
  74
+        L{IReactorSocket.adoptStreamPort} is stopped using
  75
+        C{stopListening}, the underlying socket is closed but not
  76
+        shutdown.  This allows another process which still has a
  77
+        reference to it to continue accepting connections over it.
66 78
         """
67 79
         reactor = self.buildReactor()
68 80
 
@@ -77,8 +89,9 @@ def test_stopOnlyCloses(self):
77 89
             portSocket.fileno(), portSocket.family, ServerFactory())
78 90
         d = port.stopListening()
79 91
         def stopped(ignored):
80  
-            # Should still be possible to accept a connection on portSocket.  If
81  
-            # it was shutdown, the exception would be EINVAL instead.
  92
+            # Should still be possible to accept a connection on
  93
+            # portSocket.  If it was shutdown, the exception would be
  94
+            # EINVAL instead.
82 95
             exc = self.assertRaises(socket.error, portSocket.accept)
83 96
             self.assertEqual(exc.args[0], errno.EAGAIN)
84 97
         d.addCallback(stopped)
@@ -124,5 +137,86 @@ def test_invalidAddressFamily(self):
124 137
 
125 138
 
126 139
 
  140
+class AdoptDatagramPortErrorsTestsBuilder(ReactorBuilder):
  141
+    """
  142
+    Builder for testing L{IReactorSocket.adoptDatagramPort} implementations.
  143
+    """
  144
+    requiredInterfaces = [IReactorSocket]
  145
+
  146
+
  147
+    def test_invalidDescriptor(self):
  148
+        """
  149
+        An implementation of L{IReactorSocket.adoptDatagramPort} raises
  150
+        L{socket.error} if passed an integer which is not associated with a
  151
+        socket.
  152
+        """
  153
+        reactor = self.buildReactor()
  154
+
  155
+        probe = socket.socket()
  156
+        fileno = probe.fileno()
  157
+        probe.close()
  158
+
  159
+        exc = self.assertRaises(
  160
+            socket.error,
  161
+            reactor.adoptDatagramPort, fileno, socket.AF_INET,
  162
+            DatagramProtocol())
  163
+        self.assertEqual(exc.args[0], errno.EBADF)
  164
+
  165
+
  166
+    def test_invalidAddressFamily(self):
  167
+        """
  168
+        An implementation of L{IReactorSocket.adoptDatagramPort} raises
  169
+        L{UnsupportedAddressFamily} if passed an address family it does not
  170
+        support.
  171
+        """
  172
+        reactor = self.buildReactor()
  173
+
  174
+        port = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  175
+        self.addCleanup(port.close)
  176
+
  177
+        arbitrary = 2 ** 16 + 7
  178
+
  179
+        self.assertRaises(
  180
+            UnsupportedAddressFamily,
  181
+            reactor.adoptDatagramPort, port.fileno(), arbitrary,
  182
+            DatagramProtocol())
  183
+
  184
+
  185
+    def test_stopOnlyCloses(self):
  186
+        """
  187
+        When the L{IListeningPort} returned by
  188
+        L{IReactorSocket.adoptDatagramPort} is stopped using
  189
+        C{stopListening}, the underlying socket is closed but not
  190
+        shutdown.  This allows another process which still has a
  191
+        reference to it to continue reading and writing to it.
  192
+        """
  193
+        reactor = self.buildReactor()
  194
+
  195
+        portSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  196
+        self.addCleanup(portSocket.close)
  197
+
  198
+        portSocket.setblocking(False)
  199
+
  200
+        # The file descriptor is duplicated by adoptDatagramPort
  201
+        port = reactor.adoptDatagramPort(
  202
+            portSocket.fileno(), portSocket.family, DatagramProtocol())
  203
+        d = port.stopListening()
  204
+        def stopped(ignored):
  205
+            # Should still be possible to recv on portSocket.  If
  206
+            # it was shutdown, the exception would be EINVAL instead.
  207
+            exc = self.assertRaises(socket.error, portSocket.recvfrom, 1)
  208
+            self.assertEqual(exc.args[0], errno.EAGAIN)
  209
+        d.addCallback(stopped)
  210
+        d.addErrback(err, "Failed to read on original port.")
  211
+
  212
+        needsRunningReactor(
  213
+            reactor,
  214
+            lambda: d.addCallback(lambda ignored: reactor.stop()))
  215
+
  216
+        reactor.run()
  217
+
  218
+
  219
+
127 220
 globals().update(AdoptStreamPortErrorsTestsBuilder.makeTestCaseClasses())
128 221
 globals().update(AdoptStreamConnectionErrorsTestsBuilder.makeTestCaseClasses())
  222
+globals().update(AdoptDatagramPortErrorsTestsBuilder.makeTestCaseClasses())
115  twisted/internet/test/test_udp.py
@@ -2,14 +2,15 @@
2 2
 # See LICENSE for details.
3 3
 
4 4
 """
5  
-Tests for implementations of L{IReactorUDP}.
  5
+Tests for implementations of L{IReactorUDP} and the UDP parts of
  6
+L{IReactorSocket}.
6 7
 """
7 8
 
8 9
 from __future__ import division, absolute_import
9 10
 
10 11
 __metaclass__ = type
11 12
 
12  
-from socket import SOCK_DGRAM
  13
+import socket
13 14
 
14 15
 from zope.interface import implementer
15 16
 from zope.interface.verify import verifyObject
@@ -19,20 +20,78 @@
19 20
 from twisted.internet.test.reactormixins import ReactorBuilder
20 21
 from twisted.internet.defer import Deferred, maybeDeferred
21 22
 from twisted.internet.interfaces import (
22  
-    ILoggingContext, IListeningPort, IReactorUDP)
  23
+    ILoggingContext, IListeningPort, IReactorUDP, IReactorSocket)
23 24
 from twisted.internet.address import IPv4Address
24 25
 from twisted.internet.protocol import DatagramProtocol
25 26
 
26 27
 from twisted.internet.test.connectionmixins import (LogObserverMixin,
27 28
                                                     findFreePort)
  29
+from twisted.trial.unittest import SkipTest
28 30
 
29 31
 
30  
-class UDPPortMixin(object):
31  
-    def getListeningPort(self, reactor, protocol):
  32
+
  33
+class ListenUDPMixin(object):
  34
+    """
  35
+    Mixin which uses L{IReactorUDP.listenUDP} to hand out listening UDP ports.
  36
+    """
  37
+    def getListeningPort(self, reactor, protocol, port=0, interface='',
  38
+                         maxPacketSize=8192):
32 39
         """
33 40
         Get a UDP port from a reactor.
34 41
         """
35  
-        return reactor.listenUDP(0, protocol)
  42
+        return reactor.listenUDP(port, protocol, interface=interface,
  43
+                                 maxPacketSize=maxPacketSize)
  44
+
  45
+
  46
+    def getExpectedStartListeningLogMessage(self, port, protocol):
  47
+        """
  48
+        Get the message expected to be logged when a UDP port starts listening.
  49
+        """
  50
+        return "%s starting on %d" % (protocol, port.getHost().port)
  51
+
  52
+
  53
+    def getExpectedConnectionLostLogMessage(self, port):
  54
+        """
  55
+        Get the expected connection lost message for a UDP port.
  56
+        """
  57
+        return "(UDP Port %s Closed)" % (port.getHost().port,)
  58
+
  59
+
  60
+
  61
+class SocketUDPMixin(object):
  62
+    """
  63
+    Mixin which uses L{IReactorSocket.adoptDatagramPort} to hand out
  64
+    listening UDP ports.
  65
+    """
  66
+    def getListeningPort(self, reactor, protocol, port=0, interface='',
  67
+                         maxPacketSize=8192):
  68
+        """
  69
+        Get a UDP port from a reactor, wrapping an already-initialized file
  70
+        descriptor.
  71
+        """
  72
+        if IReactorSocket.providedBy(reactor):
  73
+            if ':' in interface:
  74
+                domain = socket.AF_INET6
  75
+                address = socket.getaddrinfo(interface, port)[0][4]
  76
+            else:
  77
+                domain = socket.AF_INET
  78
+                address = (interface, port)
  79
+            portSock = socket.socket(domain, socket.SOCK_DGRAM)
  80
+            portSock.bind(address)
  81
+            portSock.setblocking(False)
  82
+            try:
  83
+                return reactor.adoptDatagramPort(
  84
+                    portSock.fileno(), portSock.family, protocol,
  85
+                    maxPacketSize)
  86
+            finally:
  87
+                # The socket should still be open; fileno will raise if it is
  88
+                # not.
  89
+                portSock.fileno()
  90
+                # Now clean it up, because the rest of the test does not need
  91
+                # it.
  92
+                portSock.close()
  93
+        else:
  94
+            raise SkipTest("Reactor does not provide IReactorSocket")
36 95
 
37 96
 
38 97
     def getExpectedStartListeningLogMessage(self, port, protocol):
@@ -133,19 +192,17 @@ def stopProtocol(self):
133 192
 
134 193
 
135 194
 
136  
-class UDPServerTestsBuilder(ReactorBuilder, UDPPortMixin,
137  
-                            DatagramTransportTestsMixin):
  195
+class UDPPortTestsMixin(object):
138 196
     """
139  
-    Builder defining tests relating to L{IReactorUDP.listenUDP}.
  197
+    Tests for L{IReactorUDP.listenUDP} and
  198
+    L{IReactorSocket.adoptDatagramPort}.
140 199
     """
141  
-    requiredInterfaces = (IReactorUDP,)
142  
-
143 200
     def test_interface(self):
144 201
         """
145 202
         L{IReactorUDP.listenUDP} returns an object providing L{IListeningPort}.
146 203
         """
147 204
         reactor = self.buildReactor()
148  
-        port = reactor.listenUDP(0, DatagramProtocol())
  205
+        port = self.getListeningPort(reactor, DatagramProtocol())
149 206
         self.assertTrue(verifyObject(IListeningPort, port))
150 207
 
151 208
 
@@ -155,10 +212,10 @@ def test_getHost(self):
155 212
         dotted-quad of the IPv4 address the port is listening on as well as
156 213
         the port number.
157 214
         """
158  
-        host, portNumber = findFreePort(type=SOCK_DGRAM)
  215
+        host, portNumber = findFreePort(type=socket.SOCK_DGRAM)
159 216
         reactor = self.buildReactor()
160  
-        port = reactor.listenUDP(
161  
-            portNumber, DatagramProtocol(), interface=host)
  217
+        port = self.getListeningPort(
  218
+            reactor, DatagramProtocol(), port=portNumber, interface=host)
162 219
         self.assertEqual(
163 220
             port.getHost(), IPv4Address('UDP', host, portNumber))
164 221
 
@@ -185,7 +242,7 @@ def datagramReceived(self, bytes, addr):
185 242
         reactor = self.buildReactor()
186 243
         protocol = CustomLogPrefixDatagramProtocol("Custom Datagrams")
187 244
         d = protocol.system
188  
-        port = reactor.listenUDP(0, protocol)
  245
+        port = self.getListeningPort(reactor, protocol)
189 246
         address = port.getHost()
190 247
 
191 248
         def gotSystem(system):
@@ -203,7 +260,7 @@ def test_str(self):
203 260
         C{str()} on the listening port object includes the port number.
204 261
         """
205 262
         reactor = self.buildReactor()
206  
-        port = reactor.listenUDP(0, DatagramProtocol())
  263
+        port = self.getListeningPort(reactor, DatagramProtocol())
207 264
         self.assertIn(str(port.getHost().port), str(port))
208 265
 
209 266
 
@@ -212,7 +269,29 @@ def test_repr(self):
212 269
         C{repr()} on the listening port object includes the port number.
213 270
         """
214 271
         reactor = self.buildReactor()
215  
-        port = reactor.listenUDP(0, DatagramProtocol())
  272
+        port = self.getListeningPort(reactor, DatagramProtocol())
216 273
         self.assertIn(repr(port.getHost().port), str(port))
217 274
 
  275
+
  276
+
  277
+class UDPServerTestsBuilder(ReactorBuilder, ListenUDPMixin,
  278
+                            UDPPortTestsMixin, DatagramTransportTestsMixin):
  279
+    """
  280
+    Run L{UDPPortTestsMixin} tests using UDP newly created UDP
  281
+    sockets.
  282
+    """
  283
+    requiredInterfaces = (IReactorUDP,)
  284
+
  285
+
  286
+
  287
+class UDPFDServerTestsBuilder(ReactorBuilder, SocketUDPMixin,
  288
+                              UDPPortTestsMixin, DatagramTransportTestsMixin):
  289
+    """
  290
+    Run L{UDPPortTestsMixin} tests using adopted UDP sockets.
  291
+    """
  292
+    requiredInterfaces = (IReactorSocket,)
  293
+
  294
+
  295
+
218 296
 globals().update(UDPServerTestsBuilder.makeTestCaseClasses())
  297
+globals().update(UDPFDServerTestsBuilder.makeTestCaseClasses())
93  twisted/internet/udp.py
@@ -53,25 +53,53 @@
53 53
 from twisted.internet import abstract, error, interfaces
54 54
 
55 55
 
  56
+
56 57
 @implementer(
57 58
     interfaces.IListeningPort, interfaces.IUDPTransport,
58 59
     interfaces.ISystemHandle)
59 60
 class Port(base.BasePort):
60 61
     """
61 62
     UDP port, listening for packets.
  63
+
  64
+    @ivar maxThroughput: Maximum number of bytes read in one event
  65
+        loop iteration.
  66
+
  67
+    @ivar _realPortNumber: Actual port number being listened on. The
  68
+        value will be C{None} until this L{Port} is listening.
  69
+
  70
+    @ivar _preexistingSocket: If not C{None}, a L{socket.socket} instance which
  71
+        was created and initialized outside of the reactor and will be used to
  72
+        listen for connections (instead of a new socket being created by this
  73
+        L{Port}).
62 74
     """
63 75
 
64 76
     addressFamily = socket.AF_INET
65 77
     socketType = socket.SOCK_DGRAM
66  
-    maxThroughput = 256 * 1024 # max bytes we read in one eventloop iteration
  78
+    maxThroughput = 256 * 1024
67 79
 
68  
-    # Actual port number being listened on, only set to a non-None
69  
-    # value when we are actually listening.
70 80
     _realPortNumber = None
  81
+    _preexistingSocket = None
71 82
 
72 83
     def __init__(self, port, proto, interface='', maxPacketSize=8192, reactor=None):
73 84
         """
74  
-        Initialize with a numeric port to listen on.
  85
+        @param port: A port number on which to listen.
  86
+        @type port: C{int}
  87
+
  88
+        @param proto: A C{DatagramProtocol} instance which will be
  89
+            connected to the given C{port}.
  90
+        @type proto: L{twisted.internet.protocol.DatagramProtocol}
  91
+
  92
+        @param interface: The local IPv4 or IPv6 address to which to bind;
  93
+            defaults to '', ie all IPv4 addresses.
  94
+        @type interface: C{str}
  95
+
  96
+        @param maxPacketSize: The maximum packet size to accept.
  97
+        @type maxPacketSize: C{int}
  98
+
  99
+        @param reactor: A reactor which will notify this C{Port} when
  100
+            its socket is ready for reading or writing. Defaults to
  101
+            C{None}, ie the default global reactor.
  102
+        @type reactor: L{interfaces.IReactorFDSet}
75 103
         """
76 104
         base.BasePort.__init__(self, reactor)
77 105
         self.port = port
@@ -81,6 +109,36 @@ def __init__(self, port, proto, interface='', maxPacketSize=8192, reactor=None):
81 109
         self.setLogStr()
82 110
         self._connectedAddr = None
83 111
 
  112
+
  113
+    @classmethod
  114
+    def _fromListeningDescriptor(cls, reactor, fd, addressFamily, protocol,
  115
+                                 maxPacketSize):
  116
+        """
  117
+        Create a new L{Port} based on an existing listening
  118
+        I{SOCK_DGRAM} socket.
  119
+
  120
+        Arguments are the same as to L{Port.__init__}, except where noted.
  121
+
  122
+        @param fd: An integer file descriptor associated with a listening
  123
+            socket.  The socket must be in non-blocking mode.  Any additional
  124
+            attributes desired, such as I{FD_CLOEXEC}, must also be set already.
  125
+        @type fd: C{int}
  126
+
  127
+        @param addressFamily: The address family (sometimes called I{domain}) of
  128
+            the existing socket.  For example, L{socket.AF_INET}.
  129
+        @param addressFamilt: C{int}
  130
+
  131
+        @return: A new instance of C{cls} wrapping the socket given by C{fd}.
  132
+        @rtype: L{Port}
  133
+        """
  134
+        port = socket.fromfd(fd, addressFamily, cls.socketType)
  135
+        interface = port.getsockname()[0]
  136
+        self = cls(None, protocol, interface=interface, reactor=reactor,
  137
+                   maxPacketSize=maxPacketSize)
  138
+        self._preexistingSocket = port
  139
+        return self
  140
+
  141
+
84 142
     def __repr__(self):
85 143
         if self._realPortNumber is not None:
86 144
             return "<%s on %s>" % (self.protocol.__class__, self._realPortNumber)
@@ -103,12 +161,28 @@ def startListening(self):
103 161
         self._bindSocket()
104 162
         self._connectToProtocol()
105 163
 
  164
+
106 165
     def _bindSocket(self):
107  
-        try:
108  
-            skt = self.createInternetSocket()
109  
-            skt.bind((self.interface, self.port))
110  
-        except socket.error as le:
111  
-            raise error.CannotListenError(self.interface, self.port, le)
  166
+        """
  167
+        Responsible for preparing and assigning a L{socket.socket}
  168
+        instance to C{self.socket}.
  169
+