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; #[derive(Debug, PartialEq, Clone)]
79pub struct Message {
80 pub transaction_id: Vec<u8>,
81
82 pub version: Option<Vec<u8>>,
84
85 pub requester_ip: Option<SocketAddr>,
88
89 pub message_type: MessageType,
90
91 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 }
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 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
550pub 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 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}