use nom::{le_u8, be_u64, rest};
use std::io::{Error, ErrorKind};
use toxcore::binary_io::*;
use toxcore::crypto_core::*;
use toxcore::dht::packed_node::PackedNode;
use toxcore::dht::codec::*;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct NodesResponse {
pub pk: PublicKey,
pub nonce: Nonce,
pub payload: Vec<u8>,
}
impl ToBytes for NodesResponse {
fn to_bytes<'a>(&self, buf: (&'a mut [u8], usize)) -> Result<(&'a mut [u8], usize), GenError> {
do_gen!(buf,
gen_be_u8!(0x04) >>
gen_slice!(self.pk.as_ref()) >>
gen_slice!(self.nonce.as_ref()) >>
gen_slice!(self.payload.as_slice())
)
}
}
impl FromBytes for NodesResponse {
named!(from_bytes<NodesResponse>, do_parse!(
tag!("\x04") >>
pk: call!(PublicKey::from_bytes) >>
nonce: call!(Nonce::from_bytes) >>
payload: map!(rest, |bytes| bytes.to_vec() ) >>
(NodesResponse { pk, nonce, payload })
));
}
impl NodesResponse {
pub fn new(shared_secret: &PrecomputedKey, pk: &PublicKey, payload: NodesResponsePayload) -> NodesResponse {
let nonce = gen_nonce();
let mut buf = [0; MAX_DHT_PACKET_SIZE];
let (_, size) = payload.to_bytes((&mut buf, 0)).unwrap();
let payload = seal_precomputed(&buf[..size], &nonce, shared_secret);
NodesResponse {
pk: *pk,
nonce,
payload,
}
}
pub fn get_payload(&self, own_secret_key: &SecretKey) -> Result<NodesResponsePayload, Error> {
debug!(target: "NodesResponse", "Getting packet data from NodesResponse.");
trace!(target: "NodesResponse", "With NodesResponse: {:?}", self);
let decrypted = open(&self.payload, &self.nonce, &self.pk, own_secret_key)
.map_err(|()| {
debug!("Decrypting NodesResponse failed!");
Error::new(ErrorKind::Other, "NodesResponse decrypt error.")
})?;
match NodesResponsePayload::from_bytes(&decrypted) {
IResult::Incomplete(e) => {
debug!(target: "NodesResponse", "NodesResponsePayload deserialize error: {:?}", e);
Err(Error::new(ErrorKind::Other,
format!("NodesResponsePayload deserialize error: {:?}", e)))
},
IResult::Error(e) => {
debug!(target: "NodesResponse", "PingRequestPayload deserialize error: {:?}", e);
Err(Error::new(ErrorKind::Other,
format!("NodesResponsePayload deserialize error: {:?}", e)))
},
IResult::Done(_, payload) => {
Ok(payload)
}
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct NodesResponsePayload {
pub nodes: Vec<PackedNode>,
pub id: u64,
}
impl ToBytes for NodesResponsePayload {
fn to_bytes<'a>(&self, buf: (&'a mut [u8], usize)) -> Result<(&'a mut [u8], usize), GenError> {
do_gen!(buf,
gen_cond!(self.nodes.len() > 4, |buf| gen_error(buf, 0)) >>
gen_be_u8!(self.nodes.len() as u8) >>
gen_many_ref!(&self.nodes, |buf, node| PackedNode::to_bytes(node, buf)) >>
gen_be_u64!(self.id)
)
}
}
impl FromBytes for NodesResponsePayload {
named!(from_bytes<NodesResponsePayload>, do_parse!(
nodes_number: le_u8 >>
nodes: cond_reduce!(
nodes_number <= 4,
count!(PackedNode::from_bytes, nodes_number as usize)
) >>
id: be_u64 >>
eof!() >>
(NodesResponsePayload { nodes, id })
));
}
#[cfg(test)]
mod tests {
use toxcore::dht::packet::nodes_response::*;
use toxcore::dht::packet::DhtPacket;
use std::net::SocketAddr;
encode_decode_test!(
nodes_response_payload_encode_decode,
NodesResponsePayload { nodes: vec![
PackedNode::new(false, SocketAddr::V4("5.6.7.8:12345".parse().unwrap()), &gen_keypair().0)
], id: 42 }
);
dht_packet_encode_decode!(nodes_response_encode_decode, NodesResponse);
dht_packet_encrypt_decrypt!(
nodes_response_payload_encrypt_decrypt,
NodesResponse,
NodesResponsePayload { nodes: vec![
PackedNode::new(false, SocketAddr::V4("5.6.7.8:12345".parse().unwrap()), &gen_keypair().0)
], id: 42 }
);
dht_packet_encrypt_decrypt_invalid_key!(
nodes_response_payload_encrypt_decrypt_invalid_key,
NodesResponse,
NodesResponsePayload { nodes: vec![
PackedNode::new(false, SocketAddr::V4("5.6.7.8:12345".parse().unwrap()), &gen_keypair().0)
], id: 42 }
);
dht_packet_decode_invalid!(nodes_response_decode_invalid, NodesResponse);
}