1 //! Socket interface functions
2 //!
3 //! [Further reading](http://man7.org/linux/man-pages/man7/socket.7.html)
4 use {Error, Errno, Result};
5 use features;
6 use fcntl::{fcntl, FD_CLOEXEC, O_NONBLOCK};
7 use fcntl::FcntlArg::{F_SETFD, F_SETFL};
8 use libc::{c_void, c_int, socklen_t, size_t, pid_t, uid_t, gid_t};
9 use std::{mem, ptr, slice};
10 use std::os::unix::io::RawFd;
11 use sys::uio::IoVec;
12 
13 mod addr;
14 mod consts;
15 mod ffi;
16 mod multicast;
17 pub mod sockopt;
18 
19 /*
20  *
21  * ===== Re-exports =====
22  *
23  */
24 
25 pub use self::addr::{
26     AddressFamily,
27     SockAddr,
28     InetAddr,
29     UnixAddr,
30     IpAddr,
31     Ipv4Addr,
32     Ipv6Addr,
33 };
34 #[cfg(any(target_os = "linux", target_os = "android"))]
35 pub use ::sys::socket::addr::netlink::NetlinkAddr;
36 
37 pub use libc::{
38     in_addr,
39     in6_addr,
40     sockaddr,
41     sockaddr_in,
42     sockaddr_in6,
43     sockaddr_un,
44     sa_family_t,
45 };
46 
47 pub use self::multicast::{
48     ip_mreq,
49     ipv6_mreq,
50 };
51 pub use self::consts::*;
52 
53 pub use libc::sockaddr_storage;
54 
55 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
56 #[repr(i32)]
57 pub enum SockType {
58     Stream = consts::SOCK_STREAM,
59     Datagram = consts::SOCK_DGRAM,
60     SeqPacket = consts::SOCK_SEQPACKET,
61     Raw = consts::SOCK_RAW,
62     Rdm = consts::SOCK_RDM,
63 }
64 
65 // Extra flags - Supported by Linux 2.6.27, normalized on other platforms
66 bitflags!(
67     pub struct SockFlag: c_int {
68         const SOCK_NONBLOCK = 0o0004000;
69         const SOCK_CLOEXEC  = 0o2000000;
70     }
71 );
72 
73 /// Copy the in-memory representation of src into the byte slice dst,
74 /// updating the slice to point to the remainder of dst only. Unsafe
75 /// because it exposes all bytes in src, which may be UB if some of them
76 /// are uninitialized (including padding).
copy_bytes<'a, 'b, T: ?Sized>(src: &T, dst: &'a mut &'b mut [u8])77 unsafe fn copy_bytes<'a, 'b, T: ?Sized>(src: &T, dst: &'a mut &'b mut [u8]) {
78     let srclen = mem::size_of_val(src);
79     let mut tmpdst = &mut [][..];
80     mem::swap(&mut tmpdst, dst);
81     let (target, mut remainder) = tmpdst.split_at_mut(srclen);
82     // Safe because the mutable borrow of dst guarantees that src does not alias it.
83     ptr::copy_nonoverlapping(src as *const T as *const u8, target.as_mut_ptr(), srclen);
84     mem::swap(dst, &mut remainder);
85 }
86 
87 
88 use self::ffi::{cmsghdr, msghdr, type_of_cmsg_len, type_of_cmsg_data};
89 
90 /// A structure used to make room in a cmsghdr passed to recvmsg. The
91 /// size and alignment match that of a cmsghdr followed by a T, but the
92 /// fields are not accessible, as the actual types will change on a call
93 /// to recvmsg.
94 ///
95 /// To make room for multiple messages, nest the type parameter with
96 /// tuples, e.g.
97 /// `let cmsg: CmsgSpace<([RawFd; 3], CmsgSpace<[RawFd; 2]>)> = CmsgSpace::new();`
98 pub struct CmsgSpace<T> {
99     _hdr: cmsghdr,
100     _data: T,
101 }
102 
103 impl<T> CmsgSpace<T> {
104     /// Create a CmsgSpace<T>. The structure is used only for space, so
105     /// the fields are uninitialized.
new() -> Self106     pub fn new() -> Self {
107         // Safe because the fields themselves aren't accessible.
108         unsafe { mem::uninitialized() }
109     }
110 }
111 
112 pub struct RecvMsg<'a> {
113     // The number of bytes received.
114     pub bytes: usize,
115     cmsg_buffer: &'a [u8],
116     pub address: Option<SockAddr>,
117     pub flags: MsgFlags,
118 }
119 
120 impl<'a> RecvMsg<'a> {
121     /// Iterate over the valid control messages pointed to by this
122     /// msghdr.
cmsgs(&self) -> CmsgIterator123     pub fn cmsgs(&self) -> CmsgIterator {
124         CmsgIterator(self.cmsg_buffer)
125     }
126 }
127 
128 pub struct CmsgIterator<'a>(&'a [u8]);
129 
130 impl<'a> Iterator for CmsgIterator<'a> {
131     type Item = ControlMessage<'a>;
132 
133     // The implementation loosely follows CMSG_FIRSTHDR / CMSG_NXTHDR,
134     // although we handle the invariants in slightly different places to
135     // get a better iterator interface.
next(&mut self) -> Option<ControlMessage<'a>>136     fn next(&mut self) -> Option<ControlMessage<'a>> {
137         let buf = self.0;
138         let sizeof_cmsghdr = mem::size_of::<cmsghdr>();
139         if buf.len() < sizeof_cmsghdr {
140             return None;
141         }
142         let cmsg: &cmsghdr = unsafe { mem::transmute(buf.as_ptr()) };
143 
144         // This check is only in the glibc implementation of CMSG_NXTHDR
145         // (although it claims the kernel header checks this), but such
146         // a structure is clearly invalid, either way.
147         let cmsg_len = cmsg.cmsg_len as usize;
148         if cmsg_len < sizeof_cmsghdr {
149             return None;
150         }
151         let len = cmsg_len - sizeof_cmsghdr;
152 
153         // Advance our internal pointer.
154         if cmsg_align(cmsg_len) > buf.len() {
155             return None;
156         }
157         self.0 = &buf[cmsg_align(cmsg_len)..];
158 
159         match (cmsg.cmsg_level, cmsg.cmsg_type) {
160             (SOL_SOCKET, SCM_RIGHTS) => unsafe {
161                 Some(ControlMessage::ScmRights(
162                     slice::from_raw_parts(
163                         &cmsg.cmsg_data as *const _ as *const _, 1)))
164             },
165             (_, _) => unsafe {
166                 Some(ControlMessage::Unknown(UnknownCmsg(
167                     &cmsg,
168                     slice::from_raw_parts(
169                         &cmsg.cmsg_data as *const _ as *const _,
170                         len))))
171             }
172         }
173     }
174 }
175 
176 /// A type-safe wrapper around a single control message. More types may
177 /// be added to this enum; do not exhaustively pattern-match it.
178 /// [Further reading](http://man7.org/linux/man-pages/man3/cmsg.3.html)
179 pub enum ControlMessage<'a> {
180     /// A message of type SCM_RIGHTS, containing an array of file
181     /// descriptors passed between processes. See the description in the
182     /// "Ancillary messages" section of the
183     /// [unix(7) man page](http://man7.org/linux/man-pages/man7/unix.7.html).
184     ScmRights(&'a [RawFd]),
185     #[doc(hidden)]
186     Unknown(UnknownCmsg<'a>),
187 }
188 
189 // An opaque structure used to prevent cmsghdr from being a public type
190 #[doc(hidden)]
191 pub struct UnknownCmsg<'a>(&'a cmsghdr, &'a [u8]);
192 
cmsg_align(len: usize) -> usize193 fn cmsg_align(len: usize) -> usize {
194     let align_bytes = mem::size_of::<type_of_cmsg_data>() - 1;
195     (len + align_bytes) & !align_bytes
196 }
197 
198 impl<'a> ControlMessage<'a> {
199     /// The value of CMSG_SPACE on this message.
space(&self) -> usize200     fn space(&self) -> usize {
201         cmsg_align(self.len())
202     }
203 
204     /// The value of CMSG_LEN on this message.
len(&self) -> usize205     fn len(&self) -> usize {
206         cmsg_align(mem::size_of::<cmsghdr>()) + match *self {
207             ControlMessage::ScmRights(fds) => {
208                 mem::size_of_val(fds)
209             },
210             ControlMessage::Unknown(UnknownCmsg(_, bytes)) => {
211                 mem::size_of_val(bytes)
212             }
213         }
214     }
215 
216     // Unsafe: start and end of buffer must be size_t-aligned (that is,
217     // cmsg_align'd). Updates the provided slice; panics if the buffer
218     // is too small.
encode_into<'b>(&self, buf: &mut &'b mut [u8])219     unsafe fn encode_into<'b>(&self, buf: &mut &'b mut [u8]) {
220         match *self {
221             ControlMessage::ScmRights(fds) => {
222                 let cmsg = cmsghdr {
223                     cmsg_len: self.len() as type_of_cmsg_len,
224                     cmsg_level: SOL_SOCKET,
225                     cmsg_type: SCM_RIGHTS,
226                     cmsg_data: [],
227                 };
228                 copy_bytes(&cmsg, buf);
229 
230                 let padlen = cmsg_align(mem::size_of_val(&cmsg)) -
231                     mem::size_of_val(&cmsg);
232 
233                 let mut tmpbuf = &mut [][..];
234                 mem::swap(&mut tmpbuf, buf);
235                 let (_padding, mut remainder) = tmpbuf.split_at_mut(padlen);
236                 mem::swap(buf, &mut remainder);
237 
238                 copy_bytes(fds, buf);
239             },
240             ControlMessage::Unknown(UnknownCmsg(orig_cmsg, bytes)) => {
241                 copy_bytes(orig_cmsg, buf);
242                 copy_bytes(bytes, buf);
243             }
244         }
245     }
246 }
247 
248 
249 /// Send data in scatter-gather vectors to a socket, possibly accompanied
250 /// by ancillary data. Optionally direct the message at the given address,
251 /// as with sendto.
252 ///
253 /// Allocates if cmsgs is nonempty.
sendmsg<'a>(fd: RawFd, iov: &[IoVec<&'a [u8]>], cmsgs: &[ControlMessage<'a>], flags: MsgFlags, addr: Option<&'a SockAddr>) -> Result<usize>254 pub fn sendmsg<'a>(fd: RawFd, iov: &[IoVec<&'a [u8]>], cmsgs: &[ControlMessage<'a>], flags: MsgFlags, addr: Option<&'a SockAddr>) -> Result<usize> {
255     let mut len = 0;
256     let mut capacity = 0;
257     for cmsg in cmsgs {
258         len += cmsg.len();
259         capacity += cmsg.space();
260     }
261     // Note that the resulting vector claims to have length == capacity,
262     // so it's presently uninitialized.
263     let mut cmsg_buffer = unsafe {
264         let mut vec = Vec::<u8>::with_capacity(len);
265         vec.set_len(len);
266         vec
267     };
268     {
269         let mut ptr = &mut cmsg_buffer[..];
270         for cmsg in cmsgs {
271             unsafe { cmsg.encode_into(&mut ptr) };
272         }
273     }
274 
275     let (name, namelen) = match addr {
276         Some(addr) => { let (x, y) = unsafe { addr.as_ffi_pair() }; (x as *const _, y) }
277         None => (0 as *const _, 0),
278     };
279 
280     let cmsg_ptr = if capacity > 0 {
281         cmsg_buffer.as_ptr() as *const c_void
282     } else {
283         ptr::null()
284     };
285 
286     let mhdr = msghdr {
287         msg_name: name as *const c_void,
288         msg_namelen: namelen,
289         msg_iov: iov.as_ptr(),
290         msg_iovlen: iov.len() as size_t,
291         msg_control: cmsg_ptr,
292         msg_controllen: capacity as size_t,
293         msg_flags: 0,
294     };
295     let ret = unsafe { ffi::sendmsg(fd, &mhdr, flags.bits()) };
296 
297     Errno::result(ret).map(|r| r as usize)
298 }
299 
300 /// Receive message in scatter-gather vectors from a socket, and
301 /// optionally receive ancillary data into the provided buffer.
302 /// If no ancillary data is desired, use () as the type parameter.
recvmsg<'a, T>(fd: RawFd, iov: &[IoVec<&mut [u8]>], cmsg_buffer: Option<&'a mut CmsgSpace<T>>, flags: MsgFlags) -> Result<RecvMsg<'a>>303 pub fn recvmsg<'a, T>(fd: RawFd, iov: &[IoVec<&mut [u8]>], cmsg_buffer: Option<&'a mut CmsgSpace<T>>, flags: MsgFlags) -> Result<RecvMsg<'a>> {
304     let mut address: sockaddr_storage = unsafe { mem::uninitialized() };
305     let (msg_control, msg_controllen) = match cmsg_buffer {
306         Some(cmsg_buffer) => (cmsg_buffer as *mut _, mem::size_of_val(cmsg_buffer)),
307         None => (0 as *mut _, 0),
308     };
309     let mut mhdr = msghdr {
310         msg_name: &mut address as *const _ as *const c_void,
311         msg_namelen: mem::size_of::<sockaddr_storage>() as socklen_t,
312         msg_iov: iov.as_ptr() as *const IoVec<&[u8]>, // safe cast to add const-ness
313         msg_iovlen: iov.len() as size_t,
314         msg_control: msg_control as *const c_void,
315         msg_controllen: msg_controllen as size_t,
316         msg_flags: 0,
317     };
318     let ret = unsafe { ffi::recvmsg(fd, &mut mhdr, flags.bits()) };
319 
320     Ok(unsafe { RecvMsg {
321         bytes: try!(Errno::result(ret)) as usize,
322         cmsg_buffer: slice::from_raw_parts(mhdr.msg_control as *const u8,
323                                            mhdr.msg_controllen as usize),
324         address: sockaddr_storage_to_addr(&address,
325                                           mhdr.msg_namelen as usize).ok(),
326         flags: MsgFlags::from_bits_truncate(mhdr.msg_flags),
327     } })
328 }
329 
330 
331 /// Create an endpoint for communication
332 ///
333 /// [Further reading](http://man7.org/linux/man-pages/man2/socket.2.html)
socket(domain: AddressFamily, ty: SockType, flags: SockFlag, protocol: c_int) -> Result<RawFd>334 pub fn socket(domain: AddressFamily, ty: SockType, flags: SockFlag, protocol: c_int) -> Result<RawFd> {
335     let mut ty = ty as c_int;
336     let feat_atomic = features::socket_atomic_cloexec();
337 
338     if feat_atomic {
339         ty = ty | flags.bits();
340     }
341 
342     // TODO: Check the kernel version
343     let res = try!(Errno::result(unsafe { ffi::socket(domain as c_int, ty, protocol) }));
344 
345     if !feat_atomic {
346         if flags.contains(SOCK_CLOEXEC) {
347             try!(fcntl(res, F_SETFD(FD_CLOEXEC)));
348         }
349 
350         if flags.contains(SOCK_NONBLOCK) {
351             try!(fcntl(res, F_SETFL(O_NONBLOCK)));
352         }
353     }
354 
355     Ok(res)
356 }
357 
358 /// Create a pair of connected sockets
359 ///
360 /// [Further reading](http://man7.org/linux/man-pages/man2/socketpair.2.html)
socketpair(domain: AddressFamily, ty: SockType, protocol: c_int, flags: SockFlag) -> Result<(RawFd, RawFd)>361 pub fn socketpair(domain: AddressFamily, ty: SockType, protocol: c_int,
362                   flags: SockFlag) -> Result<(RawFd, RawFd)> {
363     let mut ty = ty as c_int;
364     let feat_atomic = features::socket_atomic_cloexec();
365 
366     if feat_atomic {
367         ty = ty | flags.bits();
368     }
369     let mut fds = [-1, -1];
370     let res = unsafe {
371         ffi::socketpair(domain as c_int, ty, protocol, fds.as_mut_ptr())
372     };
373     try!(Errno::result(res));
374 
375     if !feat_atomic {
376         if flags.contains(SOCK_CLOEXEC) {
377             try!(fcntl(fds[0], F_SETFD(FD_CLOEXEC)));
378             try!(fcntl(fds[1], F_SETFD(FD_CLOEXEC)));
379         }
380 
381         if flags.contains(SOCK_NONBLOCK) {
382             try!(fcntl(fds[0], F_SETFL(O_NONBLOCK)));
383             try!(fcntl(fds[1], F_SETFL(O_NONBLOCK)));
384         }
385     }
386     Ok((fds[0], fds[1]))
387 }
388 
389 /// Listen for connections on a socket
390 ///
391 /// [Further reading](http://man7.org/linux/man-pages/man2/listen.2.html)
listen(sockfd: RawFd, backlog: usize) -> Result<()>392 pub fn listen(sockfd: RawFd, backlog: usize) -> Result<()> {
393     let res = unsafe { ffi::listen(sockfd, backlog as c_int) };
394 
395     Errno::result(res).map(drop)
396 }
397 
398 /// Bind a name to a socket
399 ///
400 /// [Further reading](http://man7.org/linux/man-pages/man2/bind.2.html)
401 #[cfg(not(all(target_os="android", target_pointer_width="64")))]
bind(fd: RawFd, addr: &SockAddr) -> Result<()>402 pub fn bind(fd: RawFd, addr: &SockAddr) -> Result<()> {
403     let res = unsafe {
404         let (ptr, len) = addr.as_ffi_pair();
405         ffi::bind(fd, ptr, len)
406     };
407 
408     Errno::result(res).map(drop)
409 }
410 
411 /// Bind a name to a socket
412 ///
413 /// [Further reading](http://man7.org/linux/man-pages/man2/bind.2.html)
414 // Android has some weirdness. Its 64-bit bind takes a c_int instead of a
415 // socklen_t
416 #[cfg(all(target_os="android", target_pointer_width="64"))]
bind(fd: RawFd, addr: &SockAddr) -> Result<()>417 pub fn bind(fd: RawFd, addr: &SockAddr) -> Result<()> {
418     let res = unsafe {
419         let (ptr, len) = addr.as_ffi_pair();
420         ffi::bind(fd, ptr, len as c_int)
421     };
422 
423     Errno::result(res).map(drop)
424 }
425 
426 /// Accept a connection on a socket
427 ///
428 /// [Further reading](http://man7.org/linux/man-pages/man2/accept.2.html)
accept(sockfd: RawFd) -> Result<RawFd>429 pub fn accept(sockfd: RawFd) -> Result<RawFd> {
430     let res = unsafe { ffi::accept(sockfd, ptr::null_mut(), ptr::null_mut()) };
431 
432     Errno::result(res)
433 }
434 
435 /// Accept a connection on a socket
436 ///
437 /// [Further reading](http://man7.org/linux/man-pages/man2/accept.2.html)
accept4(sockfd: RawFd, flags: SockFlag) -> Result<RawFd>438 pub fn accept4(sockfd: RawFd, flags: SockFlag) -> Result<RawFd> {
439     accept4_polyfill(sockfd, flags)
440 }
441 
442 #[inline]
accept4_polyfill(sockfd: RawFd, flags: SockFlag) -> Result<RawFd>443 fn accept4_polyfill(sockfd: RawFd, flags: SockFlag) -> Result<RawFd> {
444     let res = try!(Errno::result(unsafe { ffi::accept(sockfd, ptr::null_mut(), ptr::null_mut()) }));
445 
446     if flags.contains(SOCK_CLOEXEC) {
447         try!(fcntl(res, F_SETFD(FD_CLOEXEC)));
448     }
449 
450     if flags.contains(SOCK_NONBLOCK) {
451         try!(fcntl(res, F_SETFL(O_NONBLOCK)));
452     }
453 
454     Ok(res)
455 }
456 
457 /// Initiate a connection on a socket
458 ///
459 /// [Further reading](http://man7.org/linux/man-pages/man2/connect.2.html)
connect(fd: RawFd, addr: &SockAddr) -> Result<()>460 pub fn connect(fd: RawFd, addr: &SockAddr) -> Result<()> {
461     let res = unsafe {
462         let (ptr, len) = addr.as_ffi_pair();
463         ffi::connect(fd, ptr, len)
464     };
465 
466     Errno::result(res).map(drop)
467 }
468 
469 /// Receive data from a connection-oriented socket. Returns the number of
470 /// bytes read
471 ///
472 /// [Further reading](http://man7.org/linux/man-pages/man2/recv.2.html)
recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result<usize>473 pub fn recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result<usize> {
474     unsafe {
475         let ret = ffi::recv(
476             sockfd,
477             buf.as_ptr() as *mut c_void,
478             buf.len() as size_t,
479             flags.bits());
480 
481         Errno::result(ret).map(|r| r as usize)
482     }
483 }
484 
485 /// Receive data from a connectionless or connection-oriented socket. Returns
486 /// the number of bytes read and the socket address of the sender.
487 ///
488 /// [Further reading](http://man7.org/linux/man-pages/man2/recvmsg.2.html)
recvfrom(sockfd: RawFd, buf: &mut [u8]) -> Result<(usize, SockAddr)>489 pub fn recvfrom(sockfd: RawFd, buf: &mut [u8]) -> Result<(usize, SockAddr)> {
490     unsafe {
491         let addr: sockaddr_storage = mem::zeroed();
492         let mut len = mem::size_of::<sockaddr_storage>() as socklen_t;
493 
494         let ret = try!(Errno::result(ffi::recvfrom(
495             sockfd,
496             buf.as_ptr() as *mut c_void,
497             buf.len() as size_t,
498             0,
499             mem::transmute(&addr),
500             &mut len as *mut socklen_t)));
501 
502         sockaddr_storage_to_addr(&addr, len as usize)
503             .map(|addr| (ret as usize, addr))
504     }
505 }
506 
sendto(fd: RawFd, buf: &[u8], addr: &SockAddr, flags: MsgFlags) -> Result<usize>507 pub fn sendto(fd: RawFd, buf: &[u8], addr: &SockAddr, flags: MsgFlags) -> Result<usize> {
508     let ret = unsafe {
509         let (ptr, len) = addr.as_ffi_pair();
510         ffi::sendto(fd, buf.as_ptr() as *const c_void, buf.len() as size_t, flags.bits(), ptr, len)
511     };
512 
513     Errno::result(ret).map(|r| r as usize)
514 }
515 
516 /// Send data to a connection-oriented socket. Returns the number of bytes read
517 ///
518 /// [Further reading](http://man7.org/linux/man-pages/man2/send.2.html)
send(fd: RawFd, buf: &[u8], flags: MsgFlags) -> Result<usize>519 pub fn send(fd: RawFd, buf: &[u8], flags: MsgFlags) -> Result<usize> {
520     let ret = unsafe {
521         ffi::send(fd, buf.as_ptr() as *const c_void, buf.len() as size_t, flags.bits())
522     };
523 
524     Errno::result(ret).map(|r| r as usize)
525 }
526 
527 #[repr(C)]
528 #[derive(Clone, Copy, Debug)]
529 pub struct linger {
530     pub l_onoff: c_int,
531     pub l_linger: c_int
532 }
533 
534 #[repr(C)]
535 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
536 pub struct ucred {
537     pid: pid_t,
538     uid: uid_t,
539     gid: gid_t,
540 }
541 
542 /*
543  *
544  * ===== Socket Options =====
545  *
546  */
547 
548 /// The protocol level at which to get / set socket options. Used as an
549 /// argument to `getsockopt` and `setsockopt`.
550 ///
551 /// [Further reading](http://man7.org/linux/man-pages/man2/setsockopt.2.html)
552 #[repr(i32)]
553 pub enum SockLevel {
554     Socket = SOL_SOCKET,
555     Tcp = IPPROTO_TCP,
556     Ip = IPPROTO_IP,
557     Ipv6 = IPPROTO_IPV6,
558     Udp = IPPROTO_UDP,
559     #[cfg(any(target_os = "linux", target_os = "android"))]
560     Netlink = SOL_NETLINK,
561 }
562 
563 /// Represents a socket option that can be accessed or set. Used as an argument
564 /// to `getsockopt`
565 pub trait GetSockOpt : Copy {
566     type Val;
567 
568     #[doc(hidden)]
get(&self, fd: RawFd) -> Result<Self::Val>569     fn get(&self, fd: RawFd) -> Result<Self::Val>;
570 }
571 
572 /// Represents a socket option that can be accessed or set. Used as an argument
573 /// to `setsockopt`
574 pub trait SetSockOpt : Copy {
575     type Val;
576 
577     #[doc(hidden)]
set(&self, fd: RawFd, val: &Self::Val) -> Result<()>578     fn set(&self, fd: RawFd, val: &Self::Val) -> Result<()>;
579 }
580 
581 /// Get the current value for the requested socket option
582 ///
583 /// [Further reading](http://man7.org/linux/man-pages/man2/getsockopt.2.html)
getsockopt<O: GetSockOpt>(fd: RawFd, opt: O) -> Result<O::Val>584 pub fn getsockopt<O: GetSockOpt>(fd: RawFd, opt: O) -> Result<O::Val> {
585     opt.get(fd)
586 }
587 
588 /// Sets the value for the requested socket option
589 ///
590 /// [Further reading](http://man7.org/linux/man-pages/man2/setsockopt.2.html)
setsockopt<O: SetSockOpt>(fd: RawFd, opt: O, val: &O::Val) -> Result<()>591 pub fn setsockopt<O: SetSockOpt>(fd: RawFd, opt: O, val: &O::Val) -> Result<()> {
592     opt.set(fd, val)
593 }
594 
595 /// Get the address of the peer connected to the socket `fd`.
596 ///
597 /// [Further reading](http://man7.org/linux/man-pages/man2/getpeername.2.html)
getpeername(fd: RawFd) -> Result<SockAddr>598 pub fn getpeername(fd: RawFd) -> Result<SockAddr> {
599     unsafe {
600         let addr: sockaddr_storage = mem::uninitialized();
601         let mut len = mem::size_of::<sockaddr_storage>() as socklen_t;
602 
603         let ret = ffi::getpeername(fd, mem::transmute(&addr), &mut len);
604 
605         try!(Errno::result(ret));
606 
607         sockaddr_storage_to_addr(&addr, len as usize)
608     }
609 }
610 
611 /// Get the current address to which the socket `fd` is bound.
612 ///
613 /// [Further reading](http://man7.org/linux/man-pages/man2/getsockname.2.html)
getsockname(fd: RawFd) -> Result<SockAddr>614 pub fn getsockname(fd: RawFd) -> Result<SockAddr> {
615     unsafe {
616         let addr: sockaddr_storage = mem::uninitialized();
617         let mut len = mem::size_of::<sockaddr_storage>() as socklen_t;
618 
619         let ret = ffi::getsockname(fd, mem::transmute(&addr), &mut len);
620 
621         try!(Errno::result(ret));
622 
623         sockaddr_storage_to_addr(&addr, len as usize)
624     }
625 }
626 
627 /// Return the appropriate SockAddr type from a `sockaddr_storage` of a certain
628 /// size.  In C this would usually be done by casting.  The `len` argument
629 /// should be the number of bytes in the sockaddr_storage that are actually
630 /// allocated and valid.  It must be at least as large as all the useful parts
631 /// of the structure.  Note that in the case of a `sockaddr_un`, `len` need not
632 /// include the terminating null.
sockaddr_storage_to_addr( addr: &sockaddr_storage, len: usize) -> Result<SockAddr>633 pub unsafe fn sockaddr_storage_to_addr(
634     addr: &sockaddr_storage,
635     len: usize) -> Result<SockAddr> {
636 
637     if len < mem::size_of_val(&addr.ss_family) {
638         return Err(Error::Sys(Errno::ENOTCONN));
639     }
640 
641     match addr.ss_family as c_int {
642         consts::AF_INET => {
643             assert!(len as usize == mem::size_of::<sockaddr_in>());
644             let ret = *(addr as *const _ as *const sockaddr_in);
645             Ok(SockAddr::Inet(InetAddr::V4(ret)))
646         }
647         consts::AF_INET6 => {
648             assert!(len as usize == mem::size_of::<sockaddr_in6>());
649             Ok(SockAddr::Inet(InetAddr::V6((*(addr as *const _ as *const sockaddr_in6)))))
650         }
651         consts::AF_UNIX => {
652             let sun = *(addr as *const _ as *const sockaddr_un);
653             let pathlen = len - offset_of!(sockaddr_un, sun_path);
654             Ok(SockAddr::Unix(UnixAddr(sun, pathlen)))
655         }
656         #[cfg(any(target_os = "linux", target_os = "android"))]
657         consts::AF_NETLINK => {
658             use libc::sockaddr_nl;
659             Ok(SockAddr::Netlink(NetlinkAddr(*(addr as *const _ as *const sockaddr_nl))))
660         }
661         af => panic!("unexpected address family {}", af),
662     }
663 }
664 
665 
666 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
667 pub enum Shutdown {
668     /// Further receptions will be disallowed.
669     Read,
670     /// Further  transmissions will be disallowed.
671     Write,
672     /// Further receptions and transmissions will be disallowed.
673     Both,
674 }
675 
676 /// Shut down part of a full-duplex connection.
677 ///
678 /// [Further reading](http://man7.org/linux/man-pages/man2/shutdown.2.html)
shutdown(df: RawFd, how: Shutdown) -> Result<()>679 pub fn shutdown(df: RawFd, how: Shutdown) -> Result<()> {
680     unsafe {
681         use libc::shutdown;
682 
683         let how = match how {
684             Shutdown::Read  => consts::SHUT_RD,
685             Shutdown::Write => consts::SHUT_WR,
686             Shutdown::Both  => consts::SHUT_RDWR,
687         };
688 
689         Errno::result(shutdown(df, how)).map(drop)
690     }
691 }
692 
693 #[test]
test_struct_sizes()694 pub fn test_struct_sizes() {
695     use nixtest;
696     nixtest::assert_size_of::<sockaddr_storage>("sockaddr_storage");
697 }
698