macro_rules! ffi_call {
($name: ident( $( $arg: expr ),* )) => {{
let result = libc::$name($($arg, )*);
match result {
-1 => Err(std::io::Error::last_os_error()),
_ => Ok(result),
}
}};
($name: ident( $( $arg: expr ),+ ,)) => {
ffi_fn!( $name( $( $arg ),+ ) )
};
}
pub struct Socket(libc::c_int);
impl Socket {
pub fn try_new(
domain: libc::c_int,
ty: libc::c_int,
protocol: libc::c_int,
) -> std::io::Result<Socket> {
unsafe { ffi_call!(socket(domain, ty, protocol)).map(Socket) }
}
pub unsafe fn bind(
&self,
address: *const libc::sockaddr,
length: libc::socklen_t,
) -> std::io::Result<()> {
ffi_call!(bind(self.0, address, length)).map(|_| ())
}
pub unsafe fn set_option(
&self,
level: libc::c_int,
name: libc::c_int,
value: *const libc::c_void,
length: libc::socklen_t,
) -> std::io::Result<()> {
ffi_call!(setsockopt(self.0, level, name, value, length)).map(|_| ())
}
pub unsafe fn send(
&self,
data: *const libc::c_void,
length: libc::size_t,
flags: libc::c_int,
) -> std::io::Result<()> {
ffi_call!(send(self.0, data, length, flags)).map(|_| ())
}
pub unsafe fn receive(
&self,
buffer: *mut libc::c_void,
length: libc::size_t,
flags: libc::c_int,
) -> std::io::Result<()> {
ffi_call!(recv(self.0, buffer, length, flags)).map(|_| ())
}
}
impl Drop for Socket {
fn drop(&mut self) {
if let Err(e) = unsafe { ffi_call!(close(self.0)) } {
log::error!("An error occur while closing the socket: {}", e);
}
}
}