def handle_read (self): datagram, peer = self.recvfrom (pns_datagram_size) if peer == None: assert None == self.log ('nop', 'debug') return if self.pns_joined.has_key (peer): # in circle question ... self.pns_joined[peer].pns_question (datagram, peer) return if self.pns_accepted.has_key (peer[0]): # question from a new peer accepted at right self.pns_accepted[peer[0]].pns_question ( datagram, peer ) return # out of circle model = list (netstring.decode (datagram)) if ( len (model) != 2 or # TODO: ? 3 instead ? model[0] == '' or not public_names.valid_utf8 (model[0]) ): # log and drop invalid out-of-circle question ... self.log ( 'invalid-peer ip="%s"' % peer[0], 'error' ) return # if subscribed, joined ... if self.pns_peer.pns_subscribed.has_key (model[0]): self.pns_peer.pns_subscribed[ model[0] ].pns_joined (peer) return # not subscribed, resolve a PIRP answer >>> if not self.pns_peers.has_key (peer): self.pns_peer.pns_resolution.pns_udp_pirp ( model[0], peer )
def pns_answer (self, datagram, peer): # handle in-circle and out-of-circle answers if datagram.startswith ('0:,'): if not self.pns_right: # out-of-circle model = list (netstring.decode (datagram)) if ( len (model) == 3 and model[1] == '' and ip_peer.is_ip (model[2]) ): # bounce to join left or right of L self.pns_join (model[2]) return assert None == self.log ( datagram, 'invalid-command-answer' ) self.pns_quit () return if datagram.startswith (self.PNS_SP): # handle protocol statement model = list (netstring.decode (datagram)) if not (len (model) == 3 and ( model[2] == '' or ip_peer.is_ip (model[2]) )): assert None == self.log ( datagram, 'invalid-protocol-answer' ) self.pns_quit () return if self.pns_right: # in-circle, quitted at left! return # out-of-circle if model[2]: # accept questions from R self.pns_peer.pns_udp.pns_accepted[ model[2] ] = self else: # root join self.pns_in_circle (peer) return # validate answer model = list (netstring.decode (datagram)) if ( (len (model[0]) + len (model[1]) + len ( '%d%d' % (len (model[0]), len (model[1])) )) > 512 or not public_names.valid_utf8 ( model[0], self.pns_horizon ) ): assert None == self.log ( datagram, 'invalid-question' ) self.pns_quit () return sp = netstring.encode (model[:2]) if ( self.pns_buffer.has_key (sp) and not self.pns_statements.has_key (sp) ): # buffered not stated, drop assert None == self.log (datagram, 'drop') return # echo to all subscribers model.append (self.pns_name) self.pns_tcp_continue (model, '!') if self.pns_statements.get (sp) == model[2]: # answer circled, clear the statement, do not relay del self.pns_statements [sp] assert None == self.log (datagram, 'circle') return # relay right self.pns_sendto_right ( netstring.encode (model), self.pns_right ) if ( model[1] == '' and self.pns_peer.pns_subscribed.has_key (model[0]) ): # protocol answer, let the named circle handle it if self.pns_peer.self.pns_peer.pns_subscribed[ model[0] ].pns_protocol_answer (model[2]): return # resolve ... self.pns_peer.pns_resolution.pns_udp_answer (model)
def pns_question (self, datagram, peer): # handle in-circle question if datagram.startswith ('0:,'): # command: quit right model = list (netstring.decode (datagram)) if len (model) == 2 and ip_peer.is_ip (model[1]): self.pns_quit_right (model[1]) return assert None == self.log ( datagram, 'invalid-protocol-command' ) self.pns_quitted () return if datagram.startswith (self.PNS_SP): # protocol question for this circle if self.pns_right: # in-circle, forward quit and then close self.sendto (self.PNS_SP, ( self.pns_left, 3534 )) self.pns_quitted () elif self.pns_left: # ? joining pass else: # ? accept pass return # validate question model = list (netstring.decode (datagram)) if (len (model) != 2 or not public_names.valid_utf8 ( model[0], self.pns_horizon )): assert None == self.log ( datagram, 'invalid-question' ) # TODO: ban IP addresses that send invalid datagrams! self.pns_quit () return sp = netstring.encode (model) if ( self.pns_buffer.get (sp) == '' and not self.pns_statements.has_key (sp) ): # buffered not stated, drop assert None == self.log (datagram, 'drop') return # echo the statement to the PNS/TCP subscribers model.append ('') model.append (self.pns_name) self.pns_tcp_continue (model, '?') if self.pns_statements.get (sp) == '': # question circled, clear the statement, do not relay del self.pns_statements[sp] assert None == self.log (datagram, 'circle') return # relay left self.sendto (sp, (self.pns_left, 3534)) if ( model[1] == '' and self.pns_peer.pns_subscribed.has_key (model[0]) ): # protocol question for a subscribed circle, bounce # this peer's IP address as the answer. left = self.pns_peer.pns_udp.addr[0] self.pns_sendto_right ( '%s%d:%s' % (sp, len(left), left), self.pns_right ) return # resolve ... self.pns_peer.pns_resolution.pns_udp_question (model)