Hi,
I'm trying to call libc::recvfrom
but I'm a little lost. By looking at other repos I've came up with two methods that compile, but I'm not sure if they are correct, and if not, why they are incorrect. Note that the code is imcomplete (the methods should return something, I should check the return value of recvfrom
, etc), I just minimized it to the portion I'm struggling with.
extern crate libc;
use std::os::unix::io::RawFd;
use std::ptr;
fn main() {}
pub struct Socket(RawFd);
impl Socket {
fn recv_from_simple(&self, buf: &mut [u8]) {
let _ = unsafe {
let addr: *mut libc::sockaddr = ptr::null_mut();
let addrlen: *mut libc::socklen_t = ptr::null_mut();
// I'm not 100% sure why this cast is safe.
//
// As far as I understand buf.as_mut_ptr() is a *mut u8, on and on 64 bits platform
// lib::c_void is a *mut usize, so I guess this is fine as long as there's not pointer
// arithmetic being done in recvfrom?
let bufptr = buf.as_mut_ptr() as *mut libc::c_void;
let buflen = buf.len() as libc::size_t;
libc::recvfrom(self.0, bufptr, buflen, 0, addr, addrlen);
};
unimplemented!();
}
// This seems more complicated and I don't understand why we need the extra "&mut T as *mut _ as *mut _"
// But that's how it's done in the rust repo: https://github.com/rust-lang/rust/blob/8ff4b42064b374bb62043f7729f84b6d979c7667/src/libstd/sys/unix/net.rs#L251
fn recv_from_like_in_the_rust_repo(&self, buf: &mut [u8]) {
let _ = unsafe {
let mut addr: *mut libc::sockaddr = ptr::null_mut();
let mut addrlen: *mut libc::socklen_t = ptr::null_mut();
let mut bufptr = buf.as_mut_ptr() as *mut libc::c_void;
let buflen = buf.len() as libc::size_t;
libc::recvfrom(
self.0,
bufptr,
buflen,
0,
&mut addr as *mut _ as *mut _,
addrlen,
);
};
unimplemented!();
}
}
The second one is kind of taken from the rust repo, where it looks like:
fn recv_from_with_flags(&self, buf: &mut [u8], flags: c_int)
-> io::Result<(usize, SocketAddr)> {
let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() };
let mut addrlen = mem::size_of_val(&storage) as libc::socklen_t;
let n = cvt(unsafe {
libc::recvfrom(self.0.raw(),
buf.as_mut_ptr() as *mut c_void,
buf.len(),
flags,
&mut storage as *mut _ as *mut _,
&mut addrlen)
})?;
Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize)?))
}
Could someone explain if my solutions work, and if not, why not? I could just copy/paste from the Rust repo but I'd like to understand why this works.