use std::convert::Into;
use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
use std::time::{Duration, Instant};
use super::packets_array::*;
use crate::dht::ip_port::IsGlobal;
use tox_crypto::*;
use tox_packet::dht::*;
use crate::time::*;
pub const CRYPTO_SEND_PACKET_INTERVAL_MS: u64 = 1000;
pub const CRYPTO_SEND_PACKET_INTERVAL: Duration = Duration::from_millis(CRYPTO_SEND_PACKET_INTERVAL_MS);
pub const MAX_NUM_SENDPACKET_TRIES: u8 = 8;
pub const UDP_DIRECT_TIMEOUT: Duration = Duration::from_secs(8);
pub const DEFAULT_RTT: Duration = Duration::from_millis(1000);
pub const TCP_RTT: Duration = Duration::from_millis(500);
pub const PACKET_COUNTER_AVERAGE_INTERVAL_MS: u64 = 50;
pub const PACKET_COUNTER_AVERAGE_INTERVAL: Duration = Duration::from_millis(PACKET_COUNTER_AVERAGE_INTERVAL_MS);
pub const CONGESTION_QUEUE_ARRAY_SIZE: usize = 12;
pub const CONGESTION_LAST_SENT_ARRAY_SIZE: usize = CONGESTION_QUEUE_ARRAY_SIZE * 2;
pub const CRYPTO_PACKET_MIN_RATE: f64 = 4.0;
pub const CONGESTION_EVENT_TIMEOUT: Duration = Duration::from_secs(1);
pub const SEND_QUEUE_CLEARANCE_TIME: f64 = 2.0;
pub const CRYPTO_MIN_QUEUE_LENGTH: u32 = 64;
pub const REQUEST_PACKETS_COMPARE_CONSTANT: f64 = 0.125 * 100.0;
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum StatusPacket {
CookieRequest(CookieRequest),
CryptoHandshake(CryptoHandshake),
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct StatusPacketWithTime {
pub packet: StatusPacket,
pub sent_time: Instant,
pub num_sent: u8
}
impl StatusPacketWithTime {
pub fn new_cookie_request(packet: CookieRequest) -> StatusPacketWithTime {
StatusPacketWithTime {
packet: StatusPacket::CookieRequest(packet),
sent_time: clock_now(),
num_sent: 0
}
}
pub fn new_crypto_handshake(packet: CryptoHandshake) -> StatusPacketWithTime {
StatusPacketWithTime {
packet: StatusPacket::CryptoHandshake(packet),
sent_time: clock_now(),
num_sent: 0
}
}
fn is_time_elapsed(&self) -> bool {
clock_elapsed(self.sent_time) > CRYPTO_SEND_PACKET_INTERVAL
}
pub fn should_be_sent(&self) -> bool {
self.num_sent == 0 || self.is_time_elapsed() && self.num_sent < MAX_NUM_SENDPACKET_TRIES
}
pub fn is_timed_out(&self) -> bool {
self.num_sent >= MAX_NUM_SENDPACKET_TRIES && self.is_time_elapsed()
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ConnectionStatus {
CookieRequesting {
cookie_request_id: u64,
packet: StatusPacketWithTime,
},
HandshakeSending {
sent_nonce: Nonce,
packet: StatusPacketWithTime,
},
NotConfirmed {
sent_nonce: Nonce,
received_nonce: Nonce,
session_precomputed_key: PrecomputedKey,
packet: StatusPacketWithTime,
},
Established {
sent_nonce: Nonce,
received_nonce: Nonce,
session_precomputed_key: PrecomputedKey,
},
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SentPacket {
pub data: Vec<u8>,
pub sent_time: Instant,
pub requested: bool
}
impl SentPacket {
pub fn new(data: Vec<u8>) -> SentPacket {
SentPacket {
data,
sent_time: clock_now(),
requested: false
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct RecvPacket {
pub data: Vec<u8>
}
impl RecvPacket {
pub fn new(data: Vec<u8>) -> RecvPacket {
RecvPacket {
data
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct ConnectionAddr<T: Into<SocketAddr> + Copy> {
pub addr: T,
pub last_received_time: Instant,
}
impl<T: Into<SocketAddr> + Copy> ConnectionAddr<T> {
pub fn new(addr: T) -> Self {
ConnectionAddr {
addr,
last_received_time: clock_now(),
}
}
pub fn is_alive(&self) -> bool {
clock_elapsed(self.last_received_time) < UDP_DIRECT_TIMEOUT
}
pub fn addr(&self) -> SocketAddr {
self.addr.into()
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct CryptoConnection {
pub peer_real_pk: PublicKey,
pub peer_dht_pk: PublicKey,
pub session_sk: SecretKey,
pub session_pk: PublicKey,
pub status: ConnectionStatus,
pub udp_addr_v4: Option<ConnectionAddr<SocketAddrV4>>,
pub udp_addr_v6: Option<ConnectionAddr<SocketAddrV6>>,
pub udp_send_attempt_time: Option<Instant>,
pub send_array: PacketsArray<SentPacket>,
pub recv_array: PacketsArray<RecvPacket>,
pub rtt: Duration,
pub request_packet_sent_time: Option<Instant>,
pub stats_calculation_time: Instant,
pub packets_received: u32,
pub packets_sent: u32,
pub packets_resent: u32,
pub last_sendqueue_counter: u32,
pub last_send_array_sizes: [u32; CONGESTION_QUEUE_ARRAY_SIZE],
pub last_num_packets_sent: [u32; CONGESTION_LAST_SENT_ARRAY_SIZE],
pub last_num_packets_resent: [u32; CONGESTION_LAST_SENT_ARRAY_SIZE],
pub last_congestion_event: Option<Instant>,
pub packet_recv_rate: f64,
pub packet_send_rate: f64,
pub packet_send_rate_requested: f64,
}
impl CryptoConnection {
pub fn new(dht_precomputed_key: &PrecomputedKey, dht_pk: PublicKey, real_pk: PublicKey, peer_real_pk: PublicKey, peer_dht_pk: PublicKey) -> CryptoConnection {
let (session_pk, session_sk) = gen_keypair();
let cookie_request_id = random_u64();
let cookie_request_payload = CookieRequestPayload {
pk: real_pk,
id: cookie_request_id
};
let cookie_request = CookieRequest::new(dht_precomputed_key, &dht_pk, &cookie_request_payload);
let status = ConnectionStatus::CookieRequesting {
cookie_request_id,
packet: StatusPacketWithTime::new_cookie_request(cookie_request)
};
CryptoConnection {
peer_real_pk,
peer_dht_pk,
session_sk,
session_pk,
status,
udp_addr_v4: None,
udp_addr_v6: None,
udp_send_attempt_time: None,
send_array: PacketsArray::new(),
recv_array: PacketsArray::new(),
rtt: DEFAULT_RTT,
request_packet_sent_time: None,
stats_calculation_time: clock_now(),
packets_received: 0,
packets_sent: 0,
packets_resent: 0,
last_sendqueue_counter: 0,
last_send_array_sizes: [0; CONGESTION_QUEUE_ARRAY_SIZE],
last_num_packets_sent: [0; CONGESTION_LAST_SENT_ARRAY_SIZE],
last_num_packets_resent: [0; CONGESTION_LAST_SENT_ARRAY_SIZE],
last_congestion_event: None,
packet_recv_rate: 0.0,
packet_send_rate: CRYPTO_PACKET_MIN_RATE,
packet_send_rate_requested: CRYPTO_PACKET_MIN_RATE,
}
}
pub fn new_not_confirmed(
self_real_sk: &SecretKey,
peer_real_pk: PublicKey,
peer_dht_pk: PublicKey,
received_nonce: Nonce,
peer_session_pk: PublicKey,
cookie: EncryptedCookie,
symmetric_key: &secretbox::Key
) -> CryptoConnection {
let (session_pk, session_sk) = gen_keypair();
let sent_nonce = gen_nonce();
let our_cookie = Cookie::new(peer_real_pk, peer_dht_pk);
let our_encrypted_cookie = EncryptedCookie::new(symmetric_key, &our_cookie);
let handshake_payload = CryptoHandshakePayload {
base_nonce: sent_nonce,
session_pk,
cookie_hash: cookie.hash(),
cookie: our_encrypted_cookie,
};
let handshake = CryptoHandshake::new(&precompute(&peer_real_pk, self_real_sk), &handshake_payload, cookie);
let status = ConnectionStatus::NotConfirmed {
sent_nonce,
received_nonce,
session_precomputed_key: precompute(&peer_session_pk, &session_sk),
packet: StatusPacketWithTime::new_crypto_handshake(handshake)
};
CryptoConnection {
peer_real_pk,
peer_dht_pk,
session_sk,
session_pk,
status,
udp_addr_v4: None,
udp_addr_v6: None,
udp_send_attempt_time: None,
send_array: PacketsArray::new(),
recv_array: PacketsArray::new(),
rtt: DEFAULT_RTT,
request_packet_sent_time: None,
stats_calculation_time: clock_now(),
packets_received: 0,
packets_sent: 0,
packets_resent: 0,
last_sendqueue_counter: 0,
last_send_array_sizes: [0; CONGESTION_QUEUE_ARRAY_SIZE],
last_num_packets_sent: [0; CONGESTION_LAST_SENT_ARRAY_SIZE],
last_num_packets_resent: [0; CONGESTION_LAST_SENT_ARRAY_SIZE],
last_congestion_event: None,
packet_recv_rate: 0.0,
packet_send_rate: CRYPTO_PACKET_MIN_RATE,
packet_send_rate_requested: CRYPTO_PACKET_MIN_RATE,
}
}
pub fn packet_to_send(&mut self) -> Option<StatusPacket> {
match self.status {
ConnectionStatus::CookieRequesting { ref mut packet, .. }
| ConnectionStatus::HandshakeSending { ref mut packet, .. }
| ConnectionStatus::NotConfirmed { ref mut packet, .. } => {
if packet.should_be_sent() {
packet.num_sent += 1;
packet.sent_time = clock_now();
Some(packet.packet.clone())
} else {
None
}
},
ConnectionStatus::Established { .. } => None,
}
}
pub fn is_timed_out(&self) -> bool {
match self.status {
ConnectionStatus::CookieRequesting { ref packet, .. }
| ConnectionStatus::HandshakeSending { ref packet, .. }
| ConnectionStatus::NotConfirmed { ref packet, .. } => packet.is_timed_out(),
ConnectionStatus::Established { .. } => false, }
}
pub fn set_udp_addr(&mut self, addr: SocketAddr) {
match addr {
SocketAddr::V4(addr) => self.udp_addr_v4 = Some(ConnectionAddr::new(addr)),
SocketAddr::V6(addr) => self.udp_addr_v6 = Some(ConnectionAddr::new(addr)),
}
}
pub fn get_udp_addr_v4(&self) -> Option<SocketAddr> {
self.udp_addr_v4.as_ref().map(|addr| addr.addr())
}
pub fn get_udp_addr_v6(&self) -> Option<SocketAddr> {
self.udp_addr_v6.as_ref().map(|addr| addr.addr())
}
pub fn get_udp_addr(&self) -> Option<SocketAddr> {
if let Some(ref addr) = self.udp_addr_v6 {
if addr.is_alive() && !IsGlobal::is_global(&addr.addr().ip()) {
return Some(addr.addr());
}
}
if let Some(ref addr) = self.udp_addr_v4 {
if addr.is_alive() && !IsGlobal::is_global(&addr.addr().ip()) {
return Some(addr.addr());
}
}
if let Some(ref addr) = self.udp_addr_v6 {
if addr.is_alive() {
return Some(addr.addr());
}
}
if let Some(ref addr) = self.udp_addr_v4 {
if addr.is_alive() {
return Some(addr.addr());
}
}
if let Some(ref addr) = self.udp_addr_v6 {
return Some(addr.addr());
}
if let Some(ref addr) = self.udp_addr_v4 {
return Some(addr.addr());
}
None
}
pub fn update_udp_send_attempt_time(&mut self) {
self.udp_send_attempt_time = Some(clock_now())
}
pub fn is_udp_alive(&self) -> bool {
self.udp_addr_v4.as_ref().map_or(false, |addr| addr.is_alive()) ||
self.udp_addr_v6.as_ref().map_or(false, |addr| addr.is_alive())
}
pub fn udp_attempt_should_be_made(&self) -> bool {
self.udp_send_attempt_time
.map_or(true, |time| clock_elapsed(time) >= UDP_DIRECT_TIMEOUT / 2)
}
fn calculate_recv_rate(&mut self, now: Instant) {
let dt = now - self.stats_calculation_time;
self.packet_recv_rate = f64::from(self.packets_received) / (dt.as_secs() as f64 + f64::from(dt.subsec_millis()) / 1000.0);
}
fn calculate_send_rate(&mut self, now: Instant) {
let pos = self.last_sendqueue_counter as usize % CONGESTION_QUEUE_ARRAY_SIZE;
let n_p_pos = self.last_sendqueue_counter as usize % CONGESTION_LAST_SENT_ARRAY_SIZE;
self.last_sendqueue_counter = (self.last_sendqueue_counter + 1) %
(CONGESTION_QUEUE_ARRAY_SIZE * CONGESTION_LAST_SENT_ARRAY_SIZE) as u32;
let send_array_len = self.send_array.len();
self.last_send_array_sizes[pos] = send_array_len;
self.last_num_packets_sent[n_p_pos] = self.packets_sent;
self.last_num_packets_resent[n_p_pos] = self.packets_resent;
let sum = send_array_len as i32 - self.last_send_array_sizes[(pos + 1) % CONGESTION_QUEUE_ARRAY_SIZE] as i32;
const CONGESTION_MAX_DELAY: usize = CONGESTION_LAST_SENT_ARRAY_SIZE - CONGESTION_QUEUE_ARRAY_SIZE;
let delay = ((
self.rtt.as_secs() * 1000 +
u64::from(self.rtt.subsec_millis()) +
PACKET_COUNTER_AVERAGE_INTERVAL_MS / 2 ) / PACKET_COUNTER_AVERAGE_INTERVAL_MS) as usize;
let delay = delay.min(CONGESTION_MAX_DELAY);
let mut total_sent = 0;
let mut total_resent = 0;
for i in 0 .. CONGESTION_QUEUE_ARRAY_SIZE {
let i = (n_p_pos + (CONGESTION_MAX_DELAY - delay) + i) % CONGESTION_LAST_SENT_ARRAY_SIZE;
total_sent += self.last_num_packets_sent[i] as i32;
total_resent += self.last_num_packets_resent[i] as i32;
}
if sum > 0 {
total_sent -= sum;
} else if total_resent > -sum {
total_resent = -sum;
}
let coeff = 1000.0 / (CONGESTION_QUEUE_ARRAY_SIZE as f64 * PACKET_COUNTER_AVERAGE_INTERVAL_MS as f64);
let min_speed = (f64::from(total_sent) * coeff).max(CRYPTO_PACKET_MIN_RATE);
let min_speed_request = f64::from(total_sent + total_resent) * coeff;
let send_array_time = f64::from(send_array_len) / min_speed;
let packet_send_rate = if send_array_time > SEND_QUEUE_CLEARANCE_TIME && send_array_len > CRYPTO_MIN_QUEUE_LENGTH {
min_speed / (send_array_time / SEND_QUEUE_CLEARANCE_TIME)
} else if self.last_congestion_event.map_or(true, |time| (now - time) > CONGESTION_EVENT_TIMEOUT) {
min_speed * 1.2
} else {
min_speed * 0.9
};
let packet_send_rate = packet_send_rate.max(CRYPTO_PACKET_MIN_RATE);
let packet_send_rate_requested = min_speed_request * 1.2;
let packet_send_rate_requested = packet_send_rate_requested.max(packet_send_rate);
self.packet_send_rate = packet_send_rate;
self.packet_send_rate_requested = packet_send_rate_requested;
}
fn reset_congestion_counters(&mut self, now: Instant) {
self.packets_received = 0;
self.packets_sent = 0;
self.packets_resent = 0;
self.stats_calculation_time = now;
}
pub fn update_congestion_stats(&mut self) {
let now = clock_now();
self.calculate_recv_rate(now);
self.calculate_send_rate(now);
self.reset_congestion_counters(now);
}
pub fn request_packet_interval(&self) -> Duration {
let request_packet_interval = REQUEST_PACKETS_COMPARE_CONSTANT / ((f64::from(self.recv_array.len()) + 1.0) / (self.packet_recv_rate + 1.0));
let request_packet_interval = request_packet_interval.min(
CRYPTO_PACKET_MIN_RATE / self.packet_recv_rate * CRYPTO_SEND_PACKET_INTERVAL_MS as f64 + PACKET_COUNTER_AVERAGE_INTERVAL_MS as f64
);
let request_packet_interval = (request_packet_interval.round() as u64)
.max(PACKET_COUNTER_AVERAGE_INTERVAL_MS) .min(CRYPTO_SEND_PACKET_INTERVAL_MS); Duration::from_millis(request_packet_interval)
}
pub fn is_established(&self) -> bool {
matches!(self.status, ConnectionStatus::Established { .. })
}
pub fn is_not_confirmed(&self) -> bool {
matches!(self.status, ConnectionStatus::NotConfirmed { .. })
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn status_packet_should_be_sent() {
crypto_init().unwrap();
let mut packet = StatusPacketWithTime::new_cookie_request(CookieRequest {
pk: gen_keypair().0,
nonce: gen_nonce(),
payload: vec![42; 88]
});
assert!(packet.should_be_sent());
packet.num_sent += 1;
assert!(!packet.should_be_sent());
tokio::time::pause();
let now = clock_now();
let time = packet.sent_time + CRYPTO_SEND_PACKET_INTERVAL + Duration::from_secs(1);
tokio::time::advance(time - now).await;
assert!(packet.should_be_sent());
packet.num_sent += MAX_NUM_SENDPACKET_TRIES;
assert!(!packet.should_be_sent());
}
#[tokio::test]
async fn status_packet_is_timed_out() {
crypto_init().unwrap();
let mut packet = StatusPacketWithTime::new_cookie_request(CookieRequest {
pk: gen_keypair().0,
nonce: gen_nonce(),
payload: vec![42; 88]
});
assert!(!packet.is_timed_out());
packet.num_sent += MAX_NUM_SENDPACKET_TRIES;
tokio::time::pause();
let now = clock_now();
let time = packet.sent_time + CRYPTO_SEND_PACKET_INTERVAL + Duration::from_secs(1);
tokio::time::advance(time - now).await;
assert!(packet.is_timed_out());
}
#[test]
fn sent_packet_clone() {
crypto_init().unwrap();
let sent_packet = SentPacket::new(vec![42; 123]);
let sent_packet_c = sent_packet.clone();
assert_eq!(sent_packet_c, sent_packet);
}
#[test]
fn recv_packet_clone() {
crypto_init().unwrap();
let recv_packet = RecvPacket::new(vec![42; 123]);
let recv_packet_c = recv_packet.clone();
assert_eq!(recv_packet_c, recv_packet);
}
#[test]
fn crypto_connection_clone() {
crypto_init().unwrap();
let (dht_pk, dht_sk) = gen_keypair();
let (real_pk, _real_sk) = gen_keypair();
let (peer_dht_pk, _peer_dht_sk) = gen_keypair();
let (peer_real_pk, _peer_real_sk) = gen_keypair();
let dht_precomputed_key = precompute(&peer_dht_pk, &dht_sk);
let mut connection = CryptoConnection::new(&dht_precomputed_key, dht_pk, real_pk, peer_real_pk, peer_dht_pk);
let connection_c = connection.clone();
assert_eq!(connection_c, connection);
let crypto_handshake = CryptoHandshake {
cookie: EncryptedCookie {
nonce: secretbox::gen_nonce(),
payload: vec![42; 88]
},
nonce: gen_nonce(),
payload: vec![42; 248]
};
connection.status = ConnectionStatus::HandshakeSending {
sent_nonce: gen_nonce(),
packet: StatusPacketWithTime::new_crypto_handshake(crypto_handshake.clone())
};
let connection_c = connection.clone();
assert_eq!(connection_c, connection);
connection.status = ConnectionStatus::NotConfirmed {
sent_nonce: gen_nonce(),
received_nonce: gen_nonce(),
session_precomputed_key: precompute(&gen_keypair().0, &gen_keypair().1),
packet: StatusPacketWithTime::new_crypto_handshake(crypto_handshake),
};
let connection_c = connection.clone();
assert_eq!(connection_c, connection);
connection.status = ConnectionStatus::Established {
sent_nonce: gen_nonce(),
received_nonce: gen_nonce(),
session_precomputed_key: precompute(&gen_keypair().0, &gen_keypair().1),
};
let connection_c = connection.clone();
assert_eq!(connection_c, connection);
}
#[tokio::test]
async fn update_congestion_stats() {
crypto_init().unwrap();
let (dht_pk, dht_sk) = gen_keypair();
let (real_pk, _real_sk) = gen_keypair();
let (peer_dht_pk, _peer_dht_sk) = gen_keypair();
let (peer_real_pk, _peer_real_sk) = gen_keypair();
let dht_precomputed_key = precompute(&peer_dht_pk, &dht_sk);
let mut connection = CryptoConnection::new(&dht_precomputed_key, dht_pk, real_pk, peer_real_pk, peer_dht_pk);
tokio::time::pause();
let now = clock_now();
connection.stats_calculation_time = now;
connection.packets_received = 300;
connection.packets_sent = 200;
connection.packets_resent = 100;
let delay = PACKET_COUNTER_AVERAGE_INTERVAL;
tokio::time::advance(delay).await;
connection.update_congestion_stats();
assert_eq!(connection.packets_received, 0);
assert_eq!(connection.packets_sent, 0);
assert_eq!(connection.packets_resent, 0);
assert_eq!(connection.stats_calculation_time, now + delay);
assert!((connection.packet_recv_rate - 6000.0).abs() < 200.0);
}
#[test]
fn request_packet_interval() {
crypto_init().unwrap();
let (dht_pk, dht_sk) = gen_keypair();
let (real_pk, _real_sk) = gen_keypair();
let (peer_dht_pk, _peer_dht_sk) = gen_keypair();
let (peer_real_pk, _peer_real_sk) = gen_keypair();
let dht_precomputed_key = precompute(&peer_dht_pk, &dht_sk);
let mut connection = CryptoConnection::new(&dht_precomputed_key, dht_pk, real_pk, peer_real_pk, peer_dht_pk);
connection.packet_recv_rate = 500.0;
for &(len, interval) in &[
(80, 58),
(90, 58),
(100, 58),
(110, 56),
(120, 52),
(130, 50),
(140, 50),
(150, 50),
] {
connection.recv_array.buffer_end = len;
assert_eq!(connection.request_packet_interval().subsec_millis(), interval);
}
}
#[test]
fn is_established() {
crypto_init().unwrap();
let (dht_pk, dht_sk) = gen_keypair();
let (real_pk, _real_sk) = gen_keypair();
let (peer_dht_pk, _peer_dht_sk) = gen_keypair();
let (peer_real_pk, _peer_real_sk) = gen_keypair();
let dht_precomputed_key = precompute(&peer_dht_pk, &dht_sk);
let mut connection = CryptoConnection::new(&dht_precomputed_key, dht_pk, real_pk, peer_real_pk, peer_dht_pk);
connection.status = ConnectionStatus::Established {
sent_nonce: gen_nonce(),
received_nonce: gen_nonce(),
session_precomputed_key: precompute(&gen_keypair().0, &gen_keypair().1),
};
assert!(!connection.is_not_confirmed());
assert!(connection.is_established());
}
#[test]
fn is_not_confirmed() {
crypto_init().unwrap();
let (dht_pk, dht_sk) = gen_keypair();
let (real_pk, _real_sk) = gen_keypair();
let (peer_dht_pk, _peer_dht_sk) = gen_keypair();
let (peer_real_pk, _peer_real_sk) = gen_keypair();
let dht_precomputed_key = precompute(&peer_dht_pk, &dht_sk);
let mut connection = CryptoConnection::new(&dht_precomputed_key, dht_pk, real_pk, peer_real_pk, peer_dht_pk);
let crypto_handshake = CryptoHandshake {
cookie: EncryptedCookie {
nonce: secretbox::gen_nonce(),
payload: vec![42; 88]
},
nonce: gen_nonce(),
payload: vec![42; 248]
};
connection.status = ConnectionStatus::NotConfirmed {
sent_nonce: gen_nonce(),
received_nonce: gen_nonce(),
session_precomputed_key: precompute(&gen_keypair().0, &gen_keypair().1),
packet: StatusPacketWithTime::new_crypto_handshake(crypto_handshake),
};
assert!(connection.is_not_confirmed());
assert!(!connection.is_established());
}
#[test]
fn set_get_udp_addr_v4() {
crypto_init().unwrap();
let (dht_pk, dht_sk) = gen_keypair();
let (real_pk, _real_sk) = gen_keypair();
let (peer_dht_pk, _peer_dht_sk) = gen_keypair();
let (peer_real_pk, _peer_real_sk) = gen_keypair();
let dht_precomputed_key = precompute(&peer_dht_pk, &dht_sk);
let mut connection = CryptoConnection::new(&dht_precomputed_key, dht_pk, real_pk, peer_real_pk, peer_dht_pk);
let addr = "127.0.0.1:12345".parse().unwrap();
connection.set_udp_addr(addr);
assert_eq!(connection.get_udp_addr_v4(), Some(addr));
}
#[test]
fn set_get_udp_addr_v6() {
crypto_init().unwrap();
let (dht_pk, dht_sk) = gen_keypair();
let (real_pk, _real_sk) = gen_keypair();
let (peer_dht_pk, _peer_dht_sk) = gen_keypair();
let (peer_real_pk, _peer_real_sk) = gen_keypair();
let dht_precomputed_key = precompute(&peer_dht_pk, &dht_sk);
let mut connection = CryptoConnection::new(&dht_precomputed_key, dht_pk, real_pk, peer_real_pk, peer_dht_pk);
let addr = "[::]:12345".parse().unwrap();
connection.set_udp_addr(addr);
assert_eq!(connection.get_udp_addr_v6(), Some(addr));
}
#[test]
fn get_udp_addr_alive_ipv6_lan() {
crypto_init().unwrap();
let (dht_pk, dht_sk) = gen_keypair();
let (real_pk, _real_sk) = gen_keypair();
let (peer_dht_pk, _peer_dht_sk) = gen_keypair();
let (peer_real_pk, _peer_real_sk) = gen_keypair();
let dht_precomputed_key = precompute(&peer_dht_pk, &dht_sk);
let mut connection = CryptoConnection::new(&dht_precomputed_key, dht_pk, real_pk, peer_real_pk, peer_dht_pk);
let addr_v4 = "192.168.0.1:12345".parse().unwrap();
let addr_v6 = "[FE80::1111]:12345".parse().unwrap();
connection.set_udp_addr(addr_v4);
connection.set_udp_addr(addr_v6);
assert_eq!(connection.get_udp_addr(), Some(addr_v6));
}
#[test]
fn get_udp_addr_alive_ipv4_lan() {
crypto_init().unwrap();
let (dht_pk, dht_sk) = gen_keypair();
let (real_pk, _real_sk) = gen_keypair();
let (peer_dht_pk, _peer_dht_sk) = gen_keypair();
let (peer_real_pk, _peer_real_sk) = gen_keypair();
let dht_precomputed_key = precompute(&peer_dht_pk, &dht_sk);
let mut connection = CryptoConnection::new(&dht_precomputed_key, dht_pk, real_pk, peer_real_pk, peer_dht_pk);
let addr_v4 = "192.168.0.1:12345".parse().unwrap();
let addr_v6 = "[2606::1111]:12345".parse().unwrap();
connection.set_udp_addr(addr_v4);
connection.set_udp_addr(addr_v6);
assert_eq!(connection.get_udp_addr(), Some(addr_v4));
}
#[test]
fn get_udp_addr_alive_ipv6() {
crypto_init().unwrap();
let (dht_pk, dht_sk) = gen_keypair();
let (real_pk, _real_sk) = gen_keypair();
let (peer_dht_pk, _peer_dht_sk) = gen_keypair();
let (peer_real_pk, _peer_real_sk) = gen_keypair();
let dht_precomputed_key = precompute(&peer_dht_pk, &dht_sk);
let mut connection = CryptoConnection::new(&dht_precomputed_key, dht_pk, real_pk, peer_real_pk, peer_dht_pk);
let addr_v4 = "1.2.3.4:12345".parse().unwrap();
let addr_v6 = "[2606::1111]:12345".parse().unwrap();
connection.set_udp_addr(addr_v4);
connection.set_udp_addr(addr_v6);
assert_eq!(connection.get_udp_addr(), Some(addr_v6));
}
#[tokio::test]
async fn get_udp_addr_alive_ipv4() {
crypto_init().unwrap();
let (dht_pk, dht_sk) = gen_keypair();
let (real_pk, _real_sk) = gen_keypair();
let (peer_dht_pk, _peer_dht_sk) = gen_keypair();
let (peer_real_pk, _peer_real_sk) = gen_keypair();
let dht_precomputed_key = precompute(&peer_dht_pk, &dht_sk);
let mut connection = CryptoConnection::new(&dht_precomputed_key, dht_pk, real_pk, peer_real_pk, peer_dht_pk);
let addr_v4 = "1.2.3.4:12345".parse().unwrap();
let addr_v6 = "[2606::1111]:12345".parse().unwrap();
connection.set_udp_addr(addr_v4);
tokio::time::pause();
tokio::time::advance(UDP_DIRECT_TIMEOUT + Duration::from_secs(1)).await;
connection.set_udp_addr(addr_v6);
assert_eq!(connection.get_udp_addr(), Some(addr_v6));
}
#[tokio::test]
async fn get_udp_addr_ipv6() {
crypto_init().unwrap();
let (dht_pk, dht_sk) = gen_keypair();
let (real_pk, _real_sk) = gen_keypair();
let (peer_dht_pk, _peer_dht_sk) = gen_keypair();
let (peer_real_pk, _peer_real_sk) = gen_keypair();
let dht_precomputed_key = precompute(&peer_dht_pk, &dht_sk);
let mut connection = CryptoConnection::new(&dht_precomputed_key, dht_pk, real_pk, peer_real_pk, peer_dht_pk);
let addr_v4 = "1.2.3.4:12345".parse().unwrap();
let addr_v6 = "[2606::1111]:12345".parse().unwrap();
connection.set_udp_addr(addr_v4);
connection.set_udp_addr(addr_v6);
tokio::time::pause();
tokio::time::advance(UDP_DIRECT_TIMEOUT + Duration::from_secs(1)).await;
assert_eq!(connection.get_udp_addr(), Some(addr_v6));
}
#[tokio::test]
async fn get_udp_addr_ipv4() {
crypto_init().unwrap();
let (dht_pk, dht_sk) = gen_keypair();
let (real_pk, _real_sk) = gen_keypair();
let (peer_dht_pk, _peer_dht_sk) = gen_keypair();
let (peer_real_pk, _peer_real_sk) = gen_keypair();
let dht_precomputed_key = precompute(&peer_dht_pk, &dht_sk);
let mut connection = CryptoConnection::new(&dht_precomputed_key, dht_pk, real_pk, peer_real_pk, peer_dht_pk);
let addr_v4 = "1.2.3.4:12345".parse().unwrap();
connection.set_udp_addr(addr_v4);
tokio::time::pause();
tokio::time::advance(UDP_DIRECT_TIMEOUT + Duration::from_secs(1)).await;
assert_eq!(connection.get_udp_addr(), Some(addr_v4));
}
#[test]
fn get_udp_addr_none() {
crypto_init().unwrap();
let (dht_pk, dht_sk) = gen_keypair();
let (real_pk, _real_sk) = gen_keypair();
let (peer_dht_pk, _peer_dht_sk) = gen_keypair();
let (peer_real_pk, _peer_real_sk) = gen_keypair();
let dht_precomputed_key = precompute(&peer_dht_pk, &dht_sk);
let connection = CryptoConnection::new(&dht_precomputed_key, dht_pk, real_pk, peer_real_pk, peer_dht_pk);
assert_eq!(connection.get_udp_addr(), None);
}
}