1 | #[cfg (test)] |
2 | mod tests; |
3 | |
4 | use crate::cmp; |
5 | use crate::fmt; |
6 | use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut}; |
7 | use crate::mem; |
8 | use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; |
9 | use crate::ptr; |
10 | use crate::sys::common::small_c_string::run_with_cstr; |
11 | use crate::sys::net::netc as c; |
12 | use crate::sys::net::{cvt, cvt_gai, cvt_r, init, wrlen_t, Socket}; |
13 | use crate::sys_common::{AsInner, FromInner, IntoInner}; |
14 | use crate::time::Duration; |
15 | |
16 | use crate::ffi::{c_int, c_void}; |
17 | |
18 | cfg_if::cfg_if! { |
19 | if #[cfg(any( |
20 | target_os = "dragonfly" , target_os = "freebsd" , |
21 | target_os = "ios" , target_os = "tvos" , target_os = "macos" , target_os = "watchos" , |
22 | target_os = "openbsd" , target_os = "netbsd" , target_os = "illumos" , |
23 | target_os = "solaris" , target_os = "haiku" , target_os = "l4re" , target_os = "nto" ))] { |
24 | use crate::sys::net::netc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP; |
25 | use crate::sys::net::netc::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP; |
26 | } else { |
27 | use crate::sys::net::netc::IPV6_ADD_MEMBERSHIP; |
28 | use crate::sys::net::netc::IPV6_DROP_MEMBERSHIP; |
29 | } |
30 | } |
31 | |
32 | cfg_if::cfg_if! { |
33 | if #[cfg(any( |
34 | target_os = "linux" , target_os = "android" , |
35 | target_os = "hurd" , |
36 | target_os = "dragonfly" , target_os = "freebsd" , |
37 | target_os = "openbsd" , target_os = "netbsd" , |
38 | target_os = "haiku" , target_os = "nto" ))] { |
39 | use libc::MSG_NOSIGNAL; |
40 | } else { |
41 | const MSG_NOSIGNAL: c_int = 0x0; |
42 | } |
43 | } |
44 | |
45 | cfg_if::cfg_if! { |
46 | if #[cfg(any( |
47 | target_os = "dragonfly" , target_os = "freebsd" , |
48 | target_os = "openbsd" , target_os = "netbsd" , |
49 | target_os = "solaris" , target_os = "illumos" , |
50 | target_os = "nto" ))] { |
51 | use crate::ffi::c_uchar; |
52 | type IpV4MultiCastType = c_uchar; |
53 | } else { |
54 | type IpV4MultiCastType = c_int; |
55 | } |
56 | } |
57 | |
58 | //////////////////////////////////////////////////////////////////////////////// |
59 | // sockaddr and misc bindings |
60 | //////////////////////////////////////////////////////////////////////////////// |
61 | |
62 | pub fn setsockopt<T>( |
63 | sock: &Socket, |
64 | level: c_int, |
65 | option_name: c_int, |
66 | option_value: T, |
67 | ) -> io::Result<()> { |
68 | unsafe { |
69 | cvt(c::setsockopt( |
70 | sock.as_raw(), |
71 | level, |
72 | option_name, |
73 | &option_value as *const T as *const _, |
74 | mem::size_of::<T>() as c::socklen_t, |
75 | ))?; |
76 | Ok(()) |
77 | } |
78 | } |
79 | |
80 | pub fn getsockopt<T: Copy>(sock: &Socket, level: c_int, option_name: c_int) -> io::Result<T> { |
81 | unsafe { |
82 | let mut option_value: T = mem::zeroed(); |
83 | let mut option_len: usize = mem::size_of::<T>() as c::socklen_t; |
84 | cvt(c::getsockopt( |
85 | sock.as_raw(), |
86 | level, |
87 | option_name, |
88 | &mut option_value as *mut T as *mut _, |
89 | &mut option_len, |
90 | ))?; |
91 | Ok(option_value) |
92 | } |
93 | } |
94 | |
95 | fn sockname<F>(f: F) -> io::Result<SocketAddr> |
96 | where |
97 | F: FnOnce(*mut c::sockaddr, *mut c::socklen_t) -> c_int, |
98 | { |
99 | unsafe { |
100 | let mut storage: c::sockaddr_storage = mem::zeroed(); |
101 | let mut len: usize = mem::size_of_val(&storage) as c::socklen_t; |
102 | cvt(f(&mut storage as *mut _ as *mut _, &mut len))?; |
103 | sockaddr_to_addr(&storage, len as usize) |
104 | } |
105 | } |
106 | |
107 | pub fn sockaddr_to_addr(storage: &c::sockaddr_storage, len: usize) -> io::Result<SocketAddr> { |
108 | match storage.ss_family as c_int { |
109 | c::AF_INET => { |
110 | assert!(len as usize >= mem::size_of::<c::sockaddr_in>()); |
111 | Ok(SocketAddr::V4(FromInner::from_inner(unsafe { |
112 | *(storage as *const _ as *const c::sockaddr_in) |
113 | }))) |
114 | } |
115 | c::AF_INET6 => { |
116 | assert!(len as usize >= mem::size_of::<c::sockaddr_in6>()); |
117 | Ok(SocketAddr::V6(FromInner::from_inner(unsafe { |
118 | *(storage as *const _ as *const c::sockaddr_in6) |
119 | }))) |
120 | } |
121 | _ => Err(io::const_io_error!(ErrorKind::InvalidInput, "invalid argument" )), |
122 | } |
123 | } |
124 | |
125 | #[cfg (target_os = "android" )] |
126 | fn to_ipv6mr_interface(value: u32) -> c_int { |
127 | value as c_int |
128 | } |
129 | |
130 | #[cfg (not(target_os = "android" ))] |
131 | fn to_ipv6mr_interface(value: u32) -> crate::ffi::c_uint { |
132 | value as crate::ffi::c_uint |
133 | } |
134 | |
135 | //////////////////////////////////////////////////////////////////////////////// |
136 | // get_host_addresses |
137 | //////////////////////////////////////////////////////////////////////////////// |
138 | |
139 | pub struct LookupHost { |
140 | original: *mut c::addrinfo, |
141 | cur: *mut c::addrinfo, |
142 | port: u16, |
143 | } |
144 | |
145 | impl LookupHost { |
146 | pub fn port(&self) -> u16 { |
147 | self.port |
148 | } |
149 | } |
150 | |
151 | impl Iterator for LookupHost { |
152 | type Item = SocketAddr; |
153 | fn next(&mut self) -> Option<SocketAddr> { |
154 | loop { |
155 | unsafe { |
156 | let cur: &{unknown} = self.cur.as_ref()?; |
157 | self.cur = cur.ai_next; |
158 | match sockaddr_to_addr(storage:mem::transmute(cur.ai_addr), len:cur.ai_addrlen as usize) { |
159 | Ok(addr: SocketAddr) => return Some(addr), |
160 | Err(_) => continue, |
161 | } |
162 | } |
163 | } |
164 | } |
165 | } |
166 | |
167 | unsafe impl Sync for LookupHost {} |
168 | unsafe impl Send for LookupHost {} |
169 | |
170 | impl Drop for LookupHost { |
171 | fn drop(&mut self) { |
172 | unsafe { c::freeaddrinfo(self.original) } |
173 | } |
174 | } |
175 | |
176 | impl TryFrom<&str> for LookupHost { |
177 | type Error = io::Error; |
178 | |
179 | fn try_from(s: &str) -> io::Result<LookupHost> { |
180 | macro_rules! try_opt { |
181 | ($e:expr, $msg:expr) => { |
182 | match $e { |
183 | Some(r) => r, |
184 | None => return Err(io::const_io_error!(io::ErrorKind::InvalidInput, $msg)), |
185 | } |
186 | }; |
187 | } |
188 | |
189 | // split the string by ':' and convert the second part to u16 |
190 | let (host: &str, port_str: &str) = try_opt!(s.rsplit_once(':' ), "invalid socket address" ); |
191 | let port: u16 = try_opt!(port_str.parse().ok(), "invalid port value" ); |
192 | (host, port).try_into() |
193 | } |
194 | } |
195 | |
196 | impl<'a> TryFrom<(&'a str, u16)> for LookupHost { |
197 | type Error = io::Error; |
198 | |
199 | fn try_from((host: &str, port: u16): (&'a str, u16)) -> io::Result<LookupHost> { |
200 | init(); |
201 | |
202 | run_with_cstr(host.as_bytes(), |c_host: &CStr| { |
203 | let mut hints: c::addrinfo = unsafe { mem::zeroed() }; |
204 | hints.ai_socktype = c::SOCK_STREAM; |
205 | let mut res: *mut {unknown} = ptr::null_mut(); |
206 | unsafe { |
207 | cvt_gai(c::getaddrinfo(c_host.as_ptr(), ptr::null(), &hints, &mut res)) |
208 | .map(|_| LookupHost { original: res, cur: res, port }) |
209 | } |
210 | }) |
211 | } |
212 | } |
213 | |
214 | //////////////////////////////////////////////////////////////////////////////// |
215 | // TCP streams |
216 | //////////////////////////////////////////////////////////////////////////////// |
217 | |
218 | pub struct TcpStream { |
219 | inner: Socket, |
220 | } |
221 | |
222 | impl TcpStream { |
223 | pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> { |
224 | let addr = addr?; |
225 | |
226 | init(); |
227 | |
228 | let sock = Socket::new(addr, c::SOCK_STREAM)?; |
229 | sock.connect(addr)?; |
230 | Ok(TcpStream { inner: sock }) |
231 | } |
232 | |
233 | pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result<TcpStream> { |
234 | init(); |
235 | |
236 | let sock = Socket::new(addr, c::SOCK_STREAM)?; |
237 | sock.connect_timeout(addr, timeout)?; |
238 | Ok(TcpStream { inner: sock }) |
239 | } |
240 | |
241 | #[inline ] |
242 | pub fn socket(&self) -> &Socket { |
243 | &self.inner |
244 | } |
245 | |
246 | pub fn into_socket(self) -> Socket { |
247 | self.inner |
248 | } |
249 | |
250 | pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> { |
251 | self.inner.set_timeout(dur, c::SO_RCVTIMEO) |
252 | } |
253 | |
254 | pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> { |
255 | self.inner.set_timeout(dur, c::SO_SNDTIMEO) |
256 | } |
257 | |
258 | pub fn read_timeout(&self) -> io::Result<Option<Duration>> { |
259 | self.inner.timeout(c::SO_RCVTIMEO) |
260 | } |
261 | |
262 | pub fn write_timeout(&self) -> io::Result<Option<Duration>> { |
263 | self.inner.timeout(c::SO_SNDTIMEO) |
264 | } |
265 | |
266 | pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> { |
267 | self.inner.peek(buf) |
268 | } |
269 | |
270 | pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { |
271 | self.inner.read(buf) |
272 | } |
273 | |
274 | pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> { |
275 | self.inner.read_buf(buf) |
276 | } |
277 | |
278 | pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { |
279 | self.inner.read_vectored(bufs) |
280 | } |
281 | |
282 | #[inline ] |
283 | pub fn is_read_vectored(&self) -> bool { |
284 | self.inner.is_read_vectored() |
285 | } |
286 | |
287 | pub fn write(&self, buf: &[u8]) -> io::Result<usize> { |
288 | let len = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t; |
289 | let ret = cvt(unsafe { |
290 | c::send(self.inner.as_raw(), buf.as_ptr() as *const c_void, len, MSG_NOSIGNAL) |
291 | })?; |
292 | Ok(ret as usize) |
293 | } |
294 | |
295 | pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { |
296 | self.inner.write_vectored(bufs) |
297 | } |
298 | |
299 | #[inline ] |
300 | pub fn is_write_vectored(&self) -> bool { |
301 | self.inner.is_write_vectored() |
302 | } |
303 | |
304 | pub fn peer_addr(&self) -> io::Result<SocketAddr> { |
305 | sockname(|buf, len| unsafe { c::getpeername(self.inner.as_raw(), buf, len) }) |
306 | } |
307 | |
308 | pub fn socket_addr(&self) -> io::Result<SocketAddr> { |
309 | sockname(|buf, len| unsafe { c::getsockname(self.inner.as_raw(), buf, len) }) |
310 | } |
311 | |
312 | pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { |
313 | self.inner.shutdown(how) |
314 | } |
315 | |
316 | pub fn duplicate(&self) -> io::Result<TcpStream> { |
317 | self.inner.duplicate().map(|s| TcpStream { inner: s }) |
318 | } |
319 | |
320 | pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> { |
321 | self.inner.set_linger(linger) |
322 | } |
323 | |
324 | pub fn linger(&self) -> io::Result<Option<Duration>> { |
325 | self.inner.linger() |
326 | } |
327 | |
328 | pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { |
329 | self.inner.set_nodelay(nodelay) |
330 | } |
331 | |
332 | pub fn nodelay(&self) -> io::Result<bool> { |
333 | self.inner.nodelay() |
334 | } |
335 | |
336 | pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { |
337 | setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int) |
338 | } |
339 | |
340 | pub fn ttl(&self) -> io::Result<u32> { |
341 | let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)?; |
342 | Ok(raw as u32) |
343 | } |
344 | |
345 | pub fn take_error(&self) -> io::Result<Option<io::Error>> { |
346 | self.inner.take_error() |
347 | } |
348 | |
349 | pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { |
350 | self.inner.set_nonblocking(nonblocking) |
351 | } |
352 | } |
353 | |
354 | impl AsInner<Socket> for TcpStream { |
355 | #[inline ] |
356 | fn as_inner(&self) -> &Socket { |
357 | &self.inner |
358 | } |
359 | } |
360 | |
361 | impl FromInner<Socket> for TcpStream { |
362 | fn from_inner(socket: Socket) -> TcpStream { |
363 | TcpStream { inner: socket } |
364 | } |
365 | } |
366 | |
367 | impl fmt::Debug for TcpStream { |
368 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
369 | let mut res: DebugStruct<'_, '_> = f.debug_struct(name:"TcpStream" ); |
370 | |
371 | if let Ok(addr: SocketAddr) = self.socket_addr() { |
372 | res.field(name:"addr" , &addr); |
373 | } |
374 | |
375 | if let Ok(peer: SocketAddr) = self.peer_addr() { |
376 | res.field(name:"peer" , &peer); |
377 | } |
378 | |
379 | let name: &str = if cfg!(windows) { "socket" } else { "fd" }; |
380 | res.field(name, &self.inner.as_raw()).finish() |
381 | } |
382 | } |
383 | |
384 | //////////////////////////////////////////////////////////////////////////////// |
385 | // TCP listeners |
386 | //////////////////////////////////////////////////////////////////////////////// |
387 | |
388 | pub struct TcpListener { |
389 | inner: Socket, |
390 | } |
391 | |
392 | impl TcpListener { |
393 | pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<TcpListener> { |
394 | let addr = addr?; |
395 | |
396 | init(); |
397 | |
398 | let sock = Socket::new(addr, c::SOCK_STREAM)?; |
399 | |
400 | // On platforms with Berkeley-derived sockets, this allows to quickly |
401 | // rebind a socket, without needing to wait for the OS to clean up the |
402 | // previous one. |
403 | // |
404 | // On Windows, this allows rebinding sockets which are actively in use, |
405 | // which allows “socket hijacking”, so we explicitly don't set it here. |
406 | // https://docs.microsoft.com/en-us/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse |
407 | #[cfg (not(windows))] |
408 | setsockopt(&sock, c::SOL_SOCKET, c::SO_REUSEADDR, 1 as c_int)?; |
409 | |
410 | // Bind our new socket |
411 | let (addr, len) = addr.into_inner(); |
412 | cvt(unsafe { c::bind(sock.as_raw(), addr.as_ptr(), len as _) })?; |
413 | |
414 | cfg_if::cfg_if! { |
415 | if #[cfg(target_os = "horizon" )] { |
416 | // The 3DS doesn't support a big connection backlog. Sometimes |
417 | // it allows up to about 37, but other times it doesn't even |
418 | // accept 32. There may be a global limitation causing this. |
419 | let backlog = 20; |
420 | } else { |
421 | // The default for all other platforms |
422 | let backlog = 128; |
423 | } |
424 | } |
425 | |
426 | // Start listening |
427 | cvt(unsafe { c::listen(sock.as_raw(), backlog) })?; |
428 | Ok(TcpListener { inner: sock }) |
429 | } |
430 | |
431 | #[inline ] |
432 | pub fn socket(&self) -> &Socket { |
433 | &self.inner |
434 | } |
435 | |
436 | pub fn into_socket(self) -> Socket { |
437 | self.inner |
438 | } |
439 | |
440 | pub fn socket_addr(&self) -> io::Result<SocketAddr> { |
441 | sockname(|buf, len| unsafe { c::getsockname(self.inner.as_raw(), buf, len) }) |
442 | } |
443 | |
444 | pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { |
445 | let mut storage: c::sockaddr_storage = unsafe { mem::zeroed() }; |
446 | let mut len = mem::size_of_val(&storage) as c::socklen_t; |
447 | let sock = self.inner.accept(&mut storage as *mut _ as *mut _, &mut len)?; |
448 | let addr = sockaddr_to_addr(&storage, len as usize)?; |
449 | Ok((TcpStream { inner: sock }, addr)) |
450 | } |
451 | |
452 | pub fn duplicate(&self) -> io::Result<TcpListener> { |
453 | self.inner.duplicate().map(|s| TcpListener { inner: s }) |
454 | } |
455 | |
456 | pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { |
457 | setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int) |
458 | } |
459 | |
460 | pub fn ttl(&self) -> io::Result<u32> { |
461 | let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)?; |
462 | Ok(raw as u32) |
463 | } |
464 | |
465 | pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> { |
466 | setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_V6ONLY, only_v6 as c_int) |
467 | } |
468 | |
469 | pub fn only_v6(&self) -> io::Result<bool> { |
470 | let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_V6ONLY)?; |
471 | Ok(raw != 0) |
472 | } |
473 | |
474 | pub fn take_error(&self) -> io::Result<Option<io::Error>> { |
475 | self.inner.take_error() |
476 | } |
477 | |
478 | pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { |
479 | self.inner.set_nonblocking(nonblocking) |
480 | } |
481 | } |
482 | |
483 | impl FromInner<Socket> for TcpListener { |
484 | fn from_inner(socket: Socket) -> TcpListener { |
485 | TcpListener { inner: socket } |
486 | } |
487 | } |
488 | |
489 | impl fmt::Debug for TcpListener { |
490 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
491 | let mut res: DebugStruct<'_, '_> = f.debug_struct(name:"TcpListener" ); |
492 | |
493 | if let Ok(addr: SocketAddr) = self.socket_addr() { |
494 | res.field(name:"addr" , &addr); |
495 | } |
496 | |
497 | let name: &str = if cfg!(windows) { "socket" } else { "fd" }; |
498 | res.field(name, &self.inner.as_raw()).finish() |
499 | } |
500 | } |
501 | |
502 | //////////////////////////////////////////////////////////////////////////////// |
503 | // UDP |
504 | //////////////////////////////////////////////////////////////////////////////// |
505 | |
506 | pub struct UdpSocket { |
507 | inner: Socket, |
508 | } |
509 | |
510 | impl UdpSocket { |
511 | pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<UdpSocket> { |
512 | let addr = addr?; |
513 | |
514 | init(); |
515 | |
516 | let sock = Socket::new(addr, c::SOCK_DGRAM)?; |
517 | let (addr, len) = addr.into_inner(); |
518 | cvt(unsafe { c::bind(sock.as_raw(), addr.as_ptr(), len as _) })?; |
519 | Ok(UdpSocket { inner: sock }) |
520 | } |
521 | |
522 | #[inline ] |
523 | pub fn socket(&self) -> &Socket { |
524 | &self.inner |
525 | } |
526 | |
527 | pub fn into_socket(self) -> Socket { |
528 | self.inner |
529 | } |
530 | |
531 | pub fn peer_addr(&self) -> io::Result<SocketAddr> { |
532 | sockname(|buf, len| unsafe { c::getpeername(self.inner.as_raw(), buf, len) }) |
533 | } |
534 | |
535 | pub fn socket_addr(&self) -> io::Result<SocketAddr> { |
536 | sockname(|buf, len| unsafe { c::getsockname(self.inner.as_raw(), buf, len) }) |
537 | } |
538 | |
539 | pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { |
540 | self.inner.recv_from(buf) |
541 | } |
542 | |
543 | pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { |
544 | self.inner.peek_from(buf) |
545 | } |
546 | |
547 | pub fn send_to(&self, buf: &[u8], dst: &SocketAddr) -> io::Result<usize> { |
548 | let len = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t; |
549 | let (dst, dstlen) = dst.into_inner(); |
550 | let ret = cvt(unsafe { |
551 | c::sendto( |
552 | self.inner.as_raw(), |
553 | buf.as_ptr() as *const c_void, |
554 | len, |
555 | MSG_NOSIGNAL, |
556 | dst.as_ptr(), |
557 | dstlen, |
558 | ) |
559 | })?; |
560 | Ok(ret as usize) |
561 | } |
562 | |
563 | pub fn duplicate(&self) -> io::Result<UdpSocket> { |
564 | self.inner.duplicate().map(|s| UdpSocket { inner: s }) |
565 | } |
566 | |
567 | pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> { |
568 | self.inner.set_timeout(dur, c::SO_RCVTIMEO) |
569 | } |
570 | |
571 | pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> { |
572 | self.inner.set_timeout(dur, c::SO_SNDTIMEO) |
573 | } |
574 | |
575 | pub fn read_timeout(&self) -> io::Result<Option<Duration>> { |
576 | self.inner.timeout(c::SO_RCVTIMEO) |
577 | } |
578 | |
579 | pub fn write_timeout(&self) -> io::Result<Option<Duration>> { |
580 | self.inner.timeout(c::SO_SNDTIMEO) |
581 | } |
582 | |
583 | pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> { |
584 | setsockopt(&self.inner, c::SOL_SOCKET, c::SO_BROADCAST, broadcast as c_int) |
585 | } |
586 | |
587 | pub fn broadcast(&self) -> io::Result<bool> { |
588 | let raw: c_int = getsockopt(&self.inner, c::SOL_SOCKET, c::SO_BROADCAST)?; |
589 | Ok(raw != 0) |
590 | } |
591 | |
592 | pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> { |
593 | setsockopt( |
594 | &self.inner, |
595 | c::IPPROTO_IP, |
596 | c::IP_MULTICAST_LOOP, |
597 | multicast_loop_v4 as IpV4MultiCastType, |
598 | ) |
599 | } |
600 | |
601 | pub fn multicast_loop_v4(&self) -> io::Result<bool> { |
602 | let raw: IpV4MultiCastType = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP)?; |
603 | Ok(raw != 0) |
604 | } |
605 | |
606 | pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> { |
607 | setsockopt( |
608 | &self.inner, |
609 | c::IPPROTO_IP, |
610 | c::IP_MULTICAST_TTL, |
611 | multicast_ttl_v4 as IpV4MultiCastType, |
612 | ) |
613 | } |
614 | |
615 | pub fn multicast_ttl_v4(&self) -> io::Result<u32> { |
616 | let raw: IpV4MultiCastType = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL)?; |
617 | Ok(raw as u32) |
618 | } |
619 | |
620 | pub fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> { |
621 | setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_MULTICAST_LOOP, multicast_loop_v6 as c_int) |
622 | } |
623 | |
624 | pub fn multicast_loop_v6(&self) -> io::Result<bool> { |
625 | let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_MULTICAST_LOOP)?; |
626 | Ok(raw != 0) |
627 | } |
628 | |
629 | pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { |
630 | let mreq = c::ip_mreq { |
631 | imr_multiaddr: multiaddr.into_inner(), |
632 | imr_interface: interface.into_inner(), |
633 | }; |
634 | setsockopt(&self.inner, c::IPPROTO_IP, c::IP_ADD_MEMBERSHIP, mreq) |
635 | } |
636 | |
637 | pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { |
638 | let mreq = c::ipv6_mreq { |
639 | ipv6mr_multiaddr: multiaddr.into_inner(), |
640 | ipv6mr_interface: to_ipv6mr_interface(interface), |
641 | }; |
642 | setsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, mreq) |
643 | } |
644 | |
645 | pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { |
646 | let mreq = c::ip_mreq { |
647 | imr_multiaddr: multiaddr.into_inner(), |
648 | imr_interface: interface.into_inner(), |
649 | }; |
650 | setsockopt(&self.inner, c::IPPROTO_IP, c::IP_DROP_MEMBERSHIP, mreq) |
651 | } |
652 | |
653 | pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { |
654 | let mreq = c::ipv6_mreq { |
655 | ipv6mr_multiaddr: multiaddr.into_inner(), |
656 | ipv6mr_interface: to_ipv6mr_interface(interface), |
657 | }; |
658 | setsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, mreq) |
659 | } |
660 | |
661 | pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { |
662 | setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int) |
663 | } |
664 | |
665 | pub fn ttl(&self) -> io::Result<u32> { |
666 | let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)?; |
667 | Ok(raw as u32) |
668 | } |
669 | |
670 | pub fn take_error(&self) -> io::Result<Option<io::Error>> { |
671 | self.inner.take_error() |
672 | } |
673 | |
674 | pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { |
675 | self.inner.set_nonblocking(nonblocking) |
676 | } |
677 | |
678 | pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> { |
679 | self.inner.read(buf) |
680 | } |
681 | |
682 | pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> { |
683 | self.inner.peek(buf) |
684 | } |
685 | |
686 | pub fn send(&self, buf: &[u8]) -> io::Result<usize> { |
687 | let len = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t; |
688 | let ret = cvt(unsafe { |
689 | c::send(self.inner.as_raw(), buf.as_ptr() as *const c_void, len, MSG_NOSIGNAL) |
690 | })?; |
691 | Ok(ret as usize) |
692 | } |
693 | |
694 | pub fn connect(&self, addr: io::Result<&SocketAddr>) -> io::Result<()> { |
695 | let (addr, len) = addr?.into_inner(); |
696 | cvt_r(|| unsafe { c::connect(self.inner.as_raw(), addr.as_ptr(), len) }).map(drop) |
697 | } |
698 | } |
699 | |
700 | impl FromInner<Socket> for UdpSocket { |
701 | fn from_inner(socket: Socket) -> UdpSocket { |
702 | UdpSocket { inner: socket } |
703 | } |
704 | } |
705 | |
706 | impl fmt::Debug for UdpSocket { |
707 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
708 | let mut res: DebugStruct<'_, '_> = f.debug_struct(name:"UdpSocket" ); |
709 | |
710 | if let Ok(addr: SocketAddr) = self.socket_addr() { |
711 | res.field(name:"addr" , &addr); |
712 | } |
713 | |
714 | let name: &str = if cfg!(windows) { "socket" } else { "fd" }; |
715 | res.field(name, &self.inner.as_raw()).finish() |
716 | } |
717 | } |
718 | |
719 | //////////////////////////////////////////////////////////////////////////////// |
720 | // Converting SocketAddr to libc representation |
721 | //////////////////////////////////////////////////////////////////////////////// |
722 | |
723 | /// A type with the same memory layout as `c::sockaddr`. Used in converting Rust level |
724 | /// SocketAddr* types into their system representation. The benefit of this specific |
725 | /// type over using `c::sockaddr_storage` is that this type is exactly as large as it |
726 | /// needs to be and not a lot larger. And it can be initialized more cleanly from Rust. |
727 | #[repr (C)] |
728 | pub(crate) union SocketAddrCRepr { |
729 | v4: c::sockaddr_in, |
730 | v6: c::sockaddr_in6, |
731 | } |
732 | |
733 | impl SocketAddrCRepr { |
734 | pub fn as_ptr(&self) -> *const c::sockaddr { |
735 | self as *const _ as *const c::sockaddr |
736 | } |
737 | } |
738 | |
739 | impl<'a> IntoInner<(SocketAddrCRepr, c::socklen_t)> for &'a SocketAddr { |
740 | fn into_inner(self) -> (SocketAddrCRepr, c::socklen_t) { |
741 | match *self { |
742 | SocketAddr::V4(ref a: &SocketAddrV4) => { |
743 | let sockaddr: SocketAddrCRepr = SocketAddrCRepr { v4: a.into_inner() }; |
744 | (sockaddr, mem::size_of::<c::sockaddr_in>() as c::socklen_t) |
745 | } |
746 | SocketAddr::V6(ref a: &SocketAddrV6) => { |
747 | let sockaddr: SocketAddrCRepr = SocketAddrCRepr { v6: a.into_inner() }; |
748 | (sockaddr, mem::size_of::<c::sockaddr_in6>() as c::socklen_t) |
749 | } |
750 | } |
751 | } |
752 | } |
753 | |