diff options
Diffstat (limited to 'src/sys')
-rw-r--r-- | src/sys/mod.rs | 1 | ||||
-rw-r--r-- | src/sys/socket.rs | 107 |
2 files changed, 108 insertions, 0 deletions
diff --git a/src/sys/mod.rs b/src/sys/mod.rs index 9d19e35d..5023cce8 100644 --- a/src/sys/mod.rs +++ b/src/sys/mod.rs @@ -1,3 +1,4 @@ pub mod epoll; +pub mod socket; pub mod stat; pub mod utsname; diff --git a/src/sys/socket.rs b/src/sys/socket.rs new file mode 100644 index 00000000..66ee48e2 --- /dev/null +++ b/src/sys/socket.rs @@ -0,0 +1,107 @@ +#![cfg(target_os = "linux")] + +use std::{mem, ptr}; +use libc::{c_int, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_un, socklen_t}; +use fcntl::Fd; +use errno::{SysResult, SysError, from_ffi}; + +mod ffi { + use libc::{c_int, sockaddr, socklen_t}; + + extern { + pub fn socket(domain: c_int, ty: c_int, proto: c_int) -> c_int; + + pub fn listen(sockfd: c_int, backlog: c_int) -> c_int; + + pub fn bind(sockfd: c_int, addr: *const sockaddr, addrlen: socklen_t) -> c_int; + + pub fn accept( + sockfd: c_int, + addr: *const sockaddr, + addrlen: *mut socklen_t) -> c_int; + + pub fn accept4( + sockfd: c_int, + addr: *const sockaddr, + addrlen: *mut socklen_t, + flags: c_int) -> c_int; + } +} + +pub type AddressFamily = c_int; + +pub static AF_UNIX: AddressFamily = 1; +pub static AF_LOCAL: AddressFamily = AF_UNIX; +pub static AF_INET: AddressFamily = 2; +pub static AF_INET6: AddressFamily = 10; + +pub type SockType = c_int; + +pub static SOCK_STREAM: SockType = 1; +pub static SOCK_DGRAM: SockType = 1; +pub static SOCK_SEQPACKET: SockType = 1; +pub static SOCK_RAW: SockType = 1; +pub static SOCK_RDM: SockType = 1; + +// Extra flags - Linux 2.6.27 +bitflags!( + flags SockFlag: c_int { + static SOCK_NONBLOCK = 0o0004000, + static SOCK_CLOEXEC = 0o2000000 + } +) + +pub fn socket(domain: AddressFamily, ty: SockType, flags: SockFlag) -> SysResult<Fd> { + // TODO: Check the kernel version + let res = unsafe { ffi::socket(domain, ty | flags.bits(), 0) }; + + if res < 0 { + return Err(SysError::last()); + } + + Ok(res) +} + +pub fn listen(sockfd: Fd, backlog: uint) -> SysResult<()> { + let res = unsafe { ffi::listen(sockfd, backlog as c_int) }; + from_ffi(res) +} + +pub enum BindAddr<'a> { + BindIpV4(&'a sockaddr_in), + BindIpV6(&'a sockaddr_in6), + BindUnix(&'a sockaddr_un) +} + +pub fn bind(sockfd: Fd, addr: BindAddr) -> SysResult<()> { + let res = unsafe { + match addr { + BindIpV4(addr) => ffi::bind(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_in>() as socklen_t), + BindIpV6(addr) => ffi::bind(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_in6>() as socklen_t), + BindUnix(addr) => ffi::bind(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_un>() as socklen_t) + } + }; + + from_ffi(res) +} + +pub fn accept(sockfd: Fd) -> SysResult<Fd> { + let res = unsafe { ffi::accept(sockfd, ptr::null(), ptr::mut_null()) }; + + if res < 0 { + return Err(SysError::last()); + } + + Ok(res) +} + +pub fn accept4(sockfd: Fd, flags: SockFlag) -> SysResult<Fd> { + // TODO: Check the kernel version + let res = unsafe { ffi::accept4(sockfd, ptr::null(), ptr::mut_null(), flags.bits) }; + + if res < 0 { + return Err(SysError::last()); + } + + Ok(res) +} |