rustydht_lib/packets/
public.rs

1use super::internal;
2use crate::common::{Id, Node, ID_SIZE};
3use crate::errors;
4use anyhow::anyhow;
5use std::convert::TryInto;
6use std::net::{IpAddr, Ipv4Addr, SocketAddr};
7use std::time::Duration;
8
9const MAX_SCRAPE_INTERVAL: u64 = 21600; // 6 hours
10
11/// All packets sent and received via DHT are a serialized version of this struct.
12///
13/// It can be used to represent DHT messages throughout a program and has methods to
14/// [serialize](crate::packets::Message::to_bytes) and [deserialize](crate::packets::Message::from_bytes) DHT messages.
15///
16/// # Building
17/// The easiest way to build Message structs is to use [MessageBuilder](crate::packets::MessageBuilder).
18///
19/// But if you need more control/flexibility than provided by MessageBuilder, you can build Message structs
20/// directly:
21///
22/// ```
23/// use rustydht_lib::common::Id;
24/// use rustydht_lib::packets::{Message, MessageType, RequestSpecific, FindNodeRequestArguments};
25///
26/// // This constructs a find_node request. It would be easier with MessageBuilder.
27/// let msg = Message {
28///     transaction_id: vec![1, 2, 3],
29///     version: Some(vec![0x62, 0x61, 0x72, 0x66]),
30///     requester_ip: None,
31///     read_only: None,
32///     message_type: MessageType::Request(RequestSpecific::FindNodeRequest(
33///         FindNodeRequestArguments {
34///             target: Id::from_hex("1234123412341234123412341234123412341234").unwrap(),
35///             requester_id: Id::from_hex("5678567856785678567856785678567856785678").unwrap(),
36///         },
37///     )),
38/// };
39/// ```
40///
41/// # Deserializing
42/// ```
43/// use rustydht_lib::packets::Message;
44///
45/// // Imagine that this vector contains bytes from reading from a socket
46/// let bytes: Vec<u8> = Vec::new();
47/// match Message::from_bytes(&bytes) {
48///     Ok(msg) => {
49///         // Success! do something with the Message you just parsed
50///     }
51///     Err(e) => {
52///         eprintln!("Oh no! I hit an error while parsing a Message: {}", e);
53///     }
54/// }
55/// ```
56///
57/// # Serializing
58/// ```
59/// use rustydht_lib::common::Id;
60/// use rustydht_lib::packets::{Message, MessageBuilder};
61///
62/// let our_id = Id::from_hex("0000000000000000000000000000000000000001").unwrap();
63/// let target = Id::from_hex("ff00000000000000000000000000000000000002").unwrap();
64/// let msg = MessageBuilder::new_find_node_request()
65///     .sender_id(our_id)
66///     .target(target)
67///     .build()
68///     .unwrap();
69/// match msg.to_bytes() {
70///     Ok(bytes) => {
71///         // Success! You have a Vec<u8> that can be sent over a socket or whatever
72///     }
73///     Err(e) => {
74///         eprintln!("Oh no! Couldn't serialize: {}", e);
75///     }
76/// }
77/// ```
78#[derive(Debug, PartialEq, Clone)]
79pub struct Message {
80    pub transaction_id: Vec<u8>,
81
82    /// The version of the requester or responder.
83    pub version: Option<Vec<u8>>,
84
85    /// The IP address and port ("SocketAddr") of the requester as seen from the responder's point of view.
86    /// This should be set only on response, but is defined at this level with the other common fields to avoid defining yet another layer on the response objects.
87    pub requester_ip: Option<SocketAddr>,
88
89    pub message_type: MessageType,
90
91    /// For bep0043. When set true on a request, indicates that the requester can't reply to requests and that responders should not add requester to their routing tables.
92    /// Should only be set on requests - undefined behavior when set on a response.
93    pub read_only: Option<bool>,
94}
95
96#[derive(Debug, PartialEq, Clone)]
97pub enum MessageType {
98    Request(RequestSpecific),
99
100    Response(ResponseSpecific),
101
102    Error(ErrorSpecific),
103}
104
105#[derive(Debug, PartialEq, Clone)]
106pub enum RequestSpecific {
107    PingRequest(PingRequestArguments),
108
109    FindNodeRequest(FindNodeRequestArguments),
110
111    GetPeersRequest(GetPeersRequestArguments),
112
113    SampleInfoHashesRequest(SampleInfoHashesRequestArguments),
114
115    AnnouncePeerRequest(AnnouncePeerRequestArguments),
116}
117
118#[derive(Debug, PartialEq, Clone)]
119pub enum ResponseSpecific {
120    PingResponse(PingResponseArguments),
121
122    FindNodeResponse(FindNodeResponseArguments),
123
124    GetPeersResponse(GetPeersResponseArguments),
125
126    SampleInfoHashesResponse(SampleInfoHashesResponseArguments),
127    // AnnouncePeerResponse not needed - same as PingResponse
128}
129
130#[derive(Debug, PartialEq, Clone)]
131pub struct PingRequestArguments {
132    pub requester_id: Id,
133}
134
135#[derive(Debug, PartialEq, Clone)]
136pub struct FindNodeRequestArguments {
137    pub target: Id,
138    pub requester_id: Id,
139}
140
141#[derive(Debug, PartialEq, Clone)]
142pub struct GetPeersRequestArguments {
143    pub info_hash: Id,
144    pub requester_id: Id,
145}
146
147#[derive(Debug, PartialEq, Clone)]
148pub struct SampleInfoHashesRequestArguments {
149    pub target: Id,
150    pub requester_id: Id,
151}
152
153#[derive(Debug, PartialEq, Clone)]
154pub struct AnnouncePeerRequestArguments {
155    pub requester_id: Id,
156    pub info_hash: Id,
157    pub port: u16,
158    pub implied_port: Option<bool>,
159    pub token: Vec<u8>,
160}
161
162#[derive(Debug, PartialEq, Clone)]
163pub enum GetPeersResponseValues {
164    Nodes(Vec<Node>),
165    Peers(Vec<SocketAddr>),
166}
167
168#[derive(Debug, PartialEq, Clone)]
169pub struct PingResponseArguments {
170    pub responder_id: Id,
171}
172
173#[derive(Debug, PartialEq, Clone)]
174pub struct FindNodeResponseArguments {
175    pub responder_id: Id,
176    pub nodes: Vec<Node>,
177}
178
179#[derive(Debug, PartialEq, Clone)]
180pub struct GetPeersResponseArguments {
181    pub responder_id: Id,
182    pub token: Vec<u8>,
183    pub values: GetPeersResponseValues,
184}
185
186#[derive(Debug, PartialEq, Clone)]
187pub struct SampleInfoHashesResponseArguments {
188    pub responder_id: Id,
189    pub interval: Duration,
190    pub nodes: Vec<Node>,
191    pub samples: Vec<Id>,
192    pub num: i32,
193}
194
195#[derive(Debug, PartialEq, Clone)]
196pub struct ErrorSpecific {
197    pub code: i32,
198    pub description: String,
199}
200
201impl Message {
202    fn into_serde_message(self) -> internal::DHTMessage {
203        internal::DHTMessage {
204            transaction_id: self.transaction_id,
205            version: self.version,
206            ip: self
207                .requester_ip
208                .map(|sockaddr| sockaddr_to_bytes(&sockaddr)),
209            read_only: self
210                .read_only
211                .map(|read_only| if read_only { 1 } else { 0 }),
212            variant: match self.message_type {
213                MessageType::Request(req) => internal::DHTMessageVariant::DHTRequest(match req {
214                    RequestSpecific::PingRequest(ping_args) => internal::DHTRequestSpecific::Ping {
215                        arguments: internal::DHTPingArguments {
216                            id: ping_args.requester_id.to_vec(),
217                        },
218                    },
219
220                    RequestSpecific::FindNodeRequest(find_node_args) => {
221                        internal::DHTRequestSpecific::FindNode {
222                            arguments: internal::DHTFindNodeArguments {
223                                id: find_node_args.requester_id.to_vec(),
224                                target: find_node_args.target.to_vec(),
225                            },
226                        }
227                    }
228
229                    RequestSpecific::GetPeersRequest(get_peers_args) => {
230                        internal::DHTRequestSpecific::GetPeers {
231                            arguments: internal::DHTGetPeersArguments {
232                                id: get_peers_args.requester_id.to_vec(),
233                                info_hash: get_peers_args.info_hash.to_vec(),
234                            },
235                        }
236                    }
237
238                    RequestSpecific::SampleInfoHashesRequest(sample_info_hashes_args) => {
239                        internal::DHTRequestSpecific::SampleInfoHashes {
240                            arguments: internal::DHTSampleInfoHashesRequestArguments {
241                                id: sample_info_hashes_args.requester_id.to_vec(),
242                                target: sample_info_hashes_args.target.to_vec(),
243                            },
244                        }
245                    }
246
247                    RequestSpecific::AnnouncePeerRequest(announce_peer_args) => {
248                        internal::DHTRequestSpecific::AnnouncePeer {
249                            arguments: internal::DHTAnnouncePeerRequestArguments {
250                                id: announce_peer_args.requester_id.to_vec(),
251                                implied_port: if announce_peer_args.implied_port.is_none() {
252                                    None
253                                } else if announce_peer_args.implied_port.unwrap() {
254                                    Some(1)
255                                } else {
256                                    Some(0)
257                                },
258                                info_hash: announce_peer_args.info_hash.to_vec(),
259                                port: announce_peer_args.port,
260                                token: announce_peer_args.token,
261                            },
262                        }
263                    }
264                }),
265
266                MessageType::Response(res) => internal::DHTMessageVariant::DHTResponse(match res {
267                    ResponseSpecific::FindNodeResponse(find_node_args) => {
268                        internal::DHTResponseSpecific::FindNode {
269                            arguments: internal::DHTFindNodeResponseArguments {
270                                id: find_node_args.responder_id.to_vec(),
271                                nodes: nodes4_to_bytes(&find_node_args.nodes),
272                            },
273                        }
274                    }
275
276                    ResponseSpecific::GetPeersResponse(get_peers_args) => {
277                        internal::DHTResponseSpecific::GetPeers {
278                            arguments: internal::DHTGetPeersResponseArguments {
279                                id: get_peers_args.responder_id.to_vec(),
280                                token: get_peers_args.token.clone(),
281                                nodes: match &get_peers_args.values {
282                                    GetPeersResponseValues::Nodes(nodes) => {
283                                        Some(nodes4_to_bytes(nodes))
284                                    }
285                                    _ => None,
286                                },
287                                values: match &get_peers_args.values {
288                                    GetPeersResponseValues::Peers(peers) => {
289                                        Some(peers_to_bytes(peers))
290                                    }
291                                    _ => None,
292                                },
293                            },
294                        }
295                    }
296
297                    ResponseSpecific::PingResponse(ping_args) => {
298                        internal::DHTResponseSpecific::Ping {
299                            arguments: internal::DHTPingResponseArguments {
300                                id: ping_args.responder_id.to_vec(),
301                            },
302                        }
303                    }
304
305                    ResponseSpecific::SampleInfoHashesResponse(sample_info_hashes_args) => {
306                        internal::DHTResponseSpecific::SampleInfoHashes {
307                            arguments: internal::DHTSampleInfoHashesResponseArguments {
308                                id: sample_info_hashes_args.responder_id.to_vec(),
309                                interval: std::cmp::min(
310                                    MAX_SCRAPE_INTERVAL,
311                                    sample_info_hashes_args.interval.as_secs(),
312                                ) as i32,
313                                num: sample_info_hashes_args.num,
314                                nodes: nodes4_to_bytes(&sample_info_hashes_args.nodes),
315                                samples: {
316                                    let mut a = Vec::with_capacity(
317                                        sample_info_hashes_args.samples.len() * ID_SIZE,
318                                    );
319                                    for info_hash in &sample_info_hashes_args.samples {
320                                        a.append(&mut info_hash.to_vec());
321                                    }
322                                    a
323                                },
324                            },
325                        }
326                    }
327                }),
328
329                MessageType::Error(err) => {
330                    internal::DHTMessageVariant::DHTError(internal::DHTErrorSpecific {
331                        error_info: vec![
332                            serde_bencode::value::Value::Int(err.code.into()),
333                            serde_bencode::value::Value::Bytes(err.description.into()),
334                        ],
335                    })
336                }
337            },
338        }
339    }
340
341    fn from_serde_message(msg: internal::DHTMessage) -> Result<Message, errors::RustyDHTError> {
342        Ok(Message {
343            transaction_id: msg.transaction_id,
344            version: msg.version,
345            requester_ip: match msg.ip {
346                Some(ip) => Some(bytes_to_sockaddr(ip)?),
347                _ => None,
348            },
349            read_only: msg.read_only.map(|read_only| read_only >= 1),
350
351            message_type: match msg.variant {
352                internal::DHTMessageVariant::DHTRequest(req_variant) => {
353                    MessageType::Request(match req_variant {
354                        internal::DHTRequestSpecific::AnnouncePeer { arguments } => {
355                            RequestSpecific::AnnouncePeerRequest(AnnouncePeerRequestArguments {
356                                requester_id: Id::from_bytes(arguments.id)?,
357                                implied_port: if arguments.implied_port.is_none() {
358                                    None
359                                } else if arguments.implied_port.unwrap() != 0 {
360                                    Some(true)
361                                } else {
362                                    Some(false)
363                                },
364                                info_hash: Id::from_bytes(&arguments.info_hash)?,
365                                port: arguments.port,
366                                token: arguments.token,
367                            })
368                        }
369
370                        internal::DHTRequestSpecific::FindNode { arguments } => {
371                            RequestSpecific::FindNodeRequest(FindNodeRequestArguments {
372                                requester_id: Id::from_bytes(arguments.id)?,
373                                target: Id::from_bytes(&arguments.target)?,
374                            })
375                        }
376
377                        internal::DHTRequestSpecific::GetPeers { arguments } => {
378                            RequestSpecific::GetPeersRequest(GetPeersRequestArguments {
379                                requester_id: Id::from_bytes(arguments.id)?,
380                                info_hash: Id::from_bytes(&arguments.info_hash)?,
381                            })
382                        }
383
384                        internal::DHTRequestSpecific::Ping { arguments } => {
385                            RequestSpecific::PingRequest(PingRequestArguments {
386                                requester_id: Id::from_bytes(&arguments.id)?,
387                            })
388                        }
389
390                        internal::DHTRequestSpecific::SampleInfoHashes { arguments } => {
391                            RequestSpecific::SampleInfoHashesRequest(
392                                SampleInfoHashesRequestArguments {
393                                    requester_id: Id::from_bytes(&arguments.id)?,
394                                    target: Id::from_bytes(&arguments.target)?,
395                                },
396                            )
397                        }
398                    })
399                }
400
401                internal::DHTMessageVariant::DHTResponse(res_variant) => {
402                    MessageType::Response(match res_variant {
403                        internal::DHTResponseSpecific::FindNode { arguments } => {
404                            ResponseSpecific::FindNodeResponse(FindNodeResponseArguments {
405                                responder_id: Id::from_bytes(&arguments.id)?,
406                                nodes: bytes_to_nodes4(&arguments.nodes)?,
407                            })
408                        }
409
410                        internal::DHTResponseSpecific::GetPeers { arguments } => {
411                            ResponseSpecific::GetPeersResponse(GetPeersResponseArguments {
412                                responder_id: Id::from_bytes(&arguments.id)?,
413                                token: arguments.token.clone(),
414                                values: if arguments.values.is_some() {
415                                    GetPeersResponseValues::Peers(bytes_to_peers(
416                                        &arguments.values.as_ref().unwrap(),
417                                    )?)
418                                } else if arguments.nodes.is_some() {
419                                    GetPeersResponseValues::Nodes(bytes_to_nodes4(
420                                        &arguments.nodes.as_ref().unwrap(),
421                                    )?)
422                                } else {
423                                    GetPeersResponseValues::Nodes(vec![])
424                                },
425                            })
426                        }
427
428                        internal::DHTResponseSpecific::Ping { arguments } => {
429                            ResponseSpecific::PingResponse(PingResponseArguments {
430                                responder_id: Id::from_bytes(&arguments.id)?,
431                            })
432                        }
433
434                        internal::DHTResponseSpecific::SampleInfoHashes { arguments } => {
435                            ResponseSpecific::SampleInfoHashesResponse(
436                                SampleInfoHashesResponseArguments {
437                                    responder_id: Id::from_bytes(&arguments.id)?,
438                                    interval: Duration::from_secs(arguments.interval as u64),
439                                    num: arguments.num,
440                                    nodes: bytes_to_nodes4(&arguments.nodes)?,
441                                    samples: {
442                                        if arguments.samples.len() % ID_SIZE != 0 {
443                                            return Err(anyhow!(
444                                                "Wrong sample length {} not a multiple of {}",
445                                                arguments.samples.len(),
446                                                ID_SIZE
447                                            )
448                                            .into());
449                                        }
450                                        let num_expected = arguments.samples.len() / ID_SIZE;
451                                        let mut to_ret = Vec::with_capacity(num_expected);
452
453                                        for i in 0..num_expected {
454                                            let i = i * ID_SIZE;
455                                            let id =
456                                                Id::from_bytes(&arguments.samples[i..i + ID_SIZE])?;
457                                            to_ret.push(id);
458                                        }
459
460                                        to_ret
461                                    },
462                                },
463                            )
464                        }
465                    })
466                }
467
468                internal::DHTMessageVariant::DHTError(err) => {
469                    if err.error_info.len() < 2 {
470                        return Err(anyhow!("Error packet should have at least 2 elements").into());
471                    }
472                    MessageType::Error(ErrorSpecific {
473                        code: match err.error_info[0] {
474                            serde_bencode::value::Value::Int(code) => match code.try_into() {
475                                Ok(code) => code,
476                                Err(e) => {
477                                    return Err(errors::RustyDHTError::PacketParseError(
478                                        anyhow::Error::new(e),
479                                    ))
480                                }
481                            },
482                            _ => {
483                                return Err(errors::RustyDHTError::PacketParseError(anyhow!(
484                                    "Expected error code as first element"
485                                )))
486                            }
487                        },
488                        description: match &err.error_info[1] {
489                            serde_bencode::value::Value::Bytes(desc) => {
490                                match std::str::from_utf8(desc) {
491                                    Ok(desc) => desc.to_string(),
492                                    Err(e) => {
493                                        return Err(errors::RustyDHTError::PacketParseError(
494                                            anyhow::Error::new(e),
495                                        ))
496                                    }
497                                }
498                            }
499                            _ => {
500                                return Err(errors::RustyDHTError::PacketParseError(anyhow!(
501                                    "Expected description as second element"
502                                )))
503                            }
504                        },
505                    })
506                }
507            },
508        })
509    }
510
511    pub fn to_bytes(self) -> Result<Vec<u8>, errors::RustyDHTError> {
512        self.into_serde_message().to_bytes()
513    }
514
515    pub fn from_bytes<T: AsRef<[u8]>>(bytes: T) -> Result<Message, errors::RustyDHTError> {
516        Message::from_serde_message(internal::DHTMessage::from_bytes(bytes)?)
517    }
518
519    /// Return the Id of the sender of the Message
520    ///
521    /// This is less straightforward than it seems because not *all* messages are sent
522    /// with an Id (all are except Error messages). This is reflected in the structure
523    /// of DHT Messages, and makes it a bit annoying to learn the sender's Id without
524    /// unraveling the entire message. This method is a convenience method to extract
525    /// the sender (or "author") Id from the guts of any Message.
526    pub fn get_author_id(&self) -> Option<Id> {
527        let id = match &self.message_type {
528            MessageType::Request(request_variant) => match request_variant {
529                RequestSpecific::AnnouncePeerRequest(arguments) => arguments.requester_id,
530                RequestSpecific::FindNodeRequest(arguments) => arguments.requester_id,
531                RequestSpecific::GetPeersRequest(arguments) => arguments.requester_id,
532                RequestSpecific::PingRequest(arguments) => arguments.requester_id,
533                RequestSpecific::SampleInfoHashesRequest(arguments) => arguments.requester_id,
534            },
535            MessageType::Response(response_variant) => match response_variant {
536                ResponseSpecific::FindNodeResponse(arguments) => arguments.responder_id,
537                ResponseSpecific::GetPeersResponse(arguments) => arguments.responder_id,
538                ResponseSpecific::PingResponse(arguments) => arguments.responder_id,
539                ResponseSpecific::SampleInfoHashesResponse(arguments) => arguments.responder_id,
540            },
541            MessageType::Error(_) => {
542                return None;
543            }
544        };
545
546        Some(id)
547    }
548}
549
550/// Returns true if the response and request types specified match.
551/// E.g., PingResponse goes with PingRequest. FindNodeResponse goes with FindNodeRequest.
552pub fn response_matches_request(res: &ResponseSpecific, req: &RequestSpecific) -> bool {
553    match res {
554        ResponseSpecific::PingResponse { .. } => {
555            if let RequestSpecific::PingRequest { .. } = req {
556                return true;
557            }
558
559            // Ping responses are indistinguishable from announce_peer responses
560            if let RequestSpecific::AnnouncePeerRequest { .. } = req {
561                return true;
562            }
563        }
564
565        ResponseSpecific::FindNodeResponse { .. } => {
566            if let RequestSpecific::FindNodeRequest { .. } = req {
567                return true;
568            }
569        }
570
571        ResponseSpecific::GetPeersResponse { .. } => {
572            if let RequestSpecific::GetPeersRequest { .. } = req {
573                return true;
574            }
575        }
576
577        ResponseSpecific::SampleInfoHashesResponse { .. } => {
578            if let RequestSpecific::SampleInfoHashesRequest { .. } = req {
579                return true;
580            }
581        }
582    }
583    false
584}
585
586fn bytes_to_sockaddr<T: AsRef<[u8]>>(bytes: T) -> Result<SocketAddr, errors::RustyDHTError> {
587    let bytes = bytes.as_ref();
588    match bytes.len() {
589        6 => {
590            let ip = Ipv4Addr::new(bytes[0], bytes[1], bytes[2], bytes[3]);
591
592            let port_bytes_as_array: [u8; 2] =
593                bytes[4..6]
594                    .try_into()
595                    .map_err(|err: std::array::TryFromSliceError| {
596                        errors::RustyDHTError::PacketParseError(err.into())
597                    })?;
598
599            let port: u16 = u16::from_be_bytes(port_bytes_as_array);
600
601            Ok(SocketAddr::new(IpAddr::V4(ip), port))
602        }
603
604        18 => Err(errors::RustyDHTError::PacketParseError(anyhow!(
605            "IPv6 is not yet implemented"
606        ))),
607
608        _ => Err(errors::RustyDHTError::PacketParseError(anyhow!(
609            "Wrong number of bytes for sockaddr"
610        ))),
611    }
612}
613
614pub fn sockaddr_to_bytes(sockaddr: &SocketAddr) -> Vec<u8> {
615    let mut to_ret = Vec::new();
616
617    match sockaddr {
618        SocketAddr::V4(v4) => {
619            let ip_bytes = v4.ip().octets();
620            for item in ip_bytes {
621                to_ret.push(item);
622            }
623        }
624
625        SocketAddr::V6(v6) => {
626            let ip_bytes = v6.ip().octets();
627            for item in ip_bytes {
628                to_ret.push(item);
629            }
630        }
631    }
632
633    let port_bytes = sockaddr.port().to_be_bytes();
634    to_ret.push(port_bytes[0]);
635    to_ret.push(port_bytes[1]);
636
637    to_ret
638}
639
640fn bytes_to_nodes4<T: AsRef<[u8]>>(bytes: T) -> Result<Vec<Node>, errors::RustyDHTError> {
641    let bytes = bytes.as_ref();
642    let node4_byte_size: usize = ID_SIZE + 6;
643    if bytes.len() % node4_byte_size != 0 {
644        return Err(anyhow!("Wrong number of bytes for nodes message ({})", bytes.len()).into());
645    }
646
647    let expected_num = bytes.len() / node4_byte_size;
648    let mut to_ret = Vec::with_capacity(expected_num);
649    for i in 0..bytes.len() / node4_byte_size {
650        let i = i * node4_byte_size;
651        let id = Id::from_bytes(&bytes[i..i + ID_SIZE])?;
652        let sockaddr = bytes_to_sockaddr(&bytes[i + ID_SIZE..i + node4_byte_size])?;
653        let node = Node::new(id, sockaddr);
654        to_ret.push(node);
655    }
656
657    Ok(to_ret)
658}
659
660fn nodes4_to_bytes(nodes: &[Node]) -> Vec<u8> {
661    let node4_byte_size: usize = ID_SIZE + 6;
662    let mut to_ret = Vec::with_capacity(node4_byte_size * nodes.len());
663    for node in nodes {
664        to_ret.append(&mut node.id.to_vec());
665        to_ret.append(&mut sockaddr_to_bytes(&node.address));
666    }
667    to_ret
668}
669
670fn peers_to_bytes<T: AsRef<[SocketAddr]>>(peers: T) -> Vec<serde_bytes::ByteBuf> {
671    let peers = peers.as_ref();
672    peers
673        .iter()
674        .map(|p| serde_bytes::ByteBuf::from(sockaddr_to_bytes(p)))
675        .collect()
676}
677
678fn bytes_to_peers<T: AsRef<[serde_bytes::ByteBuf]>>(
679    bytes: T,
680) -> Result<Vec<SocketAddr>, errors::RustyDHTError> {
681    let bytes = bytes.as_ref();
682    bytes.iter().map(bytes_to_sockaddr).collect()
683}
684
685#[cfg(test)]
686mod tests {
687    use super::*;
688    use rand::prelude::*;
689
690    #[test]
691    fn test_ping_request() {
692        let original_msg = Message {
693            transaction_id: vec![0, 1, 2],
694            version: None,
695            requester_ip: None,
696            read_only: None,
697            message_type: MessageType::Request(RequestSpecific::PingRequest(
698                PingRequestArguments {
699                    requester_id: Id::from_hex("f00ff00ff00ff00ff00ff00ff00ff00ff00ff00f").unwrap(),
700                },
701            )),
702        };
703
704        let serde_msg = original_msg.clone().into_serde_message();
705        let bytes = serde_msg.to_bytes().unwrap();
706        let parsed_serde_msg = internal::DHTMessage::from_bytes(bytes).unwrap();
707        let parsed_msg = Message::from_serde_message(parsed_serde_msg).unwrap();
708        assert_eq!(parsed_msg, original_msg);
709    }
710
711    #[test]
712    fn test_ping_response() {
713        let original_msg = Message {
714            transaction_id: vec![1, 2, 3],
715            version: Some(vec![0xde, 0xad]),
716            requester_ip: Some("99.100.101.102:1030".parse().unwrap()),
717            read_only: None,
718            message_type: MessageType::Response(ResponseSpecific::PingResponse(
719                PingResponseArguments {
720                    responder_id: Id::from_hex("beefbeefbeefbeefbeefbeefbeefbeefbeefbeef").unwrap(),
721                },
722            )),
723        };
724
725        let serde_msg = original_msg.clone().into_serde_message();
726        let bytes = serde_msg.to_bytes().unwrap();
727        let parsed_serde_msg = internal::DHTMessage::from_bytes(bytes).unwrap();
728        let parsed_msg = Message::from_serde_message(parsed_serde_msg).unwrap();
729        assert_eq!(parsed_msg, original_msg);
730    }
731
732    #[test]
733    fn test_get_peers_request() {
734        let original_msg = Message {
735            transaction_id: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
736            version: Some(vec![72, 73]),
737            requester_ip: None,
738            read_only: None,
739            message_type: MessageType::Request(RequestSpecific::GetPeersRequest(
740                GetPeersRequestArguments {
741                    info_hash: Id::from_hex("deaddeaddeaddeaddeaddeaddeaddeaddeaddead").unwrap(),
742                    requester_id: Id::from_hex("beefbeefbeefbeefbeefbeefbeefbeefbeefbeef").unwrap(),
743                },
744            )),
745        };
746
747        let serde_msg = original_msg.clone().into_serde_message();
748        let bytes = serde_msg.to_bytes().unwrap();
749        let parsed_serde_msg = internal::DHTMessage::from_bytes(bytes).unwrap();
750        let parsed_msg = Message::from_serde_message(parsed_serde_msg).unwrap();
751        assert_eq!(parsed_msg, original_msg);
752    }
753
754    #[test]
755    fn test_get_peers_response() {
756        let original_msg = Message {
757            transaction_id: vec![1, 2, 3],
758            version: Some(vec![1]),
759            requester_ip: Some("50.51.52.53:5455".parse().unwrap()),
760            read_only: None,
761            message_type: MessageType::Response(ResponseSpecific::GetPeersResponse(
762                GetPeersResponseArguments {
763                    responder_id: Id::from_hex("0505050505050505050505050505050505050505").unwrap(),
764                    token: vec![99, 100, 101, 102],
765                    values: GetPeersResponseValues::Nodes(vec![Node::new(
766                        Id::from_hex("0606060606060606060606060606060606060606").unwrap(),
767                        "49.50.52.52:5354".parse().unwrap(),
768                    )]),
769                },
770            )),
771        };
772
773        let serde_msg = original_msg.clone().into_serde_message();
774        let bytes = serde_msg.to_bytes().unwrap();
775        let parsed_serde_msg = internal::DHTMessage::from_bytes(bytes).unwrap();
776        let parsed_msg = Message::from_serde_message(parsed_serde_msg).unwrap();
777        assert_eq!(parsed_msg, original_msg);
778    }
779
780    #[test]
781    fn test_get_peers_response_peers() {
782        let original_msg = Message {
783            transaction_id: vec![1, 2, 3],
784            version: Some(vec![1]),
785            requester_ip: Some("50.51.52.53:5455".parse().unwrap()),
786            read_only: None,
787            message_type: MessageType::Response(ResponseSpecific::GetPeersResponse(
788                GetPeersResponseArguments {
789                    responder_id: Id::from_hex("0505050505050505050505050505050505050505").unwrap(),
790                    token: vec![99, 100, 101, 102],
791                    values: GetPeersResponseValues::Peers(vec!["123.123.123.123:123"
792                        .parse()
793                        .unwrap()]),
794                },
795            )),
796        };
797
798        let serde_msg = original_msg.clone().into_serde_message();
799        let bytes = serde_msg.to_bytes().unwrap();
800        let parsed_serde_msg = internal::DHTMessage::from_bytes(bytes).unwrap();
801        let parsed_msg = Message::from_serde_message(parsed_serde_msg).unwrap();
802        assert_eq!(parsed_msg, original_msg);
803    }
804
805    #[test]
806    fn test_get_peers_response_neither() {
807        let serde_message = internal::DHTMessage {
808            ip: None,
809            read_only: None,
810            transaction_id: vec![1, 2, 3],
811            version: None,
812            variant: internal::DHTMessageVariant::DHTResponse(
813                internal::DHTResponseSpecific::GetPeers {
814                    arguments: internal::DHTGetPeersResponseArguments {
815                        id: Id::from_hex("0505050505050505050505050505050505050505")
816                            .unwrap()
817                            .to_vec(),
818                        token: vec![0, 1],
819                        nodes: None,
820                        values: None,
821                    },
822                },
823            ),
824        };
825        let parsed_msg = Message::from_serde_message(serde_message).unwrap();
826        assert!(matches!(
827            parsed_msg.message_type,
828            MessageType::Response(ResponseSpecific::GetPeersResponse(
829                GetPeersResponseArguments { .. }
830            ))
831        ));
832    }
833
834    #[test]
835    fn test_find_node_request() {
836        let original_msg = Message {
837            transaction_id: vec![1, 2, 3],
838            version: Some(vec![0x62, 0x61, 0x72, 0x66]),
839            requester_ip: None,
840            read_only: None,
841            message_type: MessageType::Request(RequestSpecific::FindNodeRequest(
842                FindNodeRequestArguments {
843                    target: Id::from_hex("1234123412341234123412341234123412341234").unwrap(),
844                    requester_id: Id::from_hex("5678567856785678567856785678567856785678").unwrap(),
845                },
846            )),
847        };
848
849        let serde_msg = original_msg.clone().into_serde_message();
850        let bytes = serde_msg.to_bytes().unwrap();
851        let parsed_serde_msg = internal::DHTMessage::from_bytes(bytes).unwrap();
852        let parsed_msg = Message::from_serde_message(parsed_serde_msg).unwrap();
853        assert_eq!(parsed_msg, original_msg);
854    }
855
856    #[test]
857    fn test_find_node_request_read_only() {
858        let original_msg = Message {
859            transaction_id: vec![1, 2, 3],
860            version: Some(vec![0x62, 0x61, 0x72, 0x66]),
861            requester_ip: None,
862            read_only: Some(true),
863            message_type: MessageType::Request(RequestSpecific::FindNodeRequest(
864                FindNodeRequestArguments {
865                    target: Id::from_hex("1234123412341234123412341234123412341234").unwrap(),
866                    requester_id: Id::from_hex("5678567856785678567856785678567856785678").unwrap(),
867                },
868            )),
869        };
870
871        let serde_msg = original_msg.clone().into_serde_message();
872        let bytes = serde_msg.to_bytes().unwrap();
873        let parsed_serde_msg = internal::DHTMessage::from_bytes(bytes).unwrap();
874        let parsed_msg = Message::from_serde_message(parsed_serde_msg).unwrap();
875        assert_eq!(parsed_msg, original_msg);
876    }
877
878    #[test]
879    fn test_find_node_response() {
880        let original_msg = Message {
881            transaction_id: vec![1, 2, 3],
882            version: Some(vec![1]),
883            requester_ip: Some("50.51.52.53:5455".parse().unwrap()),
884            read_only: None,
885            message_type: MessageType::Response(ResponseSpecific::FindNodeResponse(
886                FindNodeResponseArguments {
887                    responder_id: Id::from_hex("0505050505050505050505050505050505050505").unwrap(),
888                    nodes: vec![Node::new(
889                        Id::from_hex("0606060606060606060606060606060606060606").unwrap(),
890                        "49.50.52.52:5354".parse().unwrap(),
891                    )],
892                },
893            )),
894        };
895
896        let serde_msg = original_msg.clone().into_serde_message();
897        let bytes = serde_msg.to_bytes().unwrap();
898        let parsed_serde_msg = internal::DHTMessage::from_bytes(bytes).unwrap();
899        let parsed_msg = Message::from_serde_message(parsed_serde_msg).unwrap();
900        assert_eq!(parsed_msg, original_msg);
901    }
902
903    #[test]
904    fn test_announce_peer_request() {
905        let original_msg = Message {
906            transaction_id: vec![1, 2, 3],
907            version: Some(vec![0x62, 0x61, 0x72, 0x66]),
908            requester_ip: None,
909            read_only: None,
910            message_type: MessageType::Request(RequestSpecific::AnnouncePeerRequest(
911                AnnouncePeerRequestArguments {
912                    requester_id: Id::from_hex("5678567856785678567856785678567856785678").unwrap(),
913                    port: 666,
914                    implied_port: Some(false),
915                    token: vec![42, 42, 42, 42],
916                    info_hash: Id::from_hex("9899989998999899989998999899989998999899").unwrap(),
917                },
918            )),
919        };
920
921        let serde_msg = original_msg.clone().into_serde_message();
922        let bytes = serde_msg.to_bytes().unwrap();
923        let parsed_serde_msg = internal::DHTMessage::from_bytes(bytes).unwrap();
924        let parsed_msg = Message::from_serde_message(parsed_serde_msg).unwrap();
925        assert_eq!(parsed_msg, original_msg);
926    }
927
928    #[test]
929    fn test_sample_info_hashes_request() {
930        let original_msg = Message {
931            transaction_id: vec![1, 2, 3],
932            version: Some(vec![0x62, 0x61, 0x72, 0x66]),
933            requester_ip: None,
934            read_only: None,
935            message_type: MessageType::Request(RequestSpecific::SampleInfoHashesRequest(
936                SampleInfoHashesRequestArguments {
937                    requester_id: Id::from_hex("5678567856785678567856785678567856785678").unwrap(),
938                    target: Id::from_hex("3344334433443344334433443344334433443344").unwrap(),
939                },
940            )),
941        };
942
943        let serde_msg = original_msg.clone().into_serde_message();
944        let bytes = serde_msg.to_bytes().unwrap();
945        let parsed_serde_msg = internal::DHTMessage::from_bytes(bytes).unwrap();
946        let parsed_msg = Message::from_serde_message(parsed_serde_msg).unwrap();
947        assert_eq!(parsed_msg, original_msg);
948    }
949
950    #[test]
951    fn test_sample_info_hashes_response() {
952        let original_msg = Message {
953            transaction_id: vec![1, 2, 3],
954            version: Some(vec![1]),
955            requester_ip: Some("50.51.52.53:5455".parse().unwrap()),
956            read_only: None,
957            message_type: MessageType::Response(ResponseSpecific::SampleInfoHashesResponse(
958                SampleInfoHashesResponseArguments {
959                    responder_id: Id::from_hex("0505050505050505050505050505050505050505").unwrap(),
960                    interval: Duration::from_secs(32),
961                    nodes: vec![Node::new(
962                        Id::from_hex("0606060606060606060606060606060606060606").unwrap(),
963                        "49.50.52.52:5354".parse().unwrap(),
964                    )],
965                    samples: vec![
966                        Id::from_hex("3232323232323232323232323232323232323232").unwrap(),
967                        Id::from_hex("3434343434343434343434343434343434343434").unwrap(),
968                    ],
969                    num: 300,
970                },
971            )),
972        };
973
974        let serde_msg = original_msg.clone().into_serde_message();
975        let bytes = serde_msg.to_bytes().unwrap();
976        let parsed_serde_msg = internal::DHTMessage::from_bytes(bytes).unwrap();
977        let parsed_msg = Message::from_serde_message(parsed_serde_msg).unwrap();
978        assert_eq!(parsed_msg, original_msg);
979    }
980
981    #[test]
982    fn test_error_response() {
983        let original_msg = Message {
984            transaction_id: vec![97, 97],
985            version: None,
986            requester_ip: None,
987            read_only: None,
988            message_type: MessageType::Error(ErrorSpecific {
989                code: 201,
990                description: "A Generic Error Occured".to_string(),
991            }),
992        };
993
994        let serde_msg = original_msg.clone().into_serde_message();
995        let bytes = serde_msg.to_bytes().unwrap();
996        assert_eq!(
997            "d1:eli201e23:A Generic Error Occurede1:t2:aa1:y1:ee",
998            String::from_utf8_lossy(&bytes)
999        );
1000        let parsed_serde_msg = internal::DHTMessage::from_bytes(bytes).unwrap();
1001        let parsed_msg = Message::from_serde_message(parsed_serde_msg).unwrap();
1002        assert_eq!(parsed_msg, original_msg);
1003    }
1004
1005    #[test]
1006    fn test_response_matches_request_find_node() {
1007        let res = ResponseSpecific::FindNodeResponse(FindNodeResponseArguments {
1008            nodes: vec![],
1009            responder_id: Id::from_random(&mut thread_rng()),
1010        });
1011        let req = RequestSpecific::FindNodeRequest(FindNodeRequestArguments {
1012            requester_id: Id::from_random(&mut thread_rng()),
1013            target: Id::from_random(&mut thread_rng()),
1014        });
1015        assert!(response_matches_request(&res, &req));
1016    }
1017
1018    #[test]
1019    fn test_response_matches_request_find_ping() {
1020        let res = ResponseSpecific::PingResponse(PingResponseArguments {
1021            responder_id: Id::from_random(&mut thread_rng()),
1022        });
1023        let req = RequestSpecific::PingRequest(PingRequestArguments {
1024            requester_id: Id::from_random(&mut thread_rng()),
1025        });
1026        assert!(response_matches_request(&res, &req));
1027    }
1028
1029    #[test]
1030    fn test_response_matches_request_find_nonmatching() {
1031        let res = ResponseSpecific::PingResponse(PingResponseArguments {
1032            responder_id: Id::from_random(&mut thread_rng()),
1033        });
1034        let req = RequestSpecific::FindNodeRequest(FindNodeRequestArguments {
1035            requester_id: Id::from_random(&mut thread_rng()),
1036            target: Id::from_random(&mut thread_rng()),
1037        });
1038        assert!(!response_matches_request(&res, &req));
1039    }
1040}