]> git.lizzy.rs Git - rust.git/blob - src/libstd/sys/common/net2.rs
Auto merge of #24865 - bluss:range-size, r=alexcrichton
[rust.git] / src / libstd / sys / common / net2.rs
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.
4 //
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.
10
11 use prelude::v1::*;
12
13 use ffi::{CStr, CString};
14 use io::{self, Error, ErrorKind};
15 use libc::{self, c_int, c_char, c_void, socklen_t};
16 use mem;
17 use net::{SocketAddr, Shutdown, IpAddr};
18 use str::from_utf8;
19 use sys::c;
20 use sys::net::{cvt, cvt_r, cvt_gai, Socket, init, wrlen_t};
21 use sys_common::{AsInner, FromInner, IntoInner};
22
23 ////////////////////////////////////////////////////////////////////////////////
24 // sockaddr and misc bindings
25 ////////////////////////////////////////////////////////////////////////////////
26
27 fn setsockopt<T>(sock: &Socket, opt: c_int, val: c_int,
28                      payload: T) -> io::Result<()> {
29     unsafe {
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)));
33         Ok(())
34     }
35 }
36
37 #[allow(dead_code)]
38 fn getsockopt<T: Copy>(sock: &Socket, opt: c_int,
39                        val: c_int) -> io::Result<T> {
40     unsafe {
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 _,
45                                          &mut len)));
46         assert_eq!(ret as usize, mem::size_of::<T>());
47         Ok(slot)
48     }
49 }
50
51 fn sockname<F>(f: F) -> io::Result<SocketAddr>
52     where F: FnOnce(*mut libc::sockaddr, *mut socklen_t) -> c_int
53 {
54     unsafe {
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)
59     }
60 }
61
62 fn sockaddr_to_addr(storage: &libc::sockaddr_storage,
63                     len: usize) -> io::Result<SocketAddr> {
64     match storage.ss_family as libc::c_int {
65         libc::AF_INET => {
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)
69             })))
70         }
71         libc::AF_INET6 => {
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)
75             })))
76         }
77         _ => {
78             Err(Error::new(ErrorKind::InvalidInput, "invalid argument"))
79         }
80     }
81 }
82
83 ////////////////////////////////////////////////////////////////////////////////
84 // get_host_addresses
85 ////////////////////////////////////////////////////////////////////////////////
86
87 extern "system" {
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);
92 }
93
94 pub struct LookupHost {
95     original: *mut libc::addrinfo,
96     cur: *mut libc::addrinfo,
97 }
98
99 impl Iterator for LookupHost {
100     type Item = io::Result<SocketAddr>;
101     fn next(&mut self) -> Option<io::Result<SocketAddr>> {
102         unsafe {
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;
107             Some(ret)
108         }
109     }
110 }
111
112 impl Drop for LookupHost {
113     fn drop(&mut self) {
114         unsafe { freeaddrinfo(self.original) }
115     }
116 }
117
118 pub fn lookup_host(host: &str) -> io::Result<LookupHost> {
119     init();
120
121     let c_host = try!(CString::new(host));
122     let mut res = 0 as *mut _;
123     unsafe {
124         try!(cvt_gai(getaddrinfo(c_host.as_ptr(), 0 as *const _, 0 as *const _,
125                                  &mut res)));
126         Ok(LookupHost { original: res, cur: res })
127     }
128 }
129
130 ////////////////////////////////////////////////////////////////////////////////
131 // lookup_addr
132 ////////////////////////////////////////////////////////////////////////////////
133
134 extern "system" {
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;
139 }
140
141 const NI_MAXHOST: usize = 1025;
142
143 pub fn lookup_addr(addr: &IpAddr) -> io::Result<String> {
144     init();
145
146     let saddr = SocketAddr::new(*addr, 0);
147     let (inner, len) = saddr.into_inner();
148     let mut hostbuf = [0 as c_char; NI_MAXHOST];
149
150     let data = unsafe {
151         try!(cvt_gai(getnameinfo(inner, len,
152                                  hostbuf.as_mut_ptr(), NI_MAXHOST as libc::size_t,
153                                  0 as *mut _, 0, 0)));
154
155         CStr::from_ptr(hostbuf.as_ptr())
156     };
157
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"))
162     }
163 }
164
165 ////////////////////////////////////////////////////////////////////////////////
166 // TCP streams
167 ////////////////////////////////////////////////////////////////////////////////
168
169 pub struct TcpStream {
170     inner: Socket,
171 }
172
173 impl TcpStream {
174     pub fn connect(addr: &SocketAddr) -> io::Result<TcpStream> {
175         init();
176
177         let sock = try!(Socket::new(addr, libc::SOCK_STREAM));
178
179         let (addrp, len) = addr.into_inner();
180         try!(cvt_r(|| unsafe { libc::connect(*sock.as_inner(), addrp, len) }));
181         Ok(TcpStream { inner: sock })
182     }
183
184     pub fn socket(&self) -> &Socket { &self.inner }
185
186     pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
187         setsockopt(&self.inner, libc::IPPROTO_TCP, libc::TCP_NODELAY,
188                    nodelay as c_int)
189     }
190
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);
194         match seconds {
195             Some(n) => ret.and_then(|()| self.set_tcp_keepalive(n)),
196             None => ret,
197         }
198     }
199
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,
203                    seconds as c_int)
204     }
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,
210                    seconds as c_int)
211     }
212
213     #[cfg(not(any(target_os = "macos",
214                   target_os = "ios",
215                   target_os = "freebsd",
216                   target_os = "dragonfly",
217                   target_os = "linux")))]
218     fn set_tcp_keepalive(&self, _seconds: u32) -> io::Result<()> {
219         Ok(())
220     }
221
222     pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
223         self.inner.read(buf)
224     }
225
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,
231                        0)
232         }));
233         Ok(ret as usize)
234     }
235
236     pub fn peer_addr(&self) -> io::Result<SocketAddr> {
237         sockname(|buf, len| unsafe {
238             libc::getpeername(*self.inner.as_inner(), buf, len)
239         })
240     }
241
242     pub fn socket_addr(&self) -> io::Result<SocketAddr> {
243         sockname(|buf, len| unsafe {
244             libc::getsockname(*self.inner.as_inner(), buf, len)
245         })
246     }
247
248     pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
249         use libc::consts::os::bsd44::SHUT_RDWR;
250
251         let how = match how {
252             Shutdown::Write => libc::SHUT_WR,
253             Shutdown::Read => libc::SHUT_RD,
254             Shutdown::Both => SHUT_RDWR,
255         };
256         try!(cvt(unsafe { libc::shutdown(*self.inner.as_inner(), how) }));
257         Ok(())
258     }
259
260     pub fn duplicate(&self) -> io::Result<TcpStream> {
261         self.inner.duplicate().map(|s| TcpStream { inner: s })
262     }
263 }
264
265 impl FromInner<Socket> for TcpStream {
266     fn from_inner(socket: Socket) -> TcpStream {
267         TcpStream { inner: socket }
268     }
269 }
270
271 ////////////////////////////////////////////////////////////////////////////////
272 // TCP listeners
273 ////////////////////////////////////////////////////////////////////////////////
274
275 pub struct TcpListener {
276     inner: Socket,
277 }
278
279 impl TcpListener {
280     pub fn bind(addr: &SocketAddr) -> io::Result<TcpListener> {
281         init();
282
283         let sock = try!(Socket::new(addr, libc::SOCK_STREAM));
284
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.
288         if !cfg!(windows) {
289             try!(setsockopt(&sock, libc::SOL_SOCKET, libc::SO_REUSEADDR,
290                             1 as c_int));
291         }
292
293         // Bind our new socket
294         let (addrp, len) = addr.into_inner();
295         try!(cvt(unsafe { libc::bind(*sock.as_inner(), addrp, len) }));
296
297         // Start listening
298         try!(cvt(unsafe { libc::listen(*sock.as_inner(), 128) }));
299         Ok(TcpListener { inner: sock })
300     }
301
302     pub fn socket(&self) -> &Socket { &self.inner }
303
304     pub fn socket_addr(&self) -> io::Result<SocketAddr> {
305         sockname(|buf, len| unsafe {
306             libc::getsockname(*self.inner.as_inner(), buf, len)
307         })
308     }
309
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 _,
314                                           &mut len));
315         let addr = try!(sockaddr_to_addr(&storage, len as usize));
316         Ok((TcpStream { inner: sock, }, addr))
317     }
318
319     pub fn duplicate(&self) -> io::Result<TcpListener> {
320         self.inner.duplicate().map(|s| TcpListener { inner: s })
321     }
322 }
323
324 impl FromInner<Socket> for TcpListener {
325     fn from_inner(socket: Socket) -> TcpListener {
326         TcpListener { inner: socket }
327     }
328 }
329
330 ////////////////////////////////////////////////////////////////////////////////
331 // UDP
332 ////////////////////////////////////////////////////////////////////////////////
333
334 pub struct UdpSocket {
335     inner: Socket,
336 }
337
338 impl UdpSocket {
339     pub fn bind(addr: &SocketAddr) -> io::Result<UdpSocket> {
340         init();
341
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 })
346     }
347
348     pub fn socket(&self) -> &Socket { &self.inner }
349
350     pub fn socket_addr(&self) -> io::Result<SocketAddr> {
351         sockname(|buf, len| unsafe {
352             libc::getsockname(*self.inner.as_inner(), buf, len)
353         })
354     }
355
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;
359
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)
365         }));
366         Ok((n as usize, try!(sockaddr_to_addr(&storage, addrlen as usize))))
367     }
368
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,
374                          0, dstp, dstlen)
375         }));
376         Ok(ret as usize)
377     }
378
379     pub fn set_broadcast(&self, on: bool) -> io::Result<()> {
380         setsockopt(&self.inner, libc::SOL_SOCKET, libc::SO_BROADCAST,
381                    on as c_int)
382     }
383
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)
387     }
388
389     pub fn join_multicast(&self, multi: &IpAddr) -> io::Result<()> {
390         match *multi {
391             IpAddr::V4(..) => {
392                 self.set_membership(multi, libc::IP_ADD_MEMBERSHIP)
393             }
394             IpAddr::V6(..) => {
395                 self.set_membership(multi, libc::IPV6_ADD_MEMBERSHIP)
396             }
397         }
398     }
399     pub fn leave_multicast(&self, multi: &IpAddr) -> io::Result<()> {
400         match *multi {
401             IpAddr::V4(..) => {
402                 self.set_membership(multi, libc::IP_DROP_MEMBERSHIP)
403             }
404             IpAddr::V6(..) => {
405                 self.set_membership(multi, libc::IPV6_DROP_MEMBERSHIP)
406             }
407         }
408     }
409     fn set_membership(&self, addr: &IpAddr, opt: c_int) -> io::Result<()> {
410         match *addr {
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 },
416                 };
417                 setsockopt(&self.inner, libc::IPPROTO_IP, opt, mreq)
418             }
419             IpAddr::V6(ref addr) => {
420                 let mreq = libc::ip6_mreq {
421                     ipv6mr_multiaddr: *addr.as_inner(),
422                     ipv6mr_interface: 0,
423                 };
424                 setsockopt(&self.inner, libc::IPPROTO_IPV6, opt, mreq)
425             }
426         }
427     }
428
429     pub fn multicast_time_to_live(&self, ttl: i32) -> io::Result<()> {
430         setsockopt(&self.inner, libc::IPPROTO_IP, libc::IP_MULTICAST_TTL,
431                    ttl as c_int)
432     }
433
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)
436     }
437
438     pub fn duplicate(&self) -> io::Result<UdpSocket> {
439         self.inner.duplicate().map(|s| UdpSocket { inner: s })
440     }
441 }
442
443 impl FromInner<Socket> for UdpSocket {
444     fn from_inner(socket: Socket) -> UdpSocket {
445         UdpSocket { inner: socket }
446     }
447 }