f0lg0 / kademlia-dht

Implementation of the Kademlia DHT protocol in Rust
MIT License
34 stars 3 forks source link

Network module doesn't stream more than 4096 bytes #1

Open f0lg0 opened 3 years ago

f0lg0 commented 3 years ago

Issue

In Rpc::open (network.rs, line 72), we stream only 4096 bytes at the time. This means that if a packet size exceeds this limit, the message will be cut off.

loop {
    let (len, src_addr) = rpc
        .socket
        .recv_from(&mut buf)
        .expect("[FAILED] Rpc::open --> Failed to receive data from peer");

Behavior wanted

We want to stream the full message before processing it

We can't use the following method:

PSEUDO

fn stream(...) {
    let (recv, src) = socket.recv_from()
    recv
}

while stream(...) != 0
      ()

Because this will hang the thread until the sender disconnects completely.

What we want is:

1. listener: listens for incoming packets
2. sender: sends packet
3. listener: adjusts buffer size to match sender's packet size OR streams with fixed buffer size until bytes recv == bytes sent
4. listener: processes packet
5. loop to 1)

Possible solutions

1. Attach header to a message where we include the size of the entire message

EDIT: this doesn't solve the problem as the header can grow beyond the allocated buffer to read it. For example we could read the first 10 digits of the size but if the size is larger than that, problems will occur.

Something like

PACKET
+---------------------------------------------+
|   size: 5463                                |
|   --------------------------------------    |
|    <data>                                   |
+---------------------------------------------+

Where the header could be parsed at the start of the stream of bytes:

message = b'5463                                  0x770xF10xA7'

By isolating it from the data with some padding.

2. Send the header as a separate packet, used to announce the next packet.

In this case the header packet MUST be FIXED size, still don't sure how to make this possible... EDIT: it doesn't seem possible to make it fixed size

Header
{
    size_of_incoming_msg: 5463
    // other stuff
} 

|
|
|
v

MESSAGE

3. Set a max size on packets

I don't like this idea because in large networks many messages would be stopped from being sent, or we would need some checks on the length of, for example, the received NodeAndDistance array to tell when to stop receiving them. This would though make us lose some information.

4. If one packet isn't enough, then what about 2?

This is probably the only solution: if a packet is bigger than the receiver's buffer size, we proceed to send 2 or more packets until we stream the full message. In this case we would need some sort of "confirmation" for packets, something like "Wait for more packets/go ahead I'm done". Not sure how to implement this but possible

f0lg0 commented 3 years ago

UPDATE: doubled buffer size. It's not a fix but it should be enough for small networks. I've also tried method 1 but it had some bugs

f0lg0 commented 2 years ago

Update on method 1

Appending the size to the message can actually be done. sizeof(int) is 4 bytes so we should be able to read the first 4 bytes of the message to be able to extract the size of the full message. Then we just stream until bytes_read == received_length.