Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trying to deserialize bytes as SocketAddr #54

Open
nrempel opened this issue Dec 27, 2020 · 1 comment
Open

Trying to deserialize bytes as SocketAddr #54

nrempel opened this issue Dec 27, 2020 · 1 comment

Comments

@nrempel
Copy link

nrempel commented Dec 27, 2020

Hi there,

Thanks for the handy library!

I'm trying to deserialize an ip block from the Bittorrent DHT according to BEP 5.

I can use the following to deserialize the ip block into a byte vector:

#[derive(Debug, Deserialize)]
struct KRPCMessage {
    #[serde(rename = "t")]
    transaction_id: String,
    #[serde(rename = "y")]
    type_code: String,
    #[serde(rename = "v")]
    version: Option<String>,
    #[serde(rename = "r")]
    response: HashMap<String, ByteBuf>,
    #[serde(with = "serde_bytes")]
    ip: Vec<u8>,
}
from_bytes::<KRPCMessage>(&data).unwrap();

This works and gives me:

KRPCMessage { transaction_id: "aa", type_code: "r", version: None, response: {"id": [50, 245, 78, 105, 115, 81, 255, 74, 236, 41, 205, 186, 171, 242, 251, 227, 70, 124, 194, 103]}, ip: [70, 66, 178, 80, 26, 225] }

But what I would like to do is deserialize the ip block into a std::net::SocketAddr struct. I've tried various approaches including using the "new type" pattern over SocketAddr but I can't seem to figure out how to get it to work:

fn deserialize<'de, D>(deserializer: D) -> Result<SocketAddr, D::Error>
where
    D: Deserializer<'de>,
{
    Ok(SocketAddr::new(
        IpAddr::V4(Ipv4Addr::new(67, 215, 246, 10)),
        6881,
    ))
}

#[derive(Debug, Deserialize)]
struct KRPCMessage {
    #[serde(rename = "t")]
    transaction_id: String,
    #[serde(rename = "y")]
    type_code: String,
    #[serde(rename = "v")]
    version: Option<String>,
    #[serde(rename = "r")]
    response: HashMap<String, ByteBuf>,
    #[serde(with = "self")]
    ip: SocketAddr,
}
from_bytes::<KRPCMessage>(&data).unwrap();

I always get the error:

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Decode(Error { context: None, error: MalformedContent(Utf8Error { valid_up_to: 2, error_len: Some(1) }) })'

It seems that it always try to decode the block as a utf-8 string.

Can anyone guide me on how to accomplish this? Please let me know if there any obvious errors—I'm new to Rust.

@nrempel nrempel changed the title Trying to deserialize KRPC contact encoding Trying to deserialize bytes as SocketAddr Dec 27, 2020
@thequux
Copy link
Contributor

thequux commented Jan 7, 2021

Hi,

It seems that the problem is that serde's deserializer for SocketAddr expects a string of the form 1.2.3.4:5678, whereas BEP-0005 uses what it calls "compact IP address/port info", which is just 6 binary bytes. You'll need to write a custom serializer and deserializer that know how to work with this format and then tell serde to use it with the #[serde(with=...)] attribute (documented at https://serde.rs/field-attrs.html).

You may also be happier with the bendy-specific API; while it's a little bit more verbose than serde is when everything works, it is much easier to write custom encoding and decoding functions using the bendy API.

I hope that that helps.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants