mirror of
https://github.com/arnaucube/torrent-rs.git
synced 2026-02-06 19:26:39 +01:00
torrent.get_peers() done
This commit is contained in:
@@ -14,3 +14,6 @@ serde_bytes = "0.10.0"
|
|||||||
byteorder = "1.3.4"
|
byteorder = "1.3.4"
|
||||||
rand = "0.7"
|
rand = "0.7"
|
||||||
sha-1 = "0.9.0"
|
sha-1 = "0.9.0"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
rustc-hex = "1.0.0"
|
||||||
|
|||||||
121
src/lib.rs
121
src/lib.rs
@@ -1,5 +1,7 @@
|
|||||||
use async_std::net::{SocketAddr, ToSocketAddrs, UdpSocket};
|
use async_std::net::{SocketAddr, ToSocketAddrs, UdpSocket};
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
use std::net::Ipv4Addr;
|
||||||
|
use std::convert::TryInto;
|
||||||
|
|
||||||
use byteorder::{BigEndian, ByteOrder};
|
use byteorder::{BigEndian, ByteOrder};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
@@ -14,6 +16,11 @@ extern crate serde_bytes;
|
|||||||
use serde_bencode::{de, ser};
|
use serde_bencode::{de, ser};
|
||||||
use serde_bytes::ByteBuf;
|
use serde_bytes::ByteBuf;
|
||||||
|
|
||||||
|
// use rustc_hex::ToHex;
|
||||||
|
|
||||||
|
const CONNECT_MSG: u32 = 0;
|
||||||
|
const ANNOUNCE_MSG: u32 = 1;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
struct Node(String, i64);
|
struct Node(String, i64);
|
||||||
|
|
||||||
@@ -90,25 +97,30 @@ impl Torrent {
|
|||||||
let result = hasher.finalize();
|
let result = hasher.finalize();
|
||||||
result.to_vec()
|
result.to_vec()
|
||||||
}
|
}
|
||||||
pub fn protocol(&self) -> Option<&str> {
|
pub fn announce(&self) -> Option<String> {
|
||||||
|
let mut a: String = "".to_string();
|
||||||
match &self.announce {
|
match &self.announce {
|
||||||
Some(s) => {
|
Some(s) => {
|
||||||
let aux: Vec<&str> = s.split(":").collect();
|
a = s.to_string();
|
||||||
Some(aux[0])
|
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => (),
|
||||||
}
|
};
|
||||||
|
match &self.announce_list { // TODO refactor approach
|
||||||
|
Some(list) => {
|
||||||
|
a = list[0][0].clone();
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
};
|
||||||
|
Some(a)
|
||||||
}
|
}
|
||||||
// pub fn peer(&self) -> Option<&str> {
|
pub fn protocol(&self) -> Option<String> {
|
||||||
// match &self.announce {
|
let announce = &self.announce().unwrap();
|
||||||
// Some(s) => {
|
let aux: Vec<&str> = announce.split(":").collect();
|
||||||
// let aux: Vec<&str> = s.split(":").collect();
|
let protocol = aux[0];
|
||||||
// Some(aux[1])
|
Some(protocol.to_string())
|
||||||
// }
|
}
|
||||||
// _ => None,
|
pub async fn get_peers(&self) -> Result<Vec<Peer>, Box<dyn Error>> {
|
||||||
// }
|
// TODO timming system to resend request if no answer in X seconds
|
||||||
// }
|
|
||||||
pub async fn get_peers(&self) -> Result<(), Box<dyn Error>> {
|
|
||||||
if self.protocol().unwrap() != "udp" {
|
if self.protocol().unwrap() != "udp" {
|
||||||
panic!("not udp: {:?}", self.protocol().unwrap());
|
panic!("not udp: {:?}", self.protocol().unwrap());
|
||||||
}
|
}
|
||||||
@@ -121,34 +133,27 @@ impl Torrent {
|
|||||||
println!("SENDING conn_req {:?}", conn_req);
|
println!("SENDING conn_req {:?}", conn_req);
|
||||||
socket.send_to(&conn_req, &peer).await?;
|
socket.send_to(&conn_req, &peer).await?;
|
||||||
|
|
||||||
// let mut res: Vec<u8>;
|
|
||||||
let mut buf = vec![0; 1024];
|
let mut buf = vec![0; 1024];
|
||||||
|
|
||||||
let peers = loop {
|
let peers = loop {
|
||||||
let (n, src) = socket.recv_from(&mut buf).await?;
|
let (n, src) = socket.recv_from(&mut buf).await?;
|
||||||
|
|
||||||
let typ = resp_type(&buf);
|
let typ = resp_type(&buf);
|
||||||
println!("res {:?}", &buf[0..n]);
|
|
||||||
println!("t {:?}", typ);
|
|
||||||
// match typ {
|
|
||||||
if typ == CONNECT_MSG {
|
if typ == CONNECT_MSG {
|
||||||
println!("TYPE: CONNECT: {:?}", CONNECT_MSG);
|
println!("TYPE: CONNECT: {:?}", CONNECT_MSG);
|
||||||
let conn_resp = parse_connect_resp(&buf);
|
// println!("HEX {:?}", &buf[0..n].to_hex());
|
||||||
println!("conn_resp {:?}", conn_resp);
|
let conn_resp = parse_connect_resp(&buf[0..n].to_vec());
|
||||||
let announce_req = ann_req_msg(conn_resp.connection_id, self, 6681);
|
let announce_req = ann_req_msg(conn_resp.connection_id, self, 6681);
|
||||||
println!("announce_req {:?}", announce_req);
|
|
||||||
socket.send_to(&announce_req[..], &src).await?;
|
socket.send_to(&announce_req[..], &src).await?;
|
||||||
} else if typ==ANNOUNCE_MSG {
|
} else if typ==ANNOUNCE_MSG {
|
||||||
println!("TYPE: ANNOUNCE: {:?}", ANNOUNCE_MSG);
|
println!("TYPE: ANNOUNCE: {:?}", ANNOUNCE_MSG);
|
||||||
let ann_resp = parse_announce_resp(&buf);
|
// println!("HEX {:?}", &buf[0..n].to_hex());
|
||||||
println!("PEERS1 {:?}", ann_resp.peers);
|
let ann_resp = parse_announce_resp(&buf[0..n].to_vec());
|
||||||
break ann_resp.peers;
|
break ann_resp.peers;
|
||||||
}
|
}
|
||||||
println!("End");
|
|
||||||
};
|
};
|
||||||
println!("PEERS2 {:?}", peers);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(peers)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,10 +168,9 @@ fn conn_req_msg() -> [u8; 16] {
|
|||||||
fn ann_req_msg(connection_id: u64, torrent: &Torrent, port: u16) -> Vec<u8> {
|
fn ann_req_msg(connection_id: u64, torrent: &Torrent, port: u16) -> Vec<u8> {
|
||||||
let mut b: [u8; 98] = [0; 98];
|
let mut b: [u8; 98] = [0; 98];
|
||||||
BigEndian::write_u64(&mut b[0..8], connection_id);
|
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]>();
|
let random_bytes = rand::thread_rng().gen::<[u8; 4]>();
|
||||||
b[12..16].clone_from_slice(&random_bytes[..]);
|
b[12..16].clone_from_slice(&random_bytes[..]);
|
||||||
// println!("md5sum {:?}", torrent);
|
|
||||||
b[16..36].clone_from_slice(&torrent.info_hash()[..]);
|
b[16..36].clone_from_slice(&torrent.info_hash()[..]);
|
||||||
println!("info_hash: {:?}", &b[16..36]);
|
println!("info_hash: {:?}", &b[16..36]);
|
||||||
// TODO [36..56] peerId b[36..56].clone_from_slice("todo".as_bytes());
|
// TODO [36..56] peerId b[36..56].clone_from_slice("todo".as_bytes());
|
||||||
@@ -183,8 +187,6 @@ fn ann_req_msg(connection_id: u64, torrent: &Torrent, port: u16) -> Vec<u8> {
|
|||||||
b.to_vec()
|
b.to_vec()
|
||||||
}
|
}
|
||||||
|
|
||||||
const CONNECT_MSG: u32 = 0;
|
|
||||||
const ANNOUNCE_MSG: u32 = 1;
|
|
||||||
fn resp_type(b: &Vec<u8>) -> u32 {
|
fn resp_type(b: &Vec<u8>) -> u32 {
|
||||||
let action = BigEndian::read_u32(&b[0..4]);
|
let action = BigEndian::read_u32(&b[0..4]);
|
||||||
if action == 0 {
|
if action == 0 {
|
||||||
@@ -210,8 +212,8 @@ fn parse_connect_resp(b: &Vec<u8>) -> ConnResp {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Peer {
|
struct Peer {
|
||||||
ip: u32,
|
ip: String,
|
||||||
port: u32
|
port: u16
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -228,8 +230,9 @@ fn parse_announce_resp(b: &Vec<u8>) -> AnnResp {
|
|||||||
let n_peers = (b.len()-20)/6;
|
let n_peers = (b.len()-20)/6;
|
||||||
for i in 0..n_peers {
|
for i in 0..n_peers {
|
||||||
let peer: Peer = Peer {
|
let peer: Peer = Peer {
|
||||||
ip: BigEndian::read_u32(&b[20+(6*i)..24+(6*i)]),
|
// ip: BigEndian::read_u32(&b[20+(6*i)..24+(6*i)]),
|
||||||
port: BigEndian::read_u32(&b[24+(6*i)..26+(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);
|
peers.push(peer);
|
||||||
}
|
}
|
||||||
@@ -245,22 +248,60 @@ fn parse_announce_resp(b: &Vec<u8>) -> AnnResp {
|
|||||||
|
|
||||||
ann_resp
|
ann_resp
|
||||||
}
|
}
|
||||||
|
fn bytes_to_ip(b: &[u8; 4]) -> String {
|
||||||
|
Ipv4Addr::new(b[0], b[1], b[2], b[3]).to_string()
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
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_std::test]
|
||||||
async fn test_read() {
|
async fn get_peers() {
|
||||||
let t = Torrent::open("test.torrent");
|
let t = Torrent::open("test.torrent");
|
||||||
// println!("{:?}", t);
|
// println!("{:?}", t);
|
||||||
println!("torrent: {:?}", t.info.name);
|
println!("torrent: {:?}", t.info.name);
|
||||||
println!("announce: {:?}", t.announce.clone().unwrap());
|
|
||||||
println!("protocol: {:?}", t.protocol().unwrap());
|
println!("protocol: {:?}", t.protocol().unwrap());
|
||||||
|
|
||||||
println!("conn_req_msg: {:?}", conn_req_msg());
|
println!("conn_req_msg: {:?}", conn_req_msg());
|
||||||
|
|
||||||
let r = t.get_peers().await;
|
let r = t.get_peers().await;
|
||||||
println!("get_peers r: {:?}", r);
|
println!("get_peers r: {:?}", r);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user