예제 #1
0
class Server:
    
    

    def __init__(self, port = 8080):
    
        self.testargs = " ".join(sys.argv[1:])
        self.publickey, self.privatekey = rsa.newkeys(512)
        self.host = ''   # <-- works on all available network interfaces
        self.port = port
        self.chain = blockchain.Blockchain()
        self.phonebook = Phonebook()
        self.uid = uuid.uuid1()

    def activate_server(self):
        signal.signal(signal.SIGINT, graceful_shutdown)

        print ("Starting web server")
        s = Server(8080)  # Constructs server object
     
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try: # user provided in the __init__() port may be unavailable
            print("Launching HTTP server on ", self.host, ":",self.port)
            self.socket.bind((self.host, self.port))

        except Exception as e:
            for i in range (self.port, self.port+1000):
                print ("Warning: Could not acquire port:",self.port,"\n")
                print ("Attempting to register on higher port.")
                
                user_port = self.port
                self.port = self.port+1

                try:
                    print("Launching HTTP server on ", self.host, ":",self.port)
                    self.socket.bind((self.host, self.port))
                    break
                except Exception as e:
                    print("ERROR: Failed to acquire sockets for ports ", user_port, " and 8080. ")
                    #print("Try running the Server in a privileged user mode.")
                    #self.shutdown()
                    #import sys
                    #sys.exit(1)

        print ("Server successfully acquired the socket with port: ", self.port)
        print ("Press Ctrl+C to shut down the server and exit.")
        self.phonebook.add_peer_to_phonebook(str(self.uid),{'port':str(self.port),'pubkey_e':str(self.publickey.e),'pubkey_n':str(self.publickey.n)})
        if self.port != 8080:
            self.request_phonebook_from_peers()
        self._wait_for_connections()

    def shutdown(self):
     
        try:
            print("Shutting down the server")
            s.socket.shutdown(socket.SHUT_RDWR)

        except Exception as e:
            print("Warning: could not shut down the socket. Maybe it was already closed?",e)

    def request_phonebook_from_peers(self):
    
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
   
        # Can add system arguments to the method call if we wanna call just specific ports
        # Mostly used for testing
        if self.testargs != "":
            ports = [int(x) for x in self.testargs.split(" ")]
        else: 
            ports = range(8080,9080)
        
        for port_in_range in ports:
            try:
                sock.connect(('localhost', port_in_range))
                sock.sendall(bytes("book", 'utf-8'))
                    
                received = str(sock.recv(1024), "utf-8")
                message = received.split('$')
                    
                if message[0] == 'bookack':
                    
                    peers_response = json.loads(message[1])
                    clients_response = json.loads(message[2])
                    self.phonebook.update_phonebook(peers_response, clients_response)
            
            except Exception as e:
                pass
                #print (e)
                #sock.close()


    def _wait_for_connections(self):
        # Temp for testing
        b1 = block.Block()
        while True:
            try:
                print ("Awaiting New connection")
                self.socket.listen(3)

                conn, addr = self.socket.accept()

                print("Got connection from:", addr)

                data = conn.recv(1024)
                string = bytes.decode(data)

                split_message = string.split('$?$')
                
                message_type = split_message[0]
                
                if message_type == 'ping':
                
                    message_type, name, pubkey_n, pubkey_e = split_message
                    user_pubkey = {'pubkey_n': int(pubkey_n), 'pubkey_e': int(pubkey_e)}
                    self.phonebook.add_client_to_phonebook(name, user_pubkey)
                
                    ping_response = "ack {0} {1} {2} {3}".format(self.uid,self.port,self.publickey.n,self.publickey.e)
                    conn.send(bytes(ping_response,'utf-8'))
                    
                    
                elif message_type == 't':
                
                    message_type, sender, receiver, message, value, fee, timestamp, verification = split_message
                    
                    verification_message = bytes("$?$".join([receiver, message, str(value), fee, str(timestamp)]),'utf-8')
                    
                    sender_key = self.phonebook.get_pubkey_from_UID(sender)
                    try:
                        if rsa.verify(verification_message, literal_eval(verification), sender_key):
                            
                            print ("Sender: " + sender + " - Receiver: " + receiver + " - Message: " + message)
                            transaction = ts.Transaction(sender,sender,receiver,message)
                            b1.add_transaction(transaction)
                            if b1.has_enough_transactions():
                            #if 1 == 1:
                                b1.mine()
                                self.broadcast_block_to_network(b1)
                                b1.empty_transactions()
                                
                    except VerificationError as e:
                        print ('Not verified')
                        
                        
                elif message_type == 'b':
                    
                    message_type, message = split_message
                    self.chain.add_block_to_ledger(message)
                    
                    
                elif message_type == 'book':
                
                    
                    full_book = self.phonebook.get_all_peers()
                    
                    peers_serialized = json.dumps(full_book[0])
                    clients_serialized = json.dumps(full_book[1])
                    
                    book_response = "bookack$" + peers_serialized + "$" +  clients_serialized
                    
                    
                    conn.send(bytes(book_response,'utf-8'))
                    
                
            finally:
                conn.close()
            
    def broadcast_block_to_network(self, block):
        
        peers = self.phonebook.get_all_peers_for_announcement()
        
        for port_in_range in peers:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            try:
                message = "b$?$"+str(json.dumps(block))
                
                sock.connect(('localhost', int(port_in_range)))
                sock.sendall(bytes(message, 'utf-8'))
                
            
            except Exception as e:
                print (e)
                sock.close()