#!/usr/bin/env python # -*- coding: iso-8859-15 -*- ############################################################################ # Copyright (C) 2005 by Israel Herraiz # # herraiz@gsyc.info # # # # This program is free software; you can redistribute it and#or modify # # it under the terms of the GNU General Public License as published by # # the Free Software Foundation; either version 2 of the License, or # # (at your option) any later version. # # # # This program is distributed in the hope that it will be useful, # # but WITHOUT ANY WARRANTY; without even the implied warranty of # # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # # GNU General Public License for more details. # # # # You should have received a copy of the GNU General Public License # # along with this program; if not, write to the # # Free Software Foundation, Inc., # # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # ############################################################################ """ Gnutella implementation in Python. Gnutella specification: 0.4 (document revision 1.2). """ # Needed libraries import socket import os import threading import select import time import string def debug(text,servent_object = None): if servent_object: output = "*"+str(servent_object.servent_id)+"* " else: output = "" output += text print "DEBUG: "+output class ServerThread(threading.Thread): """ This thread starts a new server, avoiding to block the main thread for that reason. """ def __init__(self,servent_object): self.servent = servent_object # This class inherits from threading.Thread threading.Thread.__init__(self) def run(self): """ This method is called when the new thread starts. """ # Begin server self.servent._beginNewServer() class ListenToConnectionsThread(threading.Thread): """ This thread listens to new connections. """ def __init__(self,servent_object,socket_object): self.servent = servent_object self.server_socket = socket_object # This class inherits from threading.Thread threading.Thread.__init__(self) def run(self): """ This method is called when the new thread starts. """ self.servent._acceptSocket(self.server_socket) class AttendConnectionThread(threading.Thread): """ This thread attends to established connections. """ def __init__(self,servent_object,socket_object): self.servent = servent_object self.accepted_socket = socket_object # This class inherits from threading.Thread threading.Thread.__init__(self) def run(self): self.servent._attendSocket(self.accepted_socket) class ClientThread(threading.Thread): """ This thread establishes a connection with a server. """ def __init__(self,servent_object,host): self.servent = servent_object self.host = host # This class inherits from threading.Thread threading.Thread.__init__(self) def run(self): #debug("Client thread starting") retry = True while retry: try: self.servent._connectToServer(self.host) retry = False except self.servent.default_connect_exception: time.sleep(self.servent.default_timeout) class Servent: """ This class represents a servent (a node) of a Gnutella network. Servent are server and clients at the same time. The Servent class implements all the descriptors included in the Gnutella specification. Several methods have names begining and ending in '_'. Those methods should not be called directly, because they are intended as private. The classes trying to use those methods should be friends of the Servent class, but Python lacks of friendship declaration. """ servent_num = 0 def __init__(self): """ Initialization of servent. """ # New servent. New id Servent.servent_num += 1 self.servent_id = Servent.servent_num # List of sockets. Each new connection creates a new socket self.sockets = [] # Dict of pings and sockets used to send them self.incoming_sockets = {} # List of servers got from the host cache self.servers_from_cache = [] # List of servers who responds to pings self.alive_servers = [] # List of clients connected to this servent # They will be treated as possible new servers, # and so, they will be send to the cache self.clients_connected_to_this = [] # This should a bag structure, in order to ensure scalability # (bloom filters?) self.sent_pings = [] self.seen_pings = [] self.sent_queries = [] self.seen_queries = [] self.sent_queryhits = [] self.seen_queryhits = [] self.sent_pongs = [] self.routed_pongs = [] # Default values self.gnutella_version = '0.4' # This data is updated when needed by each node. # They are sent when sending pongs self.num_of_shared_files = 0 self.num_of_kbs_shared = 0 # Data sent with Query and QueryHit # Minimum speed in kb/s self.minimum_speed = 128 # Address of the server who tell us the list of active servers self.host_cache_address = ('193.147.71.64',6346) # Address when acting as server (localhost:6346 by default) self.host_address = ('127.0.0.1',6346) # Maximum number of clients self.max_num_of_clients = 5 # Connection request string self.request_string = 'GNUTELLA CONNECT/'+self.gnutella_version+'\n\n' self.answer_string = 'GNUTELLA OK\n\n' # TTL and hops are complementary values. Initail value for hops should be zero. #The value of the TTL is the number of times the message is forwarded in each new hop. #In each new hop, TTL is decreased by one, and hops increased also by one. self.default_ttl = 5 self.default_hops = 0 self.default_timeout = 2 #self.default_timeout_exception = "TimeoutException" self.default_connect_exception = "ConnectionErrorException" self.is_firewalled = False # Default values for each descriptor self.descriptors_length = 4 # Each descriptor has 4 bytes # Ping descriptor self.ping_default_payload_descriptor = '\x00' self.ping__default_payload_length = '\x00\x00\x00\x00' self.ping_default_payload = '' self.ping_default_timeout = 1 # Pong descriptor self.pong_default_payload_descriptor = '\x01' self.pong_default_timeout = 2 self.pong_default_payload_length = '\016\000\000\000' # 14 bytes # Query descriptor self.query_default_payload_descriptor = '\x80' self.query_default_timeout = 5 # QueryHit descriptor self.queryhit_default_payload_descriptor = '\x81' self.queryhit_default_timeout = 5 def sendPing(self,descriptor_id = None,ttl = None, hops = None,original = True,incoming_socket = None): """ Sends a ping to all connected nodes. descriptor_id should be a 16 byte string. If not provided (or bad provided), a random 16 byte string is used. """ if ttl == None: ttl = self.default_ttl if hops == None: hops = self.default_hops if ttl > 0: # If descriptor_id is None, or bad descriptor_id, generates random id if not descriptor_id or len(descriptor_id) != 16: # Get a random number of 16 bytes descriptor_id = self.__getRandomId() # Lets build the header (as the specification says) payload_descriptor = self.ping_default_payload_descriptor payload_length = self.ping__default_payload_length payload = self.ping_default_payload header = descriptor_id+payload_descriptor+chr(ttl)+chr(hops)+payload_length # Packet is the sum of header and payload packet = header + payload # Send packet (one for each socket) timeout = self.ping_default_timeout for s in self.sockets: # Don't resend the ping by the same path it came if s != incoming_socket: self.sendPacket(s,packet,timeout) # If we made this ping, add to the lists if original: self.sent_pings.append(descriptor_id) if not (descriptor_id in self.seen_pings): self.seen_pings.append(descriptor_id) def __getRandomId(self): """ Generates a 16 byte random id """ descriptor_id = os.urandom(16) return descriptor_id def __serventId(self): # FIXME: Needs to be a hash of 16 bytes of the address of the servent ip_addr = '' for i in string.split(self.host_address[0], '.'): ip_addr = ip_addr + chr(int(i)) port = chr(self.host_address[1]%256)+chr(self.host_address[1]/256) this_id = port+ip_addr # 6 bytes for i in range(10): # 10 more bytes this_id += chr(0) return this_id # 16 bytes def sendPacket(self,socket_object,packet,timeout = None): """ Sends a packet to the node connected by socket_object packet must be a well formed string, as suggested by Gnutella specification. timeout should be greater than zero. If not provided, or bad provided, self.default_timeout is used. """ # If not valid timeout, set to default if not timeout or timeout <= 0: timeout = self.default_timeout socket.setdefaulttimeout(timeout) wrong_connection = False s = socket_object # Send packet try: s.send(packet) # If error in connection, raise exception except socket.error: wrong_connection = True # If timeout, continue except socket.timeout: wrong_connection = True # Returns True if all right, False otherwise, # and the next of right connections in the next field return not wrong_connection def recvPacket(self,socket_object,length,timeout = None): """ Receives a packet from the node connected by socket_object length is the number of characters of the packet. timeout should be greater than zero. If not provided, or bad provided, self.default_timeout is used. """ # If not valid timeout, set to default if not timeout or timeout <= 0: timeout = self.default_timeout socket.setdefaulttimeout(timeout) packet = socket_object.recv(length) return packet def beginServer(self): """ Each servent acts as a server and a client. This method begins the server part. """ #Begin a new thread for listening to new connections server_thread = ServerThread(self) server_thread.start() def _beginNewServer(self): """ Called by a ServerThread when a new thread starts. Should not be called directly. """ # Server code # New socket for this server connection s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.setblocking(0) s.bind(self.host_address) s.listen(self.max_num_of_clients) # If not commented, the pings and pongs are sent to ourselves #self.sockets.append(s) # Starts new thread listening to new connections listening_thread = ListenToConnectionsThread(self,s) listening_thread.start() debug("Server started",self) # Instead of creating a new thread, accept sockets directly # (only for debugging purposes) #self.acceptSocket(s) def __processConnectionRequest(self, accepted_socket): """ Called when a node requests a connection """ #request_length = len(self.request_string) request_string = '' retry = True while retry: try: #request_string = self.recvPacket(accepted_socket,request_length,5) num_of_end_of_lines = 0 while num_of_end_of_lines < 2: received = self.recvPacket(accepted_socket,1,self.default_timeout) request_string += received if received[-1] == '\n': num_of_end_of_lines += 1 retry = False expected_request_string = self.request_string.rstrip('\n').rstrip('\r').rstrip('\n').rstrip('\r').rstrip(' ') request_string = request_string.rstrip('\n').rstrip('\r').rstrip('\n').rstrip('\r').rstrip(' ') if request_string != expected_request_string: #raise self.default_connect_exception, "Connection Error: Unknown request string "+request_string debug("Connection Error: Unknown request string *"+request_string+"* Retrying....",self) request_string = '' retry = True except socket.timeout: #raise self.default_connect_exception, "Connection Error while waiting for request string: Timeout" debug("Timeout while waiting for connection request",self) time.sleep(self.default_timeout) retry = True # Ok, send answer string answer_string = self.answer_string try: self.sendPacket(accepted_socket,answer_string,self.default_timeout) except socket.timeout: raise self.default_connect_exception, "Connection Error while sending answer: Timeout" except socket.error: raise self.default_connect_exception, "Socket error while sending answer" debug("Connection request succeded",self) def __processPingRequest(self,socket_object,ping_id,ttl,hops): """ Called when a node requests a ping """ # THIS WORKS AS EXPECTED (05.01.05) # Ignore ping if we sent it if ping_id in self.sent_pings: debug("Ping dropped because it is mine",self) # Treat ping if we did not send it else: # If we saw this ping in other moment, ignore it if ping_id in self.seen_pings: debug("Ping dropped because I have seen it at least twice",self) # If we did not see it, send pong as answer else: self.seen_pings.append(ping_id) # The pong is sent only the first time we see the ping # Send pong (following the same path that the ping) self.sendPong(socket_object,ping_id) debug("Pong response because it is not mine, and it is the first time I see it",self) # And resend to other nodes if ttl > 1: # This ping is not generated by this servent # Then original -> False self.sendPing(ping_id,ttl-1,hops+1,False,socket_object) self.incoming_sockets[ping_id] = socket_object debug("Ping routing",self) def __processPongRequest(self,socket_object,pong_id,ttl,hops,payload): """ Called when a node requests a pong """ # THIS WORKS AS EXPECTED (05.01.05) # Origin of the pong port = ord(payload[0])+ord(payload[1])*256 ip = str(ord(payload[2]))+"."+str(ord(payload[3]))+"."+str(ord(payload[4]))+"."+str(ord(payload[5])) # We can catch the pong if is ours, or resend if # we saw the ping which requested this pong # If we sent the ping, the server is alive if pong_id in self.sent_pings: # Add to a list of alive servers debug("Catched pong from socket "+str(ip)+":"+str(port),self) if not ((ip,port) in self.alive_servers): self.alive_servers.append((ip,port)) # If we have seen the ping, resend the pong elif pong_id in self.seen_pings: if ttl > 1: # Resend the pong by the same path that the incoming ping s = self.incoming_sockets[pong_id] debug("Routing pong",self) self.sendPong(s, pong_id, ttl-1,hops+1,payload) else: debug("Pong dropped due to expired ttl",self) else: debug("Pong dropped because I did not see the ping",self) def __processQueryRequest(self,socket_object,descriptor_id,ttl,hops,payload): """ Called when a node requests a query """ # OK. THIS WORKS AS EXPECTED (05.08.05) # Ignore query if we sent it if descriptor_id in self.sent_queries: debug("Query dropped because it is mine",self) else: # Don't resend previous resent queries if descriptor_id in self.seen_queries: debug("Query dropped because I have seen it at least twice",self) else: debug("Query proccesed",self) self.seen_queries.append(descriptor_id) speed = ord(payload[0])+ord(payload[1])*256 criteria = payload[2:-1] debug(str(speed),self) debug(criteria,self) # Should send a query hit by the incoming socket number_of_hits = chr(1) speed = self.minimum_speed # Result set result_set = self.__getResultSet(criteria,speed) self.sendQueryHit(socket_object,descriptor_id,number_of_hits,speed,result_set,self.__serventId()) # And resend to other nodes if ttl > 1: # This ping is not generated by this servent # Then original -> False self.sendQuery(criteria,speed,descriptor_id,ttl-1,hops+1,False,socket_object) self.incoming_sockets[descriptor_id] = socket_object debug("Query routing",self) def __getResultSet(self,criteria,speed): # TO DO: Only returns null values. It should look for the files which match the criteria, and return that info. if self.minimum_speed >= speed: # Include search code here file_index = chr(0%256)+chr(0/256)+chr(0/256**2)+chr(0/256**3) file_size = chr(0%256)+chr(0/256)+chr(0/256**2)+chr(0/256**3) file_name = 'null'+'\x0000' result_set = file_index+file_size+file_name else: file_index = chr(0%256)+chr(0/256)+chr(0/256**2)+chr(0/256**3) file_size = chr(0%256)+chr(0/256)+chr(0/256**2)+chr(0/256**3) file_name = 'null'+'\x0000' result_set = file_index+file_size+file_name return result_set def __processQueryHitRequest(self,socket_object,descriptor_id,ttl,hops,payload): """ Called when a node requests a query hit """ debug("QueryHit processed",self) if not (descriptor_id in self.seen_queries): debug("Query Hit dropped because I have not seen the Query") elif descriptor_id in self.sent_queries: debug("Query Hit processed because it's mine") # Origin of the query hit port = ord(payload[1])+ord(payload[2])*256 ip = str(ord(payload[3]))+"."+str(ord(payload[4]))+"."+str(ord(payload[5]))+"."+str(ord(payload[6])) number_of_hits = ord(payload[0]) speed = ord(payload[7])+ord(payload[8])*256+ord(payload[9])*256**2+ord(payload[10])*256**3 #print port #print ip #print number_of_hits #print speed servent_id = payload[-16:] result_set = payload[11:-16] # Each record in result set is separated by '\x0000' records = result_set.split('\x0000') for r in records: if len(r) > 0: file_index = ord(r[0])+ord(r[1])*256+ord(r[2])*256**2+ord(r[3])*256**3 file_size = ord(r[4])+ord(r[5])*256+ord(r[6])*256**2+ord(r[7])*256**3 file_name = r[8:] #print file_index #print file_size #print file_name # result_set contains the info of the files #print result_set #print servent_id # If we are behind a firewall, send a push request if self.is_firewalled: self.sendPush(socket_object,servent_id) else: debug("Query Hit routed") incoming_socket = self.incoming_sockets[descriptor_id] self.sendQueryHit(incoming_socket,descriptor_id,None,None,None,None,ttl-1,hops+1,payload) def __processPushRequest(self): """ Called when a node requests a push """ pass def _acceptSocket(self,server_socket): """ Accept a socket from one of the running threads listening to connections Should not be called directly. """ # Each new client is accepted, and its petition processed # When processed, the next client is accepted # If max_num_of_clients is reached, the next connections are refused # Get the socket ready before accept new clients # Really not needed # try: # ready = False # while not ready: # debug("Socket not ready. Waiting",self) # # ready = (select.select([accepted_socket], [], [], 0) == ([accepted_socket], [], [])) # # time.sleep(self.default_timeout) # # except: # debug("Exception while getting ready.",self) # time.sleep(self.default_timeout) # Accept connections from clients #debug("Listening to connections",self) retry = True while retry: try: accepted_socket, client_addr = server_socket.accept() retry = False debug("Client connected to this server",self) except socket.timeout: retry = True time.sleep(self.default_timeout) #debug("Listening timeout",self) except socket.error: retry = True #debug("WARNING: Error in server socket. Waiting 5 secs...",self) time.sleep(self.default_timeout) except: retry = True debug("WARNING: Unkwnow error in server socket. Waiting 5 secs...",self) time.sleep(self.default_timeout) # Connection accepted self.sockets.append(accepted_socket) # Ok, connect and wait for descriptors self.__processConnectionRequest(accepted_socket) # Now, starts a new thread for listening to new clients listening_thread = ListenToConnectionsThread(self,server_socket) listening_thread.start() # And a thread to attend the petitions of the accepted socket attending_thread = AttendConnectionThread(self,accepted_socket) attending_thread.start() #self.attendSocket(accepted_socket) def _attendSocket(self,accepted_socket): """ Once a socket is accepted, a new thread attend its petitions. That thread call this method. Should not be called directly. """ retry = True # Receive header while retry: try: header = self.recvPacket(accepted_socket,23) descriptor_id = header[0:16] payload_descriptor = header[16] ttl = ord(header[17]) hops = ord(header[18]) payload_length = ord(header[19])+ord(header[20])*256+ord(header[21])*65536+ord(header[22])*16777216 if payload_length > 0: payload = self.recvPacket(accepted_socket,payload_length) else: payload = '' if payload_descriptor == self.ping_default_payload_descriptor: self.__processPingRequest(accepted_socket, descriptor_id,ttl,hops) elif payload_descriptor == self.pong_default_payload_descriptor: self.__processPongRequest(accepted_socket,descriptor_id,ttl,hops,payload) elif payload_descriptor == self.query_default_payload_descriptor: self.__processQueryRequest(accepted_socket,descriptor_id,ttl,hops,payload) elif payload_descriptor == self.queryhit_default_payload_descriptor: self.__processQueryHitRequest(accepted_socket,descriptor_id,ttl,hops,payload) retry = False except socket.timeout: retry = True # Wait some seconds and retry time.sleep(self.default_timeout) #except: # debug("Unkown error attending socket",self) # time.sleep(self.default_timeout) # Create new thread in order to attend next requests attending_thread = AttendConnectionThread(self, accepted_socket) attending_thread.start() #self.attendSocket(accepted_socket) def connect(self,host): """ Connects to a Gnutella server, creating a new thread in order to avoid blocking the main thread while waiting for the response. If not host is provided, one of the server hosts from the cache is used. """ # Start a thread to connect to the server, and to attend the connection client_thread = ClientThread(self,host) client_thread.start() # If the thread for connecting is started at the same time that the server thread, # (in the same host, although different ports), the connections can not be # stablished. A time sleep of some seconds must be runned. #self.connect_from_thread(host) def _connectToServer(self,host = None): """ Connects to a Gnutella server. If not host is provided, one of the server hosts from the cache is used. Private method. """ debug("Begin connection",self) # Try to obtain a valid host from the cache, if host is not provided while not host: # Not yet implemented #host = self.getHostFromCache() debug("WARNING: EMPTY HOST",self) pass debug("Trying to connect to "+str(host),self) # Create socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: # Connect to server s.connect(host) except socket.error, (rn, message): raise self.default_connect_exception, message request_string = self.request_string # Send request string to the server try: self.sendPacket(s,request_string,self.default_timeout) except socket.timeout: raise self.default_connect_exception, 'Connection Error: Timeout while sending request string.' # 08.05.05: Change this method of receiving answer_string. It should expect two carriage returns, and then check the answer # See __processConnectionRequest try: expected_answer_string = self.answer_string answer_string = self.recvPacket(s, len(expected_answer_string), self.default_timeout) except socket.timeout: raise self.default_connect_exception, 'Connection Error: Timeout whiele receiving answer string.' if answer_string != expected_answer_string: raise self.default_connect_exception, 'Unknow answer string: ' + answer_string self.sockets.append(s) # A thread to attend the responses from the server # (for example, pongs in request to pings) attending_thread = AttendConnectionThread(self,s) attending_thread.start() # Instead, attend the connection directly #self.attendSocket(s) def sendPong(self,socket_object,ping_id,ttl = None,hops = None, payload = None): """ Sends a pong request, in response to a ping, using the same socket which sent the ping. """ descriptor_id = ping_id if ttl == None: ttl = self.default_ttl if hops == None: hops = self.default_hops if ttl > 0: payload_descriptor = self.pong_default_payload_descriptor payload_length = self.pong_default_payload_length ip_addr = '' for i in string.split(self.host_address[0], '.'): ip_addr = ip_addr + chr(int(i)) port = chr(self.host_address[1]%256)+chr(self.host_address[1]/256) header = descriptor_id+payload_descriptor+chr(ttl)+chr(hops)+payload_length # If we are resending a captured pong, resend the original payload # Else, build the suitable payload if payload == None: payload = port + ip_addr for num in [self.num_of_shared_files,self.num_of_kbs_shared]: for c in [256**3, 256**2, 256, 1]: quotient = num/c reminder = num%c byte = chr(quotient) payload += byte num = reminder packet = header + payload # Send packet (one for each socket) timeout = self.pong_default_timeout self.sendPacket(socket_object,packet,timeout) def sendQuery(self, search_criteria, minimum_speed = None, descriptor_id = None, ttl = None, hops = None,original = True,incoming_socket = None): """ Sends a query to all the servents in the network. Only servers with a speed over minimum_speed will respond. The answer will include the results of the search using search_criteria. """ if descriptor_id == None: descriptor_id = self.__getRandomId() if ttl == None: ttl = self.default_ttl if hops == None: hops = self.default_hops if minimum_speed == None: minimum_speed = self.minimum_speed if ttl > 0: payload_descriptor = self.query_default_payload_descriptor payload = chr(minimum_speed%256)+chr(minimum_speed/256)+search_criteria+'\x00' payload_length = len(payload) payload_length = chr(payload_length%256)+chr(payload_length/256)+chr(payload_length/256**2)+chr(payload_length/256**3) header = descriptor_id+payload_descriptor+chr(ttl)+chr(hops)+payload_length packet = header+payload # Send packet (one for each socket) timeout = self.query_default_timeout for s in self.sockets: # Don't resend the query by the same path it came if s != incoming_socket: self.sendPacket(s,packet,timeout) if original: self.sent_queries.append(descriptor_id) if not (descriptor_id in self.seen_queries): self.seen_queries.append(descriptor_id) debug("Query sent",self) else: debug("Query not sent due to expired ttl",self) def sendQueryHit(self,socket_object,descriptor_id,number_of_hits,speed,result_set,servent_id,ttl = None,hops = None,payload = None): if ttl == None: ttl = self.default_ttl if hops == None: hops = self.default_hops if speed == None: speed = self.minimum_speed if ttl > 0: payload_descriptor = self.queryhit_default_payload_descriptor if payload == None: # Build payload ip_addr = '' for i in string.split(self.host_address[0], '.'): ip_addr = ip_addr + chr(int(i)) port = chr(self.host_address[1]%256)+chr(self.host_address[1]/256) speed = chr(speed%256)+chr(speed/256)+chr(speed/256**2)+chr(speed/256**3) payload = number_of_hits+port+ip_addr+speed+result_set+servent_id payload_length = len(payload) payload_length = chr(payload_length%256)+chr(payload_length/256)+chr(payload_length/256**2)+chr(payload_length/256**3) header = descriptor_id+payload_descriptor+chr(ttl)+chr(hops)+payload_length packet = header+payload timeout = self.queryhit_default_timeout self.sendPacket(socket_object,packet,timeout) def sendPush(self,socket_object,servent_id,tll=None,hops=None): if ttl == None: ttl = self.default_ttl if hops == None: hops = self.default_hops if speed == None: speed = self.minimum_speed if ttl > 0: payload_descriptor = self.queryhit_default_payload_descriptor if payload == None: # Build payload ip_addr = '' for i in string.split(self.host_address[0], '.'): ip_addr = ip_addr + chr(int(i)) port = chr(self.host_address[1]%256)+chr(self.host_address[1]/256) speed = chr(speed%256)+chr(speed/256)+chr(speed/256**2)+chr(speed/256**3) payload = number_of_hits+port+ip_addr+speed+result_set+servent_id payload_length = len(payload) payload_length = chr(payload_length%256)+chr(payload_length/256)+chr(payload_length/256**2)+chr(payload_length/256**3) header = descriptor_id+payload_descriptor+chr(ttl)+chr(hops)+payload_length packet = header+payload timeout = self.queryhit_default_timeout def closeConnections(self): debug("Closing connections...",self) for s in self.sockets: s.close() # Code for testing this module if '__main__' == __name__: # Servents a = Servent() a.host_address = ('127.0.0.1',6346) a_addr = a.host_address #a.default_timeout = 5 b = Servent() b.host_address = ('127.0.0.1',6345) b_addr = b.host_address c = Servent() c.host_address = ('127.0.0.1',6344) c_addr = c.host_address d = Servent() d.host_address = ('127.0.0.1',6343) d_addr = d.host_address e = Servent() e.host_address = ('127.0.0.1',6331) e_addr = e.host_address #foreign_addr = ('gnutellahosts.com',6346) # Begin each servent a.beginServer() # time.sleep(2) # b.beginServer() # time.sleep(2) c.beginServer() # time.sleep(2) # d.beginServer() e.beginServer() time.sleep(5) if 1: # Connect a to b, b to c, and c to a #connected = False #while not connected: # try: b.connect(c_addr) # connected = True # except: # time.sleep(2) #time.sleep(2) #connected = False #while not connected: # try: c.connect(a_addr) # connected = True # except: # time.sleep(2) #time.sleep(2) #connected = False #while not connected: # try: d.connect(c_addr) # connected = True # except: # time.sleep(2) #time.sleep(2) #connected = False #while not connected: # try: d.connect(a_addr) # connected = True # except: # time.sleep(2) #time.sleep(2) #connected = False #while not connected: # try: e.connect(a_addr) # connected = True # except: # time.sleep(2) #time.sleep(2) #connected = False #while not connected: # try: b.connect(e_addr) # connected = True # except: # time.sleep(2) #time.sleep(2) #time.sleep(10) time.sleep(5) print "All nodes ready" b.sendPing() time.sleep(5) a.sendPing() a.sendQuery("mp3",512) #time.sleep(3) b.sendQuery("video",512) #time.sleep(2) c.sendPing() #time.sleep(1) d.sendQuery("hola",320) # # time.sleep(10) # a.sendPing() # time.sleep(3) # # for i in range(10): # a.sendPing() # time.sleep(3) # b.sendPing() # time.sleep(3) # # for i in range(15): # print i # time.sleep(1) # b.sendPing() # # time.sleep(1) # # for i in range(5): # print i # b.sendPing() #