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}
;
15 use io
::{self, Error, ErrorKind}
;
16 use libc
::{self, c_int, c_char, c_void, socklen_t}
;
18 use net
::{SocketAddr, Shutdown, IpAddr}
;
21 use sys
::net
::{cvt, cvt_r, cvt_gai, Socket, init, wrlen_t}
;
22 use sys_common
::{AsInner, FromInner, IntoInner}
;
25 ////////////////////////////////////////////////////////////////////////////////
26 // sockaddr and misc bindings
27 ////////////////////////////////////////////////////////////////////////////////
29 pub fn setsockopt
<T
>(sock
: &Socket
, opt
: c_int
, val
: c_int
,
30 payload
: T
) -> io
::Result
<()> {
32 let payload
= &payload
as *const T
as *const c_void
;
33 try
!(cvt(libc
::setsockopt(*sock
.as_inner(), opt
, val
, payload
,
34 mem
::size_of
::<T
>() as socklen_t
)));
39 pub fn getsockopt
<T
: Copy
>(sock
: &Socket
, opt
: c_int
,
40 val
: c_int
) -> io
::Result
<T
> {
42 let mut slot
: T
= mem
::zeroed();
43 let mut len
= mem
::size_of
::<T
>() as socklen_t
;
44 try
!(cvt(c
::getsockopt(*sock
.as_inner(), opt
, val
,
45 &mut slot
as *mut _
as *mut _
,
47 assert_eq
!(len
as usize, mem
::size_of
::<T
>());
52 fn sockname
<F
>(f
: F
) -> io
::Result
<SocketAddr
>
53 where F
: FnOnce(*mut libc
::sockaddr
, *mut socklen_t
) -> c_int
56 let mut storage
: libc
::sockaddr_storage
= mem
::zeroed();
57 let mut len
= mem
::size_of_val(&storage
) as socklen_t
;
58 try
!(cvt(f(&mut storage
as *mut _
as *mut _
, &mut len
)));
59 sockaddr_to_addr(&storage
, len
as usize)
63 fn sockaddr_to_addr(storage
: &libc
::sockaddr_storage
,
64 len
: usize) -> io
::Result
<SocketAddr
> {
65 match storage
.ss_family
as libc
::c_int
{
67 assert
!(len
as usize >= mem
::size_of
::<libc
::sockaddr_in
>());
68 Ok(SocketAddr
::V4(FromInner
::from_inner(unsafe {
69 *(storage
as *const _
as *const libc
::sockaddr_in
)
73 assert
!(len
as usize >= mem
::size_of
::<libc
::sockaddr_in6
>());
74 Ok(SocketAddr
::V6(FromInner
::from_inner(unsafe {
75 *(storage
as *const _
as *const libc
::sockaddr_in6
)
79 Err(Error
::new(ErrorKind
::InvalidInput
, "invalid argument"))
84 ////////////////////////////////////////////////////////////////////////////////
86 ////////////////////////////////////////////////////////////////////////////////
89 fn getaddrinfo(node
: *const c_char
, service
: *const c_char
,
90 hints
: *const libc
::addrinfo
,
91 res
: *mut *mut libc
::addrinfo
) -> c_int
;
92 fn freeaddrinfo(res
: *mut libc
::addrinfo
);
95 pub struct LookupHost
{
96 original
: *mut libc
::addrinfo
,
97 cur
: *mut libc
::addrinfo
,
100 impl Iterator
for LookupHost
{
101 type Item
= io
::Result
<SocketAddr
>;
102 fn next(&mut self) -> Option
<io
::Result
<SocketAddr
>> {
104 if self.cur
.is_null() { return None }
105 let ret
= sockaddr_to_addr(mem
::transmute((*self.cur
).ai_addr
),
106 (*self.cur
).ai_addrlen
as usize);
107 self.cur
= (*self.cur
).ai_next
as *mut libc
::addrinfo
;
113 impl Drop
for LookupHost
{
115 unsafe { freeaddrinfo(self.original) }
119 pub fn lookup_host(host
: &str) -> io
::Result
<LookupHost
> {
122 let c_host
= try
!(CString
::new(host
));
123 let mut res
= 0 as *mut _
;
125 try
!(cvt_gai(getaddrinfo(c_host
.as_ptr(), 0 as *const _
, 0 as *const _
,
127 Ok(LookupHost { original: res, cur: res }
)
131 ////////////////////////////////////////////////////////////////////////////////
133 ////////////////////////////////////////////////////////////////////////////////
136 fn getnameinfo(sa
: *const libc
::sockaddr
, salen
: socklen_t
,
137 host
: *mut c_char
, hostlen
: libc
::size_t
,
138 serv
: *mut c_char
, servlen
: libc
::size_t
,
139 flags
: c_int
) -> c_int
;
142 const NI_MAXHOST
: usize = 1025;
144 pub fn lookup_addr(addr
: &IpAddr
) -> io
::Result
<String
> {
147 let saddr
= SocketAddr
::new(*addr
, 0);
148 let (inner
, len
) = saddr
.into_inner();
149 let mut hostbuf
= [0 as c_char
; NI_MAXHOST
];
152 try
!(cvt_gai(getnameinfo(inner
, len
,
153 hostbuf
.as_mut_ptr(), NI_MAXHOST
as libc
::size_t
,
154 0 as *mut _
, 0, 0)));
156 CStr
::from_ptr(hostbuf
.as_ptr())
159 match from_utf8(data
.to_bytes()) {
160 Ok(name
) => Ok(name
.to_string()),
161 Err(_
) => Err(io
::Error
::new(io
::ErrorKind
::Other
,
162 "failed to lookup address information"))
166 ////////////////////////////////////////////////////////////////////////////////
168 ////////////////////////////////////////////////////////////////////////////////
170 pub struct TcpStream
{
175 pub fn connect(addr
: &SocketAddr
) -> io
::Result
<TcpStream
> {
178 let sock
= try
!(Socket
::new(addr
, libc
::SOCK_STREAM
));
180 let (addrp
, len
) = addr
.into_inner();
181 try
!(cvt_r(|| unsafe { libc::connect(*sock.as_inner(), addrp, len) }
));
182 Ok(TcpStream { inner: sock }
)
185 pub fn socket(&self) -> &Socket { &self.inner }
187 pub fn set_nodelay(&self, nodelay
: bool
) -> io
::Result
<()> {
188 setsockopt(&self.inner
, libc
::IPPROTO_TCP
, libc
::TCP_NODELAY
,
192 pub fn set_keepalive(&self, seconds
: Option
<u32>) -> io
::Result
<()> {
193 let ret
= setsockopt(&self.inner
, libc
::SOL_SOCKET
, libc
::SO_KEEPALIVE
,
194 seconds
.is_some() as c_int
);
196 Some(n
) => ret
.and_then(|()| self.set_tcp_keepalive(n
)),
201 #[cfg(any(target_os = "macos", target_os = "ios"))]
202 fn set_tcp_keepalive(&self, seconds
: u32) -> io
::Result
<()> {
203 setsockopt(&self.inner
, libc
::IPPROTO_TCP
, libc
::TCP_KEEPALIVE
,
206 #[cfg(any(target_os = "freebsd",
207 target_os
= "dragonfly",
208 target_os
= "linux"))]
209 fn set_tcp_keepalive(&self, seconds
: u32) -> io
::Result
<()> {
210 setsockopt(&self.inner
, libc
::IPPROTO_TCP
, libc
::TCP_KEEPIDLE
,
214 #[cfg(not(any(target_os = "macos",
216 target_os
= "freebsd",
217 target_os
= "dragonfly",
218 target_os
= "linux")))]
219 fn set_tcp_keepalive(&self, _seconds
: u32) -> io
::Result
<()> {
223 pub fn set_read_timeout(&self, dur
: Option
<Duration
>) -> io
::Result
<()> {
224 self.inner
.set_timeout(dur
, libc
::SO_RCVTIMEO
)
227 pub fn set_write_timeout(&self, dur
: Option
<Duration
>) -> io
::Result
<()> {
228 self.inner
.set_timeout(dur
, libc
::SO_SNDTIMEO
)
231 pub fn read_timeout(&self) -> io
::Result
<Option
<Duration
>> {
232 self.inner
.timeout(libc
::SO_RCVTIMEO
)
235 pub fn write_timeout(&self) -> io
::Result
<Option
<Duration
>> {
236 self.inner
.timeout(libc
::SO_SNDTIMEO
)
239 pub fn read(&self, buf
: &mut [u8]) -> io
::Result
<usize> {
243 pub fn write(&self, buf
: &[u8]) -> io
::Result
<usize> {
244 let ret
= try
!(cvt(unsafe {
245 libc
::send(*self.inner
.as_inner(),
246 buf
.as_ptr() as *const c_void
,
247 buf
.len() as wrlen_t
,
253 pub fn peer_addr(&self) -> io
::Result
<SocketAddr
> {
254 sockname(|buf
, len
| unsafe {
255 libc
::getpeername(*self.inner
.as_inner(), buf
, len
)
259 pub fn socket_addr(&self) -> io
::Result
<SocketAddr
> {
260 sockname(|buf
, len
| unsafe {
261 libc
::getsockname(*self.inner
.as_inner(), buf
, len
)
265 pub fn shutdown(&self, how
: Shutdown
) -> io
::Result
<()> {
266 use libc
::consts
::os
::bsd44
::SHUT_RDWR
;
268 let how
= match how
{
269 Shutdown
::Write
=> libc
::SHUT_WR
,
270 Shutdown
::Read
=> libc
::SHUT_RD
,
271 Shutdown
::Both
=> SHUT_RDWR
,
273 try
!(cvt(unsafe { libc::shutdown(*self.inner.as_inner(), how) }
));
277 pub fn duplicate(&self) -> io
::Result
<TcpStream
> {
278 self.inner
.duplicate().map(|s
| TcpStream { inner: s }
)
282 impl FromInner
<Socket
> for TcpStream
{
283 fn from_inner(socket
: Socket
) -> TcpStream
{
284 TcpStream { inner: socket }
288 impl fmt
::Debug
for TcpStream
{
289 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
290 let mut res
= f
.debug_struct("TcpStream");
292 if let Ok(addr
) = self.socket_addr() {
293 res
.field("addr", &addr
);
296 if let Ok(peer
) = self.peer_addr() {
297 res
.field("peer", &peer
);
300 let name
= if cfg
!(windows
) {"socket"}
else {"fd"}
;
301 res
.field(name
, &self.inner
.as_inner())
306 ////////////////////////////////////////////////////////////////////////////////
308 ////////////////////////////////////////////////////////////////////////////////
310 pub struct TcpListener
{
315 pub fn bind(addr
: &SocketAddr
) -> io
::Result
<TcpListener
> {
318 let sock
= try
!(Socket
::new(addr
, libc
::SOCK_STREAM
));
320 // On platforms with Berkeley-derived sockets, this allows
321 // to quickly rebind a socket, without needing to wait for
322 // the OS to clean up the previous one.
324 try
!(setsockopt(&sock
, libc
::SOL_SOCKET
, libc
::SO_REUSEADDR
,
328 // Bind our new socket
329 let (addrp
, len
) = addr
.into_inner();
330 try
!(cvt(unsafe { libc::bind(*sock.as_inner(), addrp, len) }
));
333 try
!(cvt(unsafe { libc::listen(*sock.as_inner(), 128) }
));
334 Ok(TcpListener { inner: sock }
)
337 pub fn socket(&self) -> &Socket { &self.inner }
339 pub fn socket_addr(&self) -> io
::Result
<SocketAddr
> {
340 sockname(|buf
, len
| unsafe {
341 libc
::getsockname(*self.inner
.as_inner(), buf
, len
)
345 pub fn accept(&self) -> io
::Result
<(TcpStream
, SocketAddr
)> {
346 let mut storage
: libc
::sockaddr_storage
= unsafe { mem::zeroed() }
;
347 let mut len
= mem
::size_of_val(&storage
) as socklen_t
;
348 let sock
= try
!(self.inner
.accept(&mut storage
as *mut _
as *mut _
,
350 let addr
= try
!(sockaddr_to_addr(&storage
, len
as usize));
351 Ok((TcpStream { inner: sock, }
, addr
))
354 pub fn duplicate(&self) -> io
::Result
<TcpListener
> {
355 self.inner
.duplicate().map(|s
| TcpListener { inner: s }
)
359 impl FromInner
<Socket
> for TcpListener
{
360 fn from_inner(socket
: Socket
) -> TcpListener
{
361 TcpListener { inner: socket }
365 impl fmt
::Debug
for TcpListener
{
366 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
367 let mut res
= f
.debug_struct("TcpListener");
369 if let Ok(addr
) = self.socket_addr() {
370 res
.field("addr", &addr
);
373 let name
= if cfg
!(windows
) {"socket"}
else {"fd"}
;
374 res
.field(name
, &self.inner
.as_inner())
379 ////////////////////////////////////////////////////////////////////////////////
381 ////////////////////////////////////////////////////////////////////////////////
383 pub struct UdpSocket
{
388 pub fn bind(addr
: &SocketAddr
) -> io
::Result
<UdpSocket
> {
391 let sock
= try
!(Socket
::new(addr
, libc
::SOCK_DGRAM
));
392 let (addrp
, len
) = addr
.into_inner();
393 try
!(cvt(unsafe { libc::bind(*sock.as_inner(), addrp, len) }
));
394 Ok(UdpSocket { inner: sock }
)
397 pub fn socket(&self) -> &Socket { &self.inner }
399 pub fn socket_addr(&self) -> io
::Result
<SocketAddr
> {
400 sockname(|buf
, len
| unsafe {
401 libc
::getsockname(*self.inner
.as_inner(), buf
, len
)
405 pub fn recv_from(&self, buf
: &mut [u8]) -> io
::Result
<(usize, SocketAddr
)> {
406 let mut storage
: libc
::sockaddr_storage
= unsafe { mem::zeroed() }
;
407 let mut addrlen
= mem
::size_of_val(&storage
) as socklen_t
;
409 let n
= try
!(cvt(unsafe {
410 libc
::recvfrom(*self.inner
.as_inner(),
411 buf
.as_mut_ptr() as *mut c_void
,
412 buf
.len() as wrlen_t
, 0,
413 &mut storage
as *mut _
as *mut _
, &mut addrlen
)
415 Ok((n
as usize, try
!(sockaddr_to_addr(&storage
, addrlen
as usize))))
418 pub fn send_to(&self, buf
: &[u8], dst
: &SocketAddr
) -> io
::Result
<usize> {
419 let (dstp
, dstlen
) = dst
.into_inner();
420 let ret
= try
!(cvt(unsafe {
421 libc
::sendto(*self.inner
.as_inner(),
422 buf
.as_ptr() as *const c_void
, buf
.len() as wrlen_t
,
428 pub fn set_broadcast(&self, on
: bool
) -> io
::Result
<()> {
429 setsockopt(&self.inner
, libc
::SOL_SOCKET
, libc
::SO_BROADCAST
,
433 pub fn set_multicast_loop(&self, on
: bool
) -> io
::Result
<()> {
434 setsockopt(&self.inner
, libc
::IPPROTO_IP
,
435 libc
::IP_MULTICAST_LOOP
, on
as c_int
)
438 pub fn join_multicast(&self, multi
: &IpAddr
) -> io
::Result
<()> {
441 self.set_membership(multi
, libc
::IP_ADD_MEMBERSHIP
)
444 self.set_membership(multi
, libc
::IPV6_ADD_MEMBERSHIP
)
448 pub fn leave_multicast(&self, multi
: &IpAddr
) -> io
::Result
<()> {
451 self.set_membership(multi
, libc
::IP_DROP_MEMBERSHIP
)
454 self.set_membership(multi
, libc
::IPV6_DROP_MEMBERSHIP
)
458 fn set_membership(&self, addr
: &IpAddr
, opt
: c_int
) -> io
::Result
<()> {
460 IpAddr
::V4(ref addr
) => {
461 let mreq
= libc
::ip_mreq
{
462 imr_multiaddr
: *addr
.as_inner(),
463 // interface == INADDR_ANY
464 imr_interface
: libc
::in_addr { s_addr: 0x0 }
,
466 setsockopt(&self.inner
, libc
::IPPROTO_IP
, opt
, mreq
)
468 IpAddr
::V6(ref addr
) => {
469 let mreq
= libc
::ip6_mreq
{
470 ipv6mr_multiaddr
: *addr
.as_inner(),
473 setsockopt(&self.inner
, libc
::IPPROTO_IPV6
, opt
, mreq
)
478 pub fn multicast_time_to_live(&self, ttl
: i32) -> io
::Result
<()> {
479 setsockopt(&self.inner
, libc
::IPPROTO_IP
, libc
::IP_MULTICAST_TTL
,
483 pub fn time_to_live(&self, ttl
: i32) -> io
::Result
<()> {
484 setsockopt(&self.inner
, libc
::IPPROTO_IP
, libc
::IP_TTL
, ttl
as c_int
)
487 pub fn duplicate(&self) -> io
::Result
<UdpSocket
> {
488 self.inner
.duplicate().map(|s
| UdpSocket { inner: s }
)
491 pub fn set_read_timeout(&self, dur
: Option
<Duration
>) -> io
::Result
<()> {
492 self.inner
.set_timeout(dur
, libc
::SO_RCVTIMEO
)
495 pub fn set_write_timeout(&self, dur
: Option
<Duration
>) -> io
::Result
<()> {
496 self.inner
.set_timeout(dur
, libc
::SO_SNDTIMEO
)
499 pub fn read_timeout(&self) -> io
::Result
<Option
<Duration
>> {
500 self.inner
.timeout(libc
::SO_RCVTIMEO
)
503 pub fn write_timeout(&self) -> io
::Result
<Option
<Duration
>> {
504 self.inner
.timeout(libc
::SO_SNDTIMEO
)
508 impl FromInner
<Socket
> for UdpSocket
{
509 fn from_inner(socket
: Socket
) -> UdpSocket
{
510 UdpSocket { inner: socket }
514 impl fmt
::Debug
for UdpSocket
{
515 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
516 let mut res
= f
.debug_struct("UdpSocket");
518 if let Ok(addr
) = self.socket_addr() {
519 res
.field("addr", &addr
);
522 let name
= if cfg
!(windows
) {"socket"}
else {"fd"}
;
523 res
.field(name
, &self.inner
.as_inner())