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