arnaucube
arnaucube/torrent-rsPublic Self-hosted repository
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}