def _foolscapEndpointForPortNumber(portnum): """ Create an endpoint that can be passed to ``Tub.listen``. :param portnum: Either an integer port number indicating which TCP/IPv4 port number the endpoint should bind or ``None`` to automatically allocate such a port number. :return: A two-tuple of the integer port number allocated and a Foolscap-compatible endpoint object. """ if portnum is None: # Bury this reactor import here to minimize the chances of it having # the effect of installing the default reactor. from twisted.internet import reactor if fcntl is not None and IReactorSocket.providedBy(reactor): # On POSIX we can take this very safe approach of binding the # actual socket to an address. Once the bind succeeds here, we're # no longer subject to any future EADDRINUSE problems. s = socket.socket() try: s.bind(('', 0)) portnum = s.getsockname()[1] s.listen(1) # File descriptors are a relatively scarce resource. The # cleanup process for the file descriptor we're about to dup # is unfortunately complicated. In particular, it involves # the Python garbage collector. See CleanupEndpoint for # details of that. Here, we need to make sure the garbage # collector actually runs frequently enough to make a # difference. Normally, the garbage collector is triggered by # allocations. It doesn't know about *file descriptor* # allocation though. So ... we'll "teach" it about those, # here. fileDescriptorResource.allocate() fd = os.dup(s.fileno()) flags = fcntl.fcntl(fd, fcntl.F_GETFD) flags = flags | os.O_NONBLOCK | fcntl.FD_CLOEXEC fcntl.fcntl(fd, fcntl.F_SETFD, flags) endpoint = AdoptedStreamServerEndpoint(reactor, fd, socket.AF_INET) return (portnum, CleanupEndpoint(endpoint, fd)) finally: s.close() else: # Get a random port number and fall through. This is necessary on # Windows where Twisted doesn't offer IReactorSocket. This # approach is error prone for the reasons described on # https://tahoe-lafs.org/trac/tahoe-lafs/ticket/2787 portnum = allocate_tcp_port() return (portnum, native_str("tcp:%d" % (portnum, )))
def getListeningPort(self, reactor, protocol, port=0, interface='', maxPacketSize=8192): """ Get a UDP port from a reactor, wrapping an already-initialized file descriptor. @param reactor: A reactor used to build the returned L{IListeningPort} provider. @type reactor: L{twisted.internet.interfaces.IReactorSocket} @param port: A port number to which the adopted socket will be bound. @type port: C{int} @param interface: The local IPv4 or IPv6 address to which the adopted socket will be bound. defaults to '', ie all IPv4 addresses. @type interface: C{str} @see: L{twisted.internet.IReactorSocket.adoptDatagramPort} for other argument and return types. """ if IReactorSocket.providedBy(reactor): if ':' in interface: domain = socket.AF_INET6 address = socket.getaddrinfo(interface, port)[0][4] else: domain = socket.AF_INET address = (interface, port) portSock = socket.socket(domain, socket.SOCK_DGRAM) portSock.bind(address) portSock.setblocking(False) try: return reactor.adoptDatagramPort(portSock.fileno(), portSock.family, protocol, maxPacketSize) finally: # The socket should still be open; fileno will raise if it is # not. portSock.fileno() # Now clean it up, because the rest of the test does not need # it. portSock.close() else: raise SkipTest("Reactor does not provide IReactorSocket")
def getListeningPort(self, reactor, protocol, port=0, interface='', maxPacketSize=8192): """ Get a UDP port from a reactor, wrapping an already-initialized file descriptor. @param reactor: A reactor used to build the returned L{IListeningPort} provider. @type reactor: L{twisted.internet.interfaces.IReactorSocket} @param port: A port number to which the adopted socket will be bound. @type port: C{int} @param interface: The local IPv4 or IPv6 address to which the adopted socket will be bound. defaults to '', ie all IPv4 addresses. @type interface: C{str} @see: L{twisted.internet.IReactorSocket.adoptDatagramPort} for other argument and return types. """ if IReactorSocket.providedBy(reactor): if ':' in interface: domain = socket.AF_INET6 address = socket.getaddrinfo(interface, port)[0][4] else: domain = socket.AF_INET address = (interface, port) portSock = socket.socket(domain, socket.SOCK_DGRAM) portSock.bind(address) portSock.setblocking(False) try: return reactor.adoptDatagramPort( portSock.fileno(), portSock.family, protocol, maxPacketSize) finally: # The socket should still be open; fileno will raise if it is # not. portSock.fileno() # Now clean it up, because the rest of the test does not need # it. portSock.close() else: raise SkipTest("Reactor does not provide IReactorSocket")
def assign(self, reactor): """ Make a new streaming server endpoint and return its string description. This is intended to help write config files that will then be read and used in this process. :param reactor: The reactor which will be used to listen with the resulting endpoint. If it provides ``IReactorSocket`` then resulting reliability will be extremely high. If it doesn't, resulting reliability will be pretty alright. :return: A two-tuple of (location hint, port endpoint description) as strings. """ if IReactorSocket.providedBy(reactor): # On this platform, we can reliable pre-allocate a listening port. # Once it is bound we know it will not fail later with EADDRINUSE. s = socket(AF_INET, SOCK_STREAM) # We need to keep ``s`` alive as long as the file descriptor we put in # this string might still be used. We could dup() the descriptor # instead but then we've only inverted the cleanup problem: gone from # don't-close-too-soon to close-just-late-enough. So we'll leave # ``s`` alive and use it as the cleanup mechanism. self._cleanups.append(s.close) s.setblocking(False) really_bind(s, ("127.0.0.1", 0)) s.listen(SOMAXCONN) host, port = s.getsockname() location_hint = "tcp:%s:%d" % (host, port) port_endpoint = "adopt-socket:fd=%d" % (s.fileno(),) # Make sure `adopt-socket` is recognized. We do this instead of # providing a dropin because we don't want to make this endpoint # available to random other applications. self._patch_plugins() else: # On other platforms, we blindly guess and hope we get lucky. portnum = iputil.allocate_tcp_port() location_hint = "tcp:127.0.0.1:%d" % (portnum,) port_endpoint = "tcp:%d:interface=127.0.0.1" % (portnum,) return location_hint, port_endpoint
def assign(self, reactor): """ Make a new streaming server endpoint and return its string description. This is intended to help write config files that will then be read and used in this process. :param reactor: The reactor which will be used to listen with the resulting endpoint. If it provides ``IReactorSocket`` then resulting reliability will be extremely high. If it doesn't, resulting reliability will be pretty alright. :return: A two-tuple of (location hint, port endpoint description) as strings. """ if IReactorSocket.providedBy(reactor): # On this platform, we can reliable pre-allocate a listening port. # Once it is bound we know it will not fail later with EADDRINUSE. s = socket(AF_INET, SOCK_STREAM) # We need to keep ``s`` alive as long as the file descriptor we put in # this string might still be used. We could dup() the descriptor # instead but then we've only inverted the cleanup problem: gone from # don't-close-too-soon to close-just-late-enough. So we'll leave # ``s`` alive and use it as the cleanup mechanism. self._cleanups.append(s.close) s.setblocking(False) really_bind(s, ("127.0.0.1", 0)) s.listen(SOMAXCONN) host, port = s.getsockname() location_hint = "tcp:%s:%d" % (host, port) port_endpoint = "adopt-socket:fd=%d" % (s.fileno(), ) # Make sure `adopt-socket` is recognized. We do this instead of # providing a dropin because we don't want to make this endpoint # available to random other applications. self._patch_plugins() else: # On other platforms, we blindly guess and hope we get lucky. portnum = iputil.allocate_tcp_port() location_hint = "tcp:127.0.0.1:%d" % (portnum, ) port_endpoint = "tcp:%d:interface=127.0.0.1" % (portnum, ) return location_hint, port_endpoint
def _foolscapEndpointForPortNumber(portnum): """ Create an endpoint that can be passed to ``Tub.listen``. :param portnum: Either an integer port number indicating which TCP/IPv4 port number the endpoint should bind or ``None`` to automatically allocate such a port number. :return: A two-tuple of the integer port number allocated and a Foolscap-compatible endpoint object. """ if portnum is None: # Bury this reactor import here to minimize the chances of it having # the effect of installing the default reactor. from twisted.internet import reactor if fcntl is not None and IReactorSocket.providedBy(reactor): # On POSIX we can take this very safe approach of binding the # actual socket to an address. Once the bind succeeds here, we're # no longer subject to any future EADDRINUSE problems. s = socket.socket() try: s.bind(('', 0)) portnum = s.getsockname()[1] s.listen(1) fd = os.dup(s.fileno()) flags = fcntl.fcntl(fd, fcntl.F_GETFD) flags = flags | os.O_NONBLOCK | fcntl.FD_CLOEXEC fcntl.fcntl(fd, fcntl.F_SETFD, flags) return ( portnum, AdoptedStreamServerEndpoint(reactor, fd, socket.AF_INET), ) finally: s.close() else: # Get a random port number and fall through. This is necessary on # Windows where Twisted doesn't offer IReactorSocket. This # approach is error prone for the reasons described on # https://tahoe-lafs.org/trac/tahoe-lafs/ticket/2787 portnum = allocate_tcp_port() return (portnum, "tcp:%d" % (portnum,))
def foolscapEndpointForPortNumber(portnum): """ Create an endpoint that can be passed to ``Tub.listen``. :param portnum: Either an integer port number indicating which TCP/IPv4 port number the endpoint should bind or ``None`` to automatically allocate such a port number. :return: A two-tuple of the integer port number allocated and a Foolscap-compatible endpoint object. """ if portnum is None: # Bury this reactor import here to minimize the chances of it having # the effect of installing the default reactor. from twisted.internet import reactor if fcntl is not None and IReactorSocket.providedBy(reactor): # On POSIX we can take this very safe approach of binding the # actual socket to an address. Once the bind succeeds here, we're # no longer subject to any future EADDRINUSE problems. s = socket() try: s.bind(('', 0)) portnum = s.getsockname()[1] s.listen(1) fd = os.dup(s.fileno()) flags = fcntl.fcntl(fd, fcntl.F_GETFD) flags = flags | os.O_NONBLOCK | fcntl.FD_CLOEXEC fcntl.fcntl(fd, fcntl.F_SETFD, flags) return ( portnum, AdoptedStreamServerEndpoint(reactor, fd, AF_INET), ) finally: s.close() else: # Get a random port number and fall through. This is necessary on # Windows where Twisted doesn't offer IReactorSocket. This # approach is error prone for the reasons described on # https://tahoe-lafs.org/trac/tahoe-lafs/ticket/2787 portnum = iputil.allocate_tcp_port() return (portnum, "tcp:%d" % (portnum, ))