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