arnaucube
arnaucube/torrent-rsPublic Self-hosted repository
torrent.get_peers() done
arnaucube root@arnaucube.com
Sun, 14 Jun 2020 15:15:26 +0200
commit

dc307c4c225e174be3a7a354900e0b088360004c

parent

aa15407d59b2777a132ee10ecec28254056e817e

2 files changed, 84 insertions(+), 40 deletions(-)

jump to
M Cargo.toml → Cargo.toml

@@ -14,3 +14,6 @@ serde_bytes = "0.10.0"

byteorder = "1.3.4" rand = "0.7" sha-1 = "0.9.0" + +[dev-dependencies] +rustc-hex = "1.0.0"
M src/lib.rs → src/lib.rs

@@ -1,5 +1,7 @@

use async_std::net::{SocketAddr, ToSocketAddrs, UdpSocket}; use std::error::Error; +use std::net::Ipv4Addr; +use std::convert::TryInto; use byteorder::{BigEndian, ByteOrder}; use rand::Rng;

@@ -13,6 +15,11 @@ extern crate serde_bytes;

use serde_bencode::{de, ser}; use serde_bytes::ByteBuf; + +// use rustc_hex::ToHex; + +const CONNECT_MSG: u32 = 0; +const ANNOUNCE_MSG: u32 = 1; #[derive(Debug, Deserialize)] struct Node(String, i64);

@@ -90,25 +97,30 @@ hasher.update(info_bytes);

let result = hasher.finalize(); result.to_vec() } - pub fn protocol(&self) -> Option<&str> { + pub fn announce(&self) -> Option<String> { + let mut a: String = "".to_string(); match &self.announce { Some(s) => { - let aux: Vec<&str> = s.split(":").collect(); - Some(aux[0]) + a = s.to_string(); } - _ => None, - } + _ => (), + }; + match &self.announce_list { // TODO refactor approach + Some(list) => { + a = list[0][0].clone(); + } + _ => (), + }; + Some(a) } - // pub fn peer(&self) -> Option<&str> { - // match &self.announce { - // Some(s) => { - // let aux: Vec<&str> = s.split(":").collect(); - // Some(aux[1]) - // } - // _ => None, - // } - // } - pub async fn get_peers(&self) -> Result<(), Box<dyn Error>> { + pub fn protocol(&self) -> Option<String> { + let announce = &self.announce().unwrap(); + let aux: Vec<&str> = announce.split(":").collect(); + let protocol = aux[0]; + Some(protocol.to_string()) + } + pub async fn get_peers(&self) -> Result<Vec<Peer>, Box<dyn Error>> { + // TODO timming system to resend request if no answer in X seconds if self.protocol().unwrap() != "udp" { panic!("not udp: {:?}", self.protocol().unwrap()); }

@@ -121,34 +133,27 @@ let conn_req = conn_req_msg().to_vec();

println!("SENDING conn_req {:?}", conn_req); socket.send_to(&conn_req, &peer).await?; - // let mut res: Vec<u8>; let mut buf = vec![0; 1024]; let peers = loop { let (n, src) = socket.recv_from(&mut buf).await?; let typ = resp_type(&buf); - println!("res {:?}", &buf[0..n]); - println!("t {:?}", typ); - // match typ { if typ == CONNECT_MSG { println!("TYPE: CONNECT: {:?}", CONNECT_MSG); - let conn_resp = parse_connect_resp(&buf); - println!("conn_resp {:?}", conn_resp); + // println!("HEX {:?}", &buf[0..n].to_hex()); + let conn_resp = parse_connect_resp(&buf[0..n].to_vec()); let announce_req = ann_req_msg(conn_resp.connection_id, self, 6681); - println!("announce_req {:?}", announce_req); socket.send_to(&announce_req[..], &src).await?; } else if typ==ANNOUNCE_MSG { println!("TYPE: ANNOUNCE: {:?}", ANNOUNCE_MSG); - let ann_resp = parse_announce_resp(&buf); - println!("PEERS1 {:?}", ann_resp.peers); + // println!("HEX {:?}", &buf[0..n].to_hex()); + let ann_resp = parse_announce_resp(&buf[0..n].to_vec()); break ann_resp.peers; } - println!("End"); }; - println!("PEERS2 {:?}", peers); - Ok(()) + Ok(peers) } }

@@ -163,10 +168,9 @@

fn ann_req_msg(connection_id: u64, torrent: &Torrent, port: u16) -> Vec<u8> { let mut b: [u8; 98] = [0; 98]; BigEndian::write_u64(&mut b[0..8], connection_id); - BigEndian::write_u32(&mut b[8..12], CONNECT_MSG); // action + BigEndian::write_u32(&mut b[8..12], ANNOUNCE_MSG); // action let random_bytes = rand::thread_rng().gen::<[u8; 4]>(); b[12..16].clone_from_slice(&random_bytes[..]); - // println!("md5sum {:?}", torrent); b[16..36].clone_from_slice(&torrent.info_hash()[..]); println!("info_hash: {:?}", &b[16..36]); // TODO [36..56] peerId b[36..56].clone_from_slice("todo".as_bytes());

@@ -183,8 +187,6 @@ BigEndian::write_u16(&mut b[96..98], port); // [96..98] port

b.to_vec() } -const CONNECT_MSG: u32 = 0; -const ANNOUNCE_MSG: u32 = 1; fn resp_type(b: &Vec<u8>) -> u32 { let action = BigEndian::read_u32(&b[0..4]); if action == 0 {

@@ -210,8 +212,8 @@ }

#[derive(Debug)] struct Peer { - ip: u32, - port: u32 + ip: String, + port: u16 } #[derive(Debug)]

@@ -228,8 +230,9 @@ let mut peers: Vec<Peer> = Vec::new();

let n_peers = (b.len()-20)/6; for i in 0..n_peers { let peer: Peer = Peer { - ip: BigEndian::read_u32(&b[20+(6*i)..24+(6*i)]), - port: BigEndian::read_u32(&b[24+(6*i)..26+(6*i)]), + // ip: BigEndian::read_u32(&b[20+(6*i)..24+(6*i)]), + ip: bytes_to_ip(&b[20+(6*i)..24+(6*i)].try_into().expect("err parsing peer ip")), + port: BigEndian::read_u16(&b[24+(6*i)..26+(6*i)]), }; peers.push(peer); }

@@ -244,23 +247,61 @@ peers: peers

}; ann_resp +} +fn bytes_to_ip(b: &[u8; 4]) -> String { + Ipv4Addr::new(b[0], b[1], b[2], b[3]).to_string() } #[cfg(test)] mod tests { use super::*; + use rustc_hex::ToHex; - // #[test] + #[test] + fn torrent_structs() { + let t = Torrent::open("test.torrent"); + assert_eq!(t.info.name, "Big Buck Bunny"); + assert_eq!(t.announce().unwrap(), "udp://tracker.leechers-paradise.org:6969"); + assert_eq!(t.info_hash().to_hex(), "dd8255ecdc7ca55fb0bbf81323d87062db1f6d1c"); + assert_eq!(t.size(), 276445467); + } + + #[test] + fn discovery_msgs() { + let t = Torrent::open("test.torrent"); + + let conn_req = conn_req_msg().to_vec(); + assert_eq!(conn_req[0..12].to_hex(), "000004172710198000000000"); // [12..16] is random + let conn_resp_buf = b"00000000d4c575c2c078f9a83418bebc"; + let conn_resp = parse_connect_resp(&conn_resp_buf.to_vec()); + println!("conn_resp {:?}", conn_resp); + assert_eq!(conn_resp.action, 808464432); + assert_eq!(conn_resp.transaction_id, 808464432); + assert_eq!(conn_resp.connection_id, 7220505182792409906); + + let announce_req = ann_req_msg(conn_resp.connection_id, &t, 6681); + assert_eq!(announce_req[0..12].to_hex(), "643463353735633200000001"); + assert_eq!(announce_req[16..72].to_hex(), "dd8255ecdc7ca55fb0bbf81323d87062db1f6d1c0000000000000000000000000000000000000000000000000000000000000000107a391b"); + assert_eq!(announce_req[92..98].to_hex(), "ffffffff1a19"); + + let announce_resp_buf = b"000000017a638a60000006e8000000030000002429d412a11ae12d53dcbd1a19d048c0e51ae1d8241960c8d5d5c36e71c8d5c5b974a31ae2c11ef348d4aabc5f370ec8d5bc4e16321ae1b9cee13b2327b94187b66f7cb94186b1c8d5b75308331ae1b068c0e0c263ac6f857911389d27ac821ae19088c2c01ae172fe2468c00a699aebe6720f68a2f99a1ae167fce2141ae163582ee41ae1634921a5d2725b72aaf5c8d559482e8fc9d257fb394cc8d55740e9ebd166524044e11aff51b6dcb6c8d54e2ebe61c3574b87860fc8d54b6e11026dff473afc7a1ec944cd47cd1ae131249b051ae124ff6b521ae105b75c13c8d50551153a1ae105024e09cd52"; + let ann_resp = parse_announce_resp(&announce_resp_buf.to_vec()); + assert_eq!(ann_resp.peers.len(), 81); + assert_eq!(ann_resp.peers[0].ip, "48.54.101.56"); + assert_eq!(ann_resp.peers[0].port, 12336); + assert_eq!(ann_resp.peers[80].ip, "52.101.48.57"); + assert_eq!(ann_resp.peers[80].port, 25444); + } + #[async_std::test] - async fn test_read() { + async fn get_peers() { let t = Torrent::open("test.torrent"); // println!("{:?}", t); println!("torrent: {:?}", t.info.name); - println!("announce: {:?}", t.announce.clone().unwrap()); println!("protocol: {:?}", t.protocol().unwrap()); - + println!("conn_req_msg: {:?}", conn_req_msg()); - + let r = t.get_peers().await; println!("get_peers r: {:?}", r); }