1 //! Socket interface functions
2 //!
3 //! [Further reading](http://man7.org/linux/man-pages/man7/socket.7.html)
4 use {Error, Result};
5 use errno::Errno;
6 use libc::{self, c_void, c_int, iovec, socklen_t, size_t,
7 CMSG_FIRSTHDR, CMSG_NXTHDR, CMSG_DATA, CMSG_LEN};
8 use std::{mem, ptr, slice};
9 use std::os::unix::io::RawFd;
10 use sys::time::TimeVal;
11 use sys::uio::IoVec;
12
13 mod addr;
14 pub mod sockopt;
15
16 /*
17 *
18 * ===== Re-exports =====
19 *
20 */
21
22 pub use self::addr::{
23 AddressFamily,
24 SockAddr,
25 InetAddr,
26 UnixAddr,
27 IpAddr,
28 Ipv4Addr,
29 Ipv6Addr,
30 LinkAddr,
31 };
32 #[cfg(any(target_os = "android", target_os = "linux"))]
33 pub use ::sys::socket::addr::netlink::NetlinkAddr;
34 #[cfg(any(target_os = "android", target_os = "linux"))]
35 pub use sys::socket::addr::alg::AlgAddr;
36 #[cfg(target_os = "linux")]
37 pub use sys::socket::addr::vsock::VsockAddr;
38
39 pub use libc::{
40 cmsghdr,
41 msghdr,
42 sa_family_t,
43 sockaddr,
44 sockaddr_in,
45 sockaddr_in6,
46 sockaddr_storage,
47 sockaddr_un,
48 };
49
50 // Needed by the cmsg_space macro
51 #[doc(hidden)]
52 pub use libc::{c_uint, CMSG_SPACE};
53
54 /// These constants are used to specify the communication semantics
55 /// when creating a socket with [`socket()`](fn.socket.html)
56 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
57 #[repr(i32)]
58 pub enum SockType {
59 /// Provides sequenced, reliable, two-way, connection-
60 /// based byte streams. An out-of-band data transmission
61 /// mechanism may be supported.
62 Stream = libc::SOCK_STREAM,
63 /// Supports datagrams (connectionless, unreliable
64 /// messages of a fixed maximum length).
65 Datagram = libc::SOCK_DGRAM,
66 /// Provides a sequenced, reliable, two-way connection-
67 /// based data transmission path for datagrams of fixed
68 /// maximum length; a consumer is required to read an
69 /// entire packet with each input system call.
70 SeqPacket = libc::SOCK_SEQPACKET,
71 /// Provides raw network protocol access.
72 Raw = libc::SOCK_RAW,
73 /// Provides a reliable datagram layer that does not
74 /// guarantee ordering.
75 Rdm = libc::SOCK_RDM,
76 }
77
78 /// Constants used in [`socket`](fn.socket.html) and [`socketpair`](fn.socketpair.html)
79 /// to specify the protocol to use.
80 #[repr(i32)]
81 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
82 pub enum SockProtocol {
83 /// TCP protocol ([ip(7)](http://man7.org/linux/man-pages/man7/ip.7.html))
84 Tcp = libc::IPPROTO_TCP,
85 /// UDP protocol ([ip(7)](http://man7.org/linux/man-pages/man7/ip.7.html))
86 Udp = libc::IPPROTO_UDP,
87 /// Allows applications and other KEXTs to be notified when certain kernel events occur
88 /// ([ref](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/control/control.html))
89 #[cfg(any(target_os = "ios", target_os = "macos"))]
90 KextEvent = libc::SYSPROTO_EVENT,
91 /// Allows applications to configure and control a KEXT
92 /// ([ref](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/control/control.html))
93 #[cfg(any(target_os = "ios", target_os = "macos"))]
94 KextControl = libc::SYSPROTO_CONTROL,
95 }
96
97 libc_bitflags!{
98 /// Additional socket options
99 pub struct SockFlag: c_int {
100 /// Set non-blocking mode on the new socket
101 #[cfg(any(target_os = "android",
102 target_os = "dragonfly",
103 target_os = "freebsd",
104 target_os = "linux",
105 target_os = "netbsd",
106 target_os = "openbsd"))]
107 SOCK_NONBLOCK;
108 /// Set close-on-exec on the new descriptor
109 #[cfg(any(target_os = "android",
110 target_os = "dragonfly",
111 target_os = "freebsd",
112 target_os = "linux",
113 target_os = "netbsd",
114 target_os = "openbsd"))]
115 SOCK_CLOEXEC;
116 /// Return `EPIPE` instead of raising `SIGPIPE`
117 #[cfg(target_os = "netbsd")]
118 SOCK_NOSIGPIPE;
119 /// For domains `AF_INET(6)`, only allow `connect(2)`, `sendto(2)`, or `sendmsg(2)`
120 /// to the DNS port (typically 53)
121 #[cfg(target_os = "openbsd")]
122 SOCK_DNS;
123 }
124 }
125
126 libc_bitflags!{
127 /// Flags for send/recv and their relatives
128 pub struct MsgFlags: c_int {
129 /// Sends or requests out-of-band data on sockets that support this notion
130 /// (e.g., of type [`Stream`](enum.SockType.html)); the underlying protocol must also
131 /// support out-of-band data.
132 MSG_OOB;
133 /// Peeks at an incoming message. The data is treated as unread and the next
134 /// [`recv()`](fn.recv.html)
135 /// or similar function shall still return this data.
136 MSG_PEEK;
137 /// Receive operation blocks until the full amount of data can be
138 /// returned. The function may return smaller amount of data if a signal
139 /// is caught, an error or disconnect occurs.
140 MSG_WAITALL;
141 /// Enables nonblocking operation; if the operation would block,
142 /// `EAGAIN` or `EWOULDBLOCK` is returned. This provides similar
143 /// behavior to setting the `O_NONBLOCK` flag
144 /// (via the [`fcntl`](../../fcntl/fn.fcntl.html)
145 /// `F_SETFL` operation), but differs in that `MSG_DONTWAIT` is a per-
146 /// call option, whereas `O_NONBLOCK` is a setting on the open file
147 /// description (see [open(2)](http://man7.org/linux/man-pages/man2/open.2.html)),
148 /// which will affect all threads in
149 /// the calling process and as well as other processes that hold
150 /// file descriptors referring to the same open file description.
151 MSG_DONTWAIT;
152 /// Receive flags: Control Data was discarded (buffer too small)
153 MSG_CTRUNC;
154 /// For raw ([`Packet`](addr/enum.AddressFamily.html)), Internet datagram
155 /// (since Linux 2.4.27/2.6.8),
156 /// netlink (since Linux 2.6.22) and UNIX datagram (since Linux 3.4)
157 /// sockets: return the real length of the packet or datagram, even
158 /// when it was longer than the passed buffer. Not implemented for UNIX
159 /// domain ([unix(7)](https://linux.die.net/man/7/unix)) sockets.
160 ///
161 /// For use with Internet stream sockets, see [tcp(7)](https://linux.die.net/man/7/tcp).
162 MSG_TRUNC;
163 /// Terminates a record (when this notion is supported, as for
164 /// sockets of type [`SeqPacket`](enum.SockType.html)).
165 MSG_EOR;
166 /// This flag specifies that queued errors should be received from
167 /// the socket error queue. (For more details, see
168 /// [recvfrom(2)](https://linux.die.net/man/2/recvfrom))
169 #[cfg(any(target_os = "android", target_os = "linux"))]
170 MSG_ERRQUEUE;
171 /// Set the `close-on-exec` flag for the file descriptor received via a UNIX domain
172 /// file descriptor using the `SCM_RIGHTS` operation (described in
173 /// [unix(7)](https://linux.die.net/man/7/unix)).
174 /// This flag is useful for the same reasons as the `O_CLOEXEC` flag of
175 /// [open(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html).
176 ///
177 /// Only used in [`recvmsg`](fn.recvmsg.html) function.
178 #[cfg(any(target_os = "android",
179 target_os = "dragonfly",
180 target_os = "freebsd",
181 target_os = "linux",
182 target_os = "netbsd",
183 target_os = "openbsd"))]
184 MSG_CMSG_CLOEXEC;
185 }
186 }
187
188 cfg_if! {
189 if #[cfg(any(target_os = "android", target_os = "linux"))] {
190 /// Unix credentials of the sending process.
191 ///
192 /// This struct is used with the `SO_PEERCRED` ancillary message for UNIX sockets.
193 #[repr(transparent)]
194 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
195 pub struct UnixCredentials(libc::ucred);
196
197 impl UnixCredentials {
198 /// Returns the process identifier
199 pub fn pid(&self) -> libc::pid_t {
200 self.0.pid
201 }
202
203 /// Returns the user identifier
204 pub fn uid(&self) -> libc::uid_t {
205 self.0.uid
206 }
207
208 /// Returns the group identifier
209 pub fn gid(&self) -> libc::gid_t {
210 self.0.gid
211 }
212 }
213
214 impl From<libc::ucred> for UnixCredentials {
215 fn from(cred: libc::ucred) -> Self {
216 UnixCredentials(cred)
217 }
218 }
219
220 impl Into<libc::ucred> for UnixCredentials {
221 fn into(self) -> libc::ucred {
222 self.0
223 }
224 }
225 }
226 }
227
228 /// Request for multicast socket operations
229 ///
230 /// This is a wrapper type around `ip_mreq`.
231 #[repr(C)]
232 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
233 pub struct IpMembershipRequest(libc::ip_mreq);
234
235 impl IpMembershipRequest {
236 /// Instantiate a new `IpMembershipRequest`
237 ///
238 /// If `interface` is `None`, then `Ipv4Addr::any()` will be used for the interface.
new(group: Ipv4Addr, interface: Option<Ipv4Addr>) -> Self239 pub fn new(group: Ipv4Addr, interface: Option<Ipv4Addr>) -> Self {
240 IpMembershipRequest(libc::ip_mreq {
241 imr_multiaddr: group.0,
242 imr_interface: interface.unwrap_or_else(Ipv4Addr::any).0,
243 })
244 }
245 }
246
247 /// Request for ipv6 multicast socket operations
248 ///
249 /// This is a wrapper type around `ipv6_mreq`.
250 #[repr(C)]
251 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
252 pub struct Ipv6MembershipRequest(libc::ipv6_mreq);
253
254 impl Ipv6MembershipRequest {
255 /// Instantiate a new `Ipv6MembershipRequest`
new(group: Ipv6Addr) -> Self256 pub fn new(group: Ipv6Addr) -> Self {
257 Ipv6MembershipRequest(libc::ipv6_mreq {
258 ipv6mr_multiaddr: group.0,
259 ipv6mr_interface: 0,
260 })
261 }
262 }
263
264 /// Create a buffer large enough for storing some control messages as returned
265 /// by [`recvmsg`](fn.recvmsg.html).
266 ///
267 /// # Examples
268 ///
269 /// ```
270 /// # #[macro_use] extern crate nix;
271 /// # use nix::sys::time::TimeVal;
272 /// # use std::os::unix::io::RawFd;
273 /// # fn main() {
274 /// // Create a buffer for a `ControlMessageOwned::ScmTimestamp` message
275 /// let _ = cmsg_space!(TimeVal);
276 /// // Create a buffer big enough for a `ControlMessageOwned::ScmRights` message
277 /// // with two file descriptors
278 /// let _ = cmsg_space!([RawFd; 2]);
279 /// // Create a buffer big enough for a `ControlMessageOwned::ScmRights` message
280 /// // and a `ControlMessageOwned::ScmTimestamp` message
281 /// let _ = cmsg_space!(RawFd, TimeVal);
282 /// # }
283 /// ```
284 // Unfortunately, CMSG_SPACE isn't a const_fn, or else we could return a
285 // stack-allocated array.
286 #[macro_export]
287 macro_rules! cmsg_space {
288 ( $( $x:ty ),* ) => {
289 {
290 use nix::sys::socket::{c_uint, CMSG_SPACE};
291 use std::mem;
292 let mut space = 0;
293 $(
294 // CMSG_SPACE is always safe
295 space += unsafe {
296 CMSG_SPACE(mem::size_of::<$x>() as c_uint)
297 } as usize;
298 )*
299 Vec::<u8>::with_capacity(space)
300 }
301 }
302 }
303
304 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
305 pub struct RecvMsg<'a> {
306 pub bytes: usize,
307 cmsghdr: Option<&'a cmsghdr>,
308 pub address: Option<SockAddr>,
309 pub flags: MsgFlags,
310 mhdr: msghdr,
311 }
312
313 impl<'a> RecvMsg<'a> {
314 /// Iterate over the valid control messages pointed to by this
315 /// msghdr.
cmsgs(&self) -> CmsgIterator316 pub fn cmsgs(&self) -> CmsgIterator {
317 CmsgIterator {
318 cmsghdr: self.cmsghdr,
319 mhdr: &self.mhdr
320 }
321 }
322 }
323
324 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
325 pub struct CmsgIterator<'a> {
326 /// Control message buffer to decode from. Must adhere to cmsg alignment.
327 cmsghdr: Option<&'a cmsghdr>,
328 mhdr: &'a msghdr
329 }
330
331 impl<'a> Iterator for CmsgIterator<'a> {
332 type Item = ControlMessageOwned;
333
next(&mut self) -> Option<ControlMessageOwned>334 fn next(&mut self) -> Option<ControlMessageOwned> {
335 match self.cmsghdr {
336 None => None, // No more messages
337 Some(hdr) => {
338 // Get the data.
339 // Safe if cmsghdr points to valid data returned by recvmsg(2)
340 let cm = unsafe { Some(ControlMessageOwned::decode_from(hdr))};
341 // Advance the internal pointer. Safe if mhdr and cmsghdr point
342 // to valid data returned by recvmsg(2)
343 self.cmsghdr = unsafe {
344 let p = CMSG_NXTHDR(self.mhdr as *const _, hdr as *const _);
345 p.as_ref()
346 };
347 cm
348 }
349 }
350 }
351 }
352
353 /// A type-safe wrapper around a single control message, as used with
354 /// [`recvmsg`](#fn.recvmsg).
355 ///
356 /// [Further reading](http://man7.org/linux/man-pages/man3/cmsg.3.html)
357 // Nix version 0.13.0 and earlier used ControlMessage for both recvmsg and
358 // sendmsg. However, on some platforms the messages returned by recvmsg may be
359 // unaligned. ControlMessageOwned takes those messages by copy, obviating any
360 // alignment issues.
361 //
362 // See https://github.com/nix-rust/nix/issues/999
363 #[derive(Clone, Debug, Eq, PartialEq)]
364 pub enum ControlMessageOwned {
365 /// Received version of
366 /// [`ControlMessage::ScmRights`][#enum.ControlMessage.html#variant.ScmRights]
367 ScmRights(Vec<RawFd>),
368 /// Received version of
369 /// [`ControlMessage::ScmCredentials`][#enum.ControlMessage.html#variant.ScmCredentials]
370 #[cfg(any(target_os = "android", target_os = "linux"))]
371 ScmCredentials(UnixCredentials),
372 /// A message of type `SCM_TIMESTAMP`, containing the time the
373 /// packet was received by the kernel.
374 ///
375 /// See the kernel's explanation in "SO_TIMESTAMP" of
376 /// [networking/timestamping](https://www.kernel.org/doc/Documentation/networking/timestamping.txt).
377 ///
378 /// # Examples
379 ///
380 // Disable this test on FreeBSD i386
381 // https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=222039
382 #[cfg_attr(not(all(target_os = "freebsd", target_arch = "x86")), doc = " ```")]
383 #[cfg_attr(all(target_os = "freebsd", target_arch = "x86"), doc = " ```no_run")]
384 /// # #[macro_use] extern crate nix;
385 /// # use nix::sys::socket::*;
386 /// # use nix::sys::uio::IoVec;
387 /// # use nix::sys::time::*;
388 /// # use std::time::*;
389 /// # fn main() {
390 /// // Set up
391 /// let message = "Ohayō!".as_bytes();
392 /// let in_socket = socket(
393 /// AddressFamily::Inet,
394 /// SockType::Datagram,
395 /// SockFlag::empty(),
396 /// None).unwrap();
397 /// setsockopt(in_socket, sockopt::ReceiveTimestamp, &true).unwrap();
398 /// let localhost = InetAddr::new(IpAddr::new_v4(127, 0, 0, 1), 0);
399 /// bind(in_socket, &SockAddr::new_inet(localhost)).unwrap();
400 /// let address = getsockname(in_socket).unwrap();
401 /// // Get initial time
402 /// let time0 = SystemTime::now();
403 /// // Send the message
404 /// let iov = [IoVec::from_slice(message)];
405 /// let flags = MsgFlags::empty();
406 /// let l = sendmsg(in_socket, &iov, &[], flags, Some(&address)).unwrap();
407 /// assert_eq!(message.len(), l);
408 /// // Receive the message
409 /// let mut buffer = vec![0u8; message.len()];
410 /// let mut cmsgspace = cmsg_space!(TimeVal);
411 /// let iov = [IoVec::from_mut_slice(&mut buffer)];
412 /// let r = recvmsg(in_socket, &iov, Some(&mut cmsgspace), flags).unwrap();
413 /// let rtime = match r.cmsgs().next() {
414 /// Some(ControlMessageOwned::ScmTimestamp(rtime)) => rtime,
415 /// Some(_) => panic!("Unexpected control message"),
416 /// None => panic!("No control message")
417 /// };
418 /// // Check the final time
419 /// let time1 = SystemTime::now();
420 /// // the packet's received timestamp should lie in-between the two system
421 /// // times, unless the system clock was adjusted in the meantime.
422 /// let rduration = Duration::new(rtime.tv_sec() as u64,
423 /// rtime.tv_usec() as u32 * 1000);
424 /// assert!(time0.duration_since(UNIX_EPOCH).unwrap() <= rduration);
425 /// assert!(rduration <= time1.duration_since(UNIX_EPOCH).unwrap());
426 /// // Close socket
427 /// nix::unistd::close(in_socket).unwrap();
428 /// # }
429 /// ```
430 ScmTimestamp(TimeVal),
431 #[cfg(any(
432 target_os = "android",
433 target_os = "ios",
434 target_os = "linux",
435 target_os = "macos",
436 target_os = "netbsd",
437 ))]
438 Ipv4PacketInfo(libc::in_pktinfo),
439 #[cfg(any(
440 target_os = "android",
441 target_os = "dragonfly",
442 target_os = "freebsd",
443 target_os = "ios",
444 target_os = "linux",
445 target_os = "macos",
446 target_os = "openbsd",
447 target_os = "netbsd",
448 ))]
449 Ipv6PacketInfo(libc::in6_pktinfo),
450 #[cfg(any(
451 target_os = "freebsd",
452 target_os = "ios",
453 target_os = "macos",
454 target_os = "netbsd",
455 target_os = "openbsd",
456 ))]
457 Ipv4RecvIf(libc::sockaddr_dl),
458 #[cfg(any(
459 target_os = "freebsd",
460 target_os = "ios",
461 target_os = "macos",
462 target_os = "netbsd",
463 target_os = "openbsd",
464 ))]
465 Ipv4RecvDstAddr(libc::in_addr),
466 /// Catch-all variant for unimplemented cmsg types.
467 #[doc(hidden)]
468 Unknown(UnknownCmsg),
469 }
470
471 impl ControlMessageOwned {
472 /// Decodes a `ControlMessageOwned` from raw bytes.
473 ///
474 /// This is only safe to call if the data is correct for the message type
475 /// specified in the header. Normally, the kernel ensures that this is the
476 /// case. "Correct" in this case includes correct length, alignment and
477 /// actual content.
478 // Clippy complains about the pointer alignment of `p`, not understanding
479 // that it's being fed to a function that can handle that.
480 #[allow(clippy::cast_ptr_alignment)]
decode_from(header: &cmsghdr) -> ControlMessageOwned481 unsafe fn decode_from(header: &cmsghdr) -> ControlMessageOwned
482 {
483 let p = CMSG_DATA(header);
484 let len = header as *const _ as usize + header.cmsg_len as usize
485 - p as usize;
486 match (header.cmsg_level, header.cmsg_type) {
487 (libc::SOL_SOCKET, libc::SCM_RIGHTS) => {
488 let n = len / mem::size_of::<RawFd>();
489 let mut fds = Vec::with_capacity(n);
490 for i in 0..n {
491 let fdp = (p as *const RawFd).add(i);
492 fds.push(ptr::read_unaligned(fdp));
493 }
494 ControlMessageOwned::ScmRights(fds)
495 },
496 #[cfg(any(target_os = "android", target_os = "linux"))]
497 (libc::SOL_SOCKET, libc::SCM_CREDENTIALS) => {
498 let cred: libc::ucred = ptr::read_unaligned(p as *const _);
499 ControlMessageOwned::ScmCredentials(cred.into())
500 }
501 (libc::SOL_SOCKET, libc::SCM_TIMESTAMP) => {
502 let tv: libc::timeval = ptr::read_unaligned(p as *const _);
503 ControlMessageOwned::ScmTimestamp(TimeVal::from(tv))
504 },
505 #[cfg(any(
506 target_os = "android",
507 target_os = "freebsd",
508 target_os = "ios",
509 target_os = "linux",
510 target_os = "macos"
511 ))]
512 (libc::IPPROTO_IPV6, libc::IPV6_PKTINFO) => {
513 let info = ptr::read_unaligned(p as *const libc::in6_pktinfo);
514 ControlMessageOwned::Ipv6PacketInfo(info)
515 }
516 #[cfg(any(
517 target_os = "android",
518 target_os = "ios",
519 target_os = "linux",
520 target_os = "macos",
521 target_os = "netbsd",
522 ))]
523 (libc::IPPROTO_IP, libc::IP_PKTINFO) => {
524 let info = ptr::read_unaligned(p as *const libc::in_pktinfo);
525 ControlMessageOwned::Ipv4PacketInfo(info)
526 }
527 #[cfg(any(
528 target_os = "freebsd",
529 target_os = "ios",
530 target_os = "macos",
531 target_os = "netbsd",
532 target_os = "openbsd",
533 ))]
534 (libc::IPPROTO_IP, libc::IP_RECVIF) => {
535 let dl = ptr::read_unaligned(p as *const libc::sockaddr_dl);
536 ControlMessageOwned::Ipv4RecvIf(dl)
537 },
538 #[cfg(any(
539 target_os = "freebsd",
540 target_os = "ios",
541 target_os = "macos",
542 target_os = "netbsd",
543 target_os = "openbsd",
544 ))]
545 (libc::IPPROTO_IP, libc::IP_RECVDSTADDR) => {
546 let dl = ptr::read_unaligned(p as *const libc::in_addr);
547 ControlMessageOwned::Ipv4RecvDstAddr(dl)
548 },
549 (_, _) => {
550 let sl = slice::from_raw_parts(p, len);
551 let ucmsg = UnknownCmsg(*header, Vec::<u8>::from(&sl[..]));
552 ControlMessageOwned::Unknown(ucmsg)
553 }
554 }
555 }
556 }
557
558 /// A type-safe zero-copy wrapper around a single control message, as used wih
559 /// [`sendmsg`](#fn.sendmsg). More types may be added to this enum; do not
560 /// exhaustively pattern-match it.
561 ///
562 /// [Further reading](http://man7.org/linux/man-pages/man3/cmsg.3.html)
563 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
564 pub enum ControlMessage<'a> {
565 /// A message of type `SCM_RIGHTS`, containing an array of file
566 /// descriptors passed between processes.
567 ///
568 /// See the description in the "Ancillary messages" section of the
569 /// [unix(7) man page](http://man7.org/linux/man-pages/man7/unix.7.html).
570 ///
571 /// Using multiple `ScmRights` messages for a single `sendmsg` call isn't
572 /// recommended since it causes platform-dependent behaviour: It might
573 /// swallow all but the first `ScmRights` message or fail with `EINVAL`.
574 /// Instead, you can put all fds to be passed into a single `ScmRights`
575 /// message.
576 ScmRights(&'a [RawFd]),
577 /// A message of type `SCM_CREDENTIALS`, containing the pid, uid and gid of
578 /// a process connected to the socket.
579 ///
580 /// This is similar to the socket option `SO_PEERCRED`, but requires a
581 /// process to explicitly send its credentials. A process running as root is
582 /// allowed to specify any credentials, while credentials sent by other
583 /// processes are verified by the kernel.
584 ///
585 /// For further information, please refer to the
586 /// [`unix(7)`](http://man7.org/linux/man-pages/man7/unix.7.html) man page.
587 #[cfg(any(target_os = "android", target_os = "linux"))]
588 ScmCredentials(&'a UnixCredentials),
589
590 /// Set IV for `AF_ALG` crypto API.
591 ///
592 /// For further information, please refer to the
593 /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html)
594 #[cfg(any(
595 target_os = "android",
596 target_os = "linux",
597 ))]
598 AlgSetIv(&'a [u8]),
599 /// Set crypto operation for `AF_ALG` crypto API. It may be one of
600 /// `ALG_OP_ENCRYPT` or `ALG_OP_DECRYPT`
601 ///
602 /// For further information, please refer to the
603 /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html)
604 #[cfg(any(
605 target_os = "android",
606 target_os = "linux",
607 ))]
608 AlgSetOp(&'a libc::c_int),
609 /// Set the length of associated authentication data (AAD) (applicable only to AEAD algorithms)
610 /// for `AF_ALG` crypto API.
611 ///
612 /// For further information, please refer to the
613 /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html)
614 #[cfg(any(
615 target_os = "android",
616 target_os = "linux",
617 ))]
618 AlgSetAeadAssoclen(&'a u32),
619
620 }
621
622 // An opaque structure used to prevent cmsghdr from being a public type
623 #[doc(hidden)]
624 #[derive(Clone, Debug, Eq, PartialEq)]
625 pub struct UnknownCmsg(cmsghdr, Vec<u8>);
626
627 impl<'a> ControlMessage<'a> {
628 /// The value of CMSG_SPACE on this message.
629 /// Safe because CMSG_SPACE is always safe
space(&self) -> usize630 fn space(&self) -> usize {
631 unsafe{CMSG_SPACE(self.len() as libc::c_uint) as usize}
632 }
633
634 /// The value of CMSG_LEN on this message.
635 /// Safe because CMSG_LEN is always safe
636 #[cfg(any(target_os = "android",
637 all(target_os = "linux", not(target_env = "musl"))))]
cmsg_len(&self) -> usize638 fn cmsg_len(&self) -> usize {
639 unsafe{CMSG_LEN(self.len() as libc::c_uint) as usize}
640 }
641
642 #[cfg(not(any(target_os = "android",
643 all(target_os = "linux", not(target_env = "musl")))))]
cmsg_len(&self) -> libc::c_uint644 fn cmsg_len(&self) -> libc::c_uint {
645 unsafe{CMSG_LEN(self.len() as libc::c_uint)}
646 }
647
648 /// Return a reference to the payload data as a byte pointer
copy_to_cmsg_data(&self, cmsg_data: *mut u8)649 fn copy_to_cmsg_data(&self, cmsg_data: *mut u8) {
650 let data_ptr = match *self {
651 ControlMessage::ScmRights(fds) => {
652 fds as *const _ as *const u8
653 },
654 #[cfg(any(target_os = "android", target_os = "linux"))]
655 ControlMessage::ScmCredentials(creds) => {
656 &creds.0 as *const libc::ucred as *const u8
657 }
658 #[cfg(any(target_os = "android", target_os = "linux"))]
659 ControlMessage::AlgSetIv(iv) => {
660 unsafe {
661 let alg_iv = cmsg_data as *mut libc::af_alg_iv;
662 (*alg_iv).ivlen = iv.len() as u32;
663 ptr::copy_nonoverlapping(
664 iv.as_ptr(),
665 (*alg_iv).iv.as_mut_ptr(),
666 iv.len()
667 );
668 };
669 return
670 },
671 #[cfg(any(target_os = "android", target_os = "linux"))]
672 ControlMessage::AlgSetOp(op) => {
673 op as *const _ as *const u8
674 },
675 #[cfg(any(target_os = "android", target_os = "linux"))]
676 ControlMessage::AlgSetAeadAssoclen(len) => {
677 len as *const _ as *const u8
678 },
679 };
680 unsafe {
681 ptr::copy_nonoverlapping(
682 data_ptr,
683 cmsg_data,
684 self.len()
685 )
686 };
687 }
688
689 /// The size of the payload, excluding its cmsghdr
len(&self) -> usize690 fn len(&self) -> usize {
691 match *self {
692 ControlMessage::ScmRights(fds) => {
693 mem::size_of_val(fds)
694 },
695 #[cfg(any(target_os = "android", target_os = "linux"))]
696 ControlMessage::ScmCredentials(creds) => {
697 mem::size_of_val(creds)
698 }
699 #[cfg(any(target_os = "android", target_os = "linux"))]
700 ControlMessage::AlgSetIv(iv) => {
701 mem::size_of::<libc::af_alg_iv>() + iv.len()
702 },
703 #[cfg(any(target_os = "android", target_os = "linux"))]
704 ControlMessage::AlgSetOp(op) => {
705 mem::size_of_val(op)
706 },
707 #[cfg(any(target_os = "android", target_os = "linux"))]
708 ControlMessage::AlgSetAeadAssoclen(len) => {
709 mem::size_of_val(len)
710 },
711 }
712 }
713
714 /// Returns the value to put into the `cmsg_level` field of the header.
cmsg_level(&self) -> libc::c_int715 fn cmsg_level(&self) -> libc::c_int {
716 match *self {
717 ControlMessage::ScmRights(_) => libc::SOL_SOCKET,
718 #[cfg(any(target_os = "android", target_os = "linux"))]
719 ControlMessage::ScmCredentials(_) => libc::SOL_SOCKET,
720 #[cfg(any(target_os = "android", target_os = "linux"))]
721 ControlMessage::AlgSetIv(_) | ControlMessage::AlgSetOp(_) |
722 ControlMessage::AlgSetAeadAssoclen(_) => libc::SOL_ALG ,
723 }
724 }
725
726 /// Returns the value to put into the `cmsg_type` field of the header.
cmsg_type(&self) -> libc::c_int727 fn cmsg_type(&self) -> libc::c_int {
728 match *self {
729 ControlMessage::ScmRights(_) => libc::SCM_RIGHTS,
730 #[cfg(any(target_os = "android", target_os = "linux"))]
731 ControlMessage::ScmCredentials(_) => libc::SCM_CREDENTIALS,
732 #[cfg(any(target_os = "android", target_os = "linux"))]
733 ControlMessage::AlgSetIv(_) => {
734 libc::ALG_SET_IV
735 },
736 #[cfg(any(target_os = "android", target_os = "linux"))]
737 ControlMessage::AlgSetOp(_) => {
738 libc::ALG_SET_OP
739 },
740 #[cfg(any(target_os = "android", target_os = "linux"))]
741 ControlMessage::AlgSetAeadAssoclen(_) => {
742 libc::ALG_SET_AEAD_ASSOCLEN
743 },
744 }
745 }
746
747 // Unsafe: cmsg must point to a valid cmsghdr with enough space to
748 // encode self.
encode_into(&self, cmsg: *mut cmsghdr)749 unsafe fn encode_into(&self, cmsg: *mut cmsghdr) {
750 (*cmsg).cmsg_level = self.cmsg_level();
751 (*cmsg).cmsg_type = self.cmsg_type();
752 (*cmsg).cmsg_len = self.cmsg_len();
753 self.copy_to_cmsg_data(CMSG_DATA(cmsg));
754 }
755 }
756
757
758 /// Send data in scatter-gather vectors to a socket, possibly accompanied
759 /// by ancillary data. Optionally direct the message at the given address,
760 /// as with sendto.
761 ///
762 /// Allocates if cmsgs is nonempty.
sendmsg(fd: RawFd, iov: &[IoVec<&[u8]>], cmsgs: &[ControlMessage], flags: MsgFlags, addr: Option<&SockAddr>) -> Result<usize>763 pub fn sendmsg(fd: RawFd, iov: &[IoVec<&[u8]>], cmsgs: &[ControlMessage],
764 flags: MsgFlags, addr: Option<&SockAddr>) -> Result<usize>
765 {
766 let capacity = cmsgs.iter().map(|c| c.space()).sum();
767
768 // First size the buffer needed to hold the cmsgs. It must be zeroed,
769 // because subsequent code will not clear the padding bytes.
770 let cmsg_buffer = vec![0u8; capacity];
771
772 // Next encode the sending address, if provided
773 let (name, namelen) = match addr {
774 Some(addr) => {
775 let (x, y) = unsafe { addr.as_ffi_pair() };
776 (x as *const _, y)
777 },
778 None => (ptr::null(), 0),
779 };
780
781 // The message header must be initialized before the individual cmsgs.
782 let cmsg_ptr = if capacity > 0 {
783 cmsg_buffer.as_ptr() as *mut c_void
784 } else {
785 ptr::null_mut()
786 };
787
788 let mhdr = unsafe {
789 // Musl's msghdr has private fields, so this is the only way to
790 // initialize it.
791 let mut mhdr = mem::MaybeUninit::<msghdr>::zeroed();
792 let p = mhdr.as_mut_ptr();
793 (*p).msg_name = name as *mut _;
794 (*p).msg_namelen = namelen;
795 // transmute iov into a mutable pointer. sendmsg doesn't really mutate
796 // the buffer, but the standard says that it takes a mutable pointer
797 (*p).msg_iov = iov.as_ptr() as *mut _;
798 (*p).msg_iovlen = iov.len() as _;
799 (*p).msg_control = cmsg_ptr;
800 (*p).msg_controllen = capacity as _;
801 (*p).msg_flags = 0;
802 mhdr.assume_init()
803 };
804
805 // Encode each cmsg. This must happen after initializing the header because
806 // CMSG_NEXT_HDR and friends read the msg_control and msg_controllen fields.
807 // CMSG_FIRSTHDR is always safe
808 let mut pmhdr: *mut cmsghdr = unsafe{CMSG_FIRSTHDR(&mhdr as *const msghdr)};
809 for cmsg in cmsgs {
810 assert_ne!(pmhdr, ptr::null_mut());
811 // Safe because we know that pmhdr is valid, and we initialized it with
812 // sufficient space
813 unsafe { cmsg.encode_into(pmhdr) };
814 // Safe because mhdr is valid
815 pmhdr = unsafe{CMSG_NXTHDR(&mhdr as *const msghdr, pmhdr)};
816 }
817
818 let ret = unsafe { libc::sendmsg(fd, &mhdr, flags.bits()) };
819
820 Errno::result(ret).map(|r| r as usize)
821 }
822
823 /// Receive message in scatter-gather vectors from a socket, and
824 /// optionally receive ancillary data into the provided buffer.
825 /// If no ancillary data is desired, use () as the type parameter.
826 ///
827 /// # Arguments
828 ///
829 /// * `fd`: Socket file descriptor
830 /// * `iov`: Scatter-gather list of buffers to receive the message
831 /// * `cmsg_buffer`: Space to receive ancillary data. Should be created by
832 /// [`cmsg_space!`](macro.cmsg_space.html)
833 /// * `flags`: Optional flags passed directly to the operating system.
834 ///
835 /// # References
836 /// [recvmsg(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html)
recvmsg<'a>(fd: RawFd, iov: &[IoVec<&mut [u8]>], mut cmsg_buffer: Option<&'a mut Vec<u8>>, flags: MsgFlags) -> Result<RecvMsg<'a>>837 pub fn recvmsg<'a>(fd: RawFd, iov: &[IoVec<&mut [u8]>],
838 mut cmsg_buffer: Option<&'a mut Vec<u8>>,
839 flags: MsgFlags) -> Result<RecvMsg<'a>>
840 {
841 let mut address = mem::MaybeUninit::uninit();
842 let (msg_control, msg_controllen) = cmsg_buffer.as_mut()
843 .map(|v| (v.as_mut_ptr(), v.capacity()))
844 .unwrap_or((ptr::null_mut(), 0));
845 let mut mhdr = {
846 unsafe {
847 // Musl's msghdr has private fields, so this is the only way to
848 // initialize it.
849 let mut mhdr = mem::MaybeUninit::<msghdr>::zeroed();
850 let p = mhdr.as_mut_ptr();
851 (*p).msg_name = address.as_mut_ptr() as *mut c_void;
852 (*p).msg_namelen = mem::size_of::<sockaddr_storage>() as socklen_t;
853 (*p).msg_iov = iov.as_ptr() as *mut iovec;
854 (*p).msg_iovlen = iov.len() as _;
855 (*p).msg_control = msg_control as *mut c_void;
856 (*p).msg_controllen = msg_controllen as _;
857 (*p).msg_flags = 0;
858 mhdr.assume_init()
859 }
860 };
861
862 let ret = unsafe { libc::recvmsg(fd, &mut mhdr, flags.bits()) };
863
864 Errno::result(ret).map(|r| {
865 let cmsghdr = unsafe {
866 if mhdr.msg_controllen > 0 {
867 // got control message(s)
868 cmsg_buffer
869 .as_mut()
870 .unwrap()
871 .set_len(mhdr.msg_controllen as usize);
872 debug_assert!(!mhdr.msg_control.is_null());
873 debug_assert!(msg_controllen >= mhdr.msg_controllen as usize);
874 CMSG_FIRSTHDR(&mhdr as *const msghdr)
875 } else {
876 ptr::null()
877 }.as_ref()
878 };
879
880 let address = unsafe {
881 sockaddr_storage_to_addr(&address.assume_init(),
882 mhdr.msg_namelen as usize
883 ).ok()
884 };
885 RecvMsg {
886 bytes: r as usize,
887 cmsghdr,
888 address,
889 flags: MsgFlags::from_bits_truncate(mhdr.msg_flags),
890 mhdr,
891 }
892 })
893 }
894
895
896 /// Create an endpoint for communication
897 ///
898 /// The `protocol` specifies a particular protocol to be used with the
899 /// socket. Normally only a single protocol exists to support a
900 /// particular socket type within a given protocol family, in which case
901 /// protocol can be specified as `None`. However, it is possible that many
902 /// protocols may exist, in which case a particular protocol must be
903 /// specified in this manner.
904 ///
905 /// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html)
socket<T: Into<Option<SockProtocol>>>(domain: AddressFamily, ty: SockType, flags: SockFlag, protocol: T) -> Result<RawFd>906 pub fn socket<T: Into<Option<SockProtocol>>>(domain: AddressFamily, ty: SockType, flags: SockFlag, protocol: T) -> Result<RawFd> {
907 let protocol = match protocol.into() {
908 None => 0,
909 Some(p) => p as c_int,
910 };
911
912 // SockFlags are usually embedded into `ty`, but we don't do that in `nix` because it's a
913 // little easier to understand by separating it out. So we have to merge these bitfields
914 // here.
915 let mut ty = ty as c_int;
916 ty |= flags.bits();
917
918 let res = unsafe { libc::socket(domain as c_int, ty, protocol) };
919
920 Errno::result(res)
921 }
922
923 /// Create a pair of connected sockets
924 ///
925 /// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/socketpair.html)
socketpair<T: Into<Option<SockProtocol>>>(domain: AddressFamily, ty: SockType, protocol: T, flags: SockFlag) -> Result<(RawFd, RawFd)>926 pub fn socketpair<T: Into<Option<SockProtocol>>>(domain: AddressFamily, ty: SockType, protocol: T,
927 flags: SockFlag) -> Result<(RawFd, RawFd)> {
928 let protocol = match protocol.into() {
929 None => 0,
930 Some(p) => p as c_int,
931 };
932
933 // SockFlags are usually embedded into `ty`, but we don't do that in `nix` because it's a
934 // little easier to understand by separating it out. So we have to merge these bitfields
935 // here.
936 let mut ty = ty as c_int;
937 ty |= flags.bits();
938
939 let mut fds = [-1, -1];
940
941 let res = unsafe { libc::socketpair(domain as c_int, ty, protocol, fds.as_mut_ptr()) };
942 Errno::result(res)?;
943
944 Ok((fds[0], fds[1]))
945 }
946
947 /// Listen for connections on a socket
948 ///
949 /// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html)
listen(sockfd: RawFd, backlog: usize) -> Result<()>950 pub fn listen(sockfd: RawFd, backlog: usize) -> Result<()> {
951 let res = unsafe { libc::listen(sockfd, backlog as c_int) };
952
953 Errno::result(res).map(drop)
954 }
955
956 /// Bind a name to a socket
957 ///
958 /// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html)
bind(fd: RawFd, addr: &SockAddr) -> Result<()>959 pub fn bind(fd: RawFd, addr: &SockAddr) -> Result<()> {
960 let res = unsafe {
961 let (ptr, len) = addr.as_ffi_pair();
962 libc::bind(fd, ptr, len)
963 };
964
965 Errno::result(res).map(drop)
966 }
967
968 /// Accept a connection on a socket
969 ///
970 /// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.html)
accept(sockfd: RawFd) -> Result<RawFd>971 pub fn accept(sockfd: RawFd) -> Result<RawFd> {
972 let res = unsafe { libc::accept(sockfd, ptr::null_mut(), ptr::null_mut()) };
973
974 Errno::result(res)
975 }
976
977 /// Accept a connection on a socket
978 ///
979 /// [Further reading](http://man7.org/linux/man-pages/man2/accept.2.html)
980 #[cfg(any(target_os = "android",
981 target_os = "freebsd",
982 target_os = "linux",
983 target_os = "openbsd"))]
accept4(sockfd: RawFd, flags: SockFlag) -> Result<RawFd>984 pub fn accept4(sockfd: RawFd, flags: SockFlag) -> Result<RawFd> {
985 let res = unsafe { libc::accept4(sockfd, ptr::null_mut(), ptr::null_mut(), flags.bits()) };
986
987 Errno::result(res)
988 }
989
990 /// Initiate a connection on a socket
991 ///
992 /// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html)
connect(fd: RawFd, addr: &SockAddr) -> Result<()>993 pub fn connect(fd: RawFd, addr: &SockAddr) -> Result<()> {
994 let res = unsafe {
995 let (ptr, len) = addr.as_ffi_pair();
996 libc::connect(fd, ptr, len)
997 };
998
999 Errno::result(res).map(drop)
1000 }
1001
1002 /// Receive data from a connection-oriented socket. Returns the number of
1003 /// bytes read
1004 ///
1005 /// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/recv.html)
recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result<usize>1006 pub fn recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result<usize> {
1007 unsafe {
1008 let ret = libc::recv(
1009 sockfd,
1010 buf.as_ptr() as *mut c_void,
1011 buf.len() as size_t,
1012 flags.bits());
1013
1014 Errno::result(ret).map(|r| r as usize)
1015 }
1016 }
1017
1018 /// Receive data from a connectionless or connection-oriented socket. Returns
1019 /// the number of bytes read and, for connectionless sockets, the socket
1020 /// address of the sender.
1021 ///
1022 /// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html)
recvfrom(sockfd: RawFd, buf: &mut [u8]) -> Result<(usize, Option<SockAddr>)>1023 pub fn recvfrom(sockfd: RawFd, buf: &mut [u8])
1024 -> Result<(usize, Option<SockAddr>)>
1025 {
1026 unsafe {
1027 let mut addr: sockaddr_storage = mem::zeroed();
1028 let mut len = mem::size_of::<sockaddr_storage>() as socklen_t;
1029
1030 let ret = Errno::result(libc::recvfrom(
1031 sockfd,
1032 buf.as_ptr() as *mut c_void,
1033 buf.len() as size_t,
1034 0,
1035 &mut addr as *mut libc::sockaddr_storage as *mut libc::sockaddr,
1036 &mut len as *mut socklen_t))? as usize;
1037
1038 match sockaddr_storage_to_addr(&addr, len as usize) {
1039 Err(Error::Sys(Errno::ENOTCONN)) => Ok((ret, None)),
1040 Ok(addr) => Ok((ret, Some(addr))),
1041 Err(e) => Err(e)
1042 }
1043 }
1044 }
1045
1046 /// Send a message to a socket
1047 ///
1048 /// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html)
sendto(fd: RawFd, buf: &[u8], addr: &SockAddr, flags: MsgFlags) -> Result<usize>1049 pub fn sendto(fd: RawFd, buf: &[u8], addr: &SockAddr, flags: MsgFlags) -> Result<usize> {
1050 let ret = unsafe {
1051 let (ptr, len) = addr.as_ffi_pair();
1052 libc::sendto(fd, buf.as_ptr() as *const c_void, buf.len() as size_t, flags.bits(), ptr, len)
1053 };
1054
1055 Errno::result(ret).map(|r| r as usize)
1056 }
1057
1058 /// Send data to a connection-oriented socket. Returns the number of bytes read
1059 ///
1060 /// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/send.html)
send(fd: RawFd, buf: &[u8], flags: MsgFlags) -> Result<usize>1061 pub fn send(fd: RawFd, buf: &[u8], flags: MsgFlags) -> Result<usize> {
1062 let ret = unsafe {
1063 libc::send(fd, buf.as_ptr() as *const c_void, buf.len() as size_t, flags.bits())
1064 };
1065
1066 Errno::result(ret).map(|r| r as usize)
1067 }
1068
1069 /*
1070 *
1071 * ===== Socket Options =====
1072 *
1073 */
1074
1075 /// The protocol level at which to get / set socket options. Used as an
1076 /// argument to `getsockopt` and `setsockopt`.
1077 ///
1078 /// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html)
1079 #[repr(i32)]
1080 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1081 pub enum SockLevel {
1082 Socket = libc::SOL_SOCKET,
1083 Tcp = libc::IPPROTO_TCP,
1084 Ip = libc::IPPROTO_IP,
1085 Ipv6 = libc::IPPROTO_IPV6,
1086 Udp = libc::IPPROTO_UDP,
1087 #[cfg(any(target_os = "android", target_os = "linux"))]
1088 Netlink = libc::SOL_NETLINK,
1089 #[cfg(any(target_os = "android", target_os = "linux"))]
1090 Alg = libc::SOL_ALG,
1091 }
1092
1093 /// Represents a socket option that can be accessed or set. Used as an argument
1094 /// to `getsockopt`
1095 pub trait GetSockOpt : Copy {
1096 type Val;
1097
1098 #[doc(hidden)]
get(&self, fd: RawFd) -> Result<Self::Val>1099 fn get(&self, fd: RawFd) -> Result<Self::Val>;
1100 }
1101
1102 /// Represents a socket option that can be accessed or set. Used as an argument
1103 /// to `setsockopt`
1104 pub trait SetSockOpt : Clone {
1105 type Val;
1106
1107 #[doc(hidden)]
set(&self, fd: RawFd, val: &Self::Val) -> Result<()>1108 fn set(&self, fd: RawFd, val: &Self::Val) -> Result<()>;
1109 }
1110
1111 /// Get the current value for the requested socket option
1112 ///
1113 /// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html)
getsockopt<O: GetSockOpt>(fd: RawFd, opt: O) -> Result<O::Val>1114 pub fn getsockopt<O: GetSockOpt>(fd: RawFd, opt: O) -> Result<O::Val> {
1115 opt.get(fd)
1116 }
1117
1118 /// Sets the value for the requested socket option
1119 ///
1120 /// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html)
1121 ///
1122 /// # Examples
1123 ///
1124 /// ```
1125 /// use nix::sys::socket::setsockopt;
1126 /// use nix::sys::socket::sockopt::KeepAlive;
1127 /// use std::net::TcpListener;
1128 /// use std::os::unix::io::AsRawFd;
1129 ///
1130 /// let listener = TcpListener::bind("0.0.0.0:0").unwrap();
1131 /// let fd = listener.as_raw_fd();
1132 /// let res = setsockopt(fd, KeepAlive, &true);
1133 /// assert!(res.is_ok());
1134 /// ```
setsockopt<O: SetSockOpt>(fd: RawFd, opt: O, val: &O::Val) -> Result<()>1135 pub fn setsockopt<O: SetSockOpt>(fd: RawFd, opt: O, val: &O::Val) -> Result<()> {
1136 opt.set(fd, val)
1137 }
1138
1139 /// Get the address of the peer connected to the socket `fd`.
1140 ///
1141 /// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpeername.html)
getpeername(fd: RawFd) -> Result<SockAddr>1142 pub fn getpeername(fd: RawFd) -> Result<SockAddr> {
1143 unsafe {
1144 let mut addr = mem::MaybeUninit::uninit();
1145 let mut len = mem::size_of::<sockaddr_storage>() as socklen_t;
1146
1147 let ret = libc::getpeername(
1148 fd,
1149 addr.as_mut_ptr() as *mut libc::sockaddr,
1150 &mut len
1151 );
1152
1153 Errno::result(ret)?;
1154
1155 sockaddr_storage_to_addr(&addr.assume_init(), len as usize)
1156 }
1157 }
1158
1159 /// Get the current address to which the socket `fd` is bound.
1160 ///
1161 /// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockname.html)
getsockname(fd: RawFd) -> Result<SockAddr>1162 pub fn getsockname(fd: RawFd) -> Result<SockAddr> {
1163 unsafe {
1164 let mut addr = mem::MaybeUninit::uninit();
1165 let mut len = mem::size_of::<sockaddr_storage>() as socklen_t;
1166
1167 let ret = libc::getsockname(
1168 fd,
1169 addr.as_mut_ptr() as *mut libc::sockaddr,
1170 &mut len
1171 );
1172
1173 Errno::result(ret)?;
1174
1175 sockaddr_storage_to_addr(&addr.assume_init(), len as usize)
1176 }
1177 }
1178
1179 /// Return the appropriate `SockAddr` type from a `sockaddr_storage` of a certain
1180 /// size. In C this would usually be done by casting. The `len` argument
1181 /// should be the number of bytes in the `sockaddr_storage` that are actually
1182 /// allocated and valid. It must be at least as large as all the useful parts
1183 /// of the structure. Note that in the case of a `sockaddr_un`, `len` need not
1184 /// include the terminating null.
sockaddr_storage_to_addr( addr: &sockaddr_storage, len: usize) -> Result<SockAddr>1185 pub unsafe fn sockaddr_storage_to_addr(
1186 addr: &sockaddr_storage,
1187 len: usize) -> Result<SockAddr> {
1188
1189 if len < mem::size_of_val(&addr.ss_family) {
1190 return Err(Error::Sys(Errno::ENOTCONN));
1191 }
1192
1193 match c_int::from(addr.ss_family) {
1194 libc::AF_INET => {
1195 assert_eq!(len as usize, mem::size_of::<sockaddr_in>());
1196 let ret = *(addr as *const _ as *const sockaddr_in);
1197 Ok(SockAddr::Inet(InetAddr::V4(ret)))
1198 }
1199 libc::AF_INET6 => {
1200 assert_eq!(len as usize, mem::size_of::<sockaddr_in6>());
1201 Ok(SockAddr::Inet(InetAddr::V6(*(addr as *const _ as *const sockaddr_in6))))
1202 }
1203 libc::AF_UNIX => {
1204 let sun = *(addr as *const _ as *const sockaddr_un);
1205 let pathlen = len - offset_of!(sockaddr_un, sun_path);
1206 Ok(SockAddr::Unix(UnixAddr(sun, pathlen)))
1207 }
1208 #[cfg(any(target_os = "android", target_os = "linux"))]
1209 libc::AF_NETLINK => {
1210 use libc::sockaddr_nl;
1211 Ok(SockAddr::Netlink(NetlinkAddr(*(addr as *const _ as *const sockaddr_nl))))
1212 }
1213 #[cfg(any(target_os = "android", target_os = "linux"))]
1214 libc::AF_ALG => {
1215 use libc::sockaddr_alg;
1216 Ok(SockAddr::Alg(AlgAddr(*(addr as *const _ as *const sockaddr_alg))))
1217 }
1218 #[cfg(target_os = "linux")]
1219 libc::AF_VSOCK => {
1220 use libc::sockaddr_vm;
1221 Ok(SockAddr::Vsock(VsockAddr(*(addr as *const _ as *const sockaddr_vm))))
1222 }
1223 af => panic!("unexpected address family {}", af),
1224 }
1225 }
1226
1227
1228 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1229 pub enum Shutdown {
1230 /// Further receptions will be disallowed.
1231 Read,
1232 /// Further transmissions will be disallowed.
1233 Write,
1234 /// Further receptions and transmissions will be disallowed.
1235 Both,
1236 }
1237
1238 /// Shut down part of a full-duplex connection.
1239 ///
1240 /// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/shutdown.html)
shutdown(df: RawFd, how: Shutdown) -> Result<()>1241 pub fn shutdown(df: RawFd, how: Shutdown) -> Result<()> {
1242 unsafe {
1243 use libc::shutdown;
1244
1245 let how = match how {
1246 Shutdown::Read => libc::SHUT_RD,
1247 Shutdown::Write => libc::SHUT_WR,
1248 Shutdown::Both => libc::SHUT_RDWR,
1249 };
1250
1251 Errno::result(shutdown(df, how)).map(drop)
1252 }
1253 }
1254