From 332a654a87e4842434209c01b5c26a9f51af26fc Mon Sep 17 00:00:00 2001 From: Titouan Rigoudy Date: Wed, 11 May 2016 19:11:01 +0200 Subject: [PATCH] Implement most of the NAT traversal protocol, still no listening port. --- src/client.rs | 77 ++++++++++++++++++++++++++++++++--- src/proto/server/constants.rs | 1 + src/proto/server/request.rs | 50 +++++++++++++++++++++++ src/proto/server/response.rs | 6 +-- 4 files changed, 126 insertions(+), 8 deletions(-) diff --git a/src/client.rs b/src/client.rs index 90d6594..e8c2c21 100644 --- a/src/client.rs +++ b/src/client.rs @@ -48,13 +48,19 @@ enum LoginStatus { #[derive(Debug)] enum PeerState { + /// We are trying to establish a direct connection. Opening, + /// We are trying to establish a reverse connection. OpeningFirewalled, + /// We are waiting for a reverse connection to be established to us. + WaitingFirewalled, + /// The connection is open. Open } #[derive(Debug)] struct Peer { + user_name: String, ip: net::Ipv4Addr, port: u16, connection_type: String, @@ -327,12 +333,64 @@ impl Client { } fn handle_peer_connection_closed(&mut self, peer_id: usize) { - info!("Connection to peer {} has closed", peer_id); - match self.peers.remove(peer_id) { - None => error!("Unknown peer {}", peer_id), + let mut occupied_entry = match self.peers.entry(peer_id) { + None | Some(slab::Entry::Vacant(_)) => { + error!("Unknown peer connection {} has closed", peer_id); + return + }, + + Some(slab::Entry::Occupied(occupied_entry)) => occupied_entry + }; + + match occupied_entry.get_mut().state { + PeerState::Open => { + info!("Peer connection {} has closed", peer_id); + occupied_entry.remove(); + }, + + PeerState::WaitingFirewalled => { + error!( + "Peer connection {} has closed, was waiting: inconsistent", + peer_id + ); + occupied_entry.remove(); + }, + + PeerState::Opening => { + info!( + "Peer connection {} has been refused, trying reverse", + peer_id + ); - Some(peer) => { - // TODO if the peer was not connected, talk to the server + let peer = occupied_entry.get_mut(); + peer.state = PeerState::WaitingFirewalled; + + self.proto_tx.send(proto::Request::ServerRequest( + server::ServerRequest::ConnectToPeerRequest( + server::ConnectToPeerRequest { + token: peer.token, + user_name: peer.user_name.clone(), + connection_type: peer.connection_type.clone(), + } + ) + )).unwrap(); + }, + + PeerState::OpeningFirewalled => { + info!( + "Peer connection {} has been refused, cannot connect", + peer_id + ); + + let (peer, _) = occupied_entry.remove(); + self.proto_tx.send(proto::Request::ServerRequest( + server::ServerRequest::CannotConnectRequest( + server::CannotConnectRequest { + token: peer.token, + user_name: peer.user_name + } + ) + )).unwrap(); } } } @@ -353,6 +411,14 @@ impl Client { return }, + Some(peer @ &mut Peer{state: PeerState::WaitingFirewalled, ..}) => { + error!( + "Peer connection {} was waiting: {:?}", + peer_id, peer + ); + return + }, + Some(peer @ &mut Peer { state: PeerState::Opening, .. }) => { info!("Peer connection {} is now open: {:?}", peer_id, peer); // Mark it as open. @@ -430,6 +496,7 @@ impl Client { &mut self, response: server::ConnectToPeerResponse) { let peer = Peer { + user_name: response.user_name, ip: response.ip, port: response.port, connection_type: response.connection_type, diff --git a/src/proto/server/constants.rs b/src/proto/server/constants.rs index bb39207..109ee1d 100644 --- a/src/proto/server/constants.rs +++ b/src/proto/server/constants.rs @@ -15,3 +15,4 @@ pub const CODE_PARENT_MIN_SPEED: u32 = 83; pub const CODE_PARENT_SPEED_RATIO: u32 = 84; pub const CODE_WISHLIST_INTERVAL: u32 = 104; pub const CODE_ROOM_TICKERS: u32 = 113; +pub const CODE_CANNOT_CONNECT: u32 = 1001; diff --git a/src/proto/server/request.rs b/src/proto/server/request.rs index 0105008..c55440f 100644 --- a/src/proto/server/request.rs +++ b/src/proto/server/request.rs @@ -12,6 +12,8 @@ use super::super::packet::{MutPacket, WriteToPacket}; #[derive(Debug)] pub enum ServerRequest { + CannotConnectRequest(CannotConnectRequest), + ConnectToPeerRequest(ConnectToPeerRequest), LoginRequest(LoginRequest), PeerAddressRequest(PeerAddressRequest), RoomJoinRequest(RoomJoinRequest), @@ -25,6 +27,16 @@ pub enum ServerRequest { impl WriteToPacket for ServerRequest { fn write_to_packet(&self, packet: &mut MutPacket) -> io::Result<()> { match *self { + ServerRequest::CannotConnectRequest(ref request) => { + try!(packet.write_value(&CODE_CANNOT_CONNECT)); + try!(packet.write_value(request)); + }, + + ServerRequest::ConnectToPeerRequest(ref request) => { + try!(packet.write_value(&CODE_CONNECT_TO_PEER)); + try!(packet.write_value(request)); + }, + ServerRequest::LoginRequest(ref request) => { try!(packet.write_value(&CODE_LOGIN)); try!(packet.write_value(request)); @@ -74,6 +86,44 @@ fn md5_str(string: &str) -> String { hasher.result_str() } +/*================* + * CANNOT CONNECT * + *================*/ + +#[derive(Debug)] +pub struct CannotConnectRequest { + pub token: u32, + pub user_name: String, +} + +impl WriteToPacket for CannotConnectRequest { + fn write_to_packet(&self, packet: &mut MutPacket) -> io::Result<()> { + try!(packet.write_value(&self.token)); + try!(packet.write_value(&self.user_name)); + Ok(()) + } +} + +/*=================* + * CONNECT TO PEER * + *=================*/ + +#[derive(Debug)] +pub struct ConnectToPeerRequest { + pub token: u32, + pub user_name: String, + pub connection_type: String, +} + +impl WriteToPacket for ConnectToPeerRequest { + fn write_to_packet(&self, packet: &mut MutPacket) -> io::Result<()> { + try!(packet.write_value(&self.token)); + try!(packet.write_value(&self.user_name)); + try!(packet.write_value(&self.connection_type)); + Ok(()) + } +} + /*=======* * LOGIN * *=======*/ diff --git a/src/proto/server/response.rs b/src/proto/server/response.rs index 5824728..50df9eb 100644 --- a/src/proto/server/response.rs +++ b/src/proto/server/response.rs @@ -134,7 +134,7 @@ impl ReadFromPacket for ServerResponse { #[derive(Debug)] pub struct ConnectToPeerResponse { - pub username: String, + pub user_name: String, pub connection_type: String, pub ip: net::Ipv4Addr, pub port: u16, @@ -144,7 +144,7 @@ pub struct ConnectToPeerResponse { impl ReadFromPacket for ConnectToPeerResponse { fn read_from_packet(packet: &mut Packet) -> Result { - let username = try!(packet.read_value()); + let user_name = try!(packet.read_value()); let connection_type = try!(packet.read_value()); let ip = try!(packet.read_value()); let port = try!(packet.read_value()); @@ -152,7 +152,7 @@ impl ReadFromPacket for ConnectToPeerResponse { let is_privileged = try!(packet.read_value()); Ok(ConnectToPeerResponse { - username: username, + user_name: user_name, connection_type: connection_type, ip: ip, port: port,