torrent-rs/src/lib.rs
src/lib.rsRaw
1use async_std::net::{SocketAddr, ToSocketAddrs, UdpSocket};
2use std::error::Error;
3
4use byteorder::{BigEndian, ByteOrder};
5use rand::Rng;
6use sha1::{Sha1, Digest};
7
8extern crate serde;
9extern crate serde_bencode;
10#[macro_use]
11extern crate serde_derive;
12extern crate serde_bytes;
13
14use serde_bencode::{de, ser};
15use serde_bytes::ByteBuf;
16
17#[derive(Debug, Deserialize)]
18struct Node(String, i64);
19
20#[derive(Debug, Serialize, Deserialize)]
21struct File {
22 path: Vec<String>,
23 length: i64,
24 #[serde(default)]
25 md5sum: Option<String>,
26}
27
28#[derive(Debug, Serialize, Deserialize)]
29struct Info {
30 name: String,
31 pieces: ByteBuf,
32 #[serde(rename = "piece length")]
33 piece_length: i64,
34 #[serde(default)]
35 md5sum: Option<String>,
36 #[serde(default)]
37 length: Option<i64>,
38 #[serde(default)]
39 files: Option<Vec<File>>,
40 #[serde(default)]
41 private: Option<u8>,
42 #[serde(default)]
43 path: Option<Vec<String>>,
44 #[serde(default)]
45 #[serde(rename = "root hash")]
46 root_hash: Option<String>,
47}
48
49#[derive(Debug, Deserialize)]
50struct Torrent {
51 info: Info,
52 #[serde(default)]
53 announce: Option<String>,
54 #[serde(default)]
55 nodes: Option<Vec<Node>>,
56 #[serde(default)]
57 encoding: Option<String>,
58 #[serde(default)]
59 httpseeds: Option<Vec<String>>,
60 #[serde(default)]
61 #[serde(rename = "announce-list")]
62 announce_list: Option<Vec<Vec<String>>>,
63 #[serde(default)]
64 #[serde(rename = "creation date")]
65 creation_date: Option<i64>,
66 #[serde(rename = "comment")]
67 comment: Option<String>,
68 #[serde(default)]
69 #[serde(rename = "created by")]
70 created_by: Option<String>,
71}
72
73impl Torrent {
74 pub fn open(path: &str) -> Torrent {
75 let b = std::fs::read(path).unwrap();
76 de::from_bytes::<Torrent>(&b).unwrap()
77 }
78 pub fn size(&self) -> u64 {
79 let files = self.info.files.as_ref().unwrap();
80 let mut size: u64 = 0;
81 for i in 0..files.len() {
82 size = size + files[i].length as u64;
83 }
84 size
85 }
86 pub fn info_hash(&self) -> Vec<u8> {
87 let info_bytes: Vec<u8> = ser::to_bytes(&self.info).unwrap();
88 let mut hasher = Sha1::new();
89 hasher.update(info_bytes);
90 let result = hasher.finalize();
91 result.to_vec()
92 }
93 pub fn protocol(&self) -> Option<&str> {
94 match &self.announce {
95 Some(s) => {
96 let aux: Vec<&str> = s.split(":").collect();
97 Some(aux[0])
98 }
99 _ => None,
100 }
101 }
102 // pub fn peer(&self) -> Option<&str> {
103 // match &self.announce {
104 // Some(s) => {
105 // let aux: Vec<&str> = s.split(":").collect();
106 // Some(aux[1])
107 // }
108 // _ => None,
109 // }
110 // }
111 pub async fn get_peers(&self) -> Result<(), Box<dyn Error>> {
112 if self.protocol().unwrap() != "udp" {
113 panic!("not udp: {:?}", self.protocol().unwrap());
114 }
115
116 let peer = self.announce.clone().unwrap().replace("udp://", "");
117 println!("peer {:?}", peer);
118 let socket = UdpSocket::bind("0.0.0.0:6681").await?;
119
120 let conn_req = conn_req_msg().to_vec();
121 println!("SENDING conn_req {:?}", conn_req);
122 socket.send_to(&conn_req, &peer).await?;
123
124 // let mut res: Vec<u8>;
125 let mut buf = vec![0; 1024];
126
127 let peers = loop {
128 let (n, src) = socket.recv_from(&mut buf).await?;
129
130 let typ = resp_type(&buf);
131 println!("res {:?}", &buf[0..n]);
132 println!("t {:?}", typ);
133 // match typ {
134 if typ == CONNECT_MSG {
135 println!("TYPE: CONNECT: {:?}", CONNECT_MSG);
136 let conn_resp = parse_connect_resp(&buf);
137 println!("conn_resp {:?}", conn_resp);
138 let announce_req = ann_req_msg(conn_resp.connection_id, self, 6681);
139 println!("announce_req {:?}", announce_req);
140 socket.send_to(&announce_req[..], &src).await?;
141 } else if typ==ANNOUNCE_MSG {
142 println!("TYPE: ANNOUNCE: {:?}", ANNOUNCE_MSG);
143 let ann_resp = parse_announce_resp(&buf);
144 println!("PEERS1 {:?}", ann_resp.peers);
145 break ann_resp.peers;
146 }
147 println!("End");
148 };
149 println!("PEERS2 {:?}", peers);
150
151 Ok(())
152 }
153}
154
155fn conn_req_msg() -> [u8; 16] {
156 let mut b: [u8; 16] = [0; 16];
157 BigEndian::write_u64(&mut b[0..8], 0x41727101980); // connection_id
158 let random_bytes = rand::thread_rng().gen::<[u8; 4]>();
159 b[12..16].clone_from_slice(&random_bytes[..]);
160 b
161}
162
163fn ann_req_msg(connection_id: u64, torrent: &Torrent, port: u16) -> Vec<u8> {
164 let mut b: [u8; 98] = [0; 98];
165 BigEndian::write_u64(&mut b[0..8], connection_id);
166 BigEndian::write_u32(&mut b[8..12], CONNECT_MSG); // action
167 let random_bytes = rand::thread_rng().gen::<[u8; 4]>();
168 b[12..16].clone_from_slice(&random_bytes[..]);
169 // println!("md5sum {:?}", torrent);
170 b[16..36].clone_from_slice(&torrent.info_hash()[..]);
171 println!("info_hash: {:?}", &b[16..36]);
172 // TODO [36..56] peerId b[36..56].clone_from_slice("todo".as_bytes());
173 // TODO [56..64] downloaded
174 println!("torrent.size(): {:?}", torrent.size());
175 BigEndian::write_u64(&mut b[64..72], torrent.size()); // [64..72] left
176 // TODO [72..80] uploaded
177 // TODO [80..84] event (0:none, 1:completed, 2:started, 3:stopped)
178 // TODO [84..88] ip address
179 let random_bytes = rand::thread_rng().gen::<[u8; 4]>();
180 b[88..92].clone_from_slice(&random_bytes[..]); // [88..92] key (random)
181 BigEndian::write_i32(&mut b[92..96], -1); // [92..96] num_want (default: -1)
182 BigEndian::write_u16(&mut b[96..98], port); // [96..98] port
183 b.to_vec()
184}
185
186const CONNECT_MSG: u32 = 0;
187const ANNOUNCE_MSG: u32 = 1;
188fn resp_type(b: &Vec<u8>) -> u32 {
189 let action = BigEndian::read_u32(&b[0..4]);
190 if action == 0 {
191 return CONNECT_MSG;
192 } else {
193 return ANNOUNCE_MSG;
194 }
195}
196
197#[derive(Debug)]
198struct ConnResp {
199 action: u32,
200 transaction_id: u32,
201 connection_id: u64,
202}
203fn parse_connect_resp(b: &Vec<u8>) -> ConnResp {
204 ConnResp {
205 action: BigEndian::read_u32(&b[0..4]),
206 transaction_id: BigEndian::read_u32(&b[4..8]),
207 connection_id: BigEndian::read_u64(&b[8..]),
208 }
209}
210
211#[derive(Debug)]
212struct Peer {
213 ip: u32,
214 port: u32
215}
216
217#[derive(Debug)]
218struct AnnResp {
219 action: u32,
220 transaction_id: u32,
221 interval: u32,
222 leechers: u32,
223 seeders: u32,
224 peers: Vec<Peer>,
225}
226fn parse_announce_resp(b: &Vec<u8>) -> AnnResp {
227 let mut peers: Vec<Peer> = Vec::new();
228 let n_peers = (b.len()-20)/6;
229 for i in 0..n_peers {
230 let peer: Peer = Peer {
231 ip: BigEndian::read_u32(&b[20+(6*i)..24+(6*i)]),
232 port: BigEndian::read_u32(&b[24+(6*i)..26+(6*i)]),
233 };
234 peers.push(peer);
235 }
236
237 let ann_resp: AnnResp = AnnResp {
238 action: BigEndian::read_u32(&b[0..4]),
239 transaction_id: BigEndian::read_u32(&b[4..8]),
240 interval: BigEndian::read_u32(&b[8..12]),
241 leechers: BigEndian::read_u32(&b[12..16]),
242 seeders: BigEndian::read_u32(&b[16..20]),
243 peers: peers
244 };
245
246 ann_resp
247}
248
249#[cfg(test)]
250mod tests {
251 use super::*;
252
253 // #[test]
254 #[async_std::test]
255 async fn test_read() {
256 let t = Torrent::open("test.torrent");
257 // println!("{:?}", t);
258 println!("torrent: {:?}", t.info.name);
259 println!("announce: {:?}", t.announce.clone().unwrap());
260 println!("protocol: {:?}", t.protocol().unwrap());
261
262 println!("conn_req_msg: {:?}", conn_req_msg());
263
264 let r = t.get_peers().await;
265 println!("get_peers r: {:?}", r);
266 }
267}