lazy_socket/raw/
unix.rs

1use std::net;
2use std::io;
3use std::mem;
4use std::ptr;
5use std::cmp;
6
7mod libc {
8    extern crate libc;
9
10    //Types
11    pub use self::libc::{
12        c_int,
13        c_void,
14        c_char,
15        c_long,
16        c_ulong,
17        ssize_t,
18        socklen_t,
19        size_t,
20        sockaddr,
21        sockaddr_storage,
22        sa_family_t,
23        in_port_t,
24        fd_set,
25        timeval,
26        time_t,
27        suseconds_t
28    };
29
30    #[cfg(target_env = "musl")]
31    pub type IoctlRequestT = c_int;
32    #[cfg(not(target_env = "musl"))]
33    pub type IoctlRequestT = c_ulong;
34
35    pub use self::libc::{
36        sockaddr_in,
37        sockaddr_in6,
38
39        in_addr,
40        in6_addr
41    };
42
43    pub type SOCKET = c_int;
44    pub const SOCKET_ERROR: c_int = -1;
45    pub const SOCKET_SHUTDOWN: c_int = libc::ESHUTDOWN;
46
47    //Constants
48    pub use self::libc::{
49        EINVAL,
50        FIONBIO,
51        F_GETFD,
52        F_SETFD,
53        FD_CLOEXEC
54    };
55
56    #[cfg(target_os = "macos")]
57    pub use self::libc::{
58        AF_UNIX,
59        AF_INET,
60        AF_INET6,
61        SOCK_STREAM,
62        SOCK_DGRAM,
63        SOCK_RAW,
64        SOCK_SEQPACKET,
65    };
66
67    #[cfg(target_os = "macos")]
68    pub const AF_UNSPEC: c_int = 0;
69    #[cfg(target_os = "macos")]
70    pub const SOCK_NONBLOCK: c_int = 0o0004000;
71    #[cfg(target_os = "macos")]
72    pub const SOCK_CLOEXEC: c_int = 0o2000000;
73
74    #[cfg(not(target_os = "macos"))]
75    pub use self::libc::{
76        AF_UNSPEC,
77        AF_UNIX,
78        AF_INET,
79        AF_INET6,
80        SOCK_STREAM,
81        SOCK_DGRAM,
82        SOCK_RAW,
83        SOCK_SEQPACKET,
84        SOCK_NONBLOCK,
85        SOCK_CLOEXEC
86    };
87
88    #[cfg(target_os = "linux")]
89    pub use self::libc::{
90        AF_NETLINK,
91        AF_PACKET,
92    };
93
94    //Functions
95    pub use self::libc::{
96        socket,
97        getsockname,
98        bind,
99        listen,
100        recv,
101        recvfrom,
102        send,
103        sendto,
104        accept,
105        connect,
106        getsockopt,
107        setsockopt,
108        fcntl,
109        ioctl,
110        shutdown,
111        close,
112        select,
113        FD_SET
114    };
115
116    #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd", target_os = "dragonflybsd"))]
117    pub use self::libc::{
118        accept4
119    };
120}
121
122use self::libc::*;
123
124macro_rules! impl_into_trait {
125    ($($t:ty), +) => {
126        $(
127            impl Into<c_int> for $t {
128                fn into(self) -> c_int {
129                    self as c_int
130                }
131            }
132        )+
133    };
134}
135
136#[allow(non_snake_case, non_upper_case_globals)]
137///Socket family
138pub mod Family {
139    use super::libc::*;
140    pub const UNSPECIFIED: c_int = AF_UNSPEC;
141    pub const UNIX: c_int = AF_UNIX;
142    pub const IPv4: c_int = AF_INET;
143    pub const IPv6: c_int = AF_INET6;
144    #[cfg(target_os = "linux")]
145    pub const NETLINK: c_int = AF_NETLINK;
146    #[cfg(target_os = "linux")]
147    pub const PACKET: c_int = AF_PACKET;
148}
149
150#[allow(non_snake_case)]
151///Socket type
152pub mod Type {
153    use super::libc::*;
154    pub const STREAM: c_int = SOCK_STREAM;
155    pub const DATAGRAM: c_int = SOCK_DGRAM;
156    pub const RAW: c_int = SOCK_RAW;
157    pub const SEQPACKET: c_int = SOCK_SEQPACKET;
158    #[cfg(not(target_os = "macos"))]
159    ///Applied through bitwise OR
160    pub const NONBLOCK: c_int = SOCK_NONBLOCK;
161    #[cfg(not(target_os = "macos"))]
162    ///Applied through bitwise OR
163    pub const CLOEXEC: c_int = SOCK_CLOEXEC;
164}
165
166#[allow(non_snake_case, non_upper_case_globals)]
167///Socket protocol
168pub mod Protocol {
169    use super::libc::*;
170    pub const NONE: c_int = 0;
171    pub const ICMPv4: c_int = 1;
172    pub const TCP: c_int = 6;
173    pub const UDP: c_int = 17;
174    pub const ICMPv6: c_int = 58;
175}
176
177#[allow(non_snake_case)]
178///Possible flags for `accept4()`
179bitflags! (pub flags AcceptFlags: c_int {
180    const NON_BLOCKING    = SOCK_NONBLOCK,
181    const NON_INHERITABLE = SOCK_CLOEXEC,
182});
183
184#[repr(i32)]
185#[derive(Copy, Clone)]
186///Type of socket's shutdown operation.
187pub enum ShutdownType {
188    ///Stops any further receives.
189    Receive = 0,
190    ///Stops any further sends.
191    Send = 1,
192    ///Stops both sends and receives.
193    Both = 2
194}
195
196impl_into_trait!(ShutdownType);
197
198///Raw socket
199pub struct Socket {
200    inner: SOCKET
201}
202
203impl Socket {
204    ///Initializes new socket.
205    ///
206    ///Corresponds to C connect()
207    pub fn new(family: c_int, _type: c_int, protocol: c_int) -> io::Result<Socket> {
208        unsafe {
209            match socket(family, _type, protocol) {
210                SOCKET_ERROR => Err(io::Error::last_os_error()),
211                fd => Ok(Socket {
212                    inner: fd
213                }),
214            }
215        }
216    }
217
218    ///Returns underlying socket descriptor.
219    ///
220    ///Note: ownership is not transferred.
221    pub fn raw(&self) -> SOCKET {
222        self.inner
223    }
224
225    ///Retrieves socket name i.e. address
226    ///
227    ///Wraps `getsockname()`
228    ///
229    ///Available for binded/connected sockets.
230    pub fn name(&self) -> io::Result<net::SocketAddr> {
231        unsafe {
232            let mut storage: sockaddr_storage = mem::zeroed();
233            let mut len = mem::size_of_val(&storage) as socklen_t;
234
235            match getsockname(self.inner, &mut storage as *mut _ as *mut _, &mut len) {
236                SOCKET_ERROR => Err(io::Error::last_os_error()),
237                _ => sockaddr_to_addr(&storage, len)
238            }
239        }
240    }
241
242    ///Binds socket to address.
243    pub fn bind(&self, addr: &net::SocketAddr) -> io::Result<()> {
244        let (addr, len) = get_raw_addr(addr);
245
246        unsafe {
247            match bind(self.inner, addr, len) {
248                0 => Ok(()),
249                _ => Err(io::Error::last_os_error())
250            }
251        }
252    }
253
254    ///Listens for incoming connections on this socket.
255    pub fn listen(&self, backlog: c_int) -> io::Result<()> {
256        unsafe {
257            match listen(self.inner, backlog) {
258                0 => Ok(()),
259                _ => Err(io::Error::last_os_error())
260            }
261        }
262    }
263
264    ///Receives some bytes from socket
265    ///
266    ///Number of received bytes is returned on success
267    pub fn recv(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> {
268        let len = buf.len();
269
270        unsafe {
271            match recv(self.inner, buf.as_mut_ptr() as *mut c_void, len, flags) {
272                -1 => Err(io::Error::last_os_error()),
273                n => Ok(n as usize)
274            }
275        }
276    }
277
278    ///Receives some bytes from socket
279    ///
280    ///Number of received bytes and remote address are returned on success.
281    pub fn recv_from(&self, buf: &mut [u8], flags: c_int) -> io::Result<(usize, net::SocketAddr)> {
282        let len = buf.len();
283
284        unsafe {
285            let mut storage: sockaddr_storage = mem::zeroed();
286            let mut storage_len = mem::size_of_val(&storage) as socklen_t;
287
288            match recvfrom(self.inner, buf.as_mut_ptr() as *mut c_void, len, flags, &mut storage as *mut _ as *mut _, &mut storage_len) {
289                -1 => Err(io::Error::last_os_error()),
290                n => {
291                    let peer_addr = sockaddr_to_addr(&storage, storage_len)?;
292                    Ok((n as usize, peer_addr))
293                }
294            }
295        }
296    }
297
298    ///Sends some bytes through socket.
299    ///
300    ///Number of sent bytes is returned.
301    pub fn send(&self, buf: &[u8], flags: c_int) -> io::Result<usize> {
302        let len = buf.len();
303
304        unsafe {
305            match send(self.inner, buf.as_ptr() as *const c_void, len, flags) {
306                -1 => {
307                    let error = io::Error::last_os_error();
308                    let raw_code = error.raw_os_error().unwrap();
309
310                    if raw_code == SOCKET_SHUTDOWN {
311                        Ok(0)
312                    }
313                    else {
314                        Err(error)
315                    }
316                },
317                n => Ok(n as usize)
318            }
319        }
320    }
321
322    ///Sends some bytes through socket toward specified peer.
323    ///
324    ///Number of sent bytes is returned.
325    ///
326    ///Note: the socket will be bound, if it isn't already.
327    ///Use method `name` to determine address.
328    pub fn send_to(&self, buf: &[u8], peer_addr: &net::SocketAddr, flags: c_int) -> io::Result<usize> {
329        let len = buf.len();
330        let (addr, addr_len) = get_raw_addr(peer_addr);
331
332        unsafe {
333            match sendto(self.inner, buf.as_ptr() as *const c_void, len, flags, addr, addr_len) {
334                -1 => {
335                    let error = io::Error::last_os_error();
336                    let raw_code = error.raw_os_error().unwrap();
337
338                    if raw_code == SOCKET_SHUTDOWN {
339                        Ok(0)
340                    }
341                    else {
342                        Err(error)
343                    }
344                },
345                n => Ok(n as usize)
346            }
347        }
348    }
349
350    ///Accept a new incoming client connection and return its files descriptor and address.
351    ///
352    ///By default the newly created socket will be inheritable by child processes and created
353    ///in blocking I/O mode. This behaviour can be customized using the `flags` parameter:
354    ///
355    /// * `AcceptFlags::NON_BLOCKING`    – Mark the newly created socket as non-blocking
356    /// * `AcceptFlags::NON_INHERITABLE` – Mark the newly created socket as not inheritable by client processes
357    ///
358    ///Depending on the operating system's availability of the `accept4(2)` system call this call
359    ///either pass the flags on to the operating system or emulate the call using `accept(2)`.
360    pub fn accept4(&self, flags: AcceptFlags) -> io::Result<(Socket, net::SocketAddr)> {
361        #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd", target_os = "dragonflybsd"))]
362        unsafe {
363            let mut storage: sockaddr_storage = mem::zeroed();
364            let mut len = mem::size_of_val(&storage) as socklen_t;
365
366            match accept4(self.inner, &mut storage as *mut _ as *mut _, &mut len, flags.bits()) {
367                SOCKET_ERROR => Err(io::Error::last_os_error()),
368                sock @ _ => {
369                    let addr = sockaddr_to_addr(&storage, len)?;
370                    Ok((Socket { inner: sock, }, addr))
371                }
372            }
373        }
374
375        #[cfg(not(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd", target_os = "dragonflybsd")))]
376        {
377            self.accept().map(|(sock, addr)| {
378                // Emulate the two most common (and useful) `accept4` flags using `ioctl`/`fcntl`
379                //
380                // The only errors that can happen here fall into two categories:
381                //
382                //  * Programming errors on our side
383                //    (unlikely, but in this case panicking is actually the right thing to do anyway)
384                //  * Another thread causing havoc with random file descriptors
385                //    (always very bad and nothing, since there is absolutely nothing
386                //     that we OR USER can do about this)
387                sock.set_blocking(!flags.contains(NON_BLOCKING)).expect("Setting newly obtained client socket blocking mode");
388                sock.set_inheritable(!flags.contains(NON_INHERITABLE)).expect("Setting newly obtained client socket inheritance mode");
389
390                (sock, addr)
391            })
392        }
393    }
394
395
396    ///Accept a new incoming client connection and return its files descriptor and address.
397    ///
398    ///As this uses the classic `accept(2)` system call internally, you are **strongly advised** to
399    ///use the `.accept4()` method instead to get defined blocking and inheritance semantics for
400    ///the created file descriptor.
401    pub fn accept(&self) -> io::Result<(Socket, net::SocketAddr)> {
402        unsafe {
403            let mut storage: sockaddr_storage = mem::zeroed();
404            let mut len = mem::size_of_val(&storage) as socklen_t;
405
406            match accept(self.inner, &mut storage as *mut _ as *mut _, &mut len) {
407                SOCKET_ERROR => Err(io::Error::last_os_error()),
408                sock @ _ => {
409                    let addr = sockaddr_to_addr(&storage, len)?;
410                    Ok((Socket { inner: sock }, addr))
411                }
412            }
413        }
414    }
415
416
417    ///Connects socket with remote address.
418    pub fn connect(&self, addr: &net::SocketAddr) -> io::Result<()> {
419        let (addr, len) = get_raw_addr(addr);
420
421        unsafe {
422            match connect(self.inner, addr, len) {
423                0 => Ok(()),
424                _ => Err(io::Error::last_os_error())
425            }
426        }
427    }
428
429    ///Retrieves socket option.
430    pub fn get_opt<T>(&self, level: c_int, name: c_int) -> io::Result<T> {
431        unsafe {
432            let mut value: T = mem::zeroed();
433            let value_ptr = &mut value as *mut T as *mut c_void;
434            let mut value_len = mem::size_of::<T>() as socklen_t;
435
436            match getsockopt(self.inner, level, name, value_ptr, &mut value_len) {
437                0 => Ok(value),
438                _ => Err(io::Error::last_os_error())
439            }
440        }
441    }
442
443    ///Sets socket option
444    ///
445    ///Value is generally integer or C struct.
446    pub fn set_opt<T>(&self, level: c_int, name: c_int, value: T) -> io::Result<()> {
447        unsafe {
448            let value = &value as *const T as *const c_void;
449
450            match setsockopt(self.inner, level, name, value, mem::size_of::<T>() as socklen_t) {
451                0 => Ok(()),
452                _ => Err(io::Error::last_os_error())
453            }
454        }
455    }
456
457    ///Sets I/O parameters of socket.
458    pub fn ioctl(&self, request: IoctlRequestT, value: c_ulong) -> io::Result<()> {
459        unsafe {
460            let mut value = value;
461            let value = &mut value as *mut c_ulong;
462
463            match ioctl(self.inner, request, value) {
464                0 => Ok(()),
465                _ => Err(io::Error::last_os_error())
466            }
467        }
468    }
469
470    ///Sets non-blocking mode.
471    pub fn set_blocking(&self, value: bool) -> io::Result<()> {
472        self.ioctl(FIONBIO, (!value) as c_ulong)
473    }
474
475
476    ///Sets whether this socket will be inherited by newly created processes or not.
477    ///
478    ///Internally this is implemented by calling `fcntl(fd, F_GETFD)` and `fcntl(fd, F_SETFD)`
479    ///to update the `FD_CLOEXEC` flag. (In the future this might use `ioctl(2)` on some
480    ///platforms instead.)
481    ///
482    ///This means that the socket will still be available to forked off child processes until it
483    ///calls `execve(2)` to complete the creation of a new process. A forking server application
484    ///(or similar) should therefore not expect this flag to have any effect on spawned off workers;
485    ///you're advised to manually call `.close()` on the socket instance in the worker process
486    ///instead. The standard library's `std::process` facility is not impacted by this however.
487    pub fn set_inheritable(&self, value: bool) -> io::Result<()> {
488        // Some (or possibly all?) OS's support the `FIOCLEX` and `FIONCLEX`
489        // `ioctl`s instead, however there is no support for that in `libc`
490        // currently and no usable documentation for figuring out who supports
491        // this feature online either
492        unsafe {
493            let mut flags: libc::c_int = libc::fcntl(self.inner, libc::F_GETFD);
494            if flags < 0 {
495                return Err(io::Error::last_os_error());
496            }
497
498            if value == true {
499                flags &= !libc::FD_CLOEXEC;
500            } else {
501                flags |= libc::FD_CLOEXEC;
502            }
503
504            if libc::fcntl(self.inner, libc::F_SETFD, flags) < 0 {
505                return Err(io::Error::last_os_error());
506            }
507        }
508
509        Ok(())
510    }
511
512    ///Returns whether this will be inherited by newly created processes or not.
513    ///
514    ///See `set_inheritable` for a detailed description of what this means.
515    pub fn get_inheritable(&self) -> io::Result<bool> {
516        unsafe {
517            let flags = libc::fcntl(self.inner, libc::F_GETFD);
518            if flags < 0 {
519                return Err(io::Error::last_os_error());
520            }
521
522            Ok((flags & libc::FD_CLOEXEC) == 0)
523        }
524    }
525
526
527    ///Stops receive and/or send over socket.
528    pub fn shutdown(&self, direction: ShutdownType) -> io::Result<()> {
529        unsafe {
530            match shutdown(self.inner, direction.into()) {
531                0 => Ok(()),
532                _ => Err(io::Error::last_os_error())
533            }
534        }
535    }
536
537    ///Closes socket.
538    ///
539    ///Note: on `Drop` socket will be closed on its own.
540    ///There is no need to close it explicitly.
541    pub fn close(&self) -> io::Result<()> {
542        unsafe {
543            match close(self.inner) {
544                0 => Ok(()),
545                _ => Err(io::Error::last_os_error())
546            }
547        }
548    }
549}
550
551fn get_raw_addr(addr: &net::SocketAddr) -> (*const sockaddr, socklen_t) {
552    match *addr {
553        net::SocketAddr::V4(ref a) => {
554            (a as *const _ as *const _, mem::size_of_val(a) as socklen_t)
555        }
556        net::SocketAddr::V6(ref a) => {
557            (a as *const _ as *const _, mem::size_of_val(a) as socklen_t)
558        }
559    }
560}
561
562fn sockaddr_to_addr(storage: &sockaddr_storage, len: socklen_t) -> io::Result<net::SocketAddr> {
563    match storage.ss_family as c_int {
564        AF_INET => {
565            assert!(len as usize >= mem::size_of::<sockaddr_in>());
566            let storage = unsafe { *(storage as *const _ as *const sockaddr_in) };
567            let address = unsafe { *(&storage.sin_addr.s_addr as *const _ as *const [u8; 4]) };
568            let ip = net::Ipv4Addr::from(address);
569
570            //Note to_be() swap bytes on LE targets
571            //As IP stuff is always BE, we need swap only on LE targets
572            Ok(net::SocketAddr::V4(net::SocketAddrV4::new(ip, storage.sin_port.to_be())))
573        }
574        AF_INET6 => {
575            assert!(len as usize >= mem::size_of::<sockaddr_in6>());
576            let storage = unsafe { *(storage as *const _ as *const sockaddr_in6) };
577            let ip = net::Ipv6Addr::from(storage.sin6_addr.s6_addr.clone());
578
579            Ok(net::SocketAddr::V6(net::SocketAddrV6::new(ip, storage.sin6_port.to_be(), storage.sin6_flowinfo, storage.sin6_scope_id)))
580        }
581        _ => {
582            Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid addr type."))
583        }
584    }
585}
586
587impl Drop for Socket {
588    fn drop(&mut self) {
589        let _ = self.shutdown(ShutdownType::Both);
590        let _ = self.close();
591    }
592}
593
594use std::os::unix::io::{
595    AsRawFd,
596    FromRawFd,
597    IntoRawFd,
598};
599
600impl AsRawFd for Socket {
601    fn as_raw_fd(&self) -> SOCKET {
602        self.inner
603    }
604}
605
606impl FromRawFd for Socket {
607    unsafe fn from_raw_fd(sock: SOCKET) -> Self {
608        Socket {inner: sock}
609    }
610}
611
612impl IntoRawFd for Socket {
613    fn into_raw_fd(self) -> SOCKET {
614        let result = self.inner;
615        mem::forget(self);
616        result
617    }
618}
619
620#[inline]
621fn ms_to_timeval(timeout_ms: u64) -> timeval {
622    timeval {
623        tv_sec: timeout_ms as time_t / 1000,
624        tv_usec: (timeout_ms as suseconds_t % 1000) * 1000
625    }
626}
627
628fn sockets_to_fd_set(sockets: &[&Socket]) -> (c_int, fd_set) {
629    let mut max_fd: c_int = 0;
630    let mut raw_fds: fd_set = unsafe { mem::zeroed() };
631
632    for socket in sockets {
633        max_fd = cmp::max(max_fd, socket.inner);
634        unsafe {
635            FD_SET(socket.inner, &mut raw_fds);
636        }
637    }
638
639    (max_fd, raw_fds)
640}
641
642///Wrapper over system `select`
643///
644///Returns number of sockets that are ready.
645///
646///If timeout isn't specified then select will be a blocking call.
647pub fn select(read_fds: &[&Socket], write_fds: &[&Socket], except_fds: &[&Socket], timeout_ms: Option<u64>) -> io::Result<c_int> {
648    let (max_read_fd, mut raw_read_fds) = sockets_to_fd_set(read_fds);
649    let (max_write_fd, mut raw_write_fds) = sockets_to_fd_set(write_fds);
650    let (max_except_fd, mut raw_except_fds) = sockets_to_fd_set(except_fds);
651
652    let nfds = cmp::max(max_read_fd, cmp::max(max_write_fd, max_except_fd)) + 1;
653
654    unsafe {
655        match libc::select(nfds,
656                           if max_read_fd > 0 { &mut raw_read_fds } else { ptr::null_mut() },
657                           if max_write_fd > 0 { &mut raw_write_fds } else { ptr::null_mut() },
658                           if max_except_fd > 0 { &mut raw_except_fds } else { ptr::null_mut() },
659                           if let Some(timeout_ms) = timeout_ms { &mut ms_to_timeval(timeout_ms) } else { ptr::null_mut() } ) {
660            SOCKET_ERROR => Err(io::Error::last_os_error()),
661            result @ _ => Ok(result)
662
663        }
664    }
665}