1use crate::common::*;
2
3pub(crate) const HEADER: &[u8; 20] = b"\x13BitTorrent protocol";
4pub(crate) const SUPPORTS_EXTENSION_PROTOCOL: u8 = 0b0001_0000;
5pub(crate) const IMDL_RESERVED_BYTES: [u8; 8] = [0, 0, 0, 0, 0, SUPPORTS_EXTENSION_PROTOCOL, 0, 0];
6
7#[derive(Debug)]
8pub(crate) struct Handshake {
9 pub(crate) peer_id: [u8; 20],
10 pub(crate) infohash: [u8; 20],
11 pub(crate) reserved: [u8; 8],
12}
13
14impl Handshake {
15 pub(crate) const LENGTH: usize = 68;
16
17 pub(crate) fn new(infohash: Infohash) -> Self {
18 Handshake {
19 peer_id: rand::rng().random(),
20 infohash: infohash.into(),
21 reserved: IMDL_RESERVED_BYTES,
22 }
23 }
24
25 pub(crate) fn serialize(&self) -> [u8; Handshake::LENGTH] {
26 let mut msg = [0u8; Handshake::LENGTH];
27
28 msg[0..20].copy_from_slice(HEADER);
29 msg[20..28].copy_from_slice(&self.reserved);
30 msg[28..48].copy_from_slice(&self.infohash);
31 msg[48..68].copy_from_slice(&self.peer_id);
32
33 msg
34 }
35
36 pub fn supports_extension_protocol(&self) -> bool {
37 self.reserved[5] & SUPPORTS_EXTENSION_PROTOCOL > 0
38 }
39}
40
41impl TryFrom<[u8; Handshake::LENGTH]> for Handshake {
42 type Error = Error;
43
44 fn try_from(buf: [u8; Handshake::LENGTH]) -> Result<Self> {
45 if &buf[0..20] != HEADER {
46 return Err(error::Error::PeerHandshakeHeader);
47 }
48
49 let mut infohash = [0u8; 20];
50 let mut reserved = [0u8; 8];
51 let mut peer_id = [0u8; 20];
52
53 reserved.clone_from_slice(&buf[20..28]);
54 infohash.clone_from_slice(&buf[28..48]);
55 peer_id.clone_from_slice(&buf[48..68]);
56
57 Ok(Handshake {
58 peer_id,
59 infohash,
60 reserved,
61 })
62 }
63}