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