commit: | 2f3b59f9022c973a34603ce6a6cdac8a43f8ec61 |
author: | Trevor Bentley |
committer: | Trevor Bentley |
date: | Thu May 23 17:40:38 2019 +0200 |
parents: | ff034bf66c0afe8dc4eda96f08e201237142dd0e |
diff --git a/src/comm.rs b/src/comm.rs line changes: +20/-7 index ec8186f..cf8c472 --- a/src/comm.rs +++ b/src/comm.rs
@@ -30,7 +30,7 @@ where T: std::ops::DerefMut<Target = U>, let packet_len = hdr.len as usize; if conn.read_buf_used < header_size + packet_len { if header_size + packet_len > PACKET_BUF_SIZE { - panic!("oversized packet"); + return Err(OssuaryError::InvalidPacket("Oversized packet".into())); } return Err(OssuaryError::WouldBlock(bytes_read)); }
@@ -183,16 +183,29 @@ impl OssuaryConnection { Ok((pkt, bytes)) => { bytes_read += bytes; if pkt.header.msg_id != self.remote_msg_id { - let msg_id = pkt.header.msg_id; - println!("Message gap detected. Restarting connection. ({} != {})", - msg_id, self.remote_msg_id); - println!("Server: {}", self.is_server()); - self.reset_state(None); - return Err(OssuaryError::InvalidPacket("Message ID mismatch".into())) + match pkt.kind() { + PacketType::Reset => {}, + _ => { + let msg_id = pkt.header.msg_id; + println!("Message gap detected. Restarting connection. ({} != {})", + msg_id, self.remote_msg_id); + self.reset_state(None); + return Err(OssuaryError::InvalidPacket("Message ID mismatch".into())) + }, + } } self.remote_msg_id = pkt.header.msg_id + 1; match pkt.kind() { + PacketType::Reset => { + self.reset_state(None); + self.state = ConnectionState::Resetting(false); + return Err(OssuaryError::ConnectionReset(bytes_read)); + }, + PacketType::Disconnect => { + self.reset_state(Some(OssuaryError::ConnectionFailed)); + return Err(OssuaryError::ConnectionFailed); + }, PacketType::EncryptedData => { match interpret_packet_extra::<EncryptedPacket>(&pkt) { Ok((data_pkt, rest)) => {
diff --git a/src/connection.rs b/src/connection.rs line changes: +35/-23 index 7e4b929..4dec8b5 --- a/src/connection.rs +++ b/src/connection.rs
@@ -5,6 +5,21 @@ use rand::RngCore; use rand::rngs::OsRng; impl OssuaryConnection { + fn generate_session_material() -> Result<SessionKeyMaterial, OssuaryError> { + let mut rng = OsRng::new().expect("RNG not available."); + let sec_key = EphemeralSecret::new(&mut rng); + let pub_key = EphemeralPublic::from(&sec_key); + let mut nonce: [u8; NONCE_LEN] = [0; NONCE_LEN]; + rng.fill_bytes(&mut nonce); + + Ok(SessionKeyMaterial { + secret: Some(sec_key), + public: *pub_key.as_bytes(), + nonce: nonce, + session: None, + }) + } + /// Allocate a new OssuaryConnection. /// /// `conn_type` is a [`ConnectionType`] indicating whether this instance
@@ -14,22 +29,13 @@ impl OssuaryConnection { /// used for host authentication. If `None` is provided, a keypair will /// be generated for the lifetime of this connection object. pub fn new(conn_type: ConnectionType, auth_secret_key: Option<&[u8]>) -> Result<OssuaryConnection, OssuaryError> { - //let mut rng = thread_rng(); let mut rng = OsRng::new().expect("RNG not available."); - let sec_key = EphemeralSecret::new(&mut rng); - let pub_key = EphemeralPublic::from(&sec_key); let mut challenge: [u8; CHALLENGE_LEN] = [0; CHALLENGE_LEN]; - let mut nonce: [u8; NONCE_LEN] = [0; NONCE_LEN]; rng.fill_bytes(&mut challenge); - rng.fill_bytes(&mut nonce); - let key = SessionKeyMaterial { - secret: Some(sec_key), - public: *pub_key.as_bytes(), - nonce: nonce, - session: None, - }; + let key = OssuaryConnection::generate_session_material()?; + let (auth_sec, auth_pub) = match auth_secret_key { Some(s) => { // Use the given secret key
@@ -73,6 +79,14 @@ impl OssuaryConnection { }) } + /// Get the initial state machine state of this connection + pub(crate) fn initial_state(&self) -> ConnectionState { + match self.conn_type { + ConnectionType::Client => ConnectionState::ClientSendHandshake, + _ => ConnectionState::ServerWaitHandshake(std::time::SystemTime::now()), + } + } + /// Reset the context back to its default state. /// /// If `permanent_err` is None, this connection can be re-established by
@@ -87,7 +101,7 @@ impl OssuaryConnection { /// connection, such as when the client's key is not authorized. /// pub(crate) fn reset_state(&mut self, permanent_err: Option<OssuaryError>) { - self.local_key = Default::default(); + self.local_key = OssuaryConnection::generate_session_material().unwrap_or_default(); self.remote_key = None; self.local_msg_id = 0; self.remote_msg_id = 0;
@@ -96,20 +110,18 @@ impl OssuaryConnection { self.read_buf_used = 0; self.write_buf = [0u8; PACKET_BUF_SIZE]; self.write_buf_used = 0; - self.state = match permanent_err { - None => { - match self.conn_type { - ConnectionType::Client => ConnectionState::ClientSendHandshake, - _ => ConnectionState::ServerWaitHandshake(std::time::SystemTime::now()), - } - }, - Some(e) => { - ConnectionState::Failed(e) - } + self.reset_count += 1; + let perm_error = match self.reset_count { + c if c < MAX_RESET_COUNT => permanent_err, + _ => Some(OssuaryError::ConnectionFailed), + }; + self.state = match perm_error { + None => ConnectionState::Resetting(true), + Some(e) => ConnectionState::Failing(e), }; } /// Whether this context represents a server (as opposed to a client). - pub(crate) fn is_server(&self) -> bool { + pub fn is_server(&self) -> bool { match self.conn_type { ConnectionType::Client => false, _ => true,
diff --git a/src/error.rs b/src/error.rs line changes: +8/-7 index 5646ad8..29ab99b --- a/src/error.rs +++ b/src/error.rs
@@ -1,5 +1,6 @@ use crate::*; +#[derive(Clone, PartialEq)] /// Error produced by Ossuary or one of its dependencies pub enum OssuaryError { /// A problem with I/O read or writes.
@@ -7,7 +8,7 @@ pub enum OssuaryError { /// An Io error is most likely raised when using an input or output buffer /// that is more complex than a simple in-memory buffer, such as a /// [`std::net::TcpStream`] - Io(std::io::Error), + Io(String), /// A buffer cannot complete a read/write without blocking. ///
@@ -54,7 +55,7 @@ pub enum OssuaryError { /// /// This error likely indicates a sync or corruption error in the data /// stream, and will trigger a connection reset. - Unpack(core::array::TryFromSliceError), + Unpack(String), /// Error reading from random number generator NoRandomSource,
@@ -109,7 +110,7 @@ pub enum OssuaryError { /// fluke, such as momentary corruption or a sync error. Reconnection with /// the same context may be possible. This must be handled by returning to /// the handshake loop. - ConnectionReset, + ConnectionReset(usize), /// The connection has reset, and reconnection is not suggested. ///
@@ -131,10 +132,10 @@ impl std::fmt::Debug for OssuaryError { OssuaryError::NoRandomSource => write!(f, "OssuaryError::NoRandomSource"), OssuaryError::KeySize(_,_) => write!(f, "OssuaryError::KeySize"), OssuaryError::InvalidKey => write!(f, "OssuaryError::InvalidKey"), - OssuaryError::InvalidPacket(_) => write!(f, "OssuaryError::InvalidPacket"), + OssuaryError::InvalidPacket(m) => write!(f, "OssuaryError::InvalidPacket: {}", m), OssuaryError::InvalidStruct => write!(f, "OssuaryError::InvalidStruct"), OssuaryError::InvalidSignature => write!(f, "OssuaryError::InvalidSignature"), - OssuaryError::ConnectionReset => write!(f, "OssuaryError::ConnectionReset"), + OssuaryError::ConnectionReset(_) => write!(f, "OssuaryError::ConnectionReset"), OssuaryError::ConnectionFailed => write!(f, "OssuaryError::ConnectionFailed"), OssuaryError::UntrustedServer(_) => write!(f, "OssuaryError::UntrustedServer"), OssuaryError::DecryptionFailed => write!(f, "OssuaryError::DecryptionFailed"),
@@ -145,13 +146,13 @@ impl From<std::io::Error> for OssuaryError { fn from(error: std::io::Error) -> Self { match error.kind() { std::io::ErrorKind::WouldBlock => OssuaryError::WouldBlock(0), - _ => OssuaryError::Io(error), + _ => OssuaryError::Io(error.to_string()), } } } impl From<core::array::TryFromSliceError> for OssuaryError { fn from(error: core::array::TryFromSliceError) -> Self { - OssuaryError::Unpack(error) + OssuaryError::Unpack(error.to_string()) } } impl From<ed25519_dalek::SignatureError> for OssuaryError {
diff --git a/src/handshake.rs b/src/handshake.rs line changes: +84/-31 index e2eb470..1b68725 --- a/src/handshake.rs +++ b/src/handshake.rs
@@ -188,6 +188,8 @@ impl OssuaryConnection { } let written = match self.state { // No-op states + ConnectionState::Failed(_) | + ConnectionState::ResetWait | ConnectionState::Encrypted | ConnectionState::ClientRaiseUntrustedServer | ConnectionState::ClientWaitServerApproval => {0},
@@ -203,6 +205,7 @@ impl OssuaryConnection { let pkt: ResetPacket = Default::default(); w = write_packet(self, &mut buf, struct_as_slice(&pkt), PacketType::Reset)?; + self.local_msg_id = 0; self.reset_state(None); } }
@@ -332,11 +335,35 @@ impl OssuaryConnection { w }, - ConnectionState::Failed(ref _e) => { - // TODO: fail - unimplemented!(); + ConnectionState::Failing(_) => { + // Tell remote host to disconnect + let pkt: ResetPacket = Default::default(); + let w = write_packet(self, &mut buf, struct_as_slice(&pkt), + PacketType::Disconnect)?; + w }, + + ConnectionState::Resetting(initial) => { + // Tell remote host to reset + let pkt: ResetPacket = Default::default(); + let w = write_packet(self, &mut buf, struct_as_slice(&pkt), + PacketType::Reset)?; + self.local_msg_id = 0; + self.state = match initial { + true => ConnectionState::ResetWait, + false => self.initial_state(), + }; + w + } }; + + // Finalize failure state if failing + match self.state { + ConnectionState::Failing(ref e) => { + self.state = ConnectionState::Failed(e.clone()); + }, + _ => {}, + } Ok(written) } pub fn recv_handshake<T,U>(&mut self, buf: T) -> Result<usize, OssuaryError>
@@ -351,7 +378,8 @@ impl OssuaryConnection { // Wait for response, with timeout if let Ok(dur) = t.elapsed() { if dur.as_secs() > MAX_HANDSHAKE_WAIT_TIME { - return Err(OssuaryError::ConnectionReset); + self.reset_state(None); + return Err(OssuaryError::ConnectionReset(0)); } } },
@@ -364,15 +392,21 @@ impl OssuaryConnection { return Err(OssuaryError::WouldBlock(b)); } Err(e) => { - self.reset_state(None); + self.reset_state(Some(e.clone())); return Err(e); } }; match pkt.kind() { PacketType::Reset => { - self.reset_state(None); - return Err(OssuaryError::ConnectionReset); + match self.state { + ConnectionState::ResetWait => {}, + _ => { + self.reset_state(None); + self.state = ConnectionState::Resetting(false); + return Err(OssuaryError::ConnectionReset(bytes_read)); + }, + } }, PacketType::Disconnect => { self.reset_state(Some(OssuaryError::ConnectionFailed));
@@ -382,15 +416,27 @@ impl OssuaryConnection { } if pkt.header.msg_id != self.remote_msg_id { - println!("Message gap detected. Restarting connection."); - println!("Server: {}", self.is_server()); - self.reset_state(None); - return Err(OssuaryError::InvalidPacket("Message ID does not match".into())); + match pkt.kind() { + PacketType::Reset => {}, + _ => { + match self.state { + ConnectionState::ResetWait => {}, + _ => { + println!("Message gap detected. Restarting connection."); + self.reset_state(None); + return Err(OssuaryError::InvalidPacket("Message ID does not match".into())); + }, + } + }, + } } self.remote_msg_id = pkt.header.msg_id + 1; match self.state { // no-op states + ConnectionState::Failing(_) | + ConnectionState::Failed(_) | + ConnectionState::Resetting(_) | ConnectionState::ClientRaiseUntrustedServer | ConnectionState::ClientWaitServerApproval => {},
@@ -457,7 +503,13 @@ impl OssuaryConnection { }; let mut pt: &mut [u8] = &mut plaintext; // note: pt is consumed by decrypt_to_bytes - let _ = decrypt_to_bytes(session, &nonce, &inner_pkt.subpacket, &mut pt)?; + match decrypt_to_bytes(session, &nonce, &inner_pkt.subpacket, &mut pt) { + Ok(_) => {}, + Err(e) => { + self.reset_state(None); + return Err(e); + } + } if let Ok(enc_pkt) = ServerEncryptedHandshakePacket::from_bytes(&plaintext) { let mut chal: [u8; CHALLENGE_LEN] = [0u8; CHALLENGE_LEN]; let mut sig: [u8; SIGNATURE_LEN] = [0u8; SIGNATURE_LEN];
@@ -548,7 +600,13 @@ impl OssuaryConnection { }; let mut pt: &mut [u8] = &mut plaintext; // note: pt is consumed by decrypt_to_bytes - let _ = decrypt_to_bytes(session, &nonce, &inner_pkt.subpacket, &mut pt)?; + match decrypt_to_bytes(session, &nonce, &inner_pkt.subpacket, &mut pt) { + Ok(_) => {}, + Err(e) => { + self.reset_state(None); + return Err(e); + } + } if let Ok(enc_pkt) = ClientEncryptedAuthenticationPacket::from_bytes(&plaintext) { let mut sig: [u8; SIGNATURE_LEN] = [0u8; SIGNATURE_LEN]; sig.copy_from_slice(&enc_pkt.signature);
@@ -615,11 +673,18 @@ impl OssuaryConnection { } }, - ConnectionState::Failed(ref _e) => { - // TODO: fail - unimplemented!(); - }, - + ConnectionState::ResetWait => { + match pkt.kind() { + PacketType::Reset => { + self.remote_msg_id = 0; + self.state = match self.conn_type { + ConnectionType::Client => ConnectionState::ClientSendHandshake, + _ => ConnectionState::ServerWaitHandshake(std::time::SystemTime::now()), + } + }, + _ => {}, + } + } }; Ok(bytes_read) }
@@ -629,21 +694,9 @@ impl OssuaryConnection { /// /// pub fn handshake_done(&mut self) -> Result<bool, OssuaryError> { - let failed = match self.state { - ConnectionState::Failed(_) => true, - _ => false, - }; - if failed { - let mut new_state = ConnectionState::Failed(OssuaryError::ConnectionFailed); - std::mem::swap(&mut self.state, &mut new_state); - match new_state { - ConnectionState::Failed(e) => return Err(e), - _ => return Err(OssuaryError::ConnectionFailed), - } - } match self.state { ConnectionState::Encrypted => Ok(true), - ConnectionState::Failed(ref _e) => Err(OssuaryError::ConnectionFailed), + ConnectionState::Failed(ref e) => Err(e.clone()), ConnectionState::ClientRaiseUntrustedServer => { self.state = ConnectionState::ClientWaitServerApproval; let mut key: Vec<u8> = Vec::new();
diff --git a/src/lib.rs b/src/lib.rs line changes: +33/-3 index 26e37fe..bd098d8 --- a/src/lib.rs +++ b/src/lib.rs
@@ -125,8 +125,6 @@ // // TODO // - consider all unexpected packet types to be errors -// - ensure that a reset on one end always sends a reset to the other -// - limit connection retries // - tests should check their received strings // - rustdoc everything //
@@ -155,6 +153,9 @@ const PROTOCOL_VERSION: u8 = 1u8; // Maximum time to wait (in seconds) for a handshake response const MAX_HANDSHAKE_WAIT_TIME: u64 = 3u64; +// Maximum number of times a connection can reset before a permanent failure. +const MAX_RESET_COUNT: usize = 5; + // Size of the random data to be signed by client const CHALLENGE_LEN: usize = 32;
@@ -318,7 +319,34 @@ enum ConnectionState { /// Connection is established, encrypted, and optionally authenticated. Encrypted, - /// Connection has failed because of the associated error. + /// Connection has temporarily failed and will be reset + /// + /// An error occurred that might be recoverable. A reset packet will be + /// sent to the remote host to inform it to reset as well. + /// + /// Parameter is true if this side is initiating the reset, false if this + /// side is responding to a received reset. + Resetting(bool), + + /// Waiting for other side of connection to confirm reset + /// + /// The local host has sent a reset packet to the remote host, and is + /// waiting for the remote host to confirm that it has reset its state. + /// This is a temporary holding state to ensure that all packets that + /// were on the wire at the time of the error are received before a + /// new connection attempt is made. + ResetWait, + + /// Connection has failed permanently because of the associated error + /// + /// The connection is known to have failed on the local side, but the + /// failure has not yet been communicated to the remote host. + Failing(OssuaryError), + + /// Connection has failed permanently + /// + /// Both hosts are informed of the failure, and the connection will not be + /// recovered. Failed(OssuaryError), }
@@ -399,6 +427,7 @@ pub struct OssuaryConnection { read_buf_used: usize, write_buf: [u8; PACKET_BUF_SIZE], write_buf_used: usize, + reset_count: usize, } impl Default for OssuaryConnection { fn default() -> Self {
@@ -416,6 +445,7 @@ impl Default for OssuaryConnection { read_buf_used: 0, write_buf: [0u8; PACKET_BUF_SIZE], write_buf_used: 0, + reset_count: 0, } } }
diff --git a/tests/basic.rs b/tests/basic.rs line changes: +1/-1 index ac26f63..9b87ca7 --- a/tests/basic.rs +++ b/tests/basic.rs
@@ -26,7 +26,7 @@ where T: std::io::Read + std::io::Write { match conn.recv_handshake(&mut stream) { Ok(_) => break, Err(OssuaryError::WouldBlock(_)) => {}, - _ => panic!("Handshake failed."), + Err(e) => panic!("Handshake failed: {:?}", e), } } }
diff --git a/tests/corruption.rs b/tests/corruption.rs line changes: +160/-0 index 0000000..8d9dffe --- /dev/null +++ b/tests/corruption.rs
@@ -0,0 +1,160 @@ +use ossuary::{OssuaryConnection, ConnectionType}; +use ossuary::OssuaryError; + +#[test] +fn corruption() { + #[derive(Debug)] + enum Corruption { + ClientKey, + ClientNonce, + ClientChal, + ClientAuth, + ClientInvalidPkt, + ServerKey, + ServerNonce, + ServerAuth, + ServerInvalidPkt, + }; + + // Corruption test tuple format: + // (test type, loop iteration, byte offset, byte value, expected recv error, permanent) + let corruptions = [ + // loop iteration 0: Client -> Server + // 8 bytes network header, 8 bytes packet header, 32 bytes key, 12 bytes nonce, 32 bytes challenge + (Corruption::ClientInvalidPkt, 0, 0, 0xaa, OssuaryError::InvalidPacket("Oversized packet".into()), true), + (Corruption::ClientInvalidPkt, 0, 2, 0xaa, OssuaryError::InvalidPacket("Message ID does not match".into()), true), + (Corruption::ClientInvalidPkt, 0, 3, 0xaa, OssuaryError::InvalidPacket("Message ID does not match".into()), true), + (Corruption::ClientInvalidPkt, 0, 4, 0xaa, OssuaryError::InvalidPacket("Received unexpected handshake packet.".into()), true), + (Corruption::ClientKey, 0, 18, 0xaa, OssuaryError::DecryptionFailed, false), + (Corruption::ClientNonce, 0, 50, 0xaa, OssuaryError::DecryptionFailed, false), + (Corruption::ClientChal, 0, 64, 0xaa, OssuaryError::InvalidSignature, false), + + // loop iteration 3: Server -> Client + // 8 bytes net header, 8 bytes packet header, 32 bytes key, 12 bytes nonce, ~150 bytes encrypted auth + (Corruption::ServerInvalidPkt, 3, 0, 0xaa, OssuaryError::InvalidPacket("Oversized packet".into()), true), + (Corruption::ServerInvalidPkt, 3, 2, 0xaa, OssuaryError::InvalidPacket("Message ID does not match".into()), true), + (Corruption::ServerInvalidPkt, 3, 4, 0xaa, OssuaryError::InvalidPacket("Received unexpected handshake packet.".into()), true), + (Corruption::ServerKey, 3, 18, 0xaa, OssuaryError::DecryptionFailed, false), + (Corruption::ServerNonce, 3, 50, 0xaa, OssuaryError::DecryptionFailed, false), + (Corruption::ServerAuth, 3, 64, 0xaa, OssuaryError::DecryptionFailed, false), + (Corruption::ServerAuth, 3, 84, 0xaa, OssuaryError::DecryptionFailed, false), + + // loop iteration 2: Client -> Server + // 8 bytes net header, 8 bytes packet header, 4 byte encryption packet, ~120 bytes encrypted auth + (Corruption::ClientInvalidPkt, 6, 18, 0xaa, OssuaryError::InvalidPacket("Invalid packet length".into()), false), + (Corruption::ClientAuth, 6, 24, 0xaa, OssuaryError::DecryptionFailed, false), + (Corruption::ClientAuth, 6, 96, 0xaa, OssuaryError::DecryptionFailed, false), + ]; + + #[derive(Debug)] + enum LoopConn { + LoopClient, + LoopServer, + }; + for corruption in &corruptions { + println!("Corruption test: {:?}", corruption.0); + let server_secret_key = &[ + 0x50, 0x29, 0x04, 0x97, 0x62, 0xbd, 0xa6, 0x07, + 0x71, 0xca, 0x29, 0x14, 0xe3, 0x83, 0x19, 0x0e, + 0xa0, 0x9e, 0xd4, 0xb7, 0x1a, 0xf9, 0xc9, 0x59, + 0x3e, 0xa3, 0x1c, 0x85, 0x0f, 0xc4, 0xfa, 0xa2, + ]; + let server_public_key = &[ + 0x20, 0x88, 0x55, 0x8e, 0xbd, 0x9b, 0x46, 0x1d, + 0xd0, 0x9d, 0xf0, 0x00, 0xda, 0xf4, 0x0f, 0x87, + 0xf7, 0x38, 0x40, 0xc5, 0x54, 0x18, 0x57, 0x60, + 0x74, 0x39, 0x3b, 0xb9, 0x70, 0xe1, 0x46, 0x98, + ]; + let pubkeys: Vec<&[u8]> = vec![server_public_key]; + let mut server_conn = OssuaryConnection::new(ConnectionType::UnauthenticatedServer, Some(server_secret_key)).unwrap(); + let mut client_conn = OssuaryConnection::new(ConnectionType::Client, None).unwrap(); + let _ = client_conn.add_authorized_keys(pubkeys).unwrap(); + + let mut loop_conn = LoopConn::LoopClient; + let mut client_buf: Vec<u8> = vec!(); + let mut server_buf: Vec<u8> = vec!(); + let mut loop_count = 0; + + loop { + let mut done = 0; + let (send_conn, recv_conn, mut send_buf, recv_buf) = match loop_conn { + LoopConn::LoopClient => (&mut client_conn, &mut server_conn, &mut client_buf, &mut server_buf), + _ => (&mut server_conn, &mut client_conn, &mut server_buf, &mut client_buf), + }; + match send_conn.handshake_done() { + Ok(true) => done += 1, + Ok(false) => {}, + Err(OssuaryError::ConnectionFailed) => { + match corruption.5 { + true => break, + false => panic!("Unexpected connection failure."), + } + } + Err(e) => panic!("Handshake failed with error: {:?}", e), + } + match recv_conn.handshake_done() { + Ok(true) => done += 1, + Ok(false) => {}, + Err(OssuaryError::ConnectionFailed) => { + match corruption.5 { + true => break, + false => panic!("Unexpected connection failure."), + } + } + Err(e) => panic!("Handshake failed with error: {:?}", e), + } + if done == 2 { + break; + } + send_conn.send_handshake(&mut send_buf).unwrap(); + if send_buf.len() > 0 { + //println!("{:?}({}) {:?}", loop_conn, loop_count, send_buf); + } + if loop_count == corruption.1 { + send_buf[corruption.2] = corruption.3; + } + match send_conn.recv_handshake(&mut recv_buf.as_slice()) { + Ok(b) => { recv_buf.drain(0..b); }, + Err(OssuaryError::WouldBlock(b)) => { recv_buf.drain(0..b); }, + Err(e) => match e { + ref e if e == &corruption.4 => {}, // expected error + OssuaryError::ConnectionFailed => { + match corruption.5 { + true => break, + false => panic!("Unexpected connection failure."), + } + }, + OssuaryError::ConnectionReset(b) => { recv_buf.drain(0..b); }, + _ => panic!("Handshake failed: {:?}", e), + }, + } + match send_conn.handshake_done() { + Ok(true) => { + let mut plaintext = Vec::<u8>::new(); + match send_conn.recv_data(&mut recv_buf.as_slice(), &mut plaintext) { + Ok((b,_)) => { recv_buf.drain(0..b); }, + Err(OssuaryError::WouldBlock(b)) => { recv_buf.drain(0..b); }, + Err(e) => match e { + ref e if e == &corruption.4 => {}, // expected error + OssuaryError::ConnectionFailed => { + match corruption.5 { + true => break, + false => panic!("Unexpected connection failure."), + } + }, + OssuaryError::ConnectionReset(b) => { recv_buf.drain(0..b); }, + _ => panic!("Handshake failed: {:?}", e), + }, + } + }, + Err(e) => panic!("ERROR: {:?}", e), + _ => {}, + } + loop_conn = match loop_conn { + LoopConn::LoopClient => LoopConn::LoopServer, + _ => LoopConn::LoopClient, + }; + loop_count += 1; + } + } +}