// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use prelude::v1::*; use ffi::{CStr, CString}; use fmt; use io::{self, Error, ErrorKind}; use libc::{self, c_int, c_char, c_void, socklen_t}; use mem; use net::{SocketAddr, Shutdown, IpAddr}; use ptr; use str::from_utf8; use sys::c; use sys::net::{cvt, cvt_r, cvt_gai, Socket, init, wrlen_t}; use sys_common::{AsInner, FromInner, IntoInner}; use time::Duration; //////////////////////////////////////////////////////////////////////////////// // sockaddr and misc bindings //////////////////////////////////////////////////////////////////////////////// pub fn setsockopt(sock: &Socket, opt: c_int, val: c_int, payload: T) -> io::Result<()> { unsafe { let payload = &payload as *const T as *const c_void; try!(cvt(libc::setsockopt(*sock.as_inner(), opt, val, payload, mem::size_of::() as socklen_t))); Ok(()) } } pub fn getsockopt(sock: &Socket, opt: c_int, val: c_int) -> io::Result { unsafe { let mut slot: T = mem::zeroed(); let mut len = mem::size_of::() as socklen_t; try!(cvt(c::getsockopt(*sock.as_inner(), opt, val, &mut slot as *mut _ as *mut _, &mut len))); assert_eq!(len as usize, mem::size_of::()); Ok(slot) } } fn sockname(f: F) -> io::Result where F: FnOnce(*mut libc::sockaddr, *mut socklen_t) -> c_int { unsafe { let mut storage: libc::sockaddr_storage = mem::zeroed(); let mut len = mem::size_of_val(&storage) as socklen_t; try!(cvt(f(&mut storage as *mut _ as *mut _, &mut len))); sockaddr_to_addr(&storage, len as usize) } } fn sockaddr_to_addr(storage: &libc::sockaddr_storage, len: usize) -> io::Result { match storage.ss_family as libc::c_int { libc::AF_INET => { assert!(len as usize >= mem::size_of::()); Ok(SocketAddr::V4(FromInner::from_inner(unsafe { *(storage as *const _ as *const libc::sockaddr_in) }))) } libc::AF_INET6 => { assert!(len as usize >= mem::size_of::()); Ok(SocketAddr::V6(FromInner::from_inner(unsafe { *(storage as *const _ as *const libc::sockaddr_in6) }))) } _ => { Err(Error::new(ErrorKind::InvalidInput, "invalid argument")) } } } //////////////////////////////////////////////////////////////////////////////// // get_host_addresses //////////////////////////////////////////////////////////////////////////////// extern "system" { fn getaddrinfo(node: *const c_char, service: *const c_char, hints: *const libc::addrinfo, res: *mut *mut libc::addrinfo) -> c_int; fn freeaddrinfo(res: *mut libc::addrinfo); } pub struct LookupHost { original: *mut libc::addrinfo, cur: *mut libc::addrinfo, } impl Iterator for LookupHost { type Item = io::Result; fn next(&mut self) -> Option> { unsafe { if self.cur.is_null() { return None } let ret = sockaddr_to_addr(mem::transmute((*self.cur).ai_addr), (*self.cur).ai_addrlen as usize); self.cur = (*self.cur).ai_next as *mut libc::addrinfo; Some(ret) } } } unsafe impl Sync for LookupHost {} unsafe impl Send for LookupHost {} impl Drop for LookupHost { fn drop(&mut self) { unsafe { freeaddrinfo(self.original) } } } pub fn lookup_host(host: &str) -> io::Result { init(); let c_host = try!(CString::new(host)); let mut res = ptr::null_mut(); unsafe { try!(cvt_gai(getaddrinfo(c_host.as_ptr(), ptr::null(), ptr::null(), &mut res))); Ok(LookupHost { original: res, cur: res }) } } //////////////////////////////////////////////////////////////////////////////// // lookup_addr //////////////////////////////////////////////////////////////////////////////// extern "system" { fn getnameinfo(sa: *const libc::sockaddr, salen: socklen_t, host: *mut c_char, hostlen: libc::size_t, serv: *mut c_char, servlen: libc::size_t, flags: c_int) -> c_int; } const NI_MAXHOST: usize = 1025; pub fn lookup_addr(addr: &IpAddr) -> io::Result { init(); let saddr = SocketAddr::new(*addr, 0); let (inner, len) = saddr.into_inner(); let mut hostbuf = [0 as c_char; NI_MAXHOST]; let data = unsafe { try!(cvt_gai(getnameinfo(inner, len, hostbuf.as_mut_ptr(), NI_MAXHOST as libc::size_t, ptr::null_mut(), 0, 0))); CStr::from_ptr(hostbuf.as_ptr()) }; match from_utf8(data.to_bytes()) { Ok(name) => Ok(name.to_owned()), Err(_) => Err(io::Error::new(io::ErrorKind::Other, "failed to lookup address information")) } } //////////////////////////////////////////////////////////////////////////////// // TCP streams //////////////////////////////////////////////////////////////////////////////// pub struct TcpStream { inner: Socket, } impl TcpStream { pub fn connect(addr: &SocketAddr) -> io::Result { init(); let sock = try!(Socket::new(addr, libc::SOCK_STREAM)); let (addrp, len) = addr.into_inner(); try!(cvt_r(|| unsafe { libc::connect(*sock.as_inner(), addrp, len) })); Ok(TcpStream { inner: sock }) } pub fn socket(&self) -> &Socket { &self.inner } pub fn into_socket(self) -> Socket { self.inner } pub fn set_read_timeout(&self, dur: Option) -> io::Result<()> { self.inner.set_timeout(dur, libc::SO_RCVTIMEO) } pub fn set_write_timeout(&self, dur: Option) -> io::Result<()> { self.inner.set_timeout(dur, libc::SO_SNDTIMEO) } pub fn read_timeout(&self) -> io::Result> { self.inner.timeout(libc::SO_RCVTIMEO) } pub fn write_timeout(&self) -> io::Result> { self.inner.timeout(libc::SO_SNDTIMEO) } pub fn read(&self, buf: &mut [u8]) -> io::Result { self.inner.read(buf) } pub fn write(&self, buf: &[u8]) -> io::Result { let ret = try!(cvt(unsafe { libc::send(*self.inner.as_inner(), buf.as_ptr() as *const c_void, buf.len() as wrlen_t, 0) })); Ok(ret as usize) } pub fn peer_addr(&self) -> io::Result { sockname(|buf, len| unsafe { libc::getpeername(*self.inner.as_inner(), buf, len) }) } pub fn socket_addr(&self) -> io::Result { sockname(|buf, len| unsafe { libc::getsockname(*self.inner.as_inner(), buf, len) }) } pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { use libc::consts::os::bsd44::SHUT_RDWR; let how = match how { Shutdown::Write => libc::SHUT_WR, Shutdown::Read => libc::SHUT_RD, Shutdown::Both => SHUT_RDWR, }; try!(cvt(unsafe { libc::shutdown(*self.inner.as_inner(), how) })); Ok(()) } pub fn duplicate(&self) -> io::Result { self.inner.duplicate().map(|s| TcpStream { inner: s }) } } impl FromInner for TcpStream { fn from_inner(socket: Socket) -> TcpStream { TcpStream { inner: socket } } } impl fmt::Debug for TcpStream { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut res = f.debug_struct("TcpStream"); if let Ok(addr) = self.socket_addr() { res.field("addr", &addr); } if let Ok(peer) = self.peer_addr() { res.field("peer", &peer); } let name = if cfg!(windows) {"socket"} else {"fd"}; res.field(name, &self.inner.as_inner()) .finish() } } //////////////////////////////////////////////////////////////////////////////// // TCP listeners //////////////////////////////////////////////////////////////////////////////// pub struct TcpListener { inner: Socket, } impl TcpListener { pub fn bind(addr: &SocketAddr) -> io::Result { init(); let sock = try!(Socket::new(addr, libc::SOCK_STREAM)); // On platforms with Berkeley-derived sockets, this allows // to quickly rebind a socket, without needing to wait for // the OS to clean up the previous one. if !cfg!(windows) { try!(setsockopt(&sock, libc::SOL_SOCKET, libc::SO_REUSEADDR, 1 as c_int)); } // Bind our new socket let (addrp, len) = addr.into_inner(); try!(cvt(unsafe { libc::bind(*sock.as_inner(), addrp, len) })); // Start listening try!(cvt(unsafe { libc::listen(*sock.as_inner(), 128) })); Ok(TcpListener { inner: sock }) } pub fn socket(&self) -> &Socket { &self.inner } pub fn into_socket(self) -> Socket { self.inner } pub fn socket_addr(&self) -> io::Result { sockname(|buf, len| unsafe { libc::getsockname(*self.inner.as_inner(), buf, len) }) } pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() }; let mut len = mem::size_of_val(&storage) as socklen_t; let sock = try!(self.inner.accept(&mut storage as *mut _ as *mut _, &mut len)); let addr = try!(sockaddr_to_addr(&storage, len as usize)); Ok((TcpStream { inner: sock, }, addr)) } pub fn duplicate(&self) -> io::Result { self.inner.duplicate().map(|s| TcpListener { inner: s }) } } impl FromInner for TcpListener { fn from_inner(socket: Socket) -> TcpListener { TcpListener { inner: socket } } } impl fmt::Debug for TcpListener { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut res = f.debug_struct("TcpListener"); if let Ok(addr) = self.socket_addr() { res.field("addr", &addr); } let name = if cfg!(windows) {"socket"} else {"fd"}; res.field(name, &self.inner.as_inner()) .finish() } } //////////////////////////////////////////////////////////////////////////////// // UDP //////////////////////////////////////////////////////////////////////////////// pub struct UdpSocket { inner: Socket, } impl UdpSocket { pub fn bind(addr: &SocketAddr) -> io::Result { init(); let sock = try!(Socket::new(addr, libc::SOCK_DGRAM)); let (addrp, len) = addr.into_inner(); try!(cvt(unsafe { libc::bind(*sock.as_inner(), addrp, len) })); Ok(UdpSocket { inner: sock }) } pub fn socket(&self) -> &Socket { &self.inner } pub fn into_socket(self) -> Socket { self.inner } pub fn socket_addr(&self) -> io::Result { sockname(|buf, len| unsafe { libc::getsockname(*self.inner.as_inner(), buf, len) }) } pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() }; let mut addrlen = mem::size_of_val(&storage) as socklen_t; let n = try!(cvt(unsafe { libc::recvfrom(*self.inner.as_inner(), buf.as_mut_ptr() as *mut c_void, buf.len() as wrlen_t, 0, &mut storage as *mut _ as *mut _, &mut addrlen) })); Ok((n as usize, try!(sockaddr_to_addr(&storage, addrlen as usize)))) } pub fn send_to(&self, buf: &[u8], dst: &SocketAddr) -> io::Result { let (dstp, dstlen) = dst.into_inner(); let ret = try!(cvt(unsafe { libc::sendto(*self.inner.as_inner(), buf.as_ptr() as *const c_void, buf.len() as wrlen_t, 0, dstp, dstlen) })); Ok(ret as usize) } pub fn duplicate(&self) -> io::Result { self.inner.duplicate().map(|s| UdpSocket { inner: s }) } pub fn set_read_timeout(&self, dur: Option) -> io::Result<()> { self.inner.set_timeout(dur, libc::SO_RCVTIMEO) } pub fn set_write_timeout(&self, dur: Option) -> io::Result<()> { self.inner.set_timeout(dur, libc::SO_SNDTIMEO) } pub fn read_timeout(&self) -> io::Result> { self.inner.timeout(libc::SO_RCVTIMEO) } pub fn write_timeout(&self) -> io::Result> { self.inner.timeout(libc::SO_SNDTIMEO) } } impl FromInner for UdpSocket { fn from_inner(socket: Socket) -> UdpSocket { UdpSocket { inner: socket } } } impl fmt::Debug for UdpSocket { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut res = f.debug_struct("UdpSocket"); if let Ok(addr) = self.socket_addr() { res.field("addr", &addr); } let name = if cfg!(windows) {"socket"} else {"fd"}; res.field(name, &self.inner.as_inner()) .finish() } }