Пример #1
0
	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
				)
Пример #2
0
	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)
Пример #3
0
	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)