def _sipreceiver(self, stack, maxsize=16386): '''Handle the messages or connections on the given SIP stack's socket, and pass it to the stack so that stack can invoke appropriate callback on this object such as receivedRequest.''' sock = stack.sock def tcpreceiver(sock, remote): # handle the messages on the given TCP connection. while True: data = yield multitask.recv(sock, maxsize) if _debug: print '%r=>%r on type=%r\n%s' % ( remote, sock.getsockname(), sock.type, data) if data: stack.received(data, remote) while True: if sock.type == socket.SOCK_DGRAM: data, remote = yield multitask.recvfrom(sock, maxsize) if _debug: print '%r=>%r on type=%r\n%s' % ( remote, sock.getsockname(), sock.type, data) if data: stack.received(data, remote) elif sock.type == socket.SOCK_STREAM: conn, remote = yield multitask.accept(sock) if conn: self.conn[remote] = conn multitask.add(tcpreceiver(conn, remote)) else: raise ValueError, 'invalid socket type'
def _sipreceiver(self, stack, maxsize=16386): '''Handle the messages or connections on the given SIP stack's socket, and pass it to the stack so that stack can invoke appropriate callback on this object such as receivedRequest.''' sock = stack.sock def tcpreceiver( sock, remote): # handle the messages on the given TCP connection. while True: data = yield multitask.recv(sock, maxsize) if _debug: print '%r=>%r on type=%r\n%s' % ( remote, sock.getsockname(), sock.type, data) if data: stack.received(data, remote) while True: if sock.type == socket.SOCK_DGRAM: data, remote = yield multitask.recvfrom(sock, maxsize) if _debug: print '%r=>%r on type=%r\n%s' % ( remote, sock.getsockname(), sock.type, data) if data: stack.received(data, remote) elif sock.type == socket.SOCK_STREAM: conn, remote = yield multitask.accept(sock) if conn: self.conn[remote] = conn multitask.add(tcpreceiver(conn, remote)) else: raise ValueError, 'invalid socket type'
def _sipreceiver(self, stack, maxsize=16386): '''Handle the messages or connections on the given SIP stack's socket, and pass it to the stack so that stack can invoke appropriate callback on this object such as receivedRequest.''' sock = stack.sock while True: if sock.type == socket.SOCK_DGRAM: data, remote = yield multitask.recvfrom(sock, maxsize) logger.debug('%r=>%r on type=%r\n%s', remote, sock.getsockname(), stack.transport.type, data) if data: try: stack.received(data, remote) except: logger.exception('received') elif sock.type == socket.SOCK_STREAM: conn, remote = yield multitask.accept(sock) if conn: logger.debug('%r=>%r connection type %r', remote, conn.getsockname(), stack.transport.type) if stack.transport.type in ('ws', 'wss'): multitask.add( self._wsreceiver(stack, conn, remote, maxsize)) else: multitask.add( self._tcpreceiver(stack, conn, remote, maxsize)) else: raise ValueError, 'invalid socket type'
def echo_server(hostname, port): addrinfo = socket.getaddrinfo(hostname, port, socket.AF_UNSPEC, socket.SOCK_STREAM) (family, socktype, proto, canonname, sockaddr) = addrinfo[0] with closing(socket.socket(family, socktype, proto)) as sock: sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.bind(sockaddr) sock.listen(5) while True: multitask.add(client_handler((yield multitask.accept(sock))[0]))
def relayaccepter(sock, fivetuple): sock.listen(5) # accept queue while True: # start the main listening loop of the tcp server try: conn, remote = (yield multitask.accept(sock)) if conn: if _debug: print 'relayaccepter().accept() from', remote sock.close() # close the original listening socket -- no more connections binding[fivetuple] = conn # update the binding del binding[sock] binding[conn] = fivetuple multitask.add(relaytcpreceiver(conn, fivetuple, remote)) break except: # some other socket error, probably sock is closed. break if _debug: print 'relaytcpaccepter() exiting'
def run(self): try: while True: sock, remote = (yield multitask.accept(self.sock)) # receive client TCP if sock == None: if _debug: print 'rtmp.Server accept(sock) returned None.' break if _debug: print 'connection received from', remote sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) # make it non-block client = Client(sock, self) except: if _debug: print 'rtmp.Server exception ', (sys and sys.exc_info() or None) if (self.sock): try: self.sock.close(); self.sock = None except: pass if (self.queue): yield self.queue.put((None, None)) self.queue = None
def _sipreceiver(self, stack, maxsize=16386): '''Handle the messages or connections on the given SIP stack's socket, and pass it to the stack so that stack can invoke appropriate callback on this object such as receivedRequest.''' sock = stack.sock while True: if sock.type == socket.SOCK_DGRAM: data, remote = yield multitask.recvfrom(sock, maxsize) logger.debug('%r=>%r on type=%r\n%s', remote, sock.getsockname(), stack.transport.type, data) if data: try: stack.received(data, remote) except: logger.exception('received') elif sock.type == socket.SOCK_STREAM: conn, remote = yield multitask.accept(sock) if conn: logger.debug('%r=>%r connection type %r', remote, conn.getsockname(), stack.transport.type) if stack.transport.type in ('ws', 'wss'): multitask.add(self._wsreceiver(stack, conn, remote, maxsize)) else: multitask.add(self._tcpreceiver(stack, conn, remote, maxsize)) else: raise ValueError, 'invalid socket type'
def echo_server(hostname, port): addrinfo = socket.getaddrinfo(hostname, port, socket.AF_UNSPEC, socket.SOCK_STREAM) (family, socktype, proto, canoname, sockaddr) = addrinfo[0] with closing(socket.socket(family, socktype, proto)) as sock: sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.bind(sockaddr) sock.listen(5) while True: multitask.add(client_handler(yield multitask.accept(sock))[0]) if __name__ == '__main__': import sys hostname = None port = 1111 if len(sys.argv) > 1: hostname = sys.argv[1] if len(sys.argv) > 2: port = int(sys.argv[2]) multitask.add(echo_server(hostname, port)) try: multitask.run() except KeyboardInterrupt: pass
def listener(sock): while True: conn, address = (yield multitask.accept(sock)) multitask.add(client_handler(conn))
def server(sock1, **kwargs): '''A simple server implementation to test the code or to use in real deployment. The application should start the server as multitask.add(server(sock)). The caller should make sure that the sock1 argument is a UDP or TCP socket which is already bound. Additionally, sock2, sock3, and sock4 can be supplied as keyword arguments and represent the socket to use for change-IP, change-port and change IP+port commands respectively. Other keyword arguments are as follows: timeout: optional acivity timeout (second) if relay is activated, defaults to 180. external: optional external (ip, port) of the socket in case it is behind a full-cone NAT and still acts as a (relay) server. handler: optional function that gets invoked as handler(sock, remote, data) for non-STUN data, and allows the application to demultiplex other types of data. maxsize: optional maximum size of packet to handle, defaults to 1500.''' sock2, sock3, sock4 = kwargs.get('sock2', None), kwargs.get('sock3', None), kwargs.get('sock4', None) addr1 = getlocaladdr(sock1) addr4 = sock4 and getlocaladdr(sock4) or None timeout = kwargs.get('timeout', 180) # three minutes external = kwargs.get('external', addr1) handler = kwargs.get('handler', None) maxsize = kwargs.get('maxsize', 1500) tcp = (sock1.type == socket.SOCK_STREAM) # whether the server is on tcp or udp. binding = dict() # allocated relay bindings if any def respond(sock, data, remote): if sock.type == socket.SOCK_STREAM: yield multitask.send(sock, data) else: yield multitask.sendto(sock, data, remote) def bindingRequest(sock, m, remote): # Serve a binding request of STUN res = Message() res.method, res.type, res.tid = Message.BINDING, Message.RESPONSE, m.tid mapped = Attribute(Attribute.MAPPED_ADDRESS) # mapped-address attribute mapped.address = (sock.family, addr1[0], addr1[1]) res.attrs.append(mapped) if Attribute.CHANGE_REQUEST not in m: # send from same address:port if addr4: # add the other address attribute other = Attribute(Attribute.OTHER_ADDRESS) other.address = (sock4.family, addr4[0], addr4[1]) res.attrs.append(other) else: change = m[Attribute.CHANGE_REQUEST] sock = change.value == '\x00\x00\x00\x06' and sock4 or change.value == '\x00\x00\x00\x02' and sock3 or change.value == '\x00\x00\x00\x04' and sock2 or None if sock: yield respond(sock, str(res), remote) raise StopIteration() def allocateRequest(sock, m, remote): # serve the allocate request of TURN fivetuple = (sock.type, getlocaladdr(sock), remote) lifetime = timeout if Attribute.LIFETIME in m: lt = struct.unpack('!L', m[Attribute.LIFETIME].value) if lt < lifetime: lifetime = lt if fivetuple in binding: # already found newsock = binding[fivetuple] if lifetime == 0: # terminate the binding del binding[fivetuple] del binding[newsock] else: if lifetime > 0: # allocate, otherwise it is already missing. newsock = socket.socket(sock.family, sock.type) newsock.bind(('0.0.0.0', 0)) # bind to any binding[newsock] = fivetuple binding[fivetuple] = newsock res = Message() res.method, res.type, res.tid = m.method, Message.RESPONSE, m.tid mapped = Attribute(Attribute.MAPPED_ADDRESS) # mapped-address attribute mapped.address = (newsock.family, (external, newsock and newsock.getsockname()[1] or 0)) res.attrs.append(mapped) res.attrs.append(Attribute(Attribute.LIFETIME, struct.pack('!L', lifetime))) if lifetime == 0 and newsock: # close any previous listening function newsock.close() # this should trigger close of functions else: if sock.type == socket.SOCK_STREAM: multitask.add(relayaccepter(newsock, fivetuple)) else: multitask.add(relayreceiver(newsock, fivetuple)) yield respond(sock, str(res), remote) def relaytcpreceiver(sock, fivetuple): pass def relayaccepter(sock, fivetuple): sock.listen(5) # accept queue while True: # start the main listening loop of the tcp server try: conn, remote = (yield multitask.accept(sock)) if conn: if _debug: print 'relayaccepter().accept() from', remote sock.close() # close the original listening socket -- no more connections binding[fivetuple] = conn # update the binding del binding[sock] binding[conn] = fivetuple multitask.add(relaytcpreceiver(conn, fivetuple, remote)) break except: # some other socket error, probably sock is closed. break if _debug: print 'relaytcpaccepter() exiting' def relayreceiver(sock, fivetuple): while True: # start the main listening loop of the udp server try: data, remote = (yield multitask.recvfrom(sock, maxsize)) # receive a packet if data: if _debug: print 'server().recvfrom() from', remote multitask.add(datahandler(sock1, data, remote)) except: # some other socket error, probably sock1 is closed. break if _debug: print 'server() exiting' def sendRequest(sock, m, remote): # serve the send request of TURN fivetuple = (sock.type, getlocaladdr(sock), remote) try: if fivetuple not in binding: # not found raise ValueError, 'no turn binding found' newsock = binding[fivetuple] destaddr = Attribute.DESTINATION_ADDRESS in m and m[Attribute.DESTINATION_ADDRESS].address[1:] or None data = Attribute.DATA in m and m[Attribute.DATA] or None if sock.type == socket.SOCK_STREAM: try: remote = newsock.getpeername() except: remote = None if not remote: newsock.connect(destaddr) remote = destaddr yield multitask.send(newsock, data) else: yield multitask.sendto(newsock, data, destaddr) # TODO: we don't lock to destaddr. This is a security risk. result = True except: if _debug: print 'sendRequest() exception', sys.exc_info() result = False res = Message() res.method, res.type, res.tid = m.method, (result and Message.RESPONSE or Message.ERROR), m.tid if not result: error = Attribute(Attribute.ERROR_CODE) error.error = (400, 'cannot send request') # TODO: be more explicit. res.attrs.append(error) yield respond(sock, str(res), remote) def datahandler(sock, data, remote): #handle a new data from given remote (ip, port) try: m = Message(data) # parse the message func = m.type == Message.REQUEST and ( \ m.method == Message.BINDING and bindingRequest \ or m.method == Message.ALLOCATE and allocateRequest \ or m.method == Message.SEND and sendRequest \ ) or None if func: yield func(sock, m, remote) else: raise ValueError, 'unhandled request or message' except StopIteration: if _debug: print 'datahandler: stop iteration' raise except: # parsing error or unhandled message if _debug: print 'datahandler() exception', sys.exc_info() if handler: handler(sock, remote, data) # invoke the application's handler. def tcpreceiver(sock, remote): # handle a new incoming TCP connection while True: data = (yield multitask.recv(sock, maxsize)) if not data: break # socket closed type, length, magic = struct.unpack('!HHL', data[:8]) valid = (type & 0xC000 == 0) and magic == Message.MAGIC and length<=(maxsize-8) # valid if valid: yield datahandler(sock, data, remote) if _debug: print 'tcpreceiver() finished data handler' else: handler(sock, data, remote) if tcp: sock1.listen(5) # create the listen queue if _debug: print 'server listening on', addr1 while True: # start the main listening loop of the server try: tcp = (sock1.type == socket.SOCK_STREAM) except: break # probably a bad file descriptor because sock1 is closed. try: if tcp: conn, remote = (yield multitask.accept(sock1, timeout=5)) if conn: if _debug: print 'server().accept() from', remote multitask.add(tcpreceiver(conn, remote)) else: data, remote = (yield multitask.recvfrom(sock1, maxsize, timeout=5)) # receive a packet if data: if _debug: print 'server().recvfrom() from', remote multitask.add(datahandler(sock1, data, remote)) except multitask.Timeout: continue except: # some other socket error, probably sock1 is closed. break if _debug: print 'server() exiting'
def tcpreceiver(self): '''Receive incoming TCP connection.''' while True: sock, addr = yield multitask.accept(self.tcp) if sock: multitask.add(self.tcphandler(sock, addr))
def accept_connections(sock): with closing(sock): while True: conn = (yield multitask.accept(sock)) multitask.add(handle_connection(*conn))