def _makeImageService(self, resource_root): from provisioningserver.rackdservices.image import ( BootImageEndpointService) from twisted.internet.endpoints import AdoptedStreamServerEndpoint port = 5248 # config["port"] # Make a socket with SO_REUSEPORT set so that we can run multiple we # applications. This is easier to do from outside of Twisted as there's # not yet official support for setting socket options. s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) try: s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) except socket_error as e: # Python's socket module was compiled using modern headers # thus defining SO_REUSEPORT would cause issues as it might # running in older kernel that does not support SO_REUSEPORT. # XXX andreserl 2015-04-08 bug=1441684: We need to add a warning # log message when we see this error, and a test for it. if e.errno != ENOPROTOOPT: raise e s.bind(('::', port)) # Use a backlog of 50, which seems to be fairly common. s.listen(50) # Adopt this socket into Twisted's reactor. site_endpoint = AdoptedStreamServerEndpoint(reactor, s.fileno(), s.family) site_endpoint.port = port # Make it easy to get the port number. site_endpoint.socket = s # Prevent garbage collection. image_service = BootImageEndpointService(resource_root=resource_root, endpoint=site_endpoint) image_service.setName("image_service") return image_service
def _makeHTTPService(self): """Create the HTTP service.""" from provisioningserver.rackdservices.http import HTTPResource from twisted.application.internet import StreamServerEndpointService from twisted.internet.endpoints import AdoptedStreamServerEndpoint from provisioningserver.utils.twisted import SiteNoLog port = 5249 s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) try: s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) except socket_error as e: if e.errno != ENOPROTOOPT: raise e s.bind(('::', port)) # Use a backlog of 50, which seems to be fairly common. s.listen(50) # Adopt this socket into Twisted's reactor. site_endpoint = AdoptedStreamServerEndpoint(reactor, s.fileno(), s.family) site_endpoint.port = port # Make it easy to get the port number. site_endpoint.socket = s # Prevent garbage collection. http_service = StreamServerEndpointService(site_endpoint, SiteNoLog(HTTPResource())) http_service.setName("http_service") return http_service
def _makeHTTPService(self, port, path, prefix=None): from twisted.internet.endpoints import AdoptedStreamServerEndpoint from provisioningserver.http import ( create_reuse_socket, EndpointService, ) # Create the HTTP socket binded to the provided port. s = create_reuse_socket() s.bind(('::', port)) # Use a backlog of 50, which seems to be fairly common. s.listen(50) # Adopt this socket into Twisted's reactor. site_endpoint = AdoptedStreamServerEndpoint( reactor, s.fileno(), s.family) site_endpoint.port = port # Make it easy to get the port number. site_endpoint.socket = s # Prevent garbage collection. # Setup the endpoing with the resource path. service = EndpointService( resource_root=path, endpoint=site_endpoint, prefix=prefix) service.setName("http_endpoint") return service
def _makeEndpoint(self): """Make the endpoint for the webapp.""" # Make a socket with SO_REUSEPORT set so that we can run multiple web # applications. This is easier to do from outside of Twisted as there's # not yet official support for setting socket options. s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) # N.B, using the IPv6 INADDR_ANY means that getpeername() returns # something like: ('::ffff:192.168.133.32', 40588, 0, 0) s.bind(("::", self.port)) # Use a backlog of 50, which seems to be fairly common. s.listen(50) # Adopt this socket into Twisted's reactor setting the endpoint. endpoint = AdoptedStreamServerEndpoint(reactor, s.fileno(), s.family) endpoint.port = self.port # Make it easy to get the port number. endpoint.socket = s # Prevent garbage collection. return endpoint
def make_WebApplicationService(postgresListener, statusWorker): from maasserver.webapp import WebApplicationService site_port = DEFAULT_PORT # config["port"] # Make a socket with SO_REUSEPORT set so that we can run multiple web # applications. This is easier to do from outside of Twisted as there's # not yet official support for setting socket options. s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) # N.B, using the IPv6 INADDR_ANY means that getpeername() returns something # like: ('::ffff:192.168.133.32', 40588, 0, 0) s.bind(('::', site_port)) # Use a backlog of 50, which seems to be fairly common. s.listen(50) # Adopt this socket into Twisted's reactor. site_endpoint = AdoptedStreamServerEndpoint(reactor, s.fileno(), s.family) site_endpoint.port = site_port # Make it easy to get the port number. site_endpoint.socket = s # Prevent garbage collection. site_service = WebApplicationService(site_endpoint, postgresListener, statusWorker) return site_service
def makeAgentService(store): """ Returns a service which will process GatewayAMPCommands, using a socket file descripter acquired by launchd @param store: an already opened store @returns: service """ from twisted.internet import reactor sockets = launchActivateSocket("AgentSocket") fd = sockets[0] family = socket.AF_INET endpoint = AdoptedStreamServerEndpoint(reactor, fd, family) directory = store.directoryService() def becameInactive(): log.warn("Agent inactive; shutting down") reactor.stop() from twistedcaldav.config import config inactivityDetector = InactivityDetector( reactor, config.AgentInactivityTimeoutSeconds, becameInactive ) root = Resource() root.putChild( "gateway", AgentGatewayResource( store, directory, inactivityDetector ) ) # We need this service to be able to return com.apple.calendarserver, # so tell it not to suppress system accounts. directory = OpenDirectoryDirectoryService( "/Local/Default", suppressSystemRecords=False ) portal = Portal( AgentRealm(root, [u"com.apple.calendarserver"]), [HTTPDigestCredentialChecker(directory)] ) credentialFactory = NoQOPDigestCredentialFactory( "md5", "/Local/Default" ) wrapper = HTTPAuthSessionWrapper(portal, [credentialFactory]) site = Site(wrapper) return StreamServerEndpointService(endpoint, site)
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 parseStreamServer(self, reactor, fd): log.msg("Adopting {}".format(fd)) # AdoptedStreamServerEndpoint wants to own the file descriptor. It # will duplicate it and then close the one we pass in. This means it # is really only possible to adopt a particular file descriptor once. # # This wouldn't matter except one of the tests wants to stop one of # the nodes and start it up again. This results in exactly an attempt # to adopt a particular file descriptor twice. # # So we'll dup it ourselves. AdoptedStreamServerEndpoint can do # whatever it wants to the result - the original will still be valid # and reusable. return AdoptedStreamServerEndpoint(reactor, os.dup(int(fd)), AF_INET)
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, ))
def test_proxying(self): pems = node_pems() # Create client and server tubs we can use to speak Foolscap through # the proxy. This should demonstrate the proxy is working. client = Tub(pems.example()) client.startService() self.addCleanup(client.stopService) server = Tub(pems.example()) server.startService() self.addCleanup(server.stopService) # Get an arbitrary local address on which the server tub can listen. while True: server_socket = socket() try: server_socket.bind(("", 0)) except Exception as e: print(e) server_socket.close() else: server_socket.listen(1) self.addCleanup(server_socket.close) break server_address = server_socket.getsockname() msg("Got server address {}".format(server_address)) server_endpoint = AdoptedStreamServerEndpoint( self.reactor, server_socket.fileno(), AF_INET, ) server.listenOn(server_endpoint) # Get a grid router that knows where the server tub really is and so # should be able to proxy connections to it for us. grid_router = _GridRouterService(self.reactor) grid_router.set_route_mapping( freeze({ server.getTubID().decode("ascii"): (None, server_address), })) # Start the proxy listening. factory = grid_router.factory() d = TCP4ServerEndpoint(self.reactor, 0).listen(factory) def listening(proxy_port): self.addCleanup(proxy_port.stopListening) # Tell the server tub where the _proxy_ is it generates a furl # pointing at the proxy. We'll use that furl to connect with the # client tub and rely on the proxy to get us to the right place. host = proxy_port.getHost().host.decode("ascii") port_number = proxy_port.getHost().port location = u"{host}:{port}".format( host=host, port=port_number, ) server.setLocation(location.encode("ascii")) msg("Set server Tub location {}".format(location)) # Register something arbitrary that we can poke at. furl = server.registerReference(Referenceable()) # Try to connect to the server tub with the client tub through the # proxy. d = Deferred() reconn = client.connectTo(furl, d.callback) self.addCleanup(reconn.stopConnecting) return d d.addCallback(listening) def connected(ref): pass d.addCallback(connected) return d