1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use bip_bencode::{Bencode, BencodeConvert, Dictionary, BencodeConvertError};
use bip_util::bt::{NodeId};
use message::compact_info::{CompactNodeInfo, CompactValueInfo};
use message::ping::{PingResponse};
use message::find_node::{FindNodeResponse};
use message::get_peers::{GetPeersResponse};
use message::announce_peer::{AnnouncePeerResponse};
use error::{DhtError, DhtErrorKind, DhtResult};
pub const RESPONSE_ARGS_KEY: &'static str = "r";
pub struct ResponseValidate<'a> {
trans_id: &'a [u8]
}
impl<'a> ResponseValidate<'a> {
pub fn new(trans_id: &'a [u8]) -> ResponseValidate<'a> {
ResponseValidate{ trans_id: trans_id }
}
pub fn validate_node_id(&self, node_id: &[u8]) -> DhtResult<NodeId> {
NodeId::from_hash(node_id).map_err(|_|
DhtError::with_detail(DhtErrorKind::InvalidResponse, "Found Node ID With Invalid Length",
format!("TransactionID: {:?}, NodeID Length: {:?}", self.trans_id, node_id.len()))
)
}
pub fn validate_nodes<'b>(&self, nodes: &'b [u8]) -> DhtResult<CompactNodeInfo<'b>> {
CompactNodeInfo::new(nodes).map_err(|_|
DhtError::with_detail(DhtErrorKind::InvalidResponse, "Found Nodes Structure With Wrong Multiple Of Bytes",
format!("TransactionID: {:?}", self.trans_id))
)
}
pub fn validate_values<'b>(&self, values: &'b [Bencode<'a>]) -> DhtResult<CompactValueInfo<'b>> {
for bencode in values.iter() {
match bencode.bytes() {
Some(_) => (),
None => return Err(DhtError::with_detail(DhtErrorKind::InvalidResponse,
"Found Values Structure Element With Wrong Bencode Type", format!("TransactionID: {:?}", self.trans_id)))
}
}
CompactValueInfo::new(values).map_err(|_|
DhtError::with_detail(DhtErrorKind::InvalidResponse, "Found values Structure Element With Wrong Number Of Bytes",
format!("TransactionID: {:?}", self.trans_id))
)
}
}
impl<'a> BencodeConvert for ResponseValidate<'a> {
type Error = DhtError;
fn handle_error(&self, error: BencodeConvertError) -> DhtError {
DhtError::with_detail(DhtErrorKind::InvalidResponse, error.desc(), error.key().to_owned())
}
}
#[allow(unused)]
pub enum ExpectedResponse {
Ping,
FindNode,
GetPeers,
AnnouncePeer,
GetData,
PutData,
None
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum ResponseType<'a> {
Ping(PingResponse<'a>),
FindNode(FindNodeResponse<'a>),
GetPeers(GetPeersResponse<'a>),
AnnouncePeer(AnnouncePeerResponse<'a>)
}
impl<'a> ResponseType<'a> {
pub fn from_parts(root: &'a Dictionary<'a, Bencode<'a>>, trans_id: &'a [u8], rsp_type: ExpectedResponse)
-> DhtResult<ResponseType<'a>> {
let validate = ResponseValidate::new(trans_id);
let rqst_root = try!(validate.lookup_and_convert_dict(root, RESPONSE_ARGS_KEY));
match rsp_type {
ExpectedResponse::Ping => {
let ping_rsp = try!(PingResponse::from_parts(rqst_root, trans_id));
Ok(ResponseType::Ping(ping_rsp))
},
ExpectedResponse::FindNode => {
let find_node_rsp = try!(FindNodeResponse::from_parts(rqst_root, trans_id));
Ok(ResponseType::FindNode(find_node_rsp))
},
ExpectedResponse::GetPeers => {
let get_peers_rsp = try!(GetPeersResponse::from_parts(rqst_root, trans_id));
Ok(ResponseType::GetPeers(get_peers_rsp))
},
ExpectedResponse::AnnouncePeer => {
let announce_peer_rsp = try!(AnnouncePeerResponse::from_parts(rqst_root, trans_id));
Ok(ResponseType::AnnouncePeer(announce_peer_rsp))
},
ExpectedResponse::GetData => {
unimplemented!();
},
ExpectedResponse::PutData => {
unimplemented!();
},
ExpectedResponse::None => {
Err(DhtError::new(DhtErrorKind::UnsolicitedResponse, "Failed To Match Node Response To A Request"))
}
}
}
}