def __init__(self, logger): ConnectBase.__init__(self, logger) self.ports = {} # maps interface -> port -> (use_tls, listening Port) self.queue = coros.queue() self.expected_local_uris = {} # maps local_uri -> Logger instance self.expected_remote_paths = {} # maps full_remote_path -> event self.new_full_remote_path_notifier = Notifier() self.factory = SpawnFactory(self._incoming_handler, MSRPTransport, local_uri=None, logger=self.logger)
def __init__(self): self.participants = [] def handler(self, conn): peer = conn.getPeer() print('new connection from %s' % (peer, )) conn.write("Welcome! There're %s participants already\n" % (len(self.participants))) self.participants.append(conn) try: for line in conn: if line: print('received from %s: %s' % (peer, line)) for buddy in self.participants: if buddy is not conn: buddy.sendline('from %s: %s' % (peer, line)) except Exception as ex: print(peer, ex) else: print(peer, 'connection done') finally: conn.loseConnection() self.participants.remove(conn) print(__doc__) chat = Chat() from twisted.internet import reactor reactor.listenTCP(8007, SpawnFactory(chat.handler, LineOnlyReceiverTransport)) reactor.run()
try: while True: x = source.recv() if not x: break print 'forwarding %s bytes' % len(x) dest.write(x) finally: dest.loseConnection() def handler(local): client = str(local.getHost()) print 'accepted connection from %s' % client remote = GreenClientCreator(reactor, UnbufferedTransport).connectTCP( remote_host, remote_port) a = proc.spawn(forward, remote, local) b = proc.spawn(forward, local, remote) proc.waitall([a, b], trap_errors=True) print 'closed connection to %s' % client try: local_port, remote_host, remote_port = sys.argv[1:] except ValueError: sys.exit(__doc__) local_port = int(local_port) remote_port = int(remote_port) reactor.listenTCP(local_port, SpawnFactory(handler)) reactor.run()
class MSRPServer(ConnectBase): """Manage listening sockets. Bind incoming requests. MSRPServer solves the problem with AcceptorDirect: concurrent using of 2 or more AcceptorDirect instances on the same non-zero port is not possible. If you initialize() those instances, one after another, one will listen on the socket and another will get BindError. MSRPServer avoids the problem by sharing the listening socket between multiple connections. It has slightly different interface from AcceptorDirect, so it cannot be considered a drop-in replacement. """ CLOSE_TIMEOUT = MSRPBindSessionTimeout.seconds * 2 def __init__(self, logger): ConnectBase.__init__(self, logger) self.ports = {} # maps interface -> port -> (use_tls, listening Port) self.queue = coros.queue() self.expected_local_uris = {} # maps local_uri -> Logger instance self.expected_remote_paths = {} # maps full_remote_path -> event self.new_full_remote_path_notifier = Notifier() self.factory = SpawnFactory(self._incoming_handler, MSRPTransport, local_uri=None, logger=self.logger) def prepare(self, local_uri=None, logger=None): """Start a listening port specified by local_uri if there isn't one on that port/interface already. Add `local_uri' to the list of expected URIs, so that incoming connections featuring this URI won't be rejected. If `logger' is provided use it for this connection instead of the default one. """ if local_uri is None: local_uri = self.generate_local_uri(2855) need_listen = True if local_uri.port: use_tls, listening_port = self.ports.get(local_uri.host, {}).get(local_uri.port, (None, None)) if listening_port is not None: if use_tls==local_uri.use_tls: need_listen = False else: listening_port.stopListening() sleep(0) # make the reactor really stop listening, so that the next listen() call won't fail self.ports.pop(local_uri.host, {}).pop(local_uri.port, None) else: # caller does not care about port number for (use_tls, port) in self.ports[local_uri.host]: if local_uri.use_tls==use_tls: local_uri.port = port.getHost().port need_listen = False if need_listen: port = self._listen(local_uri, self.factory) self.ports.setdefault(local_uri.host, {})[local_uri.port] = (local_uri.use_tls, port) self.expected_local_uris[local_uri] = logger return [local_uri] def _incoming_handler(self, msrp): msg = 'Incoming connection from %s:%s' % (msrp.getPeer().host, msrp.getPeer().port) self.logger.info(msg) with MSRPBindSessionTimeout.timeout(): chunk = msrp.read_chunk(10000) ToPath = tuple(chunk.headers['To-Path'].decoded) if len(ToPath)!=1: msrp.write_response(chunk, 400, 'Invalid To-Path', wait=False) msrp.loseConnection(wait=False) return ToPath = ToPath[0] if ToPath in self.expected_local_uris: logger = self.expected_local_uris.pop(ToPath) if logger is not None: msrp.logger = logger msrp.local_uri = ToPath else: msrp.write_response(chunk, 481, 'Unknown To-Path', wait=False) msrp.loseConnection(wait=False) return FromPath = tuple(chunk.headers['From-Path'].decoded) # at this point, must wait for complete() function to be called which will # provide an event for this full_remote_path while True: event = self.expected_remote_paths.pop(FromPath, None) if event is not None: break self.new_full_remote_path_notifier.wait() if event is not None: msrp._set_full_remote_path(list(FromPath)) error = msrp.check_incoming_SEND_chunk(chunk) else: error = MSRPNoSuchSessionError if error is None: msrp.write_response(chunk, 200, 'OK') if 'Content-Type' in chunk.headers or chunk.size>0: # chunk must be made available to read_chunk() again because it has payload raise NotImplementedError if event is not None: event.send(msrp) else: msrp.write_response(chunk, error.code, error.comment) def complete(self, full_remote_path): """Wait until one of the incoming connections binds using provided full_remote_path. Return connected and bound MSRPTransport instance. If no such binding was made within MSRPBindSessionTimeout.seconds, raise MSRPBindSessionTimeout. """ full_remote_path = tuple(full_remote_path) event = coros.event() self.expected_remote_paths[full_remote_path] = event try: self.new_full_remote_path_notifier.send() with MSRPBindSessionTimeout.timeout(): return event.wait() finally: self.expected_remote_paths.pop(full_remote_path, None) def cleanup(self, local_uri): """Remove `local_uri' from the list of expected URIs""" self.expected_local_uris.pop(local_uri, None) def stopListening(self): """Close all the sockets that MSRPServer is listening on""" for interface, rest in self.ports.iteritems(): for port, (use_tls, listening_port) in rest: listening_port.stopListening() self.ports = {} def close(self): """Stop listening. Wait for the spawned greenlets to finish""" self.stopListening() with timeout(self.CLOSE_TIMEOUT, None): self.factory.waitall()