Example #1
0
    def FindValue(self, request, context):
        node = request.node # node object (id, port, address)
        key = request.idkey  # int

        print("Serving FindKey(" + str(key) + ") request for " + str(node.id))

        # create self node to attach to findValue call
        self_node = csci4220_hw4_pb2.Node(id=self.my_id, port=self.my_port, address=self.my_address)

        
        # update the bucket so requesting is the most recent one
        b = self.my_id ^ node.id
        b = b.bit_length() - 1

        self.UpdateBucket(b, Node(node.address, node.port, node.id))

        # if self contains key
        if key in self.data:
            return csci4220_hw4_pb2.KV_Node_Wrapper(responding_node=self_node, mode_kv=True, kv=csci4220_hw4_pb2.KeyValue(node=self_node,key=key,value=self.data[key]), nodes=[])
        # if self doesn't contain key, ask peers 
        else:

            # create the nodes list to return
            nodes_list = []
            for item in self.k_buckets.items():
                for peer in item[1]:
                    nodes_list.append(csci4220_hw4_pb2.Node(id=peer.node_id, port=peer.port, address=peer.address))

            return csci4220_hw4_pb2.KV_Node_Wrapper(responding_node=self_node, mode_kv=False, kv=csci4220_hw4_pb2.KeyValue(node=self_node, key=key, value="None"), nodes=nodes_list)
Example #2
0
    def SendBootstrap(self, peer_host, peer_port):
        # temporarily connect with them to get 
        with grpc.insecure_channel(peer_host + ":" + peer_port) as channel:
            
            # access the remote server
            stub = csci4220_hw4_pb2_grpc.KadImplStub(channel)
            obj = csci4220_hw4_pb2.IDKey(node=csci4220_hw4_pb2.Node(id=self.my_id, port=int(self.my_port), address=self.my_address), idkey=self.my_id)
            
            # node contains the return from FindNode
            node = stub.FindNode(obj)

            # get the bucket it should be stored in
            bucket = self.my_id ^ node.responding_node.id
            bucket = bucket.bit_length() - 1
            

            # create a new node from the responding node and append it
            n = Node(node.responding_node.address, node.responding_node.port, node.responding_node.id)
            self.UpdateBucket(bucket,n)

            # add all the nodes that were neighbors
            for i in node.nodes:
                b = self.my_id ^ i.id
                b = b.bit_length() - 1

                if (b >= 0):
                    self.UpdateBucket(b, Node(i.address, i.port, i.id))
            print("After BOOTSTRAP(" + str(node.responding_node.id) + "), k_buckets now look like:")
            self.PrintBuckets()
Example #3
0
    def Store(self, request, context):
        node = request.node
        k = request.key
        v = request.value

        # received request, simply add it to the key value store
        print("Storing key " + str(k) + " value \"" + str(v) + "\"")
        self.data[k] = v

        # create the return object
        toReturn = csci4220_hw4_pb2.IDKey(node=csci4220_hw4_pb2.Node(id=self.my_id, port=self.my_port, address=self.my_address), idkey=self.my_id)


        # update the location of the sending store command
        bucket = self.my_id ^ node.id
        bucket = bucket.bit_length() - 1

        found = False
        # check to make sure that peer exists
        for item in self.k_buckets[bucket]:
            if item.node_id == node.id:
                found = True
        
        # if found, update it
        if found == True:
            self.UpdateBucket(bucket, Node(node.address,node.port,node.id))
    
        return toReturn
Example #4
0
    def SendFindValue(self, target_key):

        if target_key in self.data.keys():
            print("Found data \""+ self.data[target_key]+ "\" for key " + str(target_key))
            return
        
        obj = csci4220_hw4_pb2.IDKey(node=csci4220_hw4_pb2.Node(id=self.my_id, port=int(self.my_port), address=self.my_address), idkey=target_key)

        visited = []
        visited.append(self.my_id)

        # for all peers
        to_sort = []
        for item in self.k_buckets.items():
            for peer in item[1]:
                to_sort.append(peer)
        
        # sort the peers based on distance to target_key
        to_sort.sort(key=lambda node: (target_key ^ node.node_id).bit_length() -1)

        # for all peers in order
        for peer in to_sort:
            with grpc.insecure_channel(peer.address + ":" + str(peer.port)) as channel:

                # send find value command
                stub = csci4220_hw4_pb2_grpc.KadImplStub(channel)
                R = stub.FindValue(obj)
                visited.append(peer.node_id)

                b = peer.node_id ^ self.my_id
                b = b.bit_length() - 1

                # update location of the peer
                self.UpdateBucket(b, peer)
                
                # if found
                if (R.mode_kv == True):
                    print("Found value \"" + R.kv.value + "\" for key " + str(R.kv.key))
                    return
                else:
                    for i in R.nodes:
                        if i.id not in visited:

                            b = self.my_id ^ i.id
                            b = b.bit_length() - 1

                            self.UpdateBucket(b, Node(i.address, i.port, i.id))

                            # search through the returned k nearest peers
                            with grpc.insecure_channel(i.address + ":" + str(i.port)) as to_ask:
                                stub = csci4220_hw4_pb2_grpc.KadImplStub(to_ask)
                                response = stub.FindValue(obj)
                                visited.append(i.id)

                                # if found in peer list
                                if (response.mode_kv == True):
                                    print("Found value \"" + response.kv.value + "\" for key " + str(response.kv.key))
                                    return
        # if haven't found at this point, print that it couldn't be found
        print("Could not find key " + str(target_key))
Example #5
0
def run():
	if len(sys.argv) != 4:
		print("Error, correct usage is {} [my id] [my port] [k]".format(sys.argv[0]))
		sys.exit(-1)

	local_id = int(sys.argv[1])
	my_port = str(int(sys.argv[2])) # add_insecure_port() will want a string
	k = int(sys.argv[3])
	my_hostname = socket.gethostname() # Gets my host name
	my_address = socket.gethostbyname(my_hostname) # Gets my IP address from my hostname

	# list of lists of Node objects, initially each list is empty.  There are 4 lists hard coded because we
	# are using 4 bit integers, and therefore 4 k-buckets
	k_buckets = [[],[],[],[]]
	# a dictionary to hold the key value pairs we store locally
	dictionary = dict()
	meNode = csci4220_hw4_pb2.Node(id=local_id, port=int(my_port), address=my_address)

	# a new thread is created to handle listening for rpc calls so the UI thread and listening thread can run in parallel
	# thread must be a daemon thread to have it killed when the main thread ends on QUIT command
	t = threading.Thread(target=serve, args=(my_port, k_buckets, dictionary, meNode, k,), daemon = True)
	t.start()
	#serve(my_port, k_buckets, dictionary, meNode, k)

	# loop until QUIT command is received, call appropriate function for each other command
	while(True):
		command = input('').split()

		#bootstrap(remote_addr_string, remote_port_string, myId, meNode, k_buckets, k):
		if command[0] == "BOOTSTRAP":
			remote_addr_string = command[1]
			remote_port_string = command[2]
			bootstrap(remote_addr_string, remote_port_string, meNode.id, meNode, k_buckets, k)

		elif command[0] == "FIND_NODE":
			print("Before FIND_NODE command, k-buckets are:")
			printBuckets(k_buckets)
			findNode(int(command[1]), k_buckets, k, 4, meNode)

		elif command[0] == "FIND_VALUE":
			print("Before FIND_VALUE command, k-buckets are:")
			printBuckets(k_buckets)

			findValue(int(command[1]), k_buckets, k, 4, meNode, dictionary)

			print("After FIND_VALUE command, k-buckets are:")
			printBuckets(k_buckets)

		#store(key, value, k_buckets, k, meNode, storedDict)
		elif command[0] == "STORE":
			key = int(command[1])
			value = command[2]
			store(key, value, k_buckets, k, meNode, dictionary)

		elif command[0] == "QUIT":
			quit(meNode.id, meNode, k_buckets)
			sys.exit()
			break
Example #6
0
 def Quit(self, request, context):
 	global buckets
 	quit_id = int(request.idkey)
 	for i in range(4):
 		for entry in buckets[i]:
 			if int(entry.id) == quit_id:
 			    buckets[i].remove(entry)
 			    print("Evicting quitting node " + str(quit_id) + " from bucket " + str(i))
 			    return csci4220_hw4_pb2.IDKey(node = csci4220_hw4_pb2.Node(id = int(sys.argv[1]), port = int(sys.argv[2]), address = "127.0.0.1"), idkey = int(sys.argv[1]))
 	print("No record of quitting node " + str(quit_id) + " in k-buckets.")
     count = 0
     for bucket in buckets:
         sys.stdout.write('{}:'.format(str(count)))
         for entry in bucket:
             sys.stdout.write(' {}:{}'.format(str(entry.id), str(entry.port)))
         sys.stdout.write('\n')
         count += 1
         
     return csci4220_hw4_pb2.IDKey(node = csci4220_hw4_pb2.Node(id = int(sys.argv[1]), port = int(sys.argv[2]), address = "127.0.0.1"), idkey = int(sys.argv[1]))
Example #7
0
 def Store(self, request, context):
     
     global val
     global val_key
 
     print("storing something")
     val = request.value
     val_key = request.key
     
     return csci4220_hw4_pb2.IDKey(node = csci4220_hw4_pb2.Node(id = int(sys.argv[1]), port = int(sys.argv[2]), address = "127.0.0.1"), idkey = int(sys.argv[1]))
Example #8
0
    def FindNode(self, request, context):
        to_add = request.node
        request_id = request.idkey
        print("Serving FindNode("+str(to_add.id) + ") request for " + str(request_id))

        # handle bootstrap call
        if (to_add.id == request_id):

            # get the bucket
            bucket = self.my_id ^ to_add.id
            bucket = bucket.bit_length() - 1

            n = Node(to_add.address, to_add.port, to_add.id)
            self.UpdateBucket(bucket, n)
            responding = []
            for item in self.k_buckets.items():
                for peer in item[1]:
                    responding.append(csci4220_hw4_pb2.Node(id=peer.node_id, port=peer.port, address=peer.address))
            
            # create the node list
            toReturn = csci4220_hw4_pb2.NodeList(responding_node=csci4220_hw4_pb2.Node(id=self.my_id, port=self.my_port, address=self.my_address), nodes=responding)

            return toReturn

        else:
            
            responding = []
            # for all buckets
            for item in self.k_buckets.items():

                # for all peers
                for peer in item[1]:
                    responding.append(csci4220_hw4_pb2.Node(id=peer.node_id, port=peer.port, address=peer.address))

            # create the return object
            # using the array as the nodelist
            toReturn = csci4220_hw4_pb2.NodeList(responding_node=csci4220_hw4_pb2.Node(id=self.my_id, port=self.my_port, address=self.my_address), nodes=
            responding)

            return toReturn

        return toReturn
Example #9
0
 def FindNode(self, request, context):
 
     global buckets
 
     bit_len = ((int(request.node.id))^(int(sys.argv[1]))).bit_length()
     bit_len -= 1
     print("bitlen is: " + str(bit_len))
     if len(buckets[bit_len]) == int(sys.argv[3]):
         buckets[bit_len].popleft()
     buckets[bit_len].append(request.node)
     
     print('Serving FindNode({}) request for {}'.format(str(request.idkey), str(request.node.id)))
     id_in = request.idkey
     k = int(sys.argv[3])
     count = 0
     temp_list = deque([])
     #look at all Nodes in bucket
     #and insert them into the temp list
     #in the order of their distance to the
     #requested ID
     for bucket in buckets:
         for entry in bucket:
             if entry.id == request.node.id:
                 continue
             if count == 0:
                 #first entry into the temp list
                 temp_list.append(entry)
                 count += 1
             else:
                 #make sure things are sorted
                 if (int(entry.id)^int(request.idkey)) <= (int(temp_list[0].id)^int(request.idkey)):
                     temp_list.appendleft(entry)
                     count += 1
                 else:
                     temp_list.append(entry)
                     count += 1
     
     this_node = csci4220_hw4_pb2.Node(id = int(sys.argv[1]), port = int(sys.argv[2]), address = "127.0.0.1")
     node_list = None
     if count <= k:
         node_list = temp_list
     else:
         node_list = temp_list[:(k - 1)]
     
     for bucket in buckets:
         sys.stdout.write('{}:'.format(str(count)))
         for entry in bucket:
             sys.stdout.write(' {}:{}'.format(str(entry.id), str(entry.port)))
         sys.stdout.write('\n')
         count += 1
     
     return csci4220_hw4_pb2.NodeList(responding_node = this_node, nodes = node_list)
Example #10
0
 def FindValue(self, request, context):
     
     global buckets
     global val
     global val_key
     
     k = int(sys.argv[3])
     
     this_node = csci4220_hw4_pb2.Node(id = int(sys.argv[1]), port = int(sys.argv[2]), address = "127.0.0.1")
     
     if val_key == request.idkey:
         print("value found with given key")
         return csci4220_hw4_pb2.KV_Node_Wrapper(responding_node = this_node, mode_kv = True, kv = csci4220_hw4_pb2.KeyValue(node = this_node, key = val_key, value = val), nodes = None)
         
     count = 0
     temp_list = deque([])
     #look at all Nodes in bucket
     #and insert them into the temp list
     #in the order of their distance to the
     #requested ID
     for bucket in buckets:
         for entry in bucket:
             if entry.id == request.node.id:
                 continue
             if count == 0:
                 #first entry into the temp list
                 temp_list.append(entry)
                 count += 1
             else:
                 #make sure things are sorted
                 if (int(entry.id)^int(request.idkey)) <= (int(temp_list[0].id)^int(request.idkey)):
                     temp_list.appendleft(entry)
                     count += 1
                 else:
                     temp_list.append(entry)
                     count += 1
     
     node_list = None
     
     if count <= k:
         node_list = temp_list
     else:
         node_list = temp_list[:(k - 1)]
     
     print("value not found, returned a list of closest nodes")
     
     return csci4220_hw4_pb2.KV_Node_Wrapper(responding_node = this_node, mode_kv = False, kv = None, nodes = node_list)
Example #11
0
    def SendQuit(self):
        obj = csci4220_hw4_pb2.IDKey(node=csci4220_hw4_pb2.Node(id=self.my_id, port=int(self.my_port), address=self.my_address), idkey=self.my_id)

        # for all peers
        for item in self.k_buckets.items():
            for peer in item[1]:
                #send a quit to all pears
                with grpc.insecure_channel(peer.address + ":" + str(peer.port)) as channel:
                    print("Letting "+ str(peer.node_id)+" know I'm quitting.")
                    
                    # send quit to them
                    try:
                        stub = csci4220_hw4_pb2_grpc.KadImplStub(channel)
                        ret = stub.Quit(obj)
                    # if quit does not connect, do nothing
                    # hacky way as of submitty 195
                    except:
                        pass
Example #12
0
    def SendFindNode(self, target_id):
        obj = csci4220_hw4_pb2.IDKey(node=csci4220_hw4_pb2.Node(id=self.my_id, port=int(self.my_port), address=self.my_address),
        idkey=target_id)

        # keep track of visited
        visited = []
        for item in self.k_buckets.items():
            bucket = item[1]
            for index in range(len(bucket)):

                # if already visited
                if (bucket[index].node_id in visited):
                    print("alerady visited")
                    continue

                # send the peer the find node command
                with grpc.insecure_channel(bucket[index].address + ":" + str(bucket[index].port)) as channel:
                    stub = csci4220_hw4_pb2_grpc.KadImplStub(channel)

                    # make the request
                    R = stub.FindNode(obj)

                    # add this to visited
                    visited.append(bucket[index].node_id)

                    # update the position of this first node
                    self.UpdateBucket(item[0],bucket[index])

                    # update k buckets with node (move it to the front)
                    for i in R.nodes:
                        b = self.my_id ^ i.id
                        b = b.bit_length() - 1

                        # make sure not self
                        if (b >= 0):
                            found = False
                            for match in bucket:
                                if match.node_id == i.id:
                                    found = True

                            # found it
                            if (target_id == i.id):
                                print("Found destination id " + str(target_id))
                            self.UpdateBucket(b, Node(i.address, i.port, i.id))
Example #13
0
def run():
    if len(sys.argv) != 4:
        print("Error, correct usage is {} [my id] [my port] [k]".format(sys.argv[0]))
        sys.exit(-1)
    local_id = int(sys.argv[1])
    my_port = str(int(sys.argv[2])) # add_insecure_port() will want a string
    k = int(sys.argv[3])
    my_hostname = socket.gethostname() # Gets my host name
    my_address = socket.gethostbyname(my_hostname) # Gets my IP address from my hostname
    ''' Use the following code to convert a hostname to an IP and start a channel
    Note that every stub needs a channel attached to it
    When you are done with a channel you should call .close() on the channel.
    Submitty may kill your program if you have too many file descriptors open
    at the same time.'''


    # start the server in the background
    hash_table = HashTable()
    hash_table.my_port = int(my_port)
    hash_table.my_id = local_id
    hash_table.my_address = my_address

    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    csci4220_hw4_pb2_grpc.add_KadImplServicer_to_server(hash_table, server)
    server.add_insecure_port('[::]:'+my_port)
    server.start()

    # initializing the buckets 2^k
    buckets = pow(2, k)
    for i in range(buckets):
        hash_table.k_buckets[i] = []
    

    # main listening loop
    while (True):
        stdin = str(input())
        arguments = stdin.split(" ")

        # connect to another peer directly
        if (arguments[0] == "BOOTSTRAP"):
            peer_host = arguments[1]
            peer_port = arguments[2]

            hash_table.SendBootstrap(peer_host, peer_port)

        # if the command is to store a value at a key
        if (arguments[0] == "STORE"):
            key = int(arguments[1])
            value = arguments[2]
            min_dist = key ^ hash_table.my_id
            min_key = Node(hash_table.my_address, hash_table.my_port, hash_table.my_id)

            # get the minimum distance peer to the key
            for item in hash_table.k_buckets.items():
                for peer in item[1]:
                    dist = key ^ peer.node_id
                    if dist < min_dist:
                        min_dist = dist
                        min_key = peer
            
            print("Storing key " + str(key) + " at node " + str(min_key.node_id))
            if (min_key.node_id == hash_table.my_id):
                hash_table.data[key] = value
            else:

                # send the store command to that remote
                with grpc.insecure_channel(min_key.address + ":" + str(min_key.port)) as channel:
                    stub = csci4220_hw4_pb2_grpc.KadImplStub(channel)
                    obj = csci4220_hw4_pb2.KeyValue(node=csci4220_hw4_pb2.Node(id=hash_table.my_id, port=int(hash_table.my_port), address=hash_table.my_address), key=key, value=value)
                    
                    id_key = stub.Store(obj)

        # command to find a node
        if (arguments[0] == "FIND_NODE"):
            target_id = int(arguments[1])
            print("Before FIND_NODE command, k-buckets are:")
            hash_table.PrintBuckets()

            # perform searching and updating here
            hash_table.SendFindNode(target_id)

            print("After FIND_NODE command, k-buckets are:")
            hash_table.PrintBuckets()

        # command to find a value
        if (arguments[0] == "FIND_VALUE"):
            find_target = int(arguments[1])
            print("Before FIND_VALUE command, k-buckets are:")
            hash_table.PrintBuckets()

            # perform search and updating here
            hash_table.SendFindValue(find_target)

            print("After FIND_VALUE command, k-buckets are:")
            hash_table.PrintBuckets()

        # command to  quit and unregister self from pers
        if (arguments[0] == "QUIT"):

            # send quit to all peers
            hash_table.SendQuit()
            print("Shut down node " + str(local_id))
            break
Example #14
0
def run():
    if len(sys.argv) != 4:
        print("Error, correct usage is {} [my id] [my port] [k]".format(sys.argv[0]))
        sys.exit(-1)

    global val
    global val_key
    global buckets
    
    local_id = int(sys.argv[1])
    my_port = str(int(sys.argv[2])) # add_insecure_port() will want a string
    k = int(sys.argv[3])
    
    #4 buckets needed
    i = 4
    while i > 0:
        #append 4 empty deques into the bucket, the deques should contain Nodes
        buckets.append(deque([]))
        i -= 1
    
    my_hostname = socket.gethostname() # Gets my host name
    my_address = socket.gethostbyname(my_hostname) # Gets my IP address from my hostname
    
    #don't ask, gRPC tutorial said so
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    csci4220_hw4_pb2_grpc.add_KadImplServicer_to_server(KadImplServicer(), server)
    
    #listen from the port
    server.add_insecure_port("127.0.0.1" + ':' + my_port)
    server.start()
    
	# Use the following code to convert a hostname to an IP and start a channel Note that every stub needs a channel attached to it When you are done with a channel you should call .close() on the channel. Submitty may kill your program if you have too many file descriptors open at the same time.
	
    #remote_addr = socket.gethostbyname(my_hostname)
    #remote_port = int(my_port)
    
    #channel = grpc.insecure_channel(remote_addr + ':' + str(remote_port))
    
    while True:
        input_str = str(raw_input())
        input_args = input_str.split()
        
        if input_args[0] == "BOOTSTRAP":
            #print("bootstrap")
            remote_hostname = str(input_args[1])
            remote_port = int(input_args[2])
            remote_addr = socket.gethostbyname(remote_hostname)
            
            #connect to server & create stub
            channel = grpc.insecure_channel("127.0.0.1" + ':' + str(remote_port))
            stub = csci4220_hw4_pb2_grpc.KadImplStub(channel)
            
            #create the node object
            this_node = csci4220_hw4_pb2.Node(id = local_id, port = int(my_port), address = str(my_address))
            
            #call FindNode
            node_list = stub.FindNode(csci4220_hw4_pb2.IDKey(node = this_node, idkey = local_id))
            
            #add nodes from the list in node_list
            for node in node_list.nodes:
                bit_len = ((node.id)^local_id).bit_length()
                bit_len -= 1
                #pop an element if the bucket is full
                if len(buckets[bit_len]) == k:
                    buckets[bit_len].popleft()
                buckets[bit_len].append(node)
            
            #add the node that it just sent RPC to
            r_node = node_list.responding_node
            bit_len = ((r_node.id)^local_id).bit_length()
            bit_len -= 1
            if len(buckets[bit_len]) == k:
                buckets[bit_len].popleft()
            buckets[bit_len].append(r_node)
            
            #done (hopefully)
            print('After BOOTSTRAP({}), k_buckets now look like:'.format(str(r_node.id)))
            count = 0
            for bucket in buckets:
                sys.stdout.write('{}:'.format(str(count)))
                for entry in bucket:
                    sys.stdout.write(' {}:{}'.format(str(entry.id), str(entry.port)))
                sys.stdout.write('\n')
                count += 1
            
            channel.close()

        if input_args[0] == "STORE":
            print("store")
            this_key = int(input_args[1])
            this_value = input_args[2]

            closest_node = csci4220_hw4_pb2.Node(id = local_id, port = int(my_port), address = str(my_address))
            distance = abs(local_id - this_key)
            for bucket in buckets:
                for entry in bucket:
                    if abs(int(entry.id) - this_key) < distance:
                	    closest_node = entry
                	    distance = abs(int(entry.id) - this_key)
            remote_hostname = str(closest_node.id)
            remote_port = int(closest_node.port)
            remote_addr = socket.gethostbyname(remote_hostname)
            
            #connect to server & create stub
            this_addr = "127.0.0.1" + ':' + str(remote_port)
            channel = grpc.insecure_channel(this_addr)
            stub = csci4220_hw4_pb2_grpc.KadImplStub(channel)
            print(this_addr)
            some_idkey = stub.Store(csci4220_hw4_pb2.KeyValue(node = None, key = this_key, value = this_value))

            channel.close()
            
        if input_args[0] == "QUIT":
            for bucket in buckets:
                for entry in bucket:
            	    remote_hostname = str(entry.id)
            	    remote_port = int(entry.port)
            	    remote_addr = socket.gethostbyname(remote_hostname)
            	    this_addr = "127.0.0.1" + ':' + str(remote_port)
            	    channel = grpc.insecure_channel(this_addr)
            	    stub = csci4220_hw4_pb2_grpc.KadImplStub(channel)

            	    print("Letting " + remote_hostname + " know I'm quitting.")
            	    some_idkey = stub.Quit(csci4220_hw4_pb2.IDKey(node = None, idkey = local_id))
            	    channel.close()
            print("Shut down node " + str(local_id))
            break
Example #15
0
def run():
    if len(sys.argv) != 4:
        print("Error, correct usage is {} [my id] [my port] [k]".format(
            sys.argv[0]))
        sys.exit(-1)

    local_id = int(sys.argv[1])
    my_port = str(int(sys.argv[2]))  # add_insecure_port() will want a string
    k = int(sys.argv[3])
    my_hostname = socket.gethostname()  # Gets my host name
    my_address = socket.gethostbyname(
        my_hostname)  # Gets my IP address from my hostname

    # Create server
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=16))
    servicer = KadImplServicer()
    csci4220_hw4_pb2_grpc.add_KadImplServicer_to_server(servicer, server)
    server.add_insecure_port('[::]:' + my_port)
    server.start()

    servicer.k = k
    for i in range(n):
        servicer.k_buckets.append([])

    servicer.this_node = csci4220_hw4_pb2.Node(id=local_id,
                                               port=int(my_port),
                                               address=my_address)

    # Listen for commands from standard input
    while 1:
        for line in sys.stdin:
            command = line.split(" ")
            for i in range(len(command)):
                command[i] = command[i].strip()

            # BOOTSTRAP command
            if (command[0] == "BOOTSTRAP"):
                remote_addr = socket.gethostbyname(command[1])
                remote_port = int(command[2])
                with grpc.insecure_channel(remote_addr + ':' +
                                           str(remote_port)) as channel:
                    stub = csci4220_hw4_pb2_grpc.KadImplStub(channel)

                    nodeList = stub.FindNode(
                        csci4220_hw4_pb2.IDKey(node=servicer.this_node,
                                               idkey=servicer.this_node.id))

                    k_buckets_add(servicer, nodeList.responding_node)

                    # Add nodes in nodeList to k_buckets
                    for node in nodeList.nodes:
                        k_buckets_add(servicer, node)

                    print("After BOOTSTRAP(" +
                          str(nodeList.responding_node.id) +
                          "), k_buckets now look like:")
                    print_k_buckets(servicer.k_buckets)

            # FIND_NODE command
            if (command[0] == "FIND_NODE"):
                print("Before FIND_NODE command, k-buckets are:")
                print_k_buckets(servicer.k_buckets)

                key = int(command[1])
                found = 0

                if local_id == key:
                    print("Found destination id " + str(key))
                else:
                    for i in range(n):
                        for j in range(len(servicer.k_buckets[i])):
                            if found == 0:
                                with grpc.insecure_channel(
                                        servicer.k_buckets[i][j].address +
                                        ':' +
                                        str(servicer.k_buckets[i][j].port)
                                ) as channel:
                                    stub = csci4220_hw4_pb2_grpc.KadImplStub(
                                        channel)

                                    nodelist = stub.FindNode(
                                        csci4220_hw4_pb2.IDKey(
                                            node=servicer.this_node,
                                            idkey=key))

                                    for node in nodelist.nodes:
                                        k_buckets_add(servicer, node)
                                        if node.id == key:
                                            print("Found destination id " +
                                                  str(key))
                                            found = 1

                if found == 0:
                    print("Could not find destination id " + str(key))

                print("After FIND_NODE command, k-buckets are:")
                print_k_buckets(servicer.k_buckets)

            # FIND_VALUE command
            if (command[0] == "FIND_VALUE"):
                print("Before FIND_VALUE command, k-buckets are:")
                print_k_buckets(servicer.k_buckets)

                key = int(command[1])
                found = 0

                # First check if key is stored locally
                if key in servicer.values:
                    print('Found data "' + servicer.values[key] +
                          '" for key ' + str(key))
                    found = 1
                else:
                    # Find node with id closest to key
                    closest = None
                    for i in range(n):
                        for j in range(len(servicer.k_buckets[i])):
                            if closest == None:
                                closest = servicer.k_buckets[i][j]
                            if (servicer.k_buckets[i][j].id
                                    ^ key) < (closest.id ^ key):
                                closest = servicer.k_buckets[i][j]

                    # Check if bucket is empty
                    if closest != None:
                        # Ask closest node for value
                        with grpc.insecure_channel(
                                closest.address + ':' +
                                str(closest.port)) as channel:
                            stub = csci4220_hw4_pb2_grpc.KadImplStub(channel)

                            kv_wrapper = stub.FindValue(
                                csci4220_hw4_pb2.IDKey(node=servicer.this_node,
                                                       idkey=key))

                            k_buckets_add(servicer, kv_wrapper.responding_node)

                            # If value was found for key
                            if kv_wrapper.mode_kv:
                                print('Found value "' + kv_wrapper.kv.value +
                                      '" for key ' + str(key))
                                found = 1
                            else:
                                for node in kv_wrapper.nodes:
                                    k_buckets_add(servicer, node)
                                    # Correct node found, ask for value
                                    if node.id == key:
                                        with grpc.insecure_channel(
                                                node.address + ':' +
                                                str(node.port)) as channel:
                                            stub = csci4220_hw4_pb2_grpc.KadImplStub(
                                                channel)

                                            kv_wrapper1 = stub.FindValue(
                                                csci4220_hw4_pb2.IDKey(
                                                    node=servicer.this_node,
                                                    idkey=key))

                                            if kv_wrapper1.mode_kv:
                                                print('Found value "' +
                                                      kv_wrapper1.kv.value +
                                                      '" for key ' + str(key))
                                                found = 1

                if found == 0:
                    print("Could not find key " + str(key))

                print("After FIND_VALUE command, k-buckets are:")
                print_k_buckets(servicer.k_buckets)

            # STORE command
            if (command[0] == "STORE"):
                key = int(command[1])
                value = command[2]

                # Find node with id closest to key
                closest = servicer.this_node
                for i in range(n):
                    for j in range(len(servicer.k_buckets[i])):
                        if (servicer.k_buckets[i][j].id ^ key) < (closest.id
                                                                  ^ key):
                            closest = servicer.k_buckets[i][j]

                # Check if this is the closest node -> store locally
                if closest.id == servicer.this_node.id:
                    servicer.values[key] = value
                else:
                    # Send value to closest node
                    with grpc.insecure_channel(closest.address + ':' +
                                               str(closest.port)) as channel:
                        stub = csci4220_hw4_pb2_grpc.KadImplStub(channel)

                        stub.Store(
                            csci4220_hw4_pb2.KeyValue(node=servicer.this_node,
                                                      key=key,
                                                      value=value))

                print("Storing key " + str(key) + " at node " +
                      str(closest.id))

            # QUIT command
            if (command[0] == "QUIT"):
                for i in reversed(range(n)):
                    for node in reversed(servicer.k_buckets[i]):
                        with grpc.insecure_channel(node.address + ':' +
                                                   str(node.port)) as channel:
                            stub = csci4220_hw4_pb2_grpc.KadImplStub(channel)

                            print("Letting " + str(node.id) +
                                  " know I'm quitting.")
                            stub.Quit(
                                csci4220_hw4_pb2.IDKey(
                                    node=servicer.this_node,
                                    idkey=servicer.this_node.id))

                print("Shut down node " + str(local_id))
                sys.exit()