class SignalServer(Thread): sock = None logger = None sender_id = 0 buf_size = 2000 # TODO This is not nice connection_list = [] # List of established connections exit_flag = False received_packet = None fsystem = None polltime = 0.5 updatetime = 5.0 # update time. send update messages to all peers. # TODO Throw error in case bind fails (Might do it already...) def __init__(self, fsystem, dataserver, ip = "0.0.0.0", port = 5500, sender_id = random.randint(0, 65535), q = 0.0, p = 0.0, passwd = ''): Thread.__init__(self) # TODO Think trough how the program should exit #signal.signal(signal.SIGINT, self.signal_handler) self.fsystem = fsystem self.dataserver = dataserver self.sender_id = sender_id self.logger = logging.getLogger("Signal server") self.logger.info("Initializing signal server id: %d at %s" % (self.sender_id, str(time.time()))) #self.logger.setLevel(logging.WARNING) self.sock = LossySocket(socket.AF_INET, socket.SOCK_DGRAM, q = q, p = p) self.sock.bind((ip, port)) self.sock.settimeout(self.polltime) # So we can exit and wont block forever in recvfrom self.received_packet = InPacket() self.connection_list_lock = thread.allocate_lock() self.passwd = passwd if len(passwd) != 0: self.use_enc = True self.security = Security() self.privateKey,self.publicKey = self.security.generate_keys(1024) self.publicKey_plaintext = self.security.export_key(self.publicKey) self.key_hash = self.security.calculate_key_hash(self.publicKey_plaintext, passwd) else: self.use_enc = False self.security = None self.privateKey,self.publicKey = None, None self.publicKey_plaintext = '' self.key_hash = '' def run(self): self.logger.info("Server started at %s" % (str(time.time()))) while self.exit_flag == False: try: data, addr = self.sock.recvfrom(self.buf_size) except socket.error: errno, errstr = sys.exc_info()[:2] if errno == socket.timeout: for i, connection in enumerate(self.connection_list): # Check if the connection should send an update message # Also remove broken connections if not connection.check_send_update(): connection.stop() del self.connection_list[i] #self.logger.info("socket timeout") continue else: self.logger.alarm("error with socket") if self.use_enc: packet_ok = self.received_packet.packetize_header(data) else: packet_ok = self.received_packet.packetize_raw(data) self.received_packet.receive_time = time.time() found = False self.connection_list_lock.acquire() for connection in self.connection_list: if self.received_packet.txremoteID == connection.local_session_id: self.logger.info("packet belongs to existing connection. processing...") found = True if self.use_enc and connection.state == SignalConnection.State.CONNECTED and 'CRY' in self.received_packet.get_flags(): data = self.security.decrypt_AES_bin(connection.aes_key, data, 8) #PacketManager.hex_data(data) packet_ok = self.received_packet.packetize_raw(data) self.logger.info("received packet:\n%s" % str(self.received_packet)) if not packet_ok: self.logger.warning("Decrypted packet is not valid.") break connection.handle(self.received_packet) break if not found: if self.use_enc: packet_ok = self.received_packet.packetize_raw(data) self.logger.info("received packet:\n%s" % str(self.received_packet)) if packet_ok and self.received_packet.otype == OPERATION['HELLO'] and \ self.received_packet.ocode == CODE['REQUEST']: connection = SignalConnection(server = self, remote_ip = addr[0], remote_port = addr[1], local_session_id = self.get_new_session_id(random.randint(0, 65535)), remote_session_id = self.received_packet.txlocalID, version = self.received_packet.version, send_ack_no = self.received_packet.sequence, seq_no = random.randint(0, 65535), updatetime = self.updatetime) #def __init__(self, server, remote_ip, remote_port, local_session_id, remote_session_id = 0, # version = 1, send_ack_no = random.randint(0, 65534), seq_no = random.randint(0, 65535)): connection.hello_recv(self.received_packet) self.connection_list.append(connection) self.logger.info("hello packet received, new connection established\ (local id %d, remote id %d) and HELLO sent" % (connection.local_session_id, connection.remote_session_id)) elif not packet_ok: self.logger.warning("Packet is not valid.") elif not found and packet_ok: self.logger.info("Packet does not belong to any connection and not a valid HELLO. Discarding.") self.logger.info("done with packet.\n") for i, connection in enumerate(self.connection_list): # Check if the connection should send an update message # Also remove broken connections if not connection.check_send_update(): connection.stop() del self.connection_list[i] self.connection_list_lock.release() # destination list should contain (ip, port) tuples def init_connections(self, destination_list): # todo create hello packet #self.packetmanager.create_packet(2, 15, 43962, 52428, 56797, 3150765550, 286331153, 85, 102, None, None) for destination in destination_list: self.logger.info('connecting to ' + destination[0] + ', ' + destination [1]) #self.sock.sendto("daddaa", (destination[0], int(destination[1])) ) connection = SignalConnection(self, destination[0], int(destination[1]), self.get_new_session_id(random.randint(0, 65535))) connection.connect() self.connection_list.append(connection) # Returns an unigue local session_id. Takes a random number from 0 to 65535 as a parameter. def get_new_session_id(self, rand_no): for connection in self.connection_list: if rand_no == connection.local_session_id: return get_new_session_id(random.randint(0, 65535)) return rand_no def stop(self): for connection in self.connection_list: connection.stop() self.logger.info("server should stop") self.exit_flag = True