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.
13 use ffi::{CStr, CString};
14 use io::{self, Error, ErrorKind};
15 use libc::{self, c_int, c_char, c_void, socklen_t};
17 use net::{SocketAddr, Shutdown, IpAddr};
20 use sys::net::{cvt, cvt_r, cvt_gai, Socket, init, wrlen_t};
21 use sys_common::{AsInner, FromInner, IntoInner};
23 ////////////////////////////////////////////////////////////////////////////////
24 // sockaddr and misc bindings
25 ////////////////////////////////////////////////////////////////////////////////
27 fn setsockopt<T>(sock: &Socket, opt: c_int, val: c_int,
28 payload: T) -> io::Result<()> {
30 let payload = &payload as *const T as *const c_void;
31 try!(cvt(libc::setsockopt(*sock.as_inner(), opt, val, payload,
32 mem::size_of::<T>() as socklen_t)));
38 fn getsockopt<T: Copy>(sock: &Socket, opt: c_int,
39 val: c_int) -> io::Result<T> {
41 let mut slot: T = mem::zeroed();
42 let mut len = mem::size_of::<T>() as socklen_t;
43 let ret = try!(cvt(c::getsockopt(*sock.as_inner(), opt, val,
44 &mut slot as *mut _ as *mut _,
46 assert_eq!(ret as usize, mem::size_of::<T>());
51 fn sockname<F>(f: F) -> io::Result<SocketAddr>
52 where F: FnOnce(*mut libc::sockaddr, *mut socklen_t) -> c_int
55 let mut storage: libc::sockaddr_storage = mem::zeroed();
56 let mut len = mem::size_of_val(&storage) as socklen_t;
57 try!(cvt(f(&mut storage as *mut _ as *mut _, &mut len)));
58 sockaddr_to_addr(&storage, len as usize)
62 fn sockaddr_to_addr(storage: &libc::sockaddr_storage,
63 len: usize) -> io::Result<SocketAddr> {
64 match storage.ss_family as libc::c_int {
66 assert!(len as usize >= mem::size_of::<libc::sockaddr_in>());
67 Ok(SocketAddr::V4(FromInner::from_inner(unsafe {
68 *(storage as *const _ as *const libc::sockaddr_in)
72 assert!(len as usize >= mem::size_of::<libc::sockaddr_in6>());
73 Ok(SocketAddr::V6(FromInner::from_inner(unsafe {
74 *(storage as *const _ as *const libc::sockaddr_in6)
78 Err(Error::new(ErrorKind::InvalidInput, "invalid argument"))
83 ////////////////////////////////////////////////////////////////////////////////
85 ////////////////////////////////////////////////////////////////////////////////
88 fn getaddrinfo(node: *const c_char, service: *const c_char,
89 hints: *const libc::addrinfo,
90 res: *mut *mut libc::addrinfo) -> c_int;
91 fn freeaddrinfo(res: *mut libc::addrinfo);
94 pub struct LookupHost {
95 original: *mut libc::addrinfo,
96 cur: *mut libc::addrinfo,
99 impl Iterator for LookupHost {
100 type Item = io::Result<SocketAddr>;
101 fn next(&mut self) -> Option<io::Result<SocketAddr>> {
103 if self.cur.is_null() { return None }
104 let ret = sockaddr_to_addr(mem::transmute((*self.cur).ai_addr),
105 (*self.cur).ai_addrlen as usize);
106 self.cur = (*self.cur).ai_next as *mut libc::addrinfo;
112 impl Drop for LookupHost {
114 unsafe { freeaddrinfo(self.original) }
118 pub fn lookup_host(host: &str) -> io::Result<LookupHost> {
121 let c_host = try!(CString::new(host));
122 let mut res = 0 as *mut _;
124 try!(cvt_gai(getaddrinfo(c_host.as_ptr(), 0 as *const _, 0 as *const _,
126 Ok(LookupHost { original: res, cur: res })
130 ////////////////////////////////////////////////////////////////////////////////
132 ////////////////////////////////////////////////////////////////////////////////
135 fn getnameinfo(sa: *const libc::sockaddr, salen: socklen_t,
136 host: *mut c_char, hostlen: libc::size_t,
137 serv: *mut c_char, servlen: libc::size_t,
138 flags: c_int) -> c_int;
141 const NI_MAXHOST: usize = 1025;
143 pub fn lookup_addr(addr: &IpAddr) -> io::Result<String> {
146 let saddr = SocketAddr::new(*addr, 0);
147 let (inner, len) = saddr.into_inner();
148 let mut hostbuf = [0 as c_char; NI_MAXHOST];
151 try!(cvt_gai(getnameinfo(inner, len,
152 hostbuf.as_mut_ptr(), NI_MAXHOST as libc::size_t,
153 0 as *mut _, 0, 0)));
155 CStr::from_ptr(hostbuf.as_ptr())
158 match from_utf8(data.to_bytes()) {
159 Ok(name) => Ok(name.to_string()),
160 Err(_) => Err(io::Error::new(io::ErrorKind::Other,
161 "failed to lookup address information"))
165 ////////////////////////////////////////////////////////////////////////////////
167 ////////////////////////////////////////////////////////////////////////////////
169 pub struct TcpStream {
174 pub fn connect(addr: &SocketAddr) -> io::Result<TcpStream> {
177 let sock = try!(Socket::new(addr, libc::SOCK_STREAM));
179 let (addrp, len) = addr.into_inner();
180 try!(cvt_r(|| unsafe { libc::connect(*sock.as_inner(), addrp, len) }));
181 Ok(TcpStream { inner: sock })
184 pub fn socket(&self) -> &Socket { &self.inner }
186 pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
187 setsockopt(&self.inner, libc::IPPROTO_TCP, libc::TCP_NODELAY,
191 pub fn set_keepalive(&self, seconds: Option<u32>) -> io::Result<()> {
192 let ret = setsockopt(&self.inner, libc::SOL_SOCKET, libc::SO_KEEPALIVE,
193 seconds.is_some() as c_int);
195 Some(n) => ret.and_then(|()| self.set_tcp_keepalive(n)),
200 #[cfg(any(target_os = "macos", target_os = "ios"))]
201 fn set_tcp_keepalive(&self, seconds: u32) -> io::Result<()> {
202 setsockopt(&self.inner, libc::IPPROTO_TCP, libc::TCP_KEEPALIVE,
205 #[cfg(any(target_os = "freebsd",
206 target_os = "dragonfly",
207 target_os = "linux"))]
208 fn set_tcp_keepalive(&self, seconds: u32) -> io::Result<()> {
209 setsockopt(&self.inner, libc::IPPROTO_TCP, libc::TCP_KEEPIDLE,
213 #[cfg(not(any(target_os = "macos",
215 target_os = "freebsd",
216 target_os = "dragonfly",
217 target_os = "linux")))]
218 fn set_tcp_keepalive(&self, _seconds: u32) -> io::Result<()> {
222 pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
226 pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
227 let ret = try!(cvt(unsafe {
228 libc::send(*self.inner.as_inner(),
229 buf.as_ptr() as *const c_void,
230 buf.len() as wrlen_t,
236 pub fn peer_addr(&self) -> io::Result<SocketAddr> {
237 sockname(|buf, len| unsafe {
238 libc::getpeername(*self.inner.as_inner(), buf, len)
242 pub fn socket_addr(&self) -> io::Result<SocketAddr> {
243 sockname(|buf, len| unsafe {
244 libc::getsockname(*self.inner.as_inner(), buf, len)
248 pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
249 use libc::consts::os::bsd44::SHUT_RDWR;
251 let how = match how {
252 Shutdown::Write => libc::SHUT_WR,
253 Shutdown::Read => libc::SHUT_RD,
254 Shutdown::Both => SHUT_RDWR,
256 try!(cvt(unsafe { libc::shutdown(*self.inner.as_inner(), how) }));
260 pub fn duplicate(&self) -> io::Result<TcpStream> {
261 self.inner.duplicate().map(|s| TcpStream { inner: s })
265 impl FromInner<Socket> for TcpStream {
266 fn from_inner(socket: Socket) -> TcpStream {
267 TcpStream { inner: socket }
271 ////////////////////////////////////////////////////////////////////////////////
273 ////////////////////////////////////////////////////////////////////////////////
275 pub struct TcpListener {
280 pub fn bind(addr: &SocketAddr) -> io::Result<TcpListener> {
283 let sock = try!(Socket::new(addr, libc::SOCK_STREAM));
285 // On platforms with Berkeley-derived sockets, this allows
286 // to quickly rebind a socket, without needing to wait for
287 // the OS to clean up the previous one.
289 try!(setsockopt(&sock, libc::SOL_SOCKET, libc::SO_REUSEADDR,
293 // Bind our new socket
294 let (addrp, len) = addr.into_inner();
295 try!(cvt(unsafe { libc::bind(*sock.as_inner(), addrp, len) }));
298 try!(cvt(unsafe { libc::listen(*sock.as_inner(), 128) }));
299 Ok(TcpListener { inner: sock })
302 pub fn socket(&self) -> &Socket { &self.inner }
304 pub fn socket_addr(&self) -> io::Result<SocketAddr> {
305 sockname(|buf, len| unsafe {
306 libc::getsockname(*self.inner.as_inner(), buf, len)
310 pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
311 let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() };
312 let mut len = mem::size_of_val(&storage) as socklen_t;
313 let sock = try!(self.inner.accept(&mut storage as *mut _ as *mut _,
315 let addr = try!(sockaddr_to_addr(&storage, len as usize));
316 Ok((TcpStream { inner: sock, }, addr))
319 pub fn duplicate(&self) -> io::Result<TcpListener> {
320 self.inner.duplicate().map(|s| TcpListener { inner: s })
324 impl FromInner<Socket> for TcpListener {
325 fn from_inner(socket: Socket) -> TcpListener {
326 TcpListener { inner: socket }
330 ////////////////////////////////////////////////////////////////////////////////
332 ////////////////////////////////////////////////////////////////////////////////
334 pub struct UdpSocket {
339 pub fn bind(addr: &SocketAddr) -> io::Result<UdpSocket> {
342 let sock = try!(Socket::new(addr, libc::SOCK_DGRAM));
343 let (addrp, len) = addr.into_inner();
344 try!(cvt(unsafe { libc::bind(*sock.as_inner(), addrp, len) }));
345 Ok(UdpSocket { inner: sock })
348 pub fn socket(&self) -> &Socket { &self.inner }
350 pub fn socket_addr(&self) -> io::Result<SocketAddr> {
351 sockname(|buf, len| unsafe {
352 libc::getsockname(*self.inner.as_inner(), buf, len)
356 pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
357 let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() };
358 let mut addrlen = mem::size_of_val(&storage) as socklen_t;
360 let n = try!(cvt(unsafe {
361 libc::recvfrom(*self.inner.as_inner(),
362 buf.as_mut_ptr() as *mut c_void,
363 buf.len() as wrlen_t, 0,
364 &mut storage as *mut _ as *mut _, &mut addrlen)
366 Ok((n as usize, try!(sockaddr_to_addr(&storage, addrlen as usize))))
369 pub fn send_to(&self, buf: &[u8], dst: &SocketAddr) -> io::Result<usize> {
370 let (dstp, dstlen) = dst.into_inner();
371 let ret = try!(cvt(unsafe {
372 libc::sendto(*self.inner.as_inner(),
373 buf.as_ptr() as *const c_void, buf.len() as wrlen_t,
379 pub fn set_broadcast(&self, on: bool) -> io::Result<()> {
380 setsockopt(&self.inner, libc::SOL_SOCKET, libc::SO_BROADCAST,
384 pub fn set_multicast_loop(&self, on: bool) -> io::Result<()> {
385 setsockopt(&self.inner, libc::IPPROTO_IP,
386 libc::IP_MULTICAST_LOOP, on as c_int)
389 pub fn join_multicast(&self, multi: &IpAddr) -> io::Result<()> {
392 self.set_membership(multi, libc::IP_ADD_MEMBERSHIP)
395 self.set_membership(multi, libc::IPV6_ADD_MEMBERSHIP)
399 pub fn leave_multicast(&self, multi: &IpAddr) -> io::Result<()> {
402 self.set_membership(multi, libc::IP_DROP_MEMBERSHIP)
405 self.set_membership(multi, libc::IPV6_DROP_MEMBERSHIP)
409 fn set_membership(&self, addr: &IpAddr, opt: c_int) -> io::Result<()> {
411 IpAddr::V4(ref addr) => {
412 let mreq = libc::ip_mreq {
413 imr_multiaddr: *addr.as_inner(),
414 // interface == INADDR_ANY
415 imr_interface: libc::in_addr { s_addr: 0x0 },
417 setsockopt(&self.inner, libc::IPPROTO_IP, opt, mreq)
419 IpAddr::V6(ref addr) => {
420 let mreq = libc::ip6_mreq {
421 ipv6mr_multiaddr: *addr.as_inner(),
424 setsockopt(&self.inner, libc::IPPROTO_IPV6, opt, mreq)
429 pub fn multicast_time_to_live(&self, ttl: i32) -> io::Result<()> {
430 setsockopt(&self.inner, libc::IPPROTO_IP, libc::IP_MULTICAST_TTL,
434 pub fn time_to_live(&self, ttl: i32) -> io::Result<()> {
435 setsockopt(&self.inner, libc::IPPROTO_IP, libc::IP_TTL, ttl as c_int)
438 pub fn duplicate(&self) -> io::Result<UdpSocket> {
439 self.inner.duplicate().map(|s| UdpSocket { inner: s })
443 impl FromInner<Socket> for UdpSocket {
444 fn from_inner(socket: Socket) -> UdpSocket {
445 UdpSocket { inner: socket }