arnaucube
arnaucube/torrent-rsPublic Self-hosted repository
init torrent.get_peers() with async_std::UdpSocket
arnaucube root@arnaucube.com
Sat, 13 Jun 2020 19:20:49 +0200
commit

aa15407d59b2777a132ee10ecec28254056e817e

parent

794f2a292cc2fda75b69963fcb48b44e9a4d3d87

3 files changed, 82 insertions(+), 13 deletions(-)

jump to
M Cargo.toml → Cargo.toml

@@ -6,6 +6,7 @@ edition = "2018"

[dependencies] +async-std = { version = "1.6.1", features = ["attributes"] } serde_bencode = "^0.2.1" serde = "^1.0.0" serde_derive = "^1.0.0"
A README.md

@@ -0,0 +1,2 @@

+# torrent-rs +BitTorrent client
M src/lib.rs → src/lib.rs

@@ -1,6 +1,9 @@

+use async_std::net::{SocketAddr, ToSocketAddrs, UdpSocket}; +use std::error::Error; + use byteorder::{BigEndian, ByteOrder}; use rand::Rng; -use sha1::{Digest, Sha1}; +use sha1::{Sha1, Digest}; extern crate serde; extern crate serde_bencode;

@@ -87,10 +90,67 @@ hasher.update(info_bytes);

let result = hasher.finalize(); result.to_vec() } -} + pub fn protocol(&self) -> Option<&str> { + match &self.announce { + Some(s) => { + let aux: Vec<&str> = s.split(":").collect(); + Some(aux[0]) + } + _ => None, + } + } + // 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>> { + if self.protocol().unwrap() != "udp" { + panic!("not udp: {:?}", self.protocol().unwrap()); + } -const CONNECT_MSG: u32 = 0; -const ANNOUNCE_MSG: u32 = 1; + let peer = self.announce.clone().unwrap().replace("udp://", ""); + println!("peer {:?}", peer); + let socket = UdpSocket::bind("0.0.0.0:6681").await?; + + 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); + 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); + break ann_resp.peers; + } + println!("End"); + }; + println!("PEERS2 {:?}", peers); + + Ok(()) + } +} fn conn_req_msg() -> [u8; 16] { let mut b: [u8; 16] = [0; 16];

@@ -113,11 +173,9 @@ // TODO [36..56] peerId b[36..56].clone_from_slice("todo".as_bytes());

// TODO [56..64] downloaded println!("torrent.size(): {:?}", torrent.size()); BigEndian::write_u64(&mut b[64..72], torrent.size()); // [64..72] left - // TODO [72..80] uploaded // TODO [80..84] event (0:none, 1:completed, 2:started, 3:stopped) // TODO [84..88] ip address - let random_bytes = rand::thread_rng().gen::<[u8; 4]>(); b[88..92].clone_from_slice(&random_bytes[..]); // [88..92] key (random) BigEndian::write_i32(&mut b[92..96], -1); // [92..96] num_want (default: -1)

@@ -125,6 +183,8 @@ 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 {

@@ -151,7 +211,7 @@

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

@@ -165,11 +225,11 @@ peers: Vec<Peer>,

} fn parse_announce_resp(b: &Vec<u8>) -> AnnResp { let mut peers: Vec<Peer> = Vec::new(); - let n_peers = (b.len() - 20) / 6; + 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)]), + port: BigEndian::read_u32(&b[24+(6*i)..26+(6*i)]), }; peers.push(peer); }

@@ -180,7 +240,7 @@ transaction_id: BigEndian::read_u32(&b[4..8]),

interval: BigEndian::read_u32(&b[8..12]), leechers: BigEndian::read_u32(&b[12..16]), seeders: BigEndian::read_u32(&b[16..20]), - peers: peers, + peers: peers }; ann_resp

@@ -190,12 +250,18 @@ #[cfg(test)]

mod tests { use super::*; - #[test] - fn test_read() { + // #[test] + #[async_std::test] + async fn test_read() { 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); } }