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 start(self, delay=None): from p2psip.external import multitask if self.running: self.stop() # stop previous one first. if delay is not None: self.delay = delay # set the new delay self.running = True self.gen = self.run() multitask.add(self.gen)
def start(self, delay=None): from p2psip.external import multitask if self.running: self.stop() # stop previous one first. if delay is not None: self.delay = delay # set the new delay self.running = True self.gen = self.run() multitask.add(self.gen)
def start(self, net=None, servers=None): '''Start the p2p node as ordinary node. Create a network object if none.''' if self.net is None: self.net = net or Network( Ks=crypto.generateRSA()[0], cert=None, port=self.port) self.net.start() # convert from serevrs ip:port list to Node list if servers: servers = [ Node(ip=ip, port=port, type=socket.SOCK_DGRAM, guid=H(ip + ':' + str(port))) for ip, port in servers ] if _debug: print 'using servers=', servers self.client = Client(self.net, server=self.server).start(servers) if self.server: if self.router is None: self.router = dht.Router(self.net).start() if self.storage is None: self.storage = dht.Storage(self.net, self.router).start() if not self.router.initialized: self.router.initialized = True if not self._gens: for gen in [self.handler()]: multitask.add(gen) self._gens.append(gen) return self
def _testServer(): sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0) sock.bind(("0.0.0.0", 0)) # should use any port for testing multitask.add(server(sock)) sockaddr = getlocaladdr(sock) multitask.add(_testDiscoverBehavior([sockaddr, defaultServers[0]])) yield multitask.sleep(5) sock.close()
def process(self, data): # process incoming message if not isinstance(data, Message): data = Message(str(data)) self.append(data) def add(self, data): if self._queue is not None: yield self._queue.put(data) multitask.add(add(self, data))
def _testServer(): sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0) sock.bind(('0.0.0.0', 0)) # should use any port for testing multitask.add(server(sock)) sockaddr = getlocaladdr(sock) multitask.add(_testDiscoverBehavior([sockaddr, defaultServers[0]])) yield multitask.sleep(5) sock.close()
def fset(self, value): self._presence = value if self.connection is not None and value is not None: def sendPresence(value): if self.connection is not None: yield self.connection.put(msg=value) multitask.add(sendPresence(value))
def _testAlgorithm(): def testInternal(): #global _debug #_debug = dht._debug = True nodes = [ServerSocket(True).start()] for x in xrange(10): nodes.append(ServerSocket().start()) yield multitask.add(testInternal())
def _testClient(): def internalTest(): n1 = Network(crypto.PrivateKey(), '').start() n2 = Network(crypto.PrivateKey(), '').start() c1 = Client(n1, server=True).start() c2 = Client(n2).start() msg = yield n2.get(lambda x: x.name=='Discover:Indication', timeout=8) assert msg is not None and msg.neighbors[0] == n1.node multitask.add(internalTest()) # need to use a generator for test
def _testAlgorithm(): def testInternal(): #global _debug #_debug = dht._debug = True nodes = [ServerSocket(True).start()] for x in xrange(10): nodes.append(ServerSocket().start()) yield multitask.add(testInternal())
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 _testClient(): def internalTest(): n1 = Network(crypto.PrivateKey(), '').start() n2 = Network(crypto.PrivateKey(), '').start() c1 = Client(n1, server=True).start() c2 = Client(n2).start() msg = yield n2.get(lambda x: x.name == 'Discover:Indication', timeout=8) assert msg is not None and msg.neighbors[0] == n1.node multitask.add(internalTest()) # need to use a generator for test
def handler(self): '''Handle various messages from other modules such as Discover:Indication.''' supported = ['Discover:Indication'] gen = None while True: msg = yield self.net.get(lambda x: x.name in supported) if msg.name == 'Discover:Indication': if msg.neighbors and gen is None: # need to promote gen = self.promotionhandler(); multitask.add(gen) elif not msg.neighbors and gen is not None: # demotion: close promotion handler gen.close(); gen = None
def __init__(self, app, **kwargs): """Initialize the network.""" s1, s2 = self._initialize(app, **kwargs) if s1 and s2: self.rtp, self.rtcp = s1, s2 self._rtpgen = self.receiveRTP(self.rtp) self._rtcpgen = self.receiveRTCP(self.rtcp) multitask.add(self._rtpgen) multitask.add(self._rtcpgen) else: raise ValueError, "cannot allocate sockets"
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 __init__(self, app, **kwargs): '''Initialize the network.''' s1, s2 = self._initialize(app, **kwargs) if s1 and s2: self.rtp, self.rtcp = s1, s2 self._rtpgen = self.receiveRTP(self.rtp) self._rtcpgen = self.receiveRTCP(self.rtcp) multitask.add(self._rtpgen) multitask.add(self._rtcpgen) else: raise ValueError, 'cannot allocate sockets'
def start(self, servers=None): '''Start the client with the given set of optional servers list.''' if not self._gens: guid = H(ADDRESS + ':' + str(PORT)) try: bs = [Node(ip=socket.gethostbyname(BOOTSTRAP), port=PORT, type=socket.SOCK_STREAM, guid=guid)] except: bs = [] self.candidates = (servers or []) + [self.net.nodemcast] + bs if _debug: print 'Client.start candidates=', self.candidates self.neighbors = [] self._gens = [self.discoverhandler(), self.bootstrap(), self.clienthandler()] # , self.pinghandler() for gen in self._gens: multitask.add(gen) return self
def handler(self): '''Handle various messages from other modules such as Discover:Indication.''' supported = ['Discover:Indication'] gen = None while True: msg = yield self.net.get(lambda x: x.name in supported) if msg.name == 'Discover:Indication': if msg.neighbors and gen is None: # need to promote gen = self.promotionhandler() multitask.add(gen) elif not msg.neighbors and gen is not None: # demotion: close promotion handler gen.close() gen = None
def connected(self, old, new): # connection or disconnection callback if new is not None: def filter(data): if data.tag == 'presence': return True elif data.tag == 'iq' and data.type == 'set': query = F(data('query')); return query and query.xmlns == 'jabber:iq:roster' else: return False self.filter = filter multitask.add(self.fetch()) # when connected, install the onRosterSet listener and fetch the roster self.presence = Presence() else: self.filter = None self.presence = None self.clear()
def send(self, msg, node, timeout=None): '''Send some msg to dest node (Node), and if timeout is specified then return a success (True) or failure (False) within that timeout. Otherwise, the function may return immediately.''' try: start = time.time() if node.type == socket.SOCK_DGRAM and timeout is not None: # no ack required for tcp msg['ack'] = True # require a NetworkAck data = dht.int2bin(self.node.guid) + str( msg) # TODO: this assumes guid is same for all transports. if _debug and msg.name[:4] != 'Hash': print self.name, 'sending %d bytes %s=>%s: %r' % ( len(data), self.node.hostport, node.hostport, msg) if node.type == socket.SOCK_DGRAM: self.udp.sendto(data, (node.ip, node.port)) else: if node in self.tcpc: sock = self.tcpc[node] else: sock = socket.socket(type=socket.SOCK_STREAM) sock.setblocking(0) try: if _debug: print 'connecting to %s' % (node.hostport, ) sock.connect((node.ip, node.port)) except (socket.timeout, socket.error): yield multitask.sleep(2.0) ret = select.select((), (sock, ), (), 0) if len(ret[1]) == 0: if _debug: print 'connection timedout to %s' % ( node.hostport, ) raise multitask.Timeout, 'Cannot connect to the destination' self.tcpc[node] = sock # yield multitask.sleep() multitask.add(self.tcphandler(sock, (node.ip, node.port))) data = struct.pack('!H', len(data)) + data # put a length first. sock.send(data) if msg.ack: hash = H( data ) # hash property to associate the ack to the data request. ack = yield self.get( lambda x: x.name == 'Ack:Indication' and x.hash == hash, timeout=(timeout - (time.time() - start))) if _debug: 'received ack %r' % (ack) if ack is None: raise StopIteration(False) # no ack received raise StopIteration(True) except (multitask.Timeout, socket.error): raise StopIteration(False) # timeout in sendto or get
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 _testRelay(): try: sock1 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock1.bind(("0.0.0.0", 0)) multitask.add(server(sock1)) sockaddr = getlocaladdr(sock1) sock2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock2.bind(("0.0.0.0", 0)) yield multitask.sleep(2) response, mapped = request(sock2, sockaddr, method=Message.ALLOCATE) print "mapped=", mapped sock1.close() sock2.close() yield multitask.sleep(6) except: print "exception", sys.exc_info(), traceback.print_exc(file=sys.stdout)
def _testTcpRequest(): try: sock1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock1.bind(('0.0.0.0', 0)) # should use any port for testing multitask.add(server(sock1)) sockaddr = getlocaladdr(sock1) sock2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock2.bind(('0.0.0.0', 0)) yield multitask.sleep(2) # wait for server to be started. response, external = (yield request(sock2, sockaddr)) print 'external=', external sock1.close() yield multitask.sleep(6) print '_testTcpRequest() exiting' except (ValueError, multitask.Timeout), E: print 'exception - ValueError or Timeout', E
def _testTcpRequest(): try: sock1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock1.bind(("0.0.0.0", 0)) # should use any port for testing multitask.add(server(sock1)) sockaddr = getlocaladdr(sock1) sock2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock2.bind(("0.0.0.0", 0)) yield multitask.sleep(2) # wait for server to be started. response, external = (yield request(sock2, sockaddr)) print "external=", external sock1.close() yield multitask.sleep(6) print "_testTcpRequest() exiting" except (ValueError, multitask.Timeout), E: print "exception - ValueError or Timeout", E
def _testRelay(): try: sock1 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock1.bind(('0.0.0.0', 0)) multitask.add(server(sock1)) sockaddr = getlocaladdr(sock1) sock2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock2.bind(('0.0.0.0', 0)) yield multitask.sleep(2) response, mapped = request(sock2, sockaddr, method=Message.ALLOCATE) print 'mapped=', mapped sock1.close() sock2.close() yield multitask.sleep(6) except: print 'exception', sys.exc_info(), traceback.print_exc(file=sys.stdout)
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 clienthandler(self): '''Receive requests from client and send to the router module, and viceversa.''' net = self.net def requesthandler(msg): p = msg.payload; response = None if self.server: # only if a server if p.name=='Put:Request': result = yield dht.put(net, p.dest, p.value, p.nonce, p.expires, p.Ks, p.put) response = Message(name='Put:Response', seq=p.seq, result=result) elif p.name=='Get:Request': result = yield dht.get(net, p.dest, p.maxvalues, p.Kp) response = Message(name='Get:Response', seq=p.seq, guid=p.guid, vals=result) if response: yield self.net.send(Message(name='Proxy:Response', src=net.node, payload=response), node=msg.src, timeout=5) def responsehandler(msg): if not self.server: # only if a client yield net.put(msg.payload, timeout=5) while True: msg = yield self.net.get(lambda x: x.name=='Proxy:Request' or x.name=='Proxy:Response') if msg: multitask.add(requesthandler(msg) if msg.name=='Proxy:Request' else responsehandler(msg))
def start(self, net=None, servers=None): '''Start the p2p node as ordinary node. Create a network object if none.''' if self.net is None: self.net = net or Network(Ks=crypto.generateRSA()[0], cert=None, port=self.port) self.net.start() # convert from serevrs ip:port list to Node list if servers: servers=[Node(ip=ip, port=port, type=socket.SOCK_DGRAM, guid=H(ip + ':' + str(port))) for ip, port in servers] if _debug: print 'using servers=', servers self.client = Client(self.net, server=self.server).start(servers) if self.server: if self.router is None: self.router = dht.Router(self.net).start() if self.storage is None: self.storage = dht.Storage(self.net, self.router).start() if not self.router.initialized: self.router.initialized = True if not self._gens: for gen in [self.handler()]: multitask.add(gen); self._gens.append(gen) return self
def connected(self, old, new): # connection or disconnection callback if new is not None: def filter(data): if data.tag == 'presence': return True elif data.tag == 'iq' and data.type == 'set': query = F(data('query')) return query and query.xmlns == 'jabber:iq:roster' else: return False self.filter = filter multitask.add( self.fetch() ) # when connected, install the onRosterSet listener and fetch the roster self.presence = Presence() else: self.filter = None self.presence = None self.clear()
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 send(self, msg, node, timeout=None): '''Send some msg to dest node (Node), and if timeout is specified then return a success (True) or failure (False) within that timeout. Otherwise, the function may return immediately.''' try: start = time.time() if node.type==socket.SOCK_DGRAM and timeout is not None: # no ack required for tcp msg['ack'] = True # require a NetworkAck data = dht.int2bin(self.node.guid) + str(msg) # TODO: this assumes guid is same for all transports. if _debug and msg.name[:4] != 'Hash': print self.name, 'sending %d bytes %s=>%s: %r'%(len(data), self.node.hostport, node.hostport, msg) if node.type == socket.SOCK_DGRAM: self.udp.sendto(data, (node.ip, node.port)) else: if node in self.tcpc: sock = self.tcpc[node] else: sock = socket.socket(type=socket.SOCK_STREAM) sock.setblocking(0) try: if _debug: print 'connecting to %s'%(node.hostport,) sock.connect((node.ip, node.port)) except (socket.timeout, socket.error): yield multitask.sleep(2.0) ret = select.select((), (sock,), (), 0) if len(ret[1]) == 0: if _debug: print 'connection timedout to %s'%(node.hostport,) raise multitask.Timeout, 'Cannot connect to the destination' self.tcpc[node] = sock # yield multitask.sleep() multitask.add(self.tcphandler(sock, (node.ip, node.port))) data = struct.pack('!H', len(data)) + data # put a length first. sock.send(data) if msg.ack: hash = H(data) # hash property to associate the ack to the data request. ack = yield self.get(lambda x: x.name=='Ack:Indication' and x.hash==hash, timeout=(timeout - (time.time() - start))) if _debug: 'received ack %r'%(ack) if ack is None: raise StopIteration(False) # no ack received raise StopIteration(True) except (multitask.Timeout, socket.error): raise StopIteration(False) # timeout in sendto or get
def clienthandler(self): '''Receive requests from client and send to the router module, and viceversa.''' net = self.net def requesthandler(msg): p = msg.payload response = None if self.server: # only if a server if p.name == 'Put:Request': result = yield dht.put(net, p.dest, p.value, p.nonce, p.expires, p.Ks, p.put) response = Message(name='Put:Response', seq=p.seq, result=result) elif p.name == 'Get:Request': result = yield dht.get(net, p.dest, p.maxvalues, p.Kp) response = Message(name='Get:Response', seq=p.seq, guid=p.guid, vals=result) if response: yield self.net.send(Message(name='Proxy:Response', src=net.node, payload=response), node=msg.src, timeout=5) def responsehandler(msg): if not self.server: # only if a client yield net.put(msg.payload, timeout=5) while True: msg = yield self.net.get(lambda x: x.name == 'Proxy:Request' or x. name == 'Proxy:Response') if msg: multitask.add( requesthandler(msg) if msg.name == 'Proxy:Request' else responsehandler(msg))
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 send(self, data, remote, stack): '''Send a given data to remote for the SIP stack.''' def _send(self, data, remote, stack): # a generator function that does the sending logger.debug('%r=>%r on type=%r\n%s', stack.sock.getsockname(), remote, stack.transport.type, data) try: if stack.sock.type == socket.SOCK_STREAM: # for TCP send only if a connection exists to the remote. if stack.transport.type in ('ws', 'wss'): if len(data) < 126: init = struct.pack('>BB', 0x81, len(data)) elif len(data) < 65536: init = struct.pack('>BBH', 0x81, 126, len(data)) else: raise ValueError, 'cannot send long message' data = init + data if remote in self.conn: yield multitask.send(self.conn[remote], data) # and send using that connected TCP socket. else: logger.warning('ignoring message to %r as no existing connection', remote) else: # for UDP send using the stack's UDP socket. yield multitask.sendto(stack.sock, data, remote) except StopIteration: pass except: logger.exception('sending') multitask.add(_send(self, data, remote, stack))
def start(self, servers=None): '''Start the client with the given set of optional servers list.''' if not self._gens: guid = H(ADDRESS + ':' + str(PORT)) try: bs = [ Node(ip=socket.gethostbyname(BOOTSTRAP), port=PORT, type=socket.SOCK_STREAM, guid=guid) ] except: bs = [] self.candidates = (servers or []) + [self.net.nodemcast] + bs if _debug: print 'Client.start candidates=', self.candidates self.neighbors = [] self._gens = [ self.discoverhandler(), self.bootstrap(), self.clienthandler() ] # , self.pinghandler() for gen in self._gens: multitask.add(gen) return self
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"
except: print "exception", sys.exc_info() def _testRelay(): try: sock1 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock1.bind(("0.0.0.0", 0)) multitask.add(server(sock1)) sockaddr = getlocaladdr(sock1) sock2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock2.bind(("0.0.0.0", 0)) yield multitask.sleep(2) response, mapped = request(sock2, sockaddr, method=Message.ALLOCATE) print "mapped=", mapped sock1.close() sock2.close() yield multitask.sleep(6) except: print "exception", sys.exc_info(), traceback.print_exc(file=sys.stdout) if __name__ == "__main__": # multitask.add(_testRequest()) # multitask.add(_testDiscoverBehavior()) # multitask.add(_testTcpRequest()) # multitask.add(_testServer()) multitask.add(_testRelay()) multitask.run()
def _testServerSocket(): def testInternal(): s1 = ServerSocket(True).start() s2 = ServerSocket().start() multitask.add(testInternal())
except: print 'exception', sys.exc_info() def _testRelay(): try: sock1 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock1.bind(('0.0.0.0', 0)) multitask.add(server(sock1)) sockaddr = getlocaladdr(sock1) sock2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock2.bind(('0.0.0.0', 0)) yield multitask.sleep(2) response, mapped = request(sock2, sockaddr, method=Message.ALLOCATE) print 'mapped=', mapped sock1.close() sock2.close() yield multitask.sleep(6) except: print 'exception', sys.exc_info(), traceback.print_exc(file=sys.stdout) if __name__ == "__main__": #multitask.add(_testRequest()) #multitask.add(_testDiscoverBehavior()) #multitask.add(_testTcpRequest()) #multitask.add(_testServer()) multitask.add(_testRelay()) multitask.run()
u1.roster.presence = Presence(show='dnd', status='Online') h1 = u1.chat('*****@*****.**') yield h1.send(Message(body='Hello How are you?')) count = 5 for i in xrange(5): try: msg = yield h1.recv(timeout=120) print msg print '%s: %s'%(msg.frm, msg.body.cdata) yield h1.send(Message(body='You said "%s"'%(msg.body.cdata))) except Exception, e: print str(type(e)), e break yield u1.logout() print 'testPresence exiting' def testClose(): yield multitask.sleep(25); exit() if __name__ == '__main__': import doctest; doctest.testmod() # first run doctest, for f in dir(): # then run all _test* functions if str(f).find('_test') == 0 and callable(eval(f)): multitask.add(globals()[f]()) try: multitask.run() except KeyboardInterrupt: pass except select.error: print 'select error'; pass sys.exit()
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 sendRTCP(self, sendbye=False): '''Send a RTCP packet with SR or RR and SDES, and optionally BYE if sendbye is True. It returns the size of the packet sent.''' reports = [] toremove = [] for member in self.members.values(): if member.received > 0: ntp1, ntp2 = time2ntp(member.lastntp) lsr = ((ntp1 & 0x0ffff) << 16) | ((ntp2 >> 16) & 0x0ffff) dlsr = int((self.tc - member.lastntp) * 65536) member.updatelostandexpected() report = RTCP.packet(ssrc=member.ssrc, flost=member.fraction, clost=member.lost, hseq=member.cycles + member.maxseq, jitter=int(member.jitter), lsr=lsr, dlsr=dlsr) reports.append(report) member.received = 0 if member.timeout == 5: # if no packet within five RTCP intervals toremove.append(member.ssrc) # schedule it to be removed else: member.timeout = member.timeout + 1 if toremove: # remove all timedout members for ssrc in toremove: del self.members[ssrc] packet = RTCP() if self.wesent: # add a sender report p = RTCP.packet(pt=RTCP.SR, ntp=self.tc, ts=self.tsnow + self.ts0, pktcount=self.member.pktcount, octcount=self.member.octcount, reports=reports[:32]) self.wesent = False else: p = RTCP.packet(pt=RTCP.RR, reports=reports[:32]) packet.append(p) if len(reports) >= 32: # add additional RR if needed reports = reports[32:] while reports: p, reports = RTCP.packet(pt=RTCP.RR, reports=reports[:32]), reports[32:] packet.append(p) p = RTCP.packet( pt=RTCP.SDES, items=self.member.items ) # add SDES. Should add items only every few packets, except for CNAME which is added in every. packet.append(p) if sendbye: # add a BYE packet as well p = RTCP.packet(pt=RTCP.BYE, ssrcs=[self.member.ssrc ]) # Need to add a reason as well packet.append(p) data = str(packet) # format for network data if self.net is not None: multitask.add(self.net.sendRTCP( data)) # invoke app or net to send the packet elif hasattr(self.app, 'sendRTCP') and callable(self.app.sendRTCP): self.app.sendRTCP(self, data) elif _debug: print 'ignoring send RTCP' self.rtcpsent = True return len(data)
def fset(self, value): self._presence = value if self.connection is not None and value is not None: def sendPresence(value): if self.connection is not None: yield self.connection.put(msg=value) multitask.add(sendPresence(value))
def start(self): '''Start the listening tasks in this agent. It returns self for cascaded method calls.''' for s in self.stack.values(): gen = self._sipreceiver(s); self._gens.append(gen); multitask.add(gen) return self
def process(self, data): if not data: multitask.add(self.logout())
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))
print msg print '%s: %s' % (msg.frm, msg.body.cdata) yield h1.send(Message(body='You said "%s"' % (msg.body.cdata))) except Exception, e: print str(type(e)), e break yield u1.logout() print 'testPresence exiting' def testClose(): yield multitask.sleep(25) exit() if __name__ == '__main__': import doctest doctest.testmod() # first run doctest, for f in dir(): # then run all _test* functions if str(f).find('_test') == 0 and callable(eval(f)): multitask.add(globals()[f]()) try: multitask.run() except KeyboardInterrupt: pass except select.error: print 'select error' pass sys.exit()
def _testServerSocket(): def testInternal(): s1 = ServerSocket(True).start() s2 = ServerSocket().start() multitask.add(testInternal())
def process(self, data): # process incoming message if not isinstance(data, Message): data = Message(str(data)) self.append(data) def add(self, data): if self._queue is not None: yield self._queue.put(data) multitask.add(add(self, data))
def process(self, data): if not data: multitask.add(self.logout())
def sendRTCP(self, sendbye=False): """Send a RTCP packet with SR or RR and SDES, and optionally BYE if sendbye is True. It returns the size of the packet sent.""" reports = [] toremove = [] for member in self.members.values(): if member.received > 0: ntp1, ntp2 = time2ntp(member.lastntp) lsr = ((ntp1 & 0x0FFFF) << 16) | ((ntp2 >> 16) & 0x0FFFF) dlsr = int((self.tc - member.lastntp) * 65536) member.updatelostandexpected() report = RTCP.packet( ssrc=member.ssrc, flost=member.fraction, clost=member.lost, hseq=member.cycles + member.maxseq, jitter=int(member.jitter), lsr=lsr, dlsr=dlsr, ) reports.append(report) member.received = 0 if member.timeout == 5: # if no packet within five RTCP intervals toremove.append(member.ssrc) # schedule it to be removed else: member.timeout = member.timeout + 1 if toremove: # remove all timedout members for ssrc in toremove: del self.members[ssrc] packet = RTCP() if self.wesent: # add a sender report p = RTCP.packet( pt=RTCP.SR, ntp=self.tc, ts=self.tsnow + self.ts0, pktcount=self.member.pktcount, octcount=self.member.octcount, reports=reports[:32], ) self.wesent = False else: p = RTCP.packet(pt=RTCP.RR, reports=reports[:32]) packet.append(p) if len(reports) >= 32: # add additional RR if needed reports = reports[32:] while reports: p, reports = RTCP.packet(pt=RTCP.RR, reports=reports[:32]), reports[32:] packet.append(p) p = RTCP.packet( pt=RTCP.SDES, items=self.member.items ) # add SDES. Should add items only every few packets, except for CNAME which is added in every. packet.append(p) if sendbye: # add a BYE packet as well p = RTCP.packet(pt=RTCP.BYE, ssrcs=[self.member.ssrc]) # Need to add a reason as well packet.append(p) data = str(packet) # format for network data if self.net is not None: multitask.add(self.net.sendRTCP(data)) # invoke app or net to send the packet elif hasattr(self.app, "sendRTCP") and callable(self.app.sendRTCP): self.app.sendRTCP(self, data) elif _debug: print "ignoring send RTCP" self.rtcpsent = True return len(data)