Search code examples
rustsocketpair

Using socketpair() under Rust


How can you call Linux' socketpair() command in rust? I was not able to find it in the documentation.


Solution

  • This is how it works:

    use std::io;
    use std::libc;
    use std::libc::consts::os::bsd44;
    use std::libc::funcs::bsd43;
    
    extern {
        fn socketpair(
            domain:     libc::c_int,
            typ:        libc::c_int,
            protocol:   libc::c_int,
            sv:         *libc::c_int
        ) -> libc::c_int;
    }
    
    struct PairedStream {
        socket: i32
    }
    
    impl PairedStream {
        fn new(fd: i32) -> PairedStream {
            PairedStream {socket: fd}
        }
    
        fn send(&self, buf: &[u8]) -> Result<(), io::IoError> {
            let res = unsafe {
                let ptr = buf.as_ptr() as *mut libc::c_void;
                let len = buf.len() as u64;
                bsd43::send(self.socket, ptr, len, 0) as uint == buf.len()
            };
            if res {
                return Ok(());
            }
            else {
                return Err(io::IoError {
                    kind: io::OtherIoError,
                    desc: "TODO: determine error types ;)",
                    detail: None,
                })
            }
        }
    
        fn read(&self, buf: &mut [u8]) -> Result<uint, io::IoError> {
            let len = unsafe {
                let ptr = buf.as_ptr() as *mut libc::c_void;
                let len = buf.len() as u64;
                bsd43::recv(self.socket, ptr, len, 0)
            };
    
            if len == -1 {
                return Err(io::IoError {
                    kind: io::OtherIoError,
                    desc: "TODO: determine error types ;)",
                    detail: None,
                })
            }
            else {
                return Ok(len as uint);
            }
        }
    }
    
    struct SocketPair;
    
    impl SocketPair {
        fn new() -> (Result<(PairedStream, PairedStream), io::IoError>) {
            let AF_LOCAL = 1;
            let sv: [i32, ..2] = [-1, -1];
            let _type = bsd44::SOCK_DGRAM;
            let res = unsafe {
                socketpair(AF_LOCAL, _type, 0, sv.as_ptr()) == 0
            };
    
            if res {
                let s1 = PairedStream::new(sv[0]);
                let s2 = PairedStream::new(sv[1]);
    
                return Ok((s1, s2));
            }
            else {
                return Err(io::IoError {
                    kind: io::OtherIoError,
                    desc: "TODO: determine error types ;)",
                    detail: None,
                })
            }
        }
    }
    
    fn main() {
        let sockets = SocketPair::new();
        match sockets {
            Ok((s1, s2)) => {
                let mut buf = [9,8,7,6,5,4,3,2,1];
    
                s1.send([1,2,3,4,5,6,7,8,9]);
                s2.read(buf);
    
                println!("{} {}", buf[0], buf[8])
            }
            Err(ioerr) => {}
        }
    }