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