Trying to deserialize bytes as SocketAddr
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.
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.