1 // Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
12 use self::SocketStatus::*;
17 use io::net::addrinfo;
18 use io::net::ip::{SocketAddr, IpAddr, Ipv4Addr, Ipv6Addr};
19 use io::{IoResult, IoError};
20 use libc::{self, c_char, c_int};
23 use ptr::{self, null, null_mut};
25 use sys::{self, retry, c, sock_t, last_error, last_net_error, last_gai_error, close_sock,
26 wrlen, msglen_t, os, wouldblock, set_nonblocking, timer, ms_to_timeval,
27 decode_error_detailed};
28 use sync::{Arc, Mutex, MutexGuard};
29 use sys_common::{self, keep_going, short_write, timeout};
33 // FIXME: move uses of Arc and deadline tracking to std::io
36 pub enum SocketStatus {
41 ////////////////////////////////////////////////////////////////////////////////
42 // sockaddr and misc bindings
43 ////////////////////////////////////////////////////////////////////////////////
45 pub fn htons(u: u16) -> u16 {
48 pub fn ntohs(u: u16) -> u16 {
53 In4Addr(libc::in_addr),
54 In6Addr(libc::in6_addr),
57 pub fn ip_to_inaddr(ip: IpAddr) -> InAddr {
59 Ipv4Addr(a, b, c, d) => {
60 let ip = ((a as u32) << 24) |
64 In4Addr(libc::in_addr {
65 s_addr: Int::from_be(ip)
68 Ipv6Addr(a, b, c, d, e, f, g, h) => {
69 In6Addr(libc::in6_addr {
85 pub fn addr_to_sockaddr(addr: SocketAddr,
86 storage: &mut libc::sockaddr_storage)
89 let len = match ip_to_inaddr(addr.ip) {
91 let storage = storage as *mut _ as *mut libc::sockaddr_in;
92 (*storage).sin_family = libc::AF_INET as libc::sa_family_t;
93 (*storage).sin_port = htons(addr.port);
94 (*storage).sin_addr = inaddr;
95 mem::size_of::<libc::sockaddr_in>()
98 let storage = storage as *mut _ as *mut libc::sockaddr_in6;
99 (*storage).sin6_family = libc::AF_INET6 as libc::sa_family_t;
100 (*storage).sin6_port = htons(addr.port);
101 (*storage).sin6_addr = inaddr;
102 mem::size_of::<libc::sockaddr_in6>()
105 return len as libc::socklen_t;
109 pub fn socket(addr: SocketAddr, ty: libc::c_int) -> IoResult<sock_t> {
111 let fam = match addr.ip {
112 Ipv4Addr(..) => libc::AF_INET,
113 Ipv6Addr(..) => libc::AF_INET6,
115 match libc::socket(fam, ty, 0) {
116 -1 => Err(last_net_error()),
122 pub fn setsockopt<T>(fd: sock_t, opt: libc::c_int, val: libc::c_int,
123 payload: T) -> IoResult<()> {
125 let payload = &payload as *const T as *const libc::c_void;
126 let ret = libc::setsockopt(fd, opt, val,
128 mem::size_of::<T>() as libc::socklen_t);
130 Err(last_net_error())
137 pub fn getsockopt<T: Copy>(fd: sock_t, opt: libc::c_int,
138 val: libc::c_int) -> IoResult<T> {
140 let mut slot: T = mem::zeroed();
141 let mut len = mem::size_of::<T>() as libc::socklen_t;
142 let ret = c::getsockopt(fd, opt, val,
143 &mut slot as *mut _ as *mut _,
146 Err(last_net_error())
148 assert!(len as uint == mem::size_of::<T>());
154 pub fn sockname(fd: sock_t,
155 f: unsafe extern "system" fn(sock_t, *mut libc::sockaddr,
156 *mut libc::socklen_t) -> libc::c_int)
157 -> IoResult<SocketAddr>
159 let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() };
160 let mut len = mem::size_of::<libc::sockaddr_storage>() as libc::socklen_t;
162 let storage = &mut storage as *mut libc::sockaddr_storage;
164 storage as *mut libc::sockaddr,
165 &mut len as *mut libc::socklen_t);
167 return Err(last_net_error())
170 return sockaddr_to_addr(&storage, len as uint);
173 pub fn sockaddr_to_addr(storage: &libc::sockaddr_storage,
174 len: uint) -> IoResult<SocketAddr> {
175 match storage.ss_family as libc::c_int {
177 assert!(len as uint >= mem::size_of::<libc::sockaddr_in>());
178 let storage: &libc::sockaddr_in = unsafe {
179 mem::transmute(storage)
181 let ip = (storage.sin_addr.s_addr as u32).to_be();
182 let a = (ip >> 24) as u8;
183 let b = (ip >> 16) as u8;
184 let c = (ip >> 8) as u8;
185 let d = (ip >> 0) as u8;
187 ip: Ipv4Addr(a, b, c, d),
188 port: ntohs(storage.sin_port),
192 assert!(len as uint >= mem::size_of::<libc::sockaddr_in6>());
193 let storage: &libc::sockaddr_in6 = unsafe {
194 mem::transmute(storage)
196 let a = ntohs(storage.sin6_addr.s6_addr[0]);
197 let b = ntohs(storage.sin6_addr.s6_addr[1]);
198 let c = ntohs(storage.sin6_addr.s6_addr[2]);
199 let d = ntohs(storage.sin6_addr.s6_addr[3]);
200 let e = ntohs(storage.sin6_addr.s6_addr[4]);
201 let f = ntohs(storage.sin6_addr.s6_addr[5]);
202 let g = ntohs(storage.sin6_addr.s6_addr[6]);
203 let h = ntohs(storage.sin6_addr.s6_addr[7]);
205 ip: Ipv6Addr(a, b, c, d, e, f, g, h),
206 port: ntohs(storage.sin6_port),
211 kind: io::InvalidInput,
212 desc: "invalid argument",
219 ////////////////////////////////////////////////////////////////////////////////
220 // get_host_addresses
221 ////////////////////////////////////////////////////////////////////////////////
224 fn getaddrinfo(node: *const c_char, service: *const c_char,
225 hints: *const libc::addrinfo,
226 res: *mut *mut libc::addrinfo) -> c_int;
227 fn freeaddrinfo(res: *mut libc::addrinfo);
230 pub fn get_host_addresses(host: Option<&str>, servname: Option<&str>,
231 hint: Option<addrinfo::Hint>)
232 -> Result<Vec<addrinfo::Info>, IoError>
236 assert!(host.is_some() || servname.is_some());
238 let c_host = host.map(|x| CString::from_slice(x.as_bytes()));
239 let c_host = c_host.as_ref().map(|x| x.as_ptr()).unwrap_or(null());
240 let c_serv = servname.map(|x| CString::from_slice(x.as_bytes()));
241 let c_serv = c_serv.as_ref().map(|x| x.as_ptr()).unwrap_or(null());
243 let hint = hint.map(|hint| {
245 ai_flags: hint.flags as c_int,
246 ai_family: hint.family as c_int,
250 ai_canonname: null_mut(),
256 let hint_ptr = hint.as_ref().map_or(null(), |x| {
257 x as *const libc::addrinfo
259 let mut res = null_mut();
263 getaddrinfo(c_host, c_serv, hint_ptr, &mut res)
268 return Err(last_gai_error(s));
271 // Collect all the results we found
272 let mut addrs = Vec::new();
274 while !rp.is_null() {
276 let addr = try!(sockaddr_to_addr(mem::transmute((*rp).ai_addr),
277 (*rp).ai_addrlen as uint));
278 addrs.push(addrinfo::Info {
280 family: (*rp).ai_family as uint,
283 flags: (*rp).ai_flags as uint
286 rp = (*rp).ai_next as *mut libc::addrinfo;
290 unsafe { freeaddrinfo(res); }
295 ////////////////////////////////////////////////////////////////////////////////
297 ////////////////////////////////////////////////////////////////////////////////
300 fn getnameinfo(sa: *const libc::sockaddr, salen: libc::socklen_t,
301 host: *mut c_char, hostlen: libc::size_t,
302 serv: *mut c_char, servlen: libc::size_t,
303 flags: c_int) -> c_int;
306 const NI_MAXHOST: uint = 1025;
308 pub fn get_address_name(addr: IpAddr) -> Result<String, IoError> {
309 let addr = SocketAddr{ip: addr, port: 0};
311 let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() };
312 let len = addr_to_sockaddr(addr, &mut storage);
314 let mut hostbuf = [0 as c_char; NI_MAXHOST];
317 getnameinfo(&storage as *const _ as *const libc::sockaddr, len,
318 hostbuf.as_mut_ptr(), NI_MAXHOST as libc::size_t,
324 return Err(last_gai_error(res));
328 Ok(str::from_utf8(ffi::c_str_to_bytes(&hostbuf.as_ptr()))
329 .unwrap().to_string())
333 ////////////////////////////////////////////////////////////////////////////////
336 // The read/write functions below are the helpers for reading/writing a socket
337 // with a possible deadline specified. This is generally viewed as a timed out
340 // From the application's perspective, timeouts apply to the I/O object, not to
341 // the underlying file descriptor (it's one timeout per object). This means that
342 // we can't use the SO_RCVTIMEO and corresponding send timeout option.
344 // The next idea to implement timeouts would be to use nonblocking I/O. An
345 // invocation of select() would wait (with a timeout) for a socket to be ready.
346 // Once its ready, we can perform the operation. Note that the operation *must*
347 // be nonblocking, even though select() says the socket is ready. This is
348 // because some other thread could have come and stolen our data (handles can be
351 // To implement nonblocking I/O, the first option we have is to use the
352 // O_NONBLOCK flag. Remember though that this is a global setting, affecting all
353 // I/O objects, so this was initially viewed as unwise.
355 // It turns out that there's this nifty MSG_DONTWAIT flag which can be passed to
356 // send/recv, but the niftiness wears off once you realize it only works well on
357 // Linux [1] [2]. This means that it's pretty easy to get a nonblocking
358 // operation on Linux (no flag fiddling, no affecting other objects), but not on
361 // To work around this constraint on other platforms, we end up using the
362 // original strategy of flipping the O_NONBLOCK flag. As mentioned before, this
363 // could cause other objects' blocking operations to suddenly become
364 // nonblocking. To get around this, a "blocking operation" which returns EAGAIN
365 // falls back to using the same code path as nonblocking operations, but with an
366 // infinite timeout (select + send/recv). This helps emulate blocking
367 // reads/writes despite the underlying descriptor being nonblocking, as well as
368 // optimizing the fast path of just hitting one syscall in the good case.
370 // As a final caveat, this implementation uses a mutex so only one thread is
371 // doing a nonblocking operation at at time. This is the operation that comes
372 // after the select() (at which point we think the socket is ready). This is
373 // done for sanity to ensure that the state of the O_NONBLOCK flag is what we
374 // expect (wouldn't want someone turning it on when it should be off!). All
375 // operations performed in the lock are *nonblocking* to avoid holding the mutex
378 // So, in summary, Linux uses MSG_DONTWAIT and doesn't need mutexes, everyone
379 // else uses O_NONBLOCK and mutexes with some trickery to make sure blocking
380 // reads/writes are still blocking.
384 // [1] http://twistedmatrix.com/pipermail/twisted-commits/2012-April/034692.html
385 // [2] http://stackoverflow.com/questions/19819198/does-send-msg-dontwait
387 pub fn read<T, L, R>(fd: sock_t, deadline: u64, mut lock: L, mut read: R) -> IoResult<uint> where
389 R: FnMut(bool) -> libc::c_int,
393 ret = retry(|| read(false));
396 if deadline != 0 || (ret == -1 && wouldblock()) {
397 let deadline = match deadline {
402 // With a timeout, first we wait for the socket to become
403 // readable using select(), specifying the relevant timeout for
404 // our previously set deadline.
405 try!(await(&[fd], deadline, Readable));
407 // At this point, we're still within the timeout, and we've
408 // determined that the socket is readable (as returned by
409 // select). We must still read the socket in *nonblocking* mode
410 // because some other thread could come steal our data. If we
411 // fail to read some data, we retry (hence the outer loop) and
412 // wait for the socket to become readable again.
414 match retry(|| read(deadline.is_some())) {
415 -1 if wouldblock() => {}
416 -1 => return Err(last_net_error()),
417 n => { ret = n; break }
423 0 => Err(sys_common::eof()),
424 n if n < 0 => Err(last_net_error()),
429 pub fn write<T, L, W>(fd: sock_t,
432 write_everything: bool,
434 mut write: W) -> IoResult<uint> where
436 W: FnMut(bool, *const u8, uint) -> i64,
441 if write_everything {
442 ret = keep_going(buf, |inner, len| {
443 written = buf.len() - len;
444 write(false, inner, len)
447 ret = retry(|| { write(false, buf.as_ptr(), buf.len()) });
448 if ret > 0 { written = ret as uint; }
452 if deadline != 0 || (ret == -1 && wouldblock()) {
453 let deadline = match deadline {
457 while written < buf.len() && (write_everything || written == 0) {
458 // As with read(), first wait for the socket to be ready for
459 // the I/O operation.
460 match await(&[fd], deadline, Writable) {
461 Err(ref e) if e.kind == io::EndOfFile && written > 0 => {
462 assert!(deadline.is_some());
463 return Err(short_write(written, "short write"))
465 Err(e) => return Err(e),
469 // Also as with read(), we use MSG_DONTWAIT to guard ourselves
470 // against unforeseen circumstances.
472 let ptr = buf[written..].as_ptr();
473 let len = buf.len() - written;
474 match retry(|| write(deadline.is_some(), ptr, len)) {
475 -1 if wouldblock() => {}
476 -1 => return Err(last_net_error()),
477 n => { written += n as uint; }
483 Err(last_net_error())
489 // See http://developerweb.net/viewtopic.php?id=3196 for where this is
491 pub fn connect_timeout(fd: sock_t,
492 addrp: *const libc::sockaddr,
493 len: libc::socklen_t,
494 timeout_ms: u64) -> IoResult<()> {
495 #[cfg(unix)] use libc::EINPROGRESS as INPROGRESS;
496 #[cfg(windows)] use libc::WSAEINPROGRESS as INPROGRESS;
497 #[cfg(unix)] use libc::EWOULDBLOCK as WOULDBLOCK;
498 #[cfg(windows)] use libc::WSAEWOULDBLOCK as WOULDBLOCK;
500 // Make sure the call to connect() doesn't block
501 try!(set_nonblocking(fd, true));
503 let ret = match unsafe { libc::connect(fd, addrp, len) } {
504 // If the connection is in progress, then we need to wait for it to
505 // finish (with a timeout). The current strategy for doing this is
506 // to use select() with a timeout.
507 -1 if os::errno() as int == INPROGRESS as int ||
508 os::errno() as int == WOULDBLOCK as int => {
509 let mut set: c::fd_set = unsafe { mem::zeroed() };
510 c::fd_set(&mut set, fd);
511 match await(fd, &mut set, timeout_ms) {
512 0 => Err(timeout("connection timed out")),
513 -1 => Err(last_net_error()),
515 let err: libc::c_int = try!(
516 getsockopt(fd, libc::SOL_SOCKET, libc::SO_ERROR));
520 Err(decode_error_detailed(err))
526 -1 => Err(last_net_error()),
530 // be sure to turn blocking I/O back on
531 try!(set_nonblocking(fd, false));
535 fn await(fd: sock_t, set: &mut c::fd_set, timeout: u64) -> libc::c_int {
536 let start = timer::now();
538 // Recalculate the timeout each iteration (it is generally
539 // undefined what the value of the 'tv' is after select
541 let mut tv = ms_to_timeval(timeout - (timer::now() - start));
542 c::select(fd + 1, ptr::null_mut(), set as *mut _,
543 ptr::null_mut(), &mut tv)
547 fn await(_fd: sock_t, set: &mut c::fd_set, timeout: u64) -> libc::c_int {
548 let mut tv = ms_to_timeval(timeout);
549 unsafe { c::select(1, ptr::null_mut(), set, ptr::null_mut(), &mut tv) }
553 pub fn await(fds: &[sock_t], deadline: Option<u64>,
554 status: SocketStatus) -> IoResult<()> {
555 let mut set: c::fd_set = unsafe { mem::zeroed() };
557 for &fd in fds.iter() {
558 c::fd_set(&mut set, fd);
559 max = cmp::max(max, fd + 1);
562 max = fds.len() as sock_t;
565 let (read, write) = match status {
566 Readable => (&mut set as *mut _, ptr::null_mut()),
567 Writable => (ptr::null_mut(), &mut set as *mut _),
569 let mut tv: libc::timeval = unsafe { mem::zeroed() };
572 let now = timer::now();
573 let tvp = match deadline {
574 None => ptr::null_mut(),
576 // If we're past the deadline, then pass a 0 timeout to
577 // select() so we can poll the status
578 let ms = if deadline < now {0} else {deadline - now};
579 tv = ms_to_timeval(ms);
584 c::select(max as libc::c_int, read, write, ptr::null_mut(), tvp)
588 -1 => Err(last_net_error()),
589 0 => Err(timeout("timed out")),
594 ////////////////////////////////////////////////////////////////////////////////
595 // Basic socket representation
596 ////////////////////////////////////////////////////////////////////////////////
601 // Unused on Linux, where this lock is not necessary.
607 fn new(fd: sock_t) -> Inner {
608 Inner { fd: fd, lock: Mutex::new(()) }
612 impl Drop for Inner {
613 fn drop(&mut self) { unsafe { close_sock(self.fd); } }
616 pub struct Guard<'a> {
618 pub guard: MutexGuard<'a, ()>,
622 impl<'a> Drop for Guard<'a> {
624 assert!(set_nonblocking(self.fd, false).is_ok());
628 ////////////////////////////////////////////////////////////////////////////////
630 ////////////////////////////////////////////////////////////////////////////////
632 pub struct TcpStream {
639 pub fn connect(addr: SocketAddr, timeout: Option<u64>) -> IoResult<TcpStream> {
642 let fd = try!(socket(addr, libc::SOCK_STREAM));
643 let ret = TcpStream::new(fd);
645 let mut storage = unsafe { mem::zeroed() };
646 let len = addr_to_sockaddr(addr, &mut storage);
647 let addrp = &storage as *const _ as *const libc::sockaddr;
651 try!(connect_timeout(fd, addrp, len, timeout));
655 match retry(|| unsafe { libc::connect(fd, addrp, len) }) {
656 -1 => Err(last_error()),
663 pub fn new(fd: sock_t) -> TcpStream {
665 inner: Arc::new(Inner::new(fd)),
671 pub fn fd(&self) -> sock_t { self.inner.fd }
673 pub fn set_nodelay(&mut self, nodelay: bool) -> IoResult<()> {
674 setsockopt(self.fd(), libc::IPPROTO_TCP, libc::TCP_NODELAY,
675 nodelay as libc::c_int)
678 pub fn set_keepalive(&mut self, seconds: Option<uint>) -> IoResult<()> {
679 let ret = setsockopt(self.fd(), libc::SOL_SOCKET, libc::SO_KEEPALIVE,
680 seconds.is_some() as libc::c_int);
682 Some(n) => ret.and_then(|()| self.set_tcp_keepalive(n)),
687 #[cfg(any(target_os = "macos", target_os = "ios"))]
688 fn set_tcp_keepalive(&mut self, seconds: uint) -> IoResult<()> {
689 setsockopt(self.fd(), libc::IPPROTO_TCP, libc::TCP_KEEPALIVE,
690 seconds as libc::c_int)
692 #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
693 fn set_tcp_keepalive(&mut self, seconds: uint) -> IoResult<()> {
694 setsockopt(self.fd(), libc::IPPROTO_TCP, libc::TCP_KEEPIDLE,
695 seconds as libc::c_int)
697 #[cfg(not(any(target_os = "macos",
699 target_os = "freebsd",
700 target_os = "dragonfly")))]
701 fn set_tcp_keepalive(&mut self, _seconds: uint) -> IoResult<()> {
705 #[cfg(target_os = "linux")]
706 fn lock_nonblocking(&self) {}
708 #[cfg(not(target_os = "linux"))]
709 fn lock_nonblocking<'a>(&'a self) -> Guard<'a> {
712 guard: self.inner.lock.lock().unwrap(),
714 assert!(set_nonblocking(self.fd(), true).is_ok());
718 pub fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
720 let dolock = |&:| self.lock_nonblocking();
721 let doread = |&mut: nb| unsafe {
722 let flags = if nb {c::MSG_DONTWAIT} else {0};
724 buf.as_mut_ptr() as *mut libc::c_void,
726 flags) as libc::c_int
728 read(fd, self.read_deadline, dolock, doread)
731 pub fn write(&mut self, buf: &[u8]) -> IoResult<()> {
733 let dolock = |&:| self.lock_nonblocking();
734 let dowrite = |&: nb: bool, buf: *const u8, len: uint| unsafe {
735 let flags = if nb {c::MSG_DONTWAIT} else {0};
741 write(fd, self.write_deadline, buf, true, dolock, dowrite).map(|_| ())
743 pub fn peer_name(&mut self) -> IoResult<SocketAddr> {
744 sockname(self.fd(), libc::getpeername)
747 pub fn close_write(&mut self) -> IoResult<()> {
748 super::mkerr_libc(unsafe { libc::shutdown(self.fd(), libc::SHUT_WR) })
750 pub fn close_read(&mut self) -> IoResult<()> {
751 super::mkerr_libc(unsafe { libc::shutdown(self.fd(), libc::SHUT_RD) })
754 pub fn set_timeout(&mut self, timeout: Option<u64>) {
755 let deadline = timeout.map(|a| timer::now() + a).unwrap_or(0);
756 self.read_deadline = deadline;
757 self.write_deadline = deadline;
759 pub fn set_read_timeout(&mut self, timeout: Option<u64>) {
760 self.read_deadline = timeout.map(|a| timer::now() + a).unwrap_or(0);
762 pub fn set_write_timeout(&mut self, timeout: Option<u64>) {
763 self.write_deadline = timeout.map(|a| timer::now() + a).unwrap_or(0);
766 pub fn socket_name(&mut self) -> IoResult<SocketAddr> {
767 sockname(self.fd(), libc::getsockname)
771 impl Clone for TcpStream {
772 fn clone(&self) -> TcpStream {
774 inner: self.inner.clone(),
781 ////////////////////////////////////////////////////////////////////////////////
783 ////////////////////////////////////////////////////////////////////////////////
785 pub struct UdpSocket {
792 pub fn bind(addr: SocketAddr) -> IoResult<UdpSocket> {
795 let fd = try!(socket(addr, libc::SOCK_DGRAM));
796 let ret = UdpSocket {
797 inner: Arc::new(Inner::new(fd)),
802 let mut storage = unsafe { mem::zeroed() };
803 let len = addr_to_sockaddr(addr, &mut storage);
804 let addrp = &storage as *const _ as *const libc::sockaddr;
806 match unsafe { libc::bind(fd, addrp, len) } {
807 -1 => Err(last_error()),
812 pub fn fd(&self) -> sock_t { self.inner.fd }
814 pub fn set_broadcast(&mut self, on: bool) -> IoResult<()> {
815 setsockopt(self.fd(), libc::SOL_SOCKET, libc::SO_BROADCAST,
819 pub fn set_multicast_loop(&mut self, on: bool) -> IoResult<()> {
820 setsockopt(self.fd(), libc::IPPROTO_IP, libc::IP_MULTICAST_LOOP,
824 pub fn set_membership(&mut self, addr: IpAddr, opt: libc::c_int) -> IoResult<()> {
825 match ip_to_inaddr(addr) {
827 let mreq = libc::ip_mreq {
829 // interface == INADDR_ANY
830 imr_interface: libc::in_addr { s_addr: 0x0 },
832 setsockopt(self.fd(), libc::IPPROTO_IP, opt, mreq)
835 let mreq = libc::ip6_mreq {
836 ipv6mr_multiaddr: addr,
839 setsockopt(self.fd(), libc::IPPROTO_IPV6, opt, mreq)
844 #[cfg(target_os = "linux")]
845 fn lock_nonblocking(&self) {}
847 #[cfg(not(target_os = "linux"))]
848 fn lock_nonblocking<'a>(&'a self) -> Guard<'a> {
851 guard: self.inner.lock.lock().unwrap(),
853 assert!(set_nonblocking(self.fd(), true).is_ok());
857 pub fn socket_name(&mut self) -> IoResult<SocketAddr> {
858 sockname(self.fd(), libc::getsockname)
861 pub fn recv_from(&mut self, buf: &mut [u8]) -> IoResult<(uint, SocketAddr)> {
863 let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() };
864 let storagep = &mut storage as *mut _ as *mut libc::sockaddr;
865 let mut addrlen: libc::socklen_t =
866 mem::size_of::<libc::sockaddr_storage>() as libc::socklen_t;
868 let dolock = |&:| self.lock_nonblocking();
869 let n = try!(read(fd, self.read_deadline, dolock, |nb| unsafe {
870 let flags = if nb {c::MSG_DONTWAIT} else {0};
872 buf.as_mut_ptr() as *mut libc::c_void,
873 buf.len() as msglen_t,
876 &mut addrlen) as libc::c_int
878 sockaddr_to_addr(&storage, addrlen as uint).and_then(|addr| {
879 Ok((n as uint, addr))
883 pub fn send_to(&mut self, buf: &[u8], dst: SocketAddr) -> IoResult<()> {
884 let mut storage = unsafe { mem::zeroed() };
885 let dstlen = addr_to_sockaddr(dst, &mut storage);
886 let dstp = &storage as *const _ as *const libc::sockaddr;
889 let dolock = |&: | self.lock_nonblocking();
890 let dowrite = |&mut: nb, buf: *const u8, len: uint| unsafe {
891 let flags = if nb {c::MSG_DONTWAIT} else {0};
893 buf as *const libc::c_void,
900 let n = try!(write(fd, self.write_deadline, buf, false, dolock, dowrite));
902 Err(short_write(n, "couldn't send entire packet at once"))
908 pub fn join_multicast(&mut self, multi: IpAddr) -> IoResult<()> {
911 self.set_membership(multi, libc::IP_ADD_MEMBERSHIP)
914 self.set_membership(multi, libc::IPV6_ADD_MEMBERSHIP)
918 pub fn leave_multicast(&mut self, multi: IpAddr) -> IoResult<()> {
921 self.set_membership(multi, libc::IP_DROP_MEMBERSHIP)
924 self.set_membership(multi, libc::IPV6_DROP_MEMBERSHIP)
929 pub fn multicast_time_to_live(&mut self, ttl: int) -> IoResult<()> {
930 setsockopt(self.fd(), libc::IPPROTO_IP, libc::IP_MULTICAST_TTL,
933 pub fn time_to_live(&mut self, ttl: int) -> IoResult<()> {
934 setsockopt(self.fd(), libc::IPPROTO_IP, libc::IP_TTL, ttl as libc::c_int)
937 pub fn set_timeout(&mut self, timeout: Option<u64>) {
938 let deadline = timeout.map(|a| timer::now() + a).unwrap_or(0);
939 self.read_deadline = deadline;
940 self.write_deadline = deadline;
942 pub fn set_read_timeout(&mut self, timeout: Option<u64>) {
943 self.read_deadline = timeout.map(|a| timer::now() + a).unwrap_or(0);
945 pub fn set_write_timeout(&mut self, timeout: Option<u64>) {
946 self.write_deadline = timeout.map(|a| timer::now() + a).unwrap_or(0);
950 impl Clone for UdpSocket {
951 fn clone(&self) -> UdpSocket {
953 inner: self.inner.clone(),