summary history branches tags files
commit:818de112b25b1a4772bc9226e54e296171bced05
author:Trevor Bentley
committer:Trevor Bentley
date:Sun Jan 20 21:48:18 2019 +0100
parents:0f958c5f77e11c7ec9cfc888d6347df167d8cbfc
Clean up, split tests out into files
diff --git a/benches/basic.rs b/benches/basic.rs
line changes: +141/-0
index 0000000..a9c625c
--- /dev/null
+++ b/benches/basic.rs
@@ -0,0 +1,141 @@
+#![feature(test)]
+extern crate test;
+use test::Bencher;
+use std::thread;
+use std::net::{TcpListener, TcpStream};
+
+use ossuary::{ConnectionContext, ConnectionType};
+use ossuary::{crypto_send_handshake,crypto_recv_handshake, crypto_handshake_done};
+use ossuary::{crypto_send_data,crypto_recv_data,crypto_flush};
+use ossuary::OssuaryError;
+//use crate::*;
+
+#[bench]
+fn bench_test(b: &mut Bencher) {
+    let server_thread = thread::spawn(move || {
+        let listener = TcpListener::bind("127.0.0.1:9987").unwrap();
+        let mut server_stream = listener.incoming().next().unwrap().unwrap();
+        let mut server_conn = ConnectionContext::new(ConnectionType::UnauthenticatedServer);
+        while crypto_handshake_done(&server_conn).unwrap() == false {
+            if crypto_send_handshake(&mut server_conn, &mut server_stream).is_ok() {
+                loop {
+                    match crypto_recv_handshake(&mut server_conn, &mut server_stream) {
+                        Ok(_) => break,
+                        Err(OssuaryError::WouldBlock(_)) => {},
+                        _ => panic!("Handshake failed"),
+                    }
+                }
+            }
+        }
+        println!("server handshook");
+        let mut plaintext = vec!();
+        let mut bytes: u64 = 0;
+        let start = std::time::SystemTime::now();
+        loop {
+            //std::thread::sleep(std::time::Duration::from_millis(100));
+            match crypto_recv_data(&mut server_conn,
+                                   &mut server_stream,
+                                   &mut plaintext) {
+                Ok((read, _written)) => bytes += read as u64,
+                Err(OssuaryError::WouldBlock(_)) => continue,
+                Err(e) => {
+                    println!("err: {:?}", e);
+                    panic!("Recv failed")
+                },
+            }
+            if plaintext == [0xde, 0xde, 0xbe, 0xbe] {
+                println!("finished");
+                if let Ok(dur) = start.elapsed() {
+                    let t = dur.as_secs() as f64
+                        + dur.subsec_nanos() as f64 * 1e-9;
+                    println!("Benchmark done (recv): {} bytes in {:.2} s", bytes, t);
+                    println!("{:.2} MB/s", bytes as f64 / 1024.0 / 1024.0 / t);
+                }
+                break;
+            }
+            plaintext.clear();
+        }
+    });
+
+    std::thread::sleep(std::time::Duration::from_millis(500));
+    let mut client_stream = TcpStream::connect("127.0.0.1:9987").unwrap();
+    client_stream.set_nonblocking(true).unwrap();
+    let mut client_conn = ConnectionContext::new(ConnectionType::Client);
+    while crypto_handshake_done(&client_conn).unwrap() == false {
+        if crypto_send_handshake(&mut client_conn, &mut client_stream).is_ok() {
+            loop {
+                match crypto_recv_handshake(&mut client_conn, &mut client_stream) {
+                    Ok(_) => break,
+                    Err(OssuaryError::WouldBlock(_)) => {},
+                    Err(e) => {
+                        println!("err: {:?}", e);
+                        panic!("Handshake failed")
+                    },
+                }
+            }
+        }
+    }
+    println!("client handshook");
+    let mut client_stream = std::io::BufWriter::new(client_stream);
+    let mut bytes: u64 = 0;
+    let start = std::time::SystemTime::now();
+    let mut plaintext: &[u8] = &[0xaa; 16384];
+    b.iter(|| {
+        match crypto_send_data(&mut client_conn,
+                               &mut plaintext,
+                               &mut client_stream) {
+            Ok(b) => bytes += b as u64,
+            Err(OssuaryError::WouldBlock(_)) => {},
+            _ => panic!("send error"),
+        }
+    });
+    if let Ok(dur) = start.elapsed() {
+        let t = dur.as_secs() as f64
+            + dur.subsec_nanos() as f64 * 1e-9;
+        println!("Benchmark done (xmit): {} bytes in {:.2} s", bytes, t);
+        println!("{:.2} MB/s", bytes as f64 / 1024.0 / 1024.0 / t);
+    }
+    let mut plaintext: &[u8] = &[0xde, 0xde, 0xbe, 0xbe];
+    loop {
+        match crypto_send_data(&mut client_conn, &mut plaintext, &mut client_stream) {
+            Ok(w) => {
+                println!("wrote finish: {}", w);
+                break;
+            },
+            Err(OssuaryError::WouldBlock(_)) => {},
+            _ => panic!("Send failed"),
+        }
+    }
+    loop {
+        match crypto_flush(&mut client_conn, &mut client_stream) {
+            Ok(w) => {
+                if w == 0 {
+                    break;
+                }
+                println!("flushed: {}", w);
+            },
+            _ => panic!("Flush failed"),
+        }
+    }
+
+    let mut client_stream: Option<std::io::BufWriter<_>> = Some(client_stream);
+    loop {
+        client_stream = match client_stream {
+            None => break,
+            Some(s) => match s.into_inner() {
+                Ok(_) => None,
+                Err(e) => {
+                    match e.error().kind() {
+                        std::io::ErrorKind::WouldBlock => {
+                            Some(e.into_inner())
+                        },
+                        _ => panic!("error: {:?}", e.error()),
+                    }
+                },
+            }
+        };
+    }
+    println!("flushed");
+    //drop(client_stream); // flush the buffer
+    let _ = server_thread.join();
+}

diff --git a/examples/ffi.c b/examples/ffi.c
line changes: +1/-2
index af586cf..3e02309
--- a/examples/ffi.c
+++ b/examples/ffi.c
@@ -69,8 +69,7 @@ int main(int argc, char **argv) {
       }
     }
 
-    //if (++count == 8) break;
-    usleep(100000);
+    usleep(1000);
   } while (!client_done || !server_done);
 
   memset(client_buf, 0, sizeof(client_buf));

diff --git a/src/clib.rs b/src/clib.rs
line changes: +10/-157
index 1d7f99d..6702e30
--- a/src/clib.rs
+++ b/src/clib.rs
@@ -12,7 +12,7 @@ pub extern "C" fn ossuary_create_connection(conn_type: u8) -> *mut ConnectionCon
         2 => ConnectionType::UnauthenticatedServer,
         _ => { return ::std::ptr::null_mut(); }
     };
-    let mut conn = Box::new(ConnectionContext::new(conn_type)); // todo
+    let mut conn = Box::new(ConnectionContext::new(conn_type));
     let ptr: *mut _ = &mut *conn;
     ::std::mem::forget(conn);
     ptr
@@ -90,7 +90,7 @@ pub extern "C" fn ossuary_recv_handshake(conn: *mut ConnectionContext,
         _ => -1i32,
     };
     ::std::mem::forget(conn);
-    read as i32 // TODO
+    read as i32
 }
 
 #[no_mangle]
@@ -136,7 +136,8 @@ pub extern "C" fn ossuary_handshake_done(conn: *const ConnectionContext) -> i32 
 pub extern "C" fn ossuary_send_data(conn: *mut ConnectionContext,
                                     in_buf: *mut u8, in_buf_len: u16,
                                     out_buf: *mut u8, out_buf_len: *mut u16) -> i32 {
-    if conn.is_null() || in_buf.is_null() || out_buf.is_null() || out_buf_len.is_null(){
+    if conn.is_null() || in_buf.is_null() ||
+        out_buf.is_null() || out_buf_len.is_null() {
         return -1i32;
     }
     let mut conn = unsafe { &mut *conn };
@@ -170,7 +171,9 @@ pub extern "C" fn ossuary_recv_data(conn: *mut ConnectionContext,
         return -1i32;
     }
     let mut conn = unsafe { &mut *conn };
-    let r_out_buf: &mut [u8] = unsafe { std::slice::from_raw_parts_mut(out_buf, *out_buf_len as usize) };
+    let r_out_buf: &mut [u8] = unsafe {
+        std::slice::from_raw_parts_mut(out_buf, *out_buf_len as usize)
+    };
     let r_in_buf: &[u8] = unsafe { std::slice::from_raw_parts(in_buf, *in_buf_len as usize) };
     let mut out_slice = r_out_buf;
     let mut in_slice = r_in_buf;
@@ -201,7 +204,9 @@ pub extern "C" fn ossuary_flush(conn: *mut ConnectionContext,
         return -1i32;
     }
     let mut conn = unsafe { &mut *conn };
-    let r_out_buf: &mut [u8] = unsafe { std::slice::from_raw_parts_mut(out_buf, out_buf_len as usize) };
+    let r_out_buf: &mut [u8] = unsafe {
+        std::slice::from_raw_parts_mut(out_buf, out_buf_len as usize)
+    };
     let mut out_slice = r_out_buf;
     let bytes_written = match crypto_flush(&mut conn, &mut out_slice) {
         Ok(x) => x as i32,
@@ -211,155 +216,3 @@ pub extern "C" fn ossuary_flush(conn: *mut ConnectionContext,
     ::std::mem::forget(conn);
     bytes_written
 }
-
-#[cfg(test)]
-mod tests {
-    use std::thread;
-    use std::io::{Write};
-    use std::net::{TcpListener, TcpStream};
-    use std::io::BufRead;
-    use crate::clib::*;
-
-    fn server() -> Result<(), std::io::Error> {
-        let listener = TcpListener::bind("127.0.0.1:9989").unwrap();
-        for stream in listener.incoming() {
-            let mut stream: TcpStream = stream.unwrap();
-            let mut reader = std::io::BufReader::new(stream.try_clone().unwrap());
-            let mut conn = ossuary_create_connection(1);
-            let key: &[u8; 32] = &[0xbe, 0x1c, 0xa0, 0x74, 0xf4, 0xa5, 0x8b, 0xbb,
-                                   0xd2, 0x62, 0xa7, 0xf9, 0x52, 0x3b, 0x6f, 0xb0,
-                                   0xbb, 0x9e, 0x86, 0x62, 0x28, 0x7c, 0x33, 0x89,
-                                   0xa2, 0xe1, 0x63, 0xdc, 0x55, 0xde, 0x28, 0x1f];
-            let keys: &[*const u8; 1] = &[key as *const u8];
-            ossuary_set_authorized_keys(conn, keys as *const *const u8, keys.len() as u8);
-
-            let out_buf: [u8; 512] = [0; 512];
-
-            while ossuary_handshake_done(conn) == 0 {
-                let mut out_len = out_buf.len() as u16;
-                let more = ossuary_send_handshake(conn, (&out_buf) as *const u8 as *mut u8, &mut out_len);
-                let _ = stream.write_all(&out_buf[0..out_len as usize]).unwrap();
-
-                if more >= 0 {
-                    let in_buf = reader.fill_buf().unwrap();
-                    let mut in_len = in_buf.len() as u16;
-                    if in_len > 0 {
-                        let len = ossuary_recv_handshake(conn, in_buf as *const [u8] as *const u8, &mut in_len);
-                        reader.consume(len as usize);
-                    }
-                }
-            }
-
-            let mut plaintext: [u8; 256] = [0; 256];
-            plaintext[0..13].copy_from_slice("from server 1".as_bytes());
-            let mut out_len: u16 = out_buf.len() as u16;
-            let sz = ossuary_send_data(
-                conn,
-                (&plaintext) as *const u8 as *mut u8, 13 as u16,
-                (&out_buf) as *const u8 as *mut u8,
-                &mut out_len);
-            let _ = stream.write_all(&out_buf[0..sz as usize]).unwrap();
-
-            plaintext[0..13].copy_from_slice("from server 2".as_bytes());
-            let mut out_len: u16 = out_buf.len() as u16;
-            let sz = ossuary_send_data(
-                conn,
-                (&plaintext) as *const u8 as *mut u8, 13 as u16,
-                (&out_buf) as *const u8 as *mut u8,
-                &mut out_len);
-            let _ = stream.write_all(&out_buf[0..sz as usize]).unwrap();
-
-            let in_buf = reader.fill_buf().unwrap();
-            if in_buf.len() > 0 {
-                let mut out_len = out_buf.len() as u16;
-                let mut in_len = in_buf.len() as u16;
-                let len = ossuary_recv_data(
-                    conn,
-                    (in_buf) as *const [u8] as *mut u8, &mut in_len,
-                    (&out_buf) as *const u8 as *mut u8, &mut out_len);
-                if len != -1 {
-                    println!("CLIB READ: {:?}",
-                             std::str::from_utf8(&out_buf[0..out_len as usize]).unwrap());
-                reader.consume(len as usize);
-                }
-            }
-
-            ossuary_destroy_connection(&mut conn);
-            break;
-        }
-        Ok(())
-    }
-
-    fn client() -> Result<(), std::io::Error> {
-        let mut stream = TcpStream::connect("127.0.0.1:9989").unwrap();
-        let mut conn = ossuary_create_connection(0);
-        let key: &[u8; 32] = &[0x10, 0x86, 0x6e, 0xc4, 0x8a, 0x11, 0xf3, 0xc5,
-                               0x6d, 0x77, 0xa6, 0x4b, 0x2f, 0x54, 0xaa, 0x06,
-                               0x6c, 0x0c, 0xb4, 0x75, 0xd8, 0xc8, 0x7d, 0x35,
-                               0xb4, 0x91, 0xee, 0xd6, 0xac, 0x0b, 0xde, 0xbc];
-        ossuary_set_secret_key(conn, key as *const u8);
-
-        let out_buf: [u8; 512] = [0; 512];
-
-        let mut reader = std::io::BufReader::new(stream.try_clone().unwrap());
-        while ossuary_handshake_done(conn) == 0 {
-            let mut out_len = out_buf.len() as u16;
-            let more = ossuary_send_handshake(conn, (&out_buf) as *const u8 as *mut u8, &mut out_len);
-            let _ = stream.write_all(&out_buf[0.. out_len as usize]).unwrap();
-
-            if more >= 0 {
-                let in_buf = reader.fill_buf().unwrap();
-                let mut in_len = in_buf.len() as u16;
-                let len = ossuary_recv_handshake(conn, in_buf as *const [u8] as *const u8, &mut in_len);
-                reader.consume(len as usize);
-            }
-        }
-
-        let out_buf: [u8; 256] = [0; 256];
-        let mut plaintext: [u8; 256] = [0; 256];
-        plaintext[0..11].copy_from_slice("from client".as_bytes());
-        let mut out_len: u16 = out_buf.len() as u16;
-        let sz = ossuary_send_data(
-            conn,
-            (&plaintext) as *const u8 as *mut u8, 11 as u16,
-            (&out_buf) as *const u8 as *mut u8,
-            &mut out_len);
-        let _ = stream.write_all(&out_buf[0..sz as usize]).unwrap();
-
-        let mut stream = std::io::BufReader::new(stream);
-        let mut count = 0;
-        loop {
-            let in_buf = stream.fill_buf().unwrap();
-            if in_buf.len() == 0 || count == 2 {
-                break;
-            }
-            let mut out_len = out_buf.len() as u16;
-            let mut in_len = in_buf.len() as u16;
-            let len = ossuary_recv_data(
-                conn,
-                in_buf as *const [u8] as *mut u8, &mut in_len,
-                (&out_buf) as *const u8 as *mut u8, &mut out_len);
-            if len == -1 {
-                break;
-            }
-            if len > 0 {
-                println!("CLIB READ: {:?}",
-                         std::str::from_utf8(&out_buf[0..out_len as usize]).unwrap());
-                stream.consume(len as usize);
-                count += 1;
-            }
-        }
-
-        ossuary_destroy_connection(&mut conn);
-        Ok(())
-    }
-
-    #[test]
-    fn test_clib() {
-        let server = thread::spawn(move || { let _ = server(); });
-        std::thread::sleep(std::time::Duration::from_millis(500));
-        let child = thread::spawn(move || { let _ = client(); });
-        let _ = child.join();
-        let _ = server.join();
-    }
-}

diff --git a/src/lib.rs b/src/lib.rs
line changes: +33/-164
index 9d4db53..af80c3b
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,4 +1,3 @@
-#![feature(test)]
 #![feature(try_from)]
 
 extern crate x25519_dalek;
@@ -374,12 +373,14 @@ fn interpret_packet<'a, T>(pkt: &'a NetworkPacket) -> Result<&'a T, OssuaryError
     Ok(s)
 }
 
-fn interpret_packet_extra<'a, T>(pkt: &'a NetworkPacket) -> Result<(&'a T, &'a [u8]), OssuaryError> {
+fn interpret_packet_extra<'a, T>(pkt: &'a NetworkPacket)
+                                 -> Result<(&'a T, &'a [u8]), OssuaryError> {
     let s: &T = slice_as_struct(&pkt.data)?;
     Ok((s, &pkt.data[::std::mem::size_of::<T>()..]))
 }
 
-fn read_packet<T,U>(conn: &mut ConnectionContext, mut stream: T) ->Result<(NetworkPacket, usize), OssuaryError>
+fn read_packet<T,U>(conn: &mut ConnectionContext,
+                    mut stream: T) ->Result<(NetworkPacket, usize), OssuaryError>
 where T: std::ops::DerefMut<Target = U>,
       U: std::io::Read {
     let header_size = ::std::mem::size_of::<PacketHeader>();
@@ -470,7 +471,8 @@ where T: std::ops::DerefMut<Target = U>,
     Ok(written)
 }
 
-pub fn crypto_send_handshake<T,U>(conn: &mut ConnectionContext, mut buf: T) -> Result<usize, OssuaryError>
+pub fn crypto_send_handshake<T,U>(conn: &mut ConnectionContext,
+                                  mut buf: T) -> Result<usize, OssuaryError>
 where T: std::ops::DerefMut<Target = U>,
       U: std::io::Write {
     // Try to send any unsent buffered data
@@ -664,7 +666,8 @@ where T: std::ops::DerefMut<Target = U>,
     Ok(written)
 }
 
-pub fn crypto_recv_handshake<T,U>(conn: &mut ConnectionContext, buf: T) -> Result<usize, OssuaryError>
+pub fn crypto_recv_handshake<T,U>(conn: &mut ConnectionContext,
+                                  buf: T) -> Result<usize, OssuaryError>
 where T: std::ops::DerefMut<Target = U>,
       U: std::io::Read {
     let mut bytes_read: usize = 0;
@@ -762,7 +765,8 @@ where T: std::ops::DerefMut<Target = U>,
                                     &aad, &ciphertext, &tag, &mut plaintext)?;
                             let pubkey = &plaintext[0..32];
                             let sig = &plaintext[32..];
-                            if conn.authorized_keys.iter().filter(|k| &pubkey == k).count() > 0 {
+                            if conn.authorized_keys.iter().filter(
+                                |k| &pubkey == k).count() > 0 {
                                 let public = match PublicKey::from_bytes(pubkey) {
                                     Ok(p) => p,
                                     Err(_) => {
@@ -809,15 +813,6 @@ where T: std::ops::DerefMut<Target = U>,
                 _ => { error = true; }
             }
         },
-        ConnectionState::ServerSendPubKey => {
-            error = true;
-        }, // nop
-        ConnectionState::ServerSendChallenge => {
-            error = true;
-        }, // nop
-        ConnectionState::ClientNew => {
-            error = true;
-        }, // nop
         ConnectionState::ClientWaitKey(_t) => {
             match pkt.kind() {
                 PacketType::PublicKeyNonce => {
@@ -837,9 +832,6 @@ where T: std::ops::DerefMut<Target = U>,
                 }
             }
         },
-        ConnectionState::ClientSendAck => {
-            error = true;
-        }, // nop
         ConnectionState::ClientWaitAck(_t) => {
             match pkt.kind() {
                 PacketType::PubKeyAck => {
@@ -883,15 +875,17 @@ where T: std::ops::DerefMut<Target = U>,
                 },
             }
         },
-        ConnectionState::ClientSendAuth => {
-            error = true;
-        }, // nop
-        ConnectionState::Failed(_) => {
-            error = true;
-        }, // nop
+        ConnectionState::ServerSendPubKey |
+        ConnectionState::ServerSendChallenge |
+        ConnectionState::ClientNew |
+        ConnectionState::ClientSendAck |
+        ConnectionState::ClientSendAuth |
         ConnectionState::Encrypted => {
+            // no-op
+        },
+        ConnectionState::Failed(_) => {
             error = true;
-        }, // nop
+        },
     }
     if error {
         conn.reset_state(None);
@@ -907,7 +901,9 @@ pub fn crypto_handshake_done(conn: &ConnectionContext) -> Result<bool, &OssuaryE
     }
 }
 
-pub fn crypto_send_data<T,U>(conn: &mut ConnectionContext, in_buf: &[u8], mut out_buf: T) -> Result<usize, OssuaryError>
+pub fn crypto_send_data<T,U>(conn: &mut ConnectionContext,
+                             in_buf: &[u8],
+                             mut out_buf: T) -> Result<usize, OssuaryError>
 where T: std::ops::DerefMut<Target = U>,
       U: std::io::Write {
     // Try to send any unsent buffered data
@@ -919,7 +915,8 @@ where T: std::ops::DerefMut<Target = U>,
     match conn.state {
         ConnectionState::Encrypted => {},
         _ => {
-            return Err(OssuaryError::InvalidPacket("Encrypted channel not established.".into()));
+            return Err(OssuaryError::InvalidPacket(
+                "Encrypted channel not established.".into()));
         }
     }
     let aad = [];
@@ -953,7 +950,9 @@ where T: std::ops::DerefMut<Target = U>,
     Ok(written)
 }
 
-pub fn crypto_recv_data<T,U,R,V>(conn: &mut ConnectionContext, in_buf: T, mut out_buf: R) -> Result<(usize, usize), OssuaryError>
+pub fn crypto_recv_data<T,U,R,V>(conn: &mut ConnectionContext,
+                                 in_buf: T,
+                                 mut out_buf: R) -> Result<(usize, usize), OssuaryError>
 where T: std::ops::DerefMut<Target = U>,
       U: std::io::Read,
       R: std::ops::DerefMut<Target = V>,
@@ -963,7 +962,8 @@ where T: std::ops::DerefMut<Target = U>,
     match conn.state {
         ConnectionState::Encrypted => {},
         _ => {
-            return Err(OssuaryError::InvalidPacket("Encrypted channel not established.".into()));
+            return Err(OssuaryError::InvalidPacket(
+                "Encrypted channel not established.".into()));
         }
     }
 
@@ -1017,7 +1017,8 @@ where T: std::ops::DerefMut<Target = U>,
                     }
                 },
                 _ => {
-                    return Err(OssuaryError::InvalidPacket("Received non-encrypted data on encrypted channel.".into()));
+                    return Err(OssuaryError::InvalidPacket(
+                        "Received non-encrypted data on encrypted channel.".into()));
                 },
             }
         },
@@ -1031,7 +1032,8 @@ where T: std::ops::DerefMut<Target = U>,
     Ok((bytes_read, bytes_written))
 }
 
-pub fn crypto_flush<R,V>(conn: &mut ConnectionContext, mut out_buf: R) -> Result<usize, OssuaryError>
+pub fn crypto_flush<R,V>(conn: &mut ConnectionContext,
+                         mut out_buf: R) -> Result<usize, OssuaryError>
 where R: std::ops::DerefMut<Target = V>,
       V: std::io::Write {
     return write_stored_packet(conn, &mut out_buf);
@@ -1039,10 +1041,6 @@ where R: std::ops::DerefMut<Target = V>,
 
 #[cfg(test)]
 mod tests {
-    extern crate test;
-    use test::Bencher;
-    use std::thread;
-    use std::net::{TcpListener, TcpStream};
     use crate::*;
 
     #[test]
@@ -1077,133 +1075,4 @@ mod tests {
         let _ = conn.set_authorized_keys(keys.iter().map(|x| x.as_slice())).unwrap();
     }
 
-    #[bench]
-    fn bench_test(b: &mut Bencher) {
-        let server_thread = thread::spawn(move || {
-            let listener = TcpListener::bind("127.0.0.1:9987").unwrap();
-            let mut server_stream = listener.incoming().next().unwrap().unwrap();
-            let mut server_conn = ConnectionContext::new(ConnectionType::UnauthenticatedServer);
-            while crypto_handshake_done(&server_conn).unwrap() == false {
-                if crypto_send_handshake(&mut server_conn, &mut server_stream).is_ok() {
-                    loop {
-                        match crypto_recv_handshake(&mut server_conn, &mut server_stream) {
-                            Ok(_) => break,
-                            Err(OssuaryError::WouldBlock(_)) => {},
-                            _ => panic!("Handshake failed"),
-                        }
-                    }
-                }
-            }
-            println!("server handshook");
-            let mut plaintext = vec!();
-            let mut bytes: u64 = 0;
-            let start = std::time::SystemTime::now();
-            loop {
-                //std::thread::sleep(std::time::Duration::from_millis(100));
-                match crypto_recv_data(&mut server_conn,
-                                       &mut server_stream,
-                                       &mut plaintext) {
-                    Ok((read, _written)) => bytes += read as u64,
-                    Err(OssuaryError::WouldBlock(_)) => continue,
-                    Err(e) => {
-                        println!("err: {:?}", e);
-                        panic!("Recv failed")
-                    },
-                }
-                if plaintext == [0xde, 0xde, 0xbe, 0xbe] {
-                    println!("finished");
-                    if let Ok(dur) = start.elapsed() {
-                        let t = dur.as_secs() as f64
-                            + dur.subsec_nanos() as f64 * 1e-9;
-                        println!("Benchmark done (recv): {} bytes in {:.2} s", bytes, t);
-                        println!("{:.2} MB/s", bytes as f64 / 1024.0 / 1024.0 / t);
-                    }
-                    break;
-                }
-                plaintext.clear();
-            }
-        });
-
-        std::thread::sleep(std::time::Duration::from_millis(500));
-        let mut client_stream = TcpStream::connect("127.0.0.1:9987").unwrap();
-        client_stream.set_nonblocking(true).unwrap();
-        let mut client_conn = ConnectionContext::new(ConnectionType::Client);
-        while crypto_handshake_done(&client_conn).unwrap() == false {
-            if crypto_send_handshake(&mut client_conn, &mut client_stream).is_ok() {
-                loop {
-                    match crypto_recv_handshake(&mut client_conn, &mut client_stream) {
-                        Ok(_) => break,
-                        Err(OssuaryError::WouldBlock(_)) => {},
-                        Err(e) => {
-                            println!("err: {:?}", e);
-                            panic!("Handshake failed")
-                        },
-                    }
-                }
-            }
-        }
-        println!("client handshook");
-        let mut client_stream = std::io::BufWriter::new(client_stream);
-        let mut bytes: u64 = 0;
-        let start = std::time::SystemTime::now();
-        let mut plaintext: &[u8] = &[0xaa; 16384];
-        b.iter(|| {
-            match crypto_send_data(&mut client_conn,
-                                   &mut plaintext,
-                                   &mut client_stream) {
-                Ok(b) => bytes += b as u64,
-                Err(OssuaryError::WouldBlock(_)) => {},
-                _ => panic!("send error"),
-            }
-        });
-        if let Ok(dur) = start.elapsed() {
-            let t = dur.as_secs() as f64
-                + dur.subsec_nanos() as f64 * 1e-9;
-            println!("Benchmark done (xmit): {} bytes in {:.2} s", bytes, t);
-            println!("{:.2} MB/s", bytes as f64 / 1024.0 / 1024.0 / t);
-        }
-        let mut plaintext: &[u8] = &[0xde, 0xde, 0xbe, 0xbe];
-        loop {
-            match crypto_send_data(&mut client_conn, &mut plaintext, &mut client_stream) {
-                Ok(w) => {
-                    println!("wrote finish: {}", w);
-                    break;
-                },
-                Err(OssuaryError::WouldBlock(_)) => {},
-                _ => panic!("Send failed"),
-            }
-        }
-        loop {
-            match crypto_flush(&mut client_conn, &mut client_stream) {
-                Ok(w) => {
-                    if w == 0 {
-                        break;
-                    }
-                    println!("flushed: {}", w);
-                },
-                _ => panic!("Flush failed"),
-            }
-        }
-
-        let mut client_stream: Option<std::io::BufWriter<_>> = Some(client_stream);
-        loop {
-            client_stream = match client_stream {
-                None => break,
-                Some(s) => match s.into_inner() {
-                    Ok(_) => None,
-                    Err(e) => {
-                        match e.error().kind() {
-                            std::io::ErrorKind::WouldBlock => {
-                                Some(e.into_inner())
-                            },
-                            _ => panic!("error: {:?}", e.error()),
-                        }
-                    },
-                }
-            };
-        }
-        println!("flushed");
-        //drop(client_stream); // flush the buffer
-        let _ = server_thread.join();
-    }
 }

diff --git a/tests/clib_ffi.rs b/tests/clib_ffi.rs
line changes: +160/-0
index 0000000..3b8c592
--- /dev/null
+++ b/tests/clib_ffi.rs
@@ -0,0 +1,160 @@
+use ossuary::clib::{
+    ossuary_create_connection,
+    ossuary_destroy_connection,
+    ossuary_set_secret_key,
+    ossuary_set_authorized_keys,
+    ossuary_send_handshake,
+    ossuary_recv_handshake,
+    ossuary_handshake_done,
+    ossuary_send_data,
+    ossuary_recv_data,
+};
+
+use std::thread;
+use std::net::{TcpListener, TcpStream};
+
+use std::io::{Write};
+use std::io::BufRead;
+
+fn server() -> Result<(), std::io::Error> {
+    let listener = TcpListener::bind("127.0.0.1:9989").unwrap();
+    for stream in listener.incoming() {
+        let mut stream: TcpStream = stream.unwrap();
+        let mut reader = std::io::BufReader::new(stream.try_clone().unwrap());
+        let mut conn = ossuary_create_connection(1);
+        let key: &[u8; 32] = &[0xbe, 0x1c, 0xa0, 0x74, 0xf4, 0xa5, 0x8b, 0xbb,
+                               0xd2, 0x62, 0xa7, 0xf9, 0x52, 0x3b, 0x6f, 0xb0,
+                               0xbb, 0x9e, 0x86, 0x62, 0x28, 0x7c, 0x33, 0x89,
+                               0xa2, 0xe1, 0x63, 0xdc, 0x55, 0xde, 0x28, 0x1f];
+        let keys: &[*const u8; 1] = &[key as *const u8];
+        ossuary_set_authorized_keys(conn, keys as *const *const u8, keys.len() as u8);
+
+        let out_buf: [u8; 512] = [0; 512];
+
+        while ossuary_handshake_done(conn) == 0 {
+            let mut out_len = out_buf.len() as u16;
+            let more = ossuary_send_handshake(conn, (&out_buf) as *const u8 as *mut u8, &mut out_len);
+            let _ = stream.write_all(&out_buf[0..out_len as usize]).unwrap();
+
+            if more >= 0 {
+                let in_buf = reader.fill_buf().unwrap();
+                let mut in_len = in_buf.len() as u16;
+                if in_len > 0 {
+                    let len = ossuary_recv_handshake(conn, in_buf as *const [u8] as *const u8, &mut in_len);
+                    reader.consume(len as usize);
+                }
+            }
+        }
+
+        let mut plaintext: [u8; 256] = [0; 256];
+        plaintext[0..13].copy_from_slice("from server 1".as_bytes());
+        let mut out_len: u16 = out_buf.len() as u16;
+        let sz = ossuary_send_data(
+            conn,
+            (&plaintext) as *const u8 as *mut u8, 13 as u16,
+            (&out_buf) as *const u8 as *mut u8,
+            &mut out_len);
+        let _ = stream.write_all(&out_buf[0..sz as usize]).unwrap();
+
+        plaintext[0..13].copy_from_slice("from server 2".as_bytes());
+        let mut out_len: u16 = out_buf.len() as u16;
+        let sz = ossuary_send_data(
+            conn,
+            (&plaintext) as *const u8 as *mut u8, 13 as u16,
+            (&out_buf) as *const u8 as *mut u8,
+            &mut out_len);
+        let _ = stream.write_all(&out_buf[0..sz as usize]).unwrap();
+
+        let in_buf = reader.fill_buf().unwrap();
+        if in_buf.len() > 0 {
+            let mut out_len = out_buf.len() as u16;
+            let mut in_len = in_buf.len() as u16;
+            let len = ossuary_recv_data(
+                conn,
+                (in_buf) as *const [u8] as *mut u8, &mut in_len,
+                (&out_buf) as *const u8 as *mut u8, &mut out_len);
+            if len != -1 {
+                println!("CLIB READ: {:?}",
+                         std::str::from_utf8(&out_buf[0..out_len as usize]).unwrap());
+                reader.consume(len as usize);
+            }
+        }
+
+        ossuary_destroy_connection(&mut conn);
+        break;
+    }
+    Ok(())
+}
+
+fn client() -> Result<(), std::io::Error> {
+    let mut stream = TcpStream::connect("127.0.0.1:9989").unwrap();
+    let mut conn = ossuary_create_connection(0);
+    let key: &[u8; 32] = &[0x10, 0x86, 0x6e, 0xc4, 0x8a, 0x11, 0xf3, 0xc5,
+                           0x6d, 0x77, 0xa6, 0x4b, 0x2f, 0x54, 0xaa, 0x06,
+                           0x6c, 0x0c, 0xb4, 0x75, 0xd8, 0xc8, 0x7d, 0x35,
+                           0xb4, 0x91, 0xee, 0xd6, 0xac, 0x0b, 0xde, 0xbc];
+    ossuary_set_secret_key(conn, key as *const u8);
+
+    let out_buf: [u8; 512] = [0; 512];
+
+    let mut reader = std::io::BufReader::new(stream.try_clone().unwrap());
+    while ossuary_handshake_done(conn) == 0 {
+        let mut out_len = out_buf.len() as u16;
+        let more = ossuary_send_handshake(conn, (&out_buf) as *const u8 as *mut u8, &mut out_len);
+        let _ = stream.write_all(&out_buf[0.. out_len as usize]).unwrap();
+
+        if more >= 0 {
+            let in_buf = reader.fill_buf().unwrap();
+            let mut in_len = in_buf.len() as u16;
+            let len = ossuary_recv_handshake(conn, in_buf as *const [u8] as *const u8, &mut in_len);
+            reader.consume(len as usize);
+        }
+    }
+
+    let out_buf: [u8; 256] = [0; 256];
+    let mut plaintext: [u8; 256] = [0; 256];
+    plaintext[0..11].copy_from_slice("from client".as_bytes());
+    let mut out_len: u16 = out_buf.len() as u16;
+    let sz = ossuary_send_data(
+        conn,
+        (&plaintext) as *const u8 as *mut u8, 11 as u16,
+        (&out_buf) as *const u8 as *mut u8,
+        &mut out_len);
+    let _ = stream.write_all(&out_buf[0..sz as usize]).unwrap();
+
+    let mut stream = std::io::BufReader::new(stream);
+    let mut count = 0;
+    loop {
+        let in_buf = stream.fill_buf().unwrap();
+        if in_buf.len() == 0 || count == 2 {
+            break;
+        }
+        let mut out_len = out_buf.len() as u16;
+        let mut in_len = in_buf.len() as u16;
+        let len = ossuary_recv_data(
+            conn,
+            in_buf as *const [u8] as *mut u8, &mut in_len,
+            (&out_buf) as *const u8 as *mut u8, &mut out_len);
+        if len == -1 {
+            break;
+        }
+        if len > 0 {
+            println!("CLIB READ: {:?}",
+                     std::str::from_utf8(&out_buf[0..out_len as usize]).unwrap());
+            stream.consume(len as usize);
+            count += 1;
+        }
+    }
+
+    ossuary_destroy_connection(&mut conn);
+    Ok(())
+}
+
+#[test]
+fn test_clib() {
+    let server = thread::spawn(move || { let _ = server(); });
+    std::thread::sleep(std::time::Duration::from_millis(500));
+    let child = thread::spawn(move || { let _ = client(); });
+    let _ = child.join();
+    let _ = server.join();
+}