UdpSocket.recv_from fails with “end of file” but I can see the incoming package in Wireshark

两盒软妹~` 提交于 2020-03-03 12:43:50

问题


Editor's note: This code example is from a version of Rust prior to 1.0 and is not valid Rust 1.0 code. The concepts discussed in the question are still valid.

I'm experimenting with torrent scraping using Rust. I can see the incoming package in Wireshark, but my recv_from calls always return Error("End of file"). Here's my program:

use std::io::net::ip::{Ipv4Addr, SocketAddr};
use std::io::net::udp::UdpSocket;
use std::rand;

use std::io::MemWriter;

fn main() {
    let addr = SocketAddr { ip: Ipv4Addr(0, 0, 0, 0), port: 35000 };
    let mut socket = match UdpSocket::bind(addr) {
        Ok(s) => s,
        Err(e) => panic!("couldn't bind socket: {}", e),
    };

    let mut buf: Vec<u8> = Vec::with_capacity(1000);

    let transaction_id: u32 = rand::random();
    let mut req_data = MemWriter::with_capacity(16);
    req_data.write_be_u64(0x41727101980).unwrap(); // connection_id, identifies the protocol.
    req_data.write_be_u32(0).unwrap(); // action: connect
    req_data.write_be_u32(transaction_id).unwrap();

    println!("{}", socket.send_to(req_data.get_ref(), ("31.172.63.252", 80)));

    match socket.recv_from(buf.as_mut_slice()) {
        Ok((amt, src)) => {
            println!("Got {} bytes from {}.", amt, src);
        },
        Err(err) => println!("Can't recv_from: {}", err)
    }
}

The output is always:

➜  udp-bug git:(master) ✗ cargo run
   Compiling udp-bug v0.0.1 (file:///home/omer/rust/udp-bug)
     Running `target/udp-bug`
Ok(())
Can't recv_from: end of file

However, I can see the expected response coming in Wireshark:

20235   3512.148636000  31.172.63.252   192.168.1.4 QUIC    60  CID: 0, Seq: 0

This package has a 16-byte payload, exactly what I expect. What's going wrong?


回答1:


Editor's note: This code example is from a version of Rust prior to 1.0 and is not valid Rust 1.0 code. The concepts discussed in the answer are still valid.

I think your problem is that you're using Vec::with_capacity() as a mutable slice. Vec::with_capacity() only creates a vector with the specified capacity (naturally), but its length is zero. Consequently, the length of the slice taken from the vector will also be zero:

let v = Vec::with_capacity(128);
println!("{}", v.as_mut_slice().len());  // prints 0

Slices can't grow, so recv_from() has no space to write to and it fails with the error.

You have essentially two options here. First one is to use unsafe set_len() method:

let mut buf: Vec<u8> = Vec::with_capacity(1000);
unsafe { buf.set_len(1000); }

This way the buffer will have the correct length but its contents will likely be just garbage. This is not very important for this use case, however, as long as you only access the correct amount of bytes (using the information returned by recv_from()).

There is a better way, however. You can use stack-allocated fixed-size array:

let mut buf = [0u8, ..1000];

// ...

match socket.recv_from(buf.as_mut_slice()) {
    // ...
}

Same thing goes for your req_data: you can use a statically sized array and a BufWriter:

let transaction_id: u32 = rand::random();
let mut req_data_buf = [0u8, ..16];
let mut req_data = BufWriter::new(req_data_buf);
req_data.write_be_u64(0x41727101980).unwrap(); // connection_id, identifies the protocol.
req_data.write_be_u32(0).unwrap(); // action: connect
req_data.write_be_u32(transaction_id).unwrap();

println!("{}", socket.send_to(req_data_buf, ("31.172.63.252", 80)));

This will only work with fixed-size buffers though. If you don't know the size of the buffer, you will still need a Vec.



来源:https://stackoverflow.com/questions/26778657/udpsocket-recv-from-fails-with-end-of-file-but-i-can-see-the-incoming-package

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!