]>
Commit | Line | Data |
---|---|---|
532ac7d7 XL |
1 | use crate::fmt; |
2 | use crate::io::{self, Error, ErrorKind}; | |
60c5eb7d | 3 | use crate::net::{Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs}; |
532ac7d7 XL |
4 | use crate::sys_common::net as net_imp; |
5 | use crate::sys_common::{AsInner, FromInner, IntoInner}; | |
6 | use crate::time::Duration; | |
85aaf69f | 7 | |
cc61c64b | 8 | /// A UDP socket. |
85aaf69f | 9 | /// |
cc61c64b XL |
10 | /// After creating a `UdpSocket` by [`bind`]ing it to a socket address, data can be |
11 | /// [sent to] and [received from] any other socket address. | |
12 | /// | |
13 | /// Although UDP is a connectionless protocol, this implementation provides an interface | |
14 | /// to set an address where data should be sent and received from. After setting a remote | |
15 | /// address with [`connect`], data can be sent to and received from that address with | |
16 | /// [`send`] and [`recv`]. | |
17 | /// | |
18 | /// As stated in the User Datagram Protocol's specification in [IETF RFC 768], UDP is | |
19 | /// an unordered, unreliable protocol; refer to [`TcpListener`] and [`TcpStream`] for TCP | |
20 | /// primitives. | |
21 | /// | |
22 | /// [`bind`]: #method.bind | |
23 | /// [`connect`]: #method.connect | |
24 | /// [IETF RFC 768]: https://tools.ietf.org/html/rfc768 | |
25 | /// [`recv`]: #method.recv | |
26 | /// [received from]: #method.recv_from | |
27 | /// [`send`]: #method.send | |
28 | /// [sent to]: #method.send_to | |
29 | /// [`TcpListener`]: ../../std/net/struct.TcpListener.html | |
30 | /// [`TcpStream`]: ../../std/net/struct.TcpStream.html | |
85aaf69f | 31 | /// |
c34b1796 | 32 | /// # Examples |
85aaf69f SL |
33 | /// |
34 | /// ```no_run | |
35 | /// use std::net::UdpSocket; | |
36 | /// | |
0531ce1d XL |
37 | /// fn main() -> std::io::Result<()> { |
38 | /// { | |
39 | /// let mut socket = UdpSocket::bind("127.0.0.1:34254")?; | |
85aaf69f | 40 | /// |
0531ce1d XL |
41 | /// // Receives a single datagram message on the socket. If `buf` is too small to hold |
42 | /// // the message, it will be cut off. | |
43 | /// let mut buf = [0; 10]; | |
44 | /// let (amt, src) = socket.recv_from(&mut buf)?; | |
85aaf69f | 45 | /// |
0531ce1d XL |
46 | /// // Redeclare `buf` as slice of the received data and send reverse data back to origin. |
47 | /// let buf = &mut buf[..amt]; | |
48 | /// buf.reverse(); | |
49 | /// socket.send_to(buf, &src)?; | |
50 | /// } // the socket is closed here | |
51 | /// Ok(()) | |
52 | /// } | |
85aaf69f | 53 | /// ``` |
c34b1796 | 54 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
55 | pub struct UdpSocket(net_imp::UdpSocket); |
56 | ||
57 | impl UdpSocket { | |
58 | /// Creates a UDP socket from the given address. | |
59 | /// | |
476ff2be | 60 | /// The address type can be any implementor of [`ToSocketAddrs`] trait. See |
bd371182 | 61 | /// its documentation for concrete examples. |
476ff2be | 62 | /// |
ea8adc8c XL |
63 | /// If `addr` yields multiple addresses, `bind` will be attempted with |
64 | /// each of the addresses until one succeeds and returns the socket. If none | |
65 | /// of the addresses succeed in creating a socket, the error returned from | |
66 | /// the last attempt (the last address) is returned. | |
67 | /// | |
476ff2be SL |
68 | /// [`ToSocketAddrs`]: ../../std/net/trait.ToSocketAddrs.html |
69 | /// | |
70 | /// # Examples | |
71 | /// | |
9fa01778 | 72 | /// Creates a UDP socket bound to `127.0.0.1:3400`: |
ea8adc8c | 73 | /// |
476ff2be SL |
74 | /// ```no_run |
75 | /// use std::net::UdpSocket; | |
76 | /// | |
ea8adc8c XL |
77 | /// let socket = UdpSocket::bind("127.0.0.1:3400").expect("couldn't bind to address"); |
78 | /// ``` | |
79 | /// | |
9fa01778 | 80 | /// Creates a UDP socket bound to `127.0.0.1:3400`. If the socket cannot be |
ea8adc8c XL |
81 | /// bound to that address, create a UDP socket bound to `127.0.0.1:3401`: |
82 | /// | |
83 | /// ```no_run | |
84 | /// use std::net::{SocketAddr, UdpSocket}; | |
85 | /// | |
86 | /// let addrs = [ | |
87 | /// SocketAddr::from(([127, 0, 0, 1], 3400)), | |
88 | /// SocketAddr::from(([127, 0, 0, 1], 3401)), | |
89 | /// ]; | |
90 | /// let socket = UdpSocket::bind(&addrs[..]).expect("couldn't bind to address"); | |
476ff2be | 91 | /// ``` |
c34b1796 AL |
92 | #[stable(feature = "rust1", since = "1.0.0")] |
93 | pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<UdpSocket> { | |
85aaf69f SL |
94 | super::each_addr(addr, net_imp::UdpSocket::bind).map(UdpSocket) |
95 | } | |
96 | ||
ea8adc8c XL |
97 | /// Receives a single datagram message on the socket. On success, returns the number |
98 | /// of bytes read and the origin. | |
99 | /// | |
100 | /// The function must be called with valid byte array `buf` of sufficient size to | |
101 | /// hold the message bytes. If a message is too long to fit in the supplied buffer, | |
102 | /// excess bytes may be discarded. | |
476ff2be SL |
103 | /// |
104 | /// # Examples | |
105 | /// | |
106 | /// ```no_run | |
107 | /// use std::net::UdpSocket; | |
108 | /// | |
109 | /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); | |
110 | /// let mut buf = [0; 10]; | |
111 | /// let (number_of_bytes, src_addr) = socket.recv_from(&mut buf) | |
112 | /// .expect("Didn't receive data"); | |
ea8adc8c | 113 | /// let filled_buf = &mut buf[..number_of_bytes]; |
476ff2be | 114 | /// ``` |
c34b1796 | 115 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
116 | pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { |
117 | self.0.recv_from(buf) | |
118 | } | |
119 | ||
ea8adc8c XL |
120 | /// Receives a single datagram message on the socket, without removing it from the |
121 | /// queue. On success, returns the number of bytes read and the origin. | |
122 | /// | |
123 | /// The function must be called with valid byte array `buf` of sufficient size to | |
124 | /// hold the message bytes. If a message is too long to fit in the supplied buffer, | |
125 | /// excess bytes may be discarded. | |
8bb4bdeb XL |
126 | /// |
127 | /// Successive calls return the same data. This is accomplished by passing | |
128 | /// `MSG_PEEK` as a flag to the underlying `recvfrom` system call. | |
129 | /// | |
ea8adc8c XL |
130 | /// Do not use this function to implement busy waiting, instead use `libc::poll` to |
131 | /// synchronize IO events on one or more sockets. | |
8bb4bdeb XL |
132 | /// |
133 | /// # Examples | |
134 | /// | |
135 | /// ```no_run | |
8bb4bdeb XL |
136 | /// use std::net::UdpSocket; |
137 | /// | |
138 | /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); | |
139 | /// let mut buf = [0; 10]; | |
140 | /// let (number_of_bytes, src_addr) = socket.peek_from(&mut buf) | |
141 | /// .expect("Didn't receive data"); | |
ea8adc8c | 142 | /// let filled_buf = &mut buf[..number_of_bytes]; |
8bb4bdeb | 143 | /// ``` |
cc61c64b | 144 | #[stable(feature = "peek", since = "1.18.0")] |
8bb4bdeb XL |
145 | pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { |
146 | self.0.peek_from(buf) | |
147 | } | |
148 | ||
bd371182 AL |
149 | /// Sends data on the socket to the given address. On success, returns the |
150 | /// number of bytes written. | |
85aaf69f | 151 | /// |
476ff2be | 152 | /// Address type can be any implementor of [`ToSocketAddrs`] trait. See its |
85aaf69f | 153 | /// documentation for concrete examples. |
476ff2be | 154 | /// |
ea8adc8c XL |
155 | /// It is possible for `addr` to yield multiple addresses, but `send_to` |
156 | /// will only send data to the first address yielded by `addr`. | |
157 | /// | |
476ff2be SL |
158 | /// This will return an error when the IP version of the local socket |
159 | /// does not match that returned from [`ToSocketAddrs`]. | |
160 | /// | |
9fa01778 | 161 | /// See issue #34202 for more details. |
476ff2be SL |
162 | /// |
163 | /// [`ToSocketAddrs`]: ../../std/net/trait.ToSocketAddrs.html | |
164 | /// | |
165 | /// # Examples | |
166 | /// | |
167 | /// ```no_run | |
168 | /// use std::net::UdpSocket; | |
169 | /// | |
170 | /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); | |
171 | /// socket.send_to(&[0; 10], "127.0.0.1:4242").expect("couldn't send data"); | |
172 | /// ``` | |
c34b1796 | 173 | #[stable(feature = "rust1", since = "1.0.0")] |
60c5eb7d | 174 | pub fn send_to<A: ToSocketAddrs>(&self, buf: &[u8], addr: A) -> io::Result<usize> { |
54a0048b | 175 | match addr.to_socket_addrs()?.next() { |
85aaf69f | 176 | Some(addr) => self.0.send_to(buf, &addr), |
60c5eb7d | 177 | None => Err(Error::new(ErrorKind::InvalidInput, "no addresses to send data to")), |
85aaf69f SL |
178 | } |
179 | } | |
180 | ||
532ac7d7 XL |
181 | /// Returns the socket address of the remote peer this socket was connected to. |
182 | /// | |
183 | /// # Examples | |
184 | /// | |
185 | /// ```no_run | |
532ac7d7 XL |
186 | /// use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket}; |
187 | /// | |
188 | /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); | |
189 | /// socket.connect("192.168.0.1:41203").expect("couldn't connect to address"); | |
190 | /// assert_eq!(socket.peer_addr().unwrap(), | |
191 | /// SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(192, 168, 0, 1), 41203))); | |
192 | /// ``` | |
193 | /// | |
194 | /// If the socket isn't connected, it will return a [`NotConnected`] error. | |
195 | /// | |
196 | /// [`NotConnected`]: ../../std/io/enum.ErrorKind.html#variant.NotConnected | |
197 | /// | |
198 | /// ```no_run | |
532ac7d7 XL |
199 | /// use std::net::UdpSocket; |
200 | /// | |
201 | /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); | |
202 | /// assert_eq!(socket.peer_addr().unwrap_err().kind(), | |
e74abb32 | 203 | /// std::io::ErrorKind::NotConnected); |
532ac7d7 | 204 | /// ``` |
e74abb32 | 205 | #[stable(feature = "udp_peer_addr", since = "1.40.0")] |
532ac7d7 XL |
206 | pub fn peer_addr(&self) -> io::Result<SocketAddr> { |
207 | self.0.peer_addr() | |
208 | } | |
209 | ||
85aaf69f | 210 | /// Returns the socket address that this socket was created from. |
476ff2be SL |
211 | /// |
212 | /// # Examples | |
213 | /// | |
214 | /// ```no_run | |
215 | /// use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket}; | |
216 | /// | |
217 | /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); | |
218 | /// assert_eq!(socket.local_addr().unwrap(), | |
219 | /// SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 34254))); | |
220 | /// ``` | |
c34b1796 AL |
221 | #[stable(feature = "rust1", since = "1.0.0")] |
222 | pub fn local_addr(&self) -> io::Result<SocketAddr> { | |
85aaf69f SL |
223 | self.0.socket_addr() |
224 | } | |
225 | ||
9346a6ac | 226 | /// Creates a new independently owned handle to the underlying socket. |
85aaf69f SL |
227 | /// |
228 | /// The returned `UdpSocket` is a reference to the same socket that this | |
229 | /// object references. Both handles will read and write the same port, and | |
230 | /// options set on one socket will be propagated to the other. | |
476ff2be SL |
231 | /// |
232 | /// # Examples | |
233 | /// | |
234 | /// ```no_run | |
235 | /// use std::net::UdpSocket; | |
236 | /// | |
237 | /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); | |
238 | /// let socket_clone = socket.try_clone().expect("couldn't clone the socket"); | |
239 | /// ``` | |
c34b1796 | 240 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
241 | pub fn try_clone(&self) -> io::Result<UdpSocket> { |
242 | self.0.duplicate().map(UdpSocket) | |
243 | } | |
244 | ||
62682a34 SL |
245 | /// Sets the read timeout to the timeout specified. |
246 | /// | |
cc61c64b | 247 | /// If the value specified is [`None`], then [`read`] calls will block |
0531ce1d XL |
248 | /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is |
249 | /// passed to this method. | |
e9174d1e | 250 | /// |
0531ce1d | 251 | /// # Platform-specific behavior |
e9174d1e SL |
252 | /// |
253 | /// Platforms may return a different error code whenever a read times out as | |
254 | /// a result of setting this option. For example Unix typically returns an | |
476ff2be SL |
255 | /// error of the kind [`WouldBlock`], but Windows may return [`TimedOut`]. |
256 | /// | |
257 | /// [`None`]: ../../std/option/enum.Option.html#variant.None | |
0531ce1d | 258 | /// [`Err`]: ../../std/result/enum.Result.html#variant.Err |
cc61c64b | 259 | /// [`read`]: ../../std/io/trait.Read.html#tymethod.read |
476ff2be SL |
260 | /// [`Duration`]: ../../std/time/struct.Duration.html |
261 | /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock | |
262 | /// [`TimedOut`]: ../../std/io/enum.ErrorKind.html#variant.TimedOut | |
263 | /// | |
264 | /// # Examples | |
265 | /// | |
266 | /// ```no_run | |
267 | /// use std::net::UdpSocket; | |
268 | /// | |
269 | /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); | |
270 | /// socket.set_read_timeout(None).expect("set_read_timeout call failed"); | |
271 | /// ``` | |
0531ce1d XL |
272 | /// |
273 | /// An [`Err`] is returned if the zero [`Duration`] is passed to this | |
274 | /// method: | |
275 | /// | |
276 | /// ```no_run | |
277 | /// use std::io; | |
278 | /// use std::net::UdpSocket; | |
279 | /// use std::time::Duration; | |
280 | /// | |
281 | /// let socket = UdpSocket::bind("127.0.0.1:34254").unwrap(); | |
282 | /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); | |
283 | /// let err = result.unwrap_err(); | |
284 | /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) | |
285 | /// ``` | |
e9174d1e | 286 | #[stable(feature = "socket_timeout", since = "1.4.0")] |
62682a34 SL |
287 | pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> { |
288 | self.0.set_read_timeout(dur) | |
289 | } | |
290 | ||
291 | /// Sets the write timeout to the timeout specified. | |
292 | /// | |
cc61c64b | 293 | /// If the value specified is [`None`], then [`write`] calls will block |
0531ce1d XL |
294 | /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is |
295 | /// passed to this method. | |
e9174d1e | 296 | /// |
0531ce1d | 297 | /// # Platform-specific behavior |
e9174d1e SL |
298 | /// |
299 | /// Platforms may return a different error code whenever a write times out | |
300 | /// as a result of setting this option. For example Unix typically returns | |
476ff2be SL |
301 | /// an error of the kind [`WouldBlock`], but Windows may return [`TimedOut`]. |
302 | /// | |
303 | /// [`None`]: ../../std/option/enum.Option.html#variant.None | |
0531ce1d | 304 | /// [`Err`]: ../../std/result/enum.Result.html#variant.Err |
cc61c64b | 305 | /// [`write`]: ../../std/io/trait.Write.html#tymethod.write |
476ff2be SL |
306 | /// [`Duration`]: ../../std/time/struct.Duration.html |
307 | /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock | |
308 | /// [`TimedOut`]: ../../std/io/enum.ErrorKind.html#variant.TimedOut | |
309 | /// | |
310 | /// # Examples | |
311 | /// | |
312 | /// ```no_run | |
313 | /// use std::net::UdpSocket; | |
314 | /// | |
315 | /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); | |
316 | /// socket.set_write_timeout(None).expect("set_write_timeout call failed"); | |
317 | /// ``` | |
0531ce1d XL |
318 | /// |
319 | /// An [`Err`] is returned if the zero [`Duration`] is passed to this | |
320 | /// method: | |
321 | /// | |
322 | /// ```no_run | |
323 | /// use std::io; | |
324 | /// use std::net::UdpSocket; | |
325 | /// use std::time::Duration; | |
326 | /// | |
327 | /// let socket = UdpSocket::bind("127.0.0.1:34254").unwrap(); | |
328 | /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); | |
329 | /// let err = result.unwrap_err(); | |
330 | /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) | |
331 | /// ``` | |
e9174d1e | 332 | #[stable(feature = "socket_timeout", since = "1.4.0")] |
62682a34 SL |
333 | pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> { |
334 | self.0.set_write_timeout(dur) | |
335 | } | |
336 | ||
337 | /// Returns the read timeout of this socket. | |
338 | /// | |
cc61c64b | 339 | /// If the timeout is [`None`], then [`read`] calls will block indefinitely. |
476ff2be SL |
340 | /// |
341 | /// [`None`]: ../../std/option/enum.Option.html#variant.None | |
cc61c64b | 342 | /// [`read`]: ../../std/io/trait.Read.html#tymethod.read |
476ff2be SL |
343 | /// |
344 | /// # Examples | |
345 | /// | |
346 | /// ```no_run | |
347 | /// use std::net::UdpSocket; | |
348 | /// | |
349 | /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); | |
350 | /// socket.set_read_timeout(None).expect("set_read_timeout call failed"); | |
351 | /// assert_eq!(socket.read_timeout().unwrap(), None); | |
352 | /// ``` | |
e9174d1e | 353 | #[stable(feature = "socket_timeout", since = "1.4.0")] |
62682a34 SL |
354 | pub fn read_timeout(&self) -> io::Result<Option<Duration>> { |
355 | self.0.read_timeout() | |
356 | } | |
357 | ||
358 | /// Returns the write timeout of this socket. | |
359 | /// | |
cc61c64b | 360 | /// If the timeout is [`None`], then [`write`] calls will block indefinitely. |
476ff2be SL |
361 | /// |
362 | /// [`None`]: ../../std/option/enum.Option.html#variant.None | |
cc61c64b | 363 | /// [`write`]: ../../std/io/trait.Write.html#tymethod.write |
476ff2be SL |
364 | /// |
365 | /// # Examples | |
366 | /// | |
367 | /// ```no_run | |
368 | /// use std::net::UdpSocket; | |
369 | /// | |
370 | /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); | |
371 | /// socket.set_write_timeout(None).expect("set_write_timeout call failed"); | |
372 | /// assert_eq!(socket.write_timeout().unwrap(), None); | |
373 | /// ``` | |
e9174d1e | 374 | #[stable(feature = "socket_timeout", since = "1.4.0")] |
62682a34 SL |
375 | pub fn write_timeout(&self) -> io::Result<Option<Duration>> { |
376 | self.0.write_timeout() | |
377 | } | |
54a0048b SL |
378 | |
379 | /// Sets the value of the `SO_BROADCAST` option for this socket. | |
380 | /// | |
381 | /// When enabled, this socket is allowed to send packets to a broadcast | |
382 | /// address. | |
476ff2be SL |
383 | /// |
384 | /// # Examples | |
385 | /// | |
386 | /// ```no_run | |
387 | /// use std::net::UdpSocket; | |
388 | /// | |
389 | /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); | |
390 | /// socket.set_broadcast(false).expect("set_broadcast call failed"); | |
391 | /// ``` | |
54a0048b SL |
392 | #[stable(feature = "net2_mutators", since = "1.9.0")] |
393 | pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> { | |
394 | self.0.set_broadcast(broadcast) | |
395 | } | |
396 | ||
397 | /// Gets the value of the `SO_BROADCAST` option for this socket. | |
398 | /// | |
399 | /// For more information about this option, see | |
400 | /// [`set_broadcast`][link]. | |
401 | /// | |
402 | /// [link]: #method.set_broadcast | |
476ff2be SL |
403 | /// |
404 | /// # Examples | |
405 | /// | |
406 | /// ```no_run | |
407 | /// use std::net::UdpSocket; | |
408 | /// | |
409 | /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); | |
410 | /// socket.set_broadcast(false).expect("set_broadcast call failed"); | |
411 | /// assert_eq!(socket.broadcast().unwrap(), false); | |
412 | /// ``` | |
54a0048b SL |
413 | #[stable(feature = "net2_mutators", since = "1.9.0")] |
414 | pub fn broadcast(&self) -> io::Result<bool> { | |
415 | self.0.broadcast() | |
416 | } | |
417 | ||
418 | /// Sets the value of the `IP_MULTICAST_LOOP` option for this socket. | |
419 | /// | |
420 | /// If enabled, multicast packets will be looped back to the local socket. | |
416331ca | 421 | /// Note that this may not have any effect on IPv6 sockets. |
476ff2be SL |
422 | /// |
423 | /// # Examples | |
424 | /// | |
425 | /// ```no_run | |
426 | /// use std::net::UdpSocket; | |
427 | /// | |
428 | /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); | |
429 | /// socket.set_multicast_loop_v4(false).expect("set_multicast_loop_v4 call failed"); | |
430 | /// ``` | |
54a0048b SL |
431 | #[stable(feature = "net2_mutators", since = "1.9.0")] |
432 | pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> { | |
433 | self.0.set_multicast_loop_v4(multicast_loop_v4) | |
434 | } | |
435 | ||
436 | /// Gets the value of the `IP_MULTICAST_LOOP` option for this socket. | |
437 | /// | |
438 | /// For more information about this option, see | |
439 | /// [`set_multicast_loop_v4`][link]. | |
440 | /// | |
441 | /// [link]: #method.set_multicast_loop_v4 | |
476ff2be SL |
442 | /// |
443 | /// # Examples | |
444 | /// | |
445 | /// ```no_run | |
446 | /// use std::net::UdpSocket; | |
447 | /// | |
448 | /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); | |
449 | /// socket.set_multicast_loop_v4(false).expect("set_multicast_loop_v4 call failed"); | |
450 | /// assert_eq!(socket.multicast_loop_v4().unwrap(), false); | |
451 | /// ``` | |
54a0048b SL |
452 | #[stable(feature = "net2_mutators", since = "1.9.0")] |
453 | pub fn multicast_loop_v4(&self) -> io::Result<bool> { | |
454 | self.0.multicast_loop_v4() | |
455 | } | |
456 | ||
457 | /// Sets the value of the `IP_MULTICAST_TTL` option for this socket. | |
458 | /// | |
459 | /// Indicates the time-to-live value of outgoing multicast packets for | |
460 | /// this socket. The default value is 1 which means that multicast packets | |
461 | /// don't leave the local network unless explicitly requested. | |
462 | /// | |
416331ca | 463 | /// Note that this may not have any effect on IPv6 sockets. |
476ff2be SL |
464 | /// |
465 | /// # Examples | |
466 | /// | |
467 | /// ```no_run | |
468 | /// use std::net::UdpSocket; | |
469 | /// | |
470 | /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); | |
471 | /// socket.set_multicast_ttl_v4(42).expect("set_multicast_ttl_v4 call failed"); | |
472 | /// ``` | |
54a0048b SL |
473 | #[stable(feature = "net2_mutators", since = "1.9.0")] |
474 | pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> { | |
475 | self.0.set_multicast_ttl_v4(multicast_ttl_v4) | |
476 | } | |
477 | ||
478 | /// Gets the value of the `IP_MULTICAST_TTL` option for this socket. | |
479 | /// | |
480 | /// For more information about this option, see | |
481 | /// [`set_multicast_ttl_v4`][link]. | |
482 | /// | |
483 | /// [link]: #method.set_multicast_ttl_v4 | |
476ff2be SL |
484 | /// |
485 | /// # Examples | |
486 | /// | |
487 | /// ```no_run | |
488 | /// use std::net::UdpSocket; | |
489 | /// | |
490 | /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); | |
491 | /// socket.set_multicast_ttl_v4(42).expect("set_multicast_ttl_v4 call failed"); | |
492 | /// assert_eq!(socket.multicast_ttl_v4().unwrap(), 42); | |
493 | /// ``` | |
54a0048b SL |
494 | #[stable(feature = "net2_mutators", since = "1.9.0")] |
495 | pub fn multicast_ttl_v4(&self) -> io::Result<u32> { | |
496 | self.0.multicast_ttl_v4() | |
497 | } | |
498 | ||
499 | /// Sets the value of the `IPV6_MULTICAST_LOOP` option for this socket. | |
500 | /// | |
501 | /// Controls whether this socket sees the multicast packets it sends itself. | |
502 | /// Note that this may not have any affect on IPv4 sockets. | |
476ff2be SL |
503 | /// |
504 | /// # Examples | |
505 | /// | |
506 | /// ```no_run | |
507 | /// use std::net::UdpSocket; | |
508 | /// | |
509 | /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); | |
510 | /// socket.set_multicast_loop_v6(false).expect("set_multicast_loop_v6 call failed"); | |
511 | /// ``` | |
54a0048b SL |
512 | #[stable(feature = "net2_mutators", since = "1.9.0")] |
513 | pub fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> { | |
514 | self.0.set_multicast_loop_v6(multicast_loop_v6) | |
515 | } | |
516 | ||
517 | /// Gets the value of the `IPV6_MULTICAST_LOOP` option for this socket. | |
518 | /// | |
519 | /// For more information about this option, see | |
520 | /// [`set_multicast_loop_v6`][link]. | |
521 | /// | |
522 | /// [link]: #method.set_multicast_loop_v6 | |
476ff2be SL |
523 | /// |
524 | /// # Examples | |
525 | /// | |
526 | /// ```no_run | |
527 | /// use std::net::UdpSocket; | |
528 | /// | |
529 | /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); | |
530 | /// socket.set_multicast_loop_v6(false).expect("set_multicast_loop_v6 call failed"); | |
531 | /// assert_eq!(socket.multicast_loop_v6().unwrap(), false); | |
532 | /// ``` | |
54a0048b SL |
533 | #[stable(feature = "net2_mutators", since = "1.9.0")] |
534 | pub fn multicast_loop_v6(&self) -> io::Result<bool> { | |
535 | self.0.multicast_loop_v6() | |
536 | } | |
537 | ||
538 | /// Sets the value for the `IP_TTL` option on this socket. | |
539 | /// | |
540 | /// This value sets the time-to-live field that is used in every packet sent | |
541 | /// from this socket. | |
476ff2be SL |
542 | /// |
543 | /// # Examples | |
544 | /// | |
545 | /// ```no_run | |
546 | /// use std::net::UdpSocket; | |
547 | /// | |
548 | /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); | |
549 | /// socket.set_ttl(42).expect("set_ttl call failed"); | |
550 | /// ``` | |
54a0048b SL |
551 | #[stable(feature = "net2_mutators", since = "1.9.0")] |
552 | pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { | |
553 | self.0.set_ttl(ttl) | |
554 | } | |
555 | ||
556 | /// Gets the value of the `IP_TTL` option for this socket. | |
557 | /// | |
558 | /// For more information about this option, see [`set_ttl`][link]. | |
559 | /// | |
560 | /// [link]: #method.set_ttl | |
476ff2be SL |
561 | /// |
562 | /// # Examples | |
563 | /// | |
564 | /// ```no_run | |
565 | /// use std::net::UdpSocket; | |
566 | /// | |
567 | /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); | |
568 | /// socket.set_ttl(42).expect("set_ttl call failed"); | |
569 | /// assert_eq!(socket.ttl().unwrap(), 42); | |
570 | /// ``` | |
54a0048b SL |
571 | #[stable(feature = "net2_mutators", since = "1.9.0")] |
572 | pub fn ttl(&self) -> io::Result<u32> { | |
573 | self.0.ttl() | |
574 | } | |
575 | ||
576 | /// Executes an operation of the `IP_ADD_MEMBERSHIP` type. | |
577 | /// | |
578 | /// This function specifies a new multicast group for this socket to join. | |
579 | /// The address must be a valid multicast address, and `interface` is the | |
580 | /// address of the local interface with which the system should join the | |
581 | /// multicast group. If it's equal to `INADDR_ANY` then an appropriate | |
582 | /// interface is chosen by the system. | |
583 | #[stable(feature = "net2_mutators", since = "1.9.0")] | |
584 | pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { | |
585 | self.0.join_multicast_v4(multiaddr, interface) | |
586 | } | |
587 | ||
588 | /// Executes an operation of the `IPV6_ADD_MEMBERSHIP` type. | |
589 | /// | |
590 | /// This function specifies a new multicast group for this socket to join. | |
591 | /// The address must be a valid multicast address, and `interface` is the | |
592 | /// index of the interface to join/leave (or 0 to indicate any interface). | |
593 | #[stable(feature = "net2_mutators", since = "1.9.0")] | |
594 | pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { | |
595 | self.0.join_multicast_v6(multiaddr, interface) | |
596 | } | |
597 | ||
598 | /// Executes an operation of the `IP_DROP_MEMBERSHIP` type. | |
599 | /// | |
600 | /// For more information about this option, see | |
601 | /// [`join_multicast_v4`][link]. | |
602 | /// | |
603 | /// [link]: #method.join_multicast_v4 | |
604 | #[stable(feature = "net2_mutators", since = "1.9.0")] | |
605 | pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { | |
606 | self.0.leave_multicast_v4(multiaddr, interface) | |
607 | } | |
608 | ||
609 | /// Executes an operation of the `IPV6_DROP_MEMBERSHIP` type. | |
610 | /// | |
611 | /// For more information about this option, see | |
612 | /// [`join_multicast_v6`][link]. | |
613 | /// | |
614 | /// [link]: #method.join_multicast_v6 | |
615 | #[stable(feature = "net2_mutators", since = "1.9.0")] | |
616 | pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { | |
617 | self.0.leave_multicast_v6(multiaddr, interface) | |
618 | } | |
619 | ||
9fa01778 | 620 | /// Gets the value of the `SO_ERROR` option on this socket. |
54a0048b SL |
621 | /// |
622 | /// This will retrieve the stored error in the underlying socket, clearing | |
623 | /// the field in the process. This can be useful for checking errors between | |
624 | /// calls. | |
476ff2be SL |
625 | /// |
626 | /// # Examples | |
627 | /// | |
628 | /// ```no_run | |
629 | /// use std::net::UdpSocket; | |
630 | /// | |
631 | /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); | |
632 | /// match socket.take_error() { | |
633 | /// Ok(Some(error)) => println!("UdpSocket error: {:?}", error), | |
634 | /// Ok(None) => println!("No error"), | |
635 | /// Err(error) => println!("UdpSocket.take_error failed: {:?}", error), | |
636 | /// } | |
637 | /// ``` | |
54a0048b SL |
638 | #[stable(feature = "net2_mutators", since = "1.9.0")] |
639 | pub fn take_error(&self) -> io::Result<Option<io::Error>> { | |
640 | self.0.take_error() | |
641 | } | |
642 | ||
643 | /// Connects this UDP socket to a remote address, allowing the `send` and | |
644 | /// `recv` syscalls to be used to send data and also applies filters to only | |
645 | /// receive data from the specified address. | |
476ff2be | 646 | /// |
ea8adc8c XL |
647 | /// If `addr` yields multiple addresses, `connect` will be attempted with |
648 | /// each of the addresses until the underlying OS function returns no | |
649 | /// error. Note that usually, a successful `connect` call does not specify | |
650 | /// that there is a remote server listening on the port, rather, such an | |
651 | /// error would only be detected after the first send. If the OS returns an | |
652 | /// error for each of the specified addresses, the error returned from the | |
653 | /// last connection attempt (the last address) is returned. | |
654 | /// | |
476ff2be SL |
655 | /// # Examples |
656 | /// | |
9fa01778 | 657 | /// Creates a UDP socket bound to `127.0.0.1:3400` and connect the socket to |
ea8adc8c XL |
658 | /// `127.0.0.1:8080`: |
659 | /// | |
476ff2be SL |
660 | /// ```no_run |
661 | /// use std::net::UdpSocket; | |
662 | /// | |
ea8adc8c | 663 | /// let socket = UdpSocket::bind("127.0.0.1:3400").expect("couldn't bind to address"); |
476ff2be SL |
664 | /// socket.connect("127.0.0.1:8080").expect("connect function failed"); |
665 | /// ``` | |
ea8adc8c XL |
666 | /// |
667 | /// Unlike in the TCP case, passing an array of addresses to the `connect` | |
668 | /// function of a UDP socket is not a useful thing to do: The OS will be | |
669 | /// unable to determine whether something is listening on the remote | |
670 | /// address without the application sending data. | |
54a0048b SL |
671 | #[stable(feature = "net2_mutators", since = "1.9.0")] |
672 | pub fn connect<A: ToSocketAddrs>(&self, addr: A) -> io::Result<()> { | |
673 | super::each_addr(addr, |addr| self.0.connect(addr)) | |
674 | } | |
675 | ||
676 | /// Sends data on the socket to the remote address to which it is connected. | |
677 | /// | |
cc61c64b | 678 | /// The [`connect`] method will connect this socket to a remote address. This |
54a0048b | 679 | /// method will fail if the socket is not connected. |
476ff2be | 680 | /// |
cc61c64b | 681 | /// [`connect`]: #method.connect |
476ff2be SL |
682 | /// |
683 | /// # Examples | |
684 | /// | |
685 | /// ```no_run | |
686 | /// use std::net::UdpSocket; | |
687 | /// | |
688 | /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); | |
689 | /// socket.connect("127.0.0.1:8080").expect("connect function failed"); | |
690 | /// socket.send(&[0, 1, 2]).expect("couldn't send message"); | |
691 | /// ``` | |
54a0048b SL |
692 | #[stable(feature = "net2_mutators", since = "1.9.0")] |
693 | pub fn send(&self, buf: &[u8]) -> io::Result<usize> { | |
694 | self.0.send(buf) | |
695 | } | |
696 | ||
ea8adc8c XL |
697 | /// Receives a single datagram message on the socket from the remote address to |
698 | /// which it is connected. On success, returns the number of bytes read. | |
699 | /// | |
700 | /// The function must be called with valid byte array `buf` of sufficient size to | |
701 | /// hold the message bytes. If a message is too long to fit in the supplied buffer, | |
702 | /// excess bytes may be discarded. | |
54a0048b | 703 | /// |
cc61c64b | 704 | /// The [`connect`] method will connect this socket to a remote address. This |
54a0048b | 705 | /// method will fail if the socket is not connected. |
476ff2be | 706 | /// |
cc61c64b XL |
707 | /// [`connect`]: #method.connect |
708 | /// | |
476ff2be SL |
709 | /// # Examples |
710 | /// | |
711 | /// ```no_run | |
712 | /// use std::net::UdpSocket; | |
713 | /// | |
714 | /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); | |
715 | /// socket.connect("127.0.0.1:8080").expect("connect function failed"); | |
716 | /// let mut buf = [0; 10]; | |
717 | /// match socket.recv(&mut buf) { | |
ea8adc8c | 718 | /// Ok(received) => println!("received {} bytes {:?}", received, &buf[..received]), |
476ff2be SL |
719 | /// Err(e) => println!("recv function failed: {:?}", e), |
720 | /// } | |
721 | /// ``` | |
54a0048b SL |
722 | #[stable(feature = "net2_mutators", since = "1.9.0")] |
723 | pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> { | |
724 | self.0.recv(buf) | |
725 | } | |
726 | ||
ea8adc8c XL |
727 | /// Receives single datagram on the socket from the remote address to which it is |
728 | /// connected, without removing the message from input queue. On success, returns | |
729 | /// the number of bytes peeked. | |
730 | /// | |
731 | /// The function must be called with valid byte array `buf` of sufficient size to | |
732 | /// hold the message bytes. If a message is too long to fit in the supplied buffer, | |
733 | /// excess bytes may be discarded. | |
8bb4bdeb XL |
734 | /// |
735 | /// Successive calls return the same data. This is accomplished by passing | |
736 | /// `MSG_PEEK` as a flag to the underlying `recv` system call. | |
737 | /// | |
ea8adc8c XL |
738 | /// Do not use this function to implement busy waiting, instead use `libc::poll` to |
739 | /// synchronize IO events on one or more sockets. | |
740 | /// | |
741 | /// The [`connect`] method will connect this socket to a remote address. This | |
742 | /// method will fail if the socket is not connected. | |
743 | /// | |
744 | /// [`connect`]: #method.connect | |
745 | /// | |
8bb4bdeb XL |
746 | /// # Errors |
747 | /// | |
748 | /// This method will fail if the socket is not connected. The `connect` method | |
749 | /// will connect this socket to a remote address. | |
750 | /// | |
751 | /// # Examples | |
752 | /// | |
753 | /// ```no_run | |
8bb4bdeb XL |
754 | /// use std::net::UdpSocket; |
755 | /// | |
756 | /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); | |
757 | /// socket.connect("127.0.0.1:8080").expect("connect function failed"); | |
758 | /// let mut buf = [0; 10]; | |
759 | /// match socket.peek(&mut buf) { | |
760 | /// Ok(received) => println!("received {} bytes", received), | |
761 | /// Err(e) => println!("peek function failed: {:?}", e), | |
762 | /// } | |
763 | /// ``` | |
cc61c64b | 764 | #[stable(feature = "peek", since = "1.18.0")] |
8bb4bdeb XL |
765 | pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> { |
766 | self.0.peek(buf) | |
767 | } | |
768 | ||
a7813a04 | 769 | /// Moves this UDP socket into or out of nonblocking mode. |
54a0048b | 770 | /// |
abe05a73 | 771 | /// This will result in `recv`, `recv_from`, `send`, and `send_to` |
0731742a | 772 | /// operations becoming nonblocking, i.e., immediately returning from their |
abe05a73 XL |
773 | /// calls. If the IO operation is successful, `Ok` is returned and no |
774 | /// further action is required. If the IO operation could not be completed | |
775 | /// and needs to be retried, an error with kind | |
776 | /// [`io::ErrorKind::WouldBlock`] is returned. | |
777 | /// | |
778 | /// On Unix platforms, calling this method corresponds to calling `fcntl` | |
779 | /// `FIONBIO`. On Windows calling this method corresponds to calling | |
780 | /// `ioctlsocket` `FIONBIO`. | |
781 | /// | |
782 | /// [`io::ErrorKind::WouldBlock`]: ../io/enum.ErrorKind.html#variant.WouldBlock | |
476ff2be SL |
783 | /// |
784 | /// # Examples | |
785 | /// | |
9fa01778 | 786 | /// Creates a UDP socket bound to `127.0.0.1:7878` and read bytes in |
abe05a73 XL |
787 | /// nonblocking mode: |
788 | /// | |
476ff2be | 789 | /// ```no_run |
abe05a73 | 790 | /// use std::io; |
476ff2be SL |
791 | /// use std::net::UdpSocket; |
792 | /// | |
abe05a73 XL |
793 | /// let socket = UdpSocket::bind("127.0.0.1:7878").unwrap(); |
794 | /// socket.set_nonblocking(true).unwrap(); | |
795 | /// | |
796 | /// # fn wait_for_fd() { unimplemented!() } | |
797 | /// let mut buf = [0; 10]; | |
798 | /// let (num_bytes_read, _) = loop { | |
799 | /// match socket.recv_from(&mut buf) { | |
800 | /// Ok(n) => break n, | |
801 | /// Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => { | |
802 | /// // wait until network socket is ready, typically implemented | |
803 | /// // via platform-specific APIs such as epoll or IOCP | |
804 | /// wait_for_fd(); | |
805 | /// } | |
806 | /// Err(e) => panic!("encountered IO error: {}", e), | |
807 | /// } | |
808 | /// }; | |
809 | /// println!("bytes: {:?}", &buf[..num_bytes_read]); | |
476ff2be | 810 | /// ``` |
54a0048b SL |
811 | #[stable(feature = "net2_mutators", since = "1.9.0")] |
812 | pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { | |
813 | self.0.set_nonblocking(nonblocking) | |
814 | } | |
85aaf69f SL |
815 | } |
816 | ||
817 | impl AsInner<net_imp::UdpSocket> for UdpSocket { | |
60c5eb7d XL |
818 | fn as_inner(&self) -> &net_imp::UdpSocket { |
819 | &self.0 | |
820 | } | |
85aaf69f SL |
821 | } |
822 | ||
c34b1796 | 823 | impl FromInner<net_imp::UdpSocket> for UdpSocket { |
60c5eb7d XL |
824 | fn from_inner(inner: net_imp::UdpSocket) -> UdpSocket { |
825 | UdpSocket(inner) | |
826 | } | |
c34b1796 AL |
827 | } |
828 | ||
c1a9b12d | 829 | impl IntoInner<net_imp::UdpSocket> for UdpSocket { |
60c5eb7d XL |
830 | fn into_inner(self) -> net_imp::UdpSocket { |
831 | self.0 | |
832 | } | |
c1a9b12d SL |
833 | } |
834 | ||
92a42be0 | 835 | #[stable(feature = "rust1", since = "1.0.0")] |
d9579d0f | 836 | impl fmt::Debug for UdpSocket { |
532ac7d7 | 837 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
d9579d0f AL |
838 | self.0.fmt(f) |
839 | } | |
840 | } | |
841 | ||
532ac7d7 | 842 | #[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))] |
85aaf69f | 843 | mod tests { |
532ac7d7 | 844 | use crate::io::ErrorKind; |
532ac7d7 | 845 | use crate::net::test::{next_test_ip4, next_test_ip6}; |
60c5eb7d | 846 | use crate::net::*; |
532ac7d7 XL |
847 | use crate::sync::mpsc::channel; |
848 | use crate::sys_common::AsInner; | |
532ac7d7 | 849 | use crate::thread; |
60c5eb7d | 850 | use crate::time::{Duration, Instant}; |
85aaf69f | 851 | |
8faf50e0 | 852 | fn each_ip(f: &mut dyn FnMut(SocketAddr, SocketAddr)) { |
85aaf69f SL |
853 | f(next_test_ip4(), next_test_ip4()); |
854 | f(next_test_ip6(), next_test_ip6()); | |
855 | } | |
856 | ||
857 | macro_rules! t { | |
858 | ($e:expr) => { | |
859 | match $e { | |
860 | Ok(t) => t, | |
861 | Err(e) => panic!("received error for `{}`: {}", stringify!($e), e), | |
862 | } | |
60c5eb7d | 863 | }; |
85aaf69f SL |
864 | } |
865 | ||
85aaf69f SL |
866 | #[test] |
867 | fn bind_error() { | |
b039eaaf | 868 | match UdpSocket::bind("1.1.1.1:9999") { |
85aaf69f | 869 | Ok(..) => panic!(), |
60c5eb7d | 870 | Err(e) => assert_eq!(e.kind(), ErrorKind::AddrNotAvailable), |
85aaf69f SL |
871 | } |
872 | } | |
873 | ||
874 | #[test] | |
875 | fn socket_smoke_test_ip4() { | |
876 | each_ip(&mut |server_ip, client_ip| { | |
877 | let (tx1, rx1) = channel(); | |
878 | let (tx2, rx2) = channel(); | |
879 | ||
60c5eb7d | 880 | let _t = thread::spawn(move || { |
85aaf69f SL |
881 | let client = t!(UdpSocket::bind(&client_ip)); |
882 | rx1.recv().unwrap(); | |
883 | t!(client.send_to(&[99], &server_ip)); | |
884 | tx2.send(()).unwrap(); | |
885 | }); | |
886 | ||
887 | let server = t!(UdpSocket::bind(&server_ip)); | |
888 | tx1.send(()).unwrap(); | |
889 | let mut buf = [0]; | |
890 | let (nread, src) = t!(server.recv_from(&mut buf)); | |
891 | assert_eq!(nread, 1); | |
892 | assert_eq!(buf[0], 99); | |
893 | assert_eq!(src, client_ip); | |
894 | rx2.recv().unwrap(); | |
895 | }) | |
896 | } | |
897 | ||
898 | #[test] | |
532ac7d7 | 899 | fn socket_name() { |
85aaf69f SL |
900 | each_ip(&mut |addr, _| { |
901 | let server = t!(UdpSocket::bind(&addr)); | |
c34b1796 | 902 | assert_eq!(addr, t!(server.local_addr())); |
85aaf69f SL |
903 | }) |
904 | } | |
905 | ||
532ac7d7 XL |
906 | #[test] |
907 | fn socket_peer() { | |
908 | each_ip(&mut |addr1, addr2| { | |
909 | let server = t!(UdpSocket::bind(&addr1)); | |
910 | assert_eq!(server.peer_addr().unwrap_err().kind(), ErrorKind::NotConnected); | |
911 | t!(server.connect(&addr2)); | |
912 | assert_eq!(addr2, t!(server.peer_addr())); | |
913 | }) | |
914 | } | |
915 | ||
85aaf69f SL |
916 | #[test] |
917 | fn udp_clone_smoke() { | |
918 | each_ip(&mut |addr1, addr2| { | |
919 | let sock1 = t!(UdpSocket::bind(&addr1)); | |
920 | let sock2 = t!(UdpSocket::bind(&addr2)); | |
921 | ||
60c5eb7d | 922 | let _t = thread::spawn(move || { |
85aaf69f | 923 | let mut buf = [0, 0]; |
c34b1796 | 924 | assert_eq!(sock2.recv_from(&mut buf).unwrap(), (1, addr1)); |
85aaf69f SL |
925 | assert_eq!(buf[0], 1); |
926 | t!(sock2.send_to(&[2], &addr1)); | |
927 | }); | |
928 | ||
929 | let sock3 = t!(sock1.try_clone()); | |
930 | ||
931 | let (tx1, rx1) = channel(); | |
932 | let (tx2, rx2) = channel(); | |
60c5eb7d | 933 | let _t = thread::spawn(move || { |
85aaf69f SL |
934 | rx1.recv().unwrap(); |
935 | t!(sock3.send_to(&[1], &addr2)); | |
936 | tx2.send(()).unwrap(); | |
937 | }); | |
938 | tx1.send(()).unwrap(); | |
939 | let mut buf = [0, 0]; | |
c34b1796 | 940 | assert_eq!(sock1.recv_from(&mut buf).unwrap(), (1, addr2)); |
85aaf69f SL |
941 | rx2.recv().unwrap(); |
942 | }) | |
943 | } | |
944 | ||
945 | #[test] | |
946 | fn udp_clone_two_read() { | |
947 | each_ip(&mut |addr1, addr2| { | |
948 | let sock1 = t!(UdpSocket::bind(&addr1)); | |
949 | let sock2 = t!(UdpSocket::bind(&addr2)); | |
950 | let (tx1, rx) = channel(); | |
951 | let tx2 = tx1.clone(); | |
952 | ||
60c5eb7d | 953 | let _t = thread::spawn(move || { |
85aaf69f SL |
954 | t!(sock2.send_to(&[1], &addr1)); |
955 | rx.recv().unwrap(); | |
956 | t!(sock2.send_to(&[2], &addr1)); | |
957 | rx.recv().unwrap(); | |
958 | }); | |
959 | ||
960 | let sock3 = t!(sock1.try_clone()); | |
961 | ||
962 | let (done, rx) = channel(); | |
60c5eb7d | 963 | let _t = thread::spawn(move || { |
85aaf69f SL |
964 | let mut buf = [0, 0]; |
965 | t!(sock3.recv_from(&mut buf)); | |
966 | tx2.send(()).unwrap(); | |
967 | done.send(()).unwrap(); | |
968 | }); | |
969 | let mut buf = [0, 0]; | |
970 | t!(sock1.recv_from(&mut buf)); | |
971 | tx1.send(()).unwrap(); | |
972 | ||
973 | rx.recv().unwrap(); | |
974 | }) | |
975 | } | |
976 | ||
977 | #[test] | |
978 | fn udp_clone_two_write() { | |
979 | each_ip(&mut |addr1, addr2| { | |
980 | let sock1 = t!(UdpSocket::bind(&addr1)); | |
981 | let sock2 = t!(UdpSocket::bind(&addr2)); | |
982 | ||
983 | let (tx, rx) = channel(); | |
984 | let (serv_tx, serv_rx) = channel(); | |
985 | ||
60c5eb7d | 986 | let _t = thread::spawn(move || { |
85aaf69f SL |
987 | let mut buf = [0, 1]; |
988 | rx.recv().unwrap(); | |
989 | t!(sock2.recv_from(&mut buf)); | |
990 | serv_tx.send(()).unwrap(); | |
991 | }); | |
992 | ||
993 | let sock3 = t!(sock1.try_clone()); | |
994 | ||
995 | let (done, rx) = channel(); | |
996 | let tx2 = tx.clone(); | |
60c5eb7d | 997 | let _t = thread::spawn(move || { |
85aaf69f | 998 | match sock3.send_to(&[1], &addr2) { |
60c5eb7d XL |
999 | Ok(..) => { |
1000 | let _ = tx2.send(()); | |
1001 | } | |
85aaf69f SL |
1002 | Err(..) => {} |
1003 | } | |
1004 | done.send(()).unwrap(); | |
1005 | }); | |
1006 | match sock1.send_to(&[2], &addr2) { | |
60c5eb7d XL |
1007 | Ok(..) => { |
1008 | let _ = tx.send(()); | |
1009 | } | |
85aaf69f SL |
1010 | Err(..) => {} |
1011 | } | |
1012 | drop(tx); | |
1013 | ||
1014 | rx.recv().unwrap(); | |
1015 | serv_rx.recv().unwrap(); | |
1016 | }) | |
1017 | } | |
d9579d0f AL |
1018 | |
1019 | #[test] | |
1020 | fn debug() { | |
60c5eb7d | 1021 | let name = if cfg!(windows) { "socket" } else { "fd" }; |
d9579d0f AL |
1022 | let socket_addr = next_test_ip4(); |
1023 | ||
1024 | let udpsock = t!(UdpSocket::bind(&socket_addr)); | |
1025 | let udpsock_inner = udpsock.0.socket().as_inner(); | |
60c5eb7d XL |
1026 | let compare = |
1027 | format!("UdpSocket {{ addr: {:?}, {}: {:?} }}", socket_addr, name, udpsock_inner); | |
d9579d0f AL |
1028 | assert_eq!(format!("{:?}", udpsock), compare); |
1029 | } | |
62682a34 | 1030 | |
48663c56 | 1031 | // FIXME: re-enabled openbsd/netbsd tests once their socket timeout code |
62682a34 | 1032 | // no longer has rounding errors. |
e1599b0c XL |
1033 | // VxWorks ignores SO_SNDTIMEO. |
1034 | #[cfg_attr(any(target_os = "netbsd", target_os = "openbsd", target_os = "vxworks"), ignore)] | |
62682a34 SL |
1035 | #[test] |
1036 | fn timeouts() { | |
1037 | let addr = next_test_ip4(); | |
1038 | ||
1039 | let stream = t!(UdpSocket::bind(&addr)); | |
1040 | let dur = Duration::new(15410, 0); | |
1041 | ||
1042 | assert_eq!(None, t!(stream.read_timeout())); | |
1043 | ||
1044 | t!(stream.set_read_timeout(Some(dur))); | |
1045 | assert_eq!(Some(dur), t!(stream.read_timeout())); | |
1046 | ||
1047 | assert_eq!(None, t!(stream.write_timeout())); | |
1048 | ||
1049 | t!(stream.set_write_timeout(Some(dur))); | |
1050 | assert_eq!(Some(dur), t!(stream.write_timeout())); | |
1051 | ||
1052 | t!(stream.set_read_timeout(None)); | |
1053 | assert_eq!(None, t!(stream.read_timeout())); | |
1054 | ||
1055 | t!(stream.set_write_timeout(None)); | |
1056 | assert_eq!(None, t!(stream.write_timeout())); | |
1057 | } | |
1058 | ||
1059 | #[test] | |
1060 | fn test_read_timeout() { | |
1061 | let addr = next_test_ip4(); | |
1062 | ||
9cc50fc6 | 1063 | let stream = t!(UdpSocket::bind(&addr)); |
62682a34 SL |
1064 | t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); |
1065 | ||
1066 | let mut buf = [0; 10]; | |
9cc50fc6 SL |
1067 | |
1068 | let start = Instant::now(); | |
a1dfa0c6 XL |
1069 | loop { |
1070 | let kind = stream.recv_from(&mut buf).err().expect("expected error").kind(); | |
1071 | if kind != ErrorKind::Interrupted { | |
60c5eb7d XL |
1072 | assert!( |
1073 | kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, | |
1074 | "unexpected_error: {:?}", | |
1075 | kind | |
1076 | ); | |
a1dfa0c6 XL |
1077 | break; |
1078 | } | |
1079 | } | |
9cc50fc6 | 1080 | assert!(start.elapsed() > Duration::from_millis(400)); |
62682a34 SL |
1081 | } |
1082 | ||
1083 | #[test] | |
1084 | fn test_read_with_timeout() { | |
1085 | let addr = next_test_ip4(); | |
1086 | ||
9cc50fc6 | 1087 | let stream = t!(UdpSocket::bind(&addr)); |
62682a34 SL |
1088 | t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); |
1089 | ||
1090 | t!(stream.send_to(b"hello world", &addr)); | |
1091 | ||
1092 | let mut buf = [0; 11]; | |
1093 | t!(stream.recv_from(&mut buf)); | |
1094 | assert_eq!(b"hello world", &buf[..]); | |
1095 | ||
9cc50fc6 | 1096 | let start = Instant::now(); |
a1dfa0c6 XL |
1097 | loop { |
1098 | let kind = stream.recv_from(&mut buf).err().expect("expected error").kind(); | |
1099 | if kind != ErrorKind::Interrupted { | |
60c5eb7d XL |
1100 | assert!( |
1101 | kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, | |
1102 | "unexpected_error: {:?}", | |
1103 | kind | |
1104 | ); | |
a1dfa0c6 XL |
1105 | break; |
1106 | } | |
1107 | } | |
9cc50fc6 | 1108 | assert!(start.elapsed() > Duration::from_millis(400)); |
62682a34 | 1109 | } |
54a0048b | 1110 | |
0531ce1d XL |
1111 | // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors |
1112 | // when passed zero Durations | |
1113 | #[test] | |
1114 | fn test_timeout_zero_duration() { | |
1115 | let addr = next_test_ip4(); | |
1116 | ||
1117 | let socket = t!(UdpSocket::bind(&addr)); | |
1118 | ||
1119 | let result = socket.set_write_timeout(Some(Duration::new(0, 0))); | |
1120 | let err = result.unwrap_err(); | |
1121 | assert_eq!(err.kind(), ErrorKind::InvalidInput); | |
1122 | ||
1123 | let result = socket.set_read_timeout(Some(Duration::new(0, 0))); | |
1124 | let err = result.unwrap_err(); | |
1125 | assert_eq!(err.kind(), ErrorKind::InvalidInput); | |
1126 | } | |
1127 | ||
54a0048b SL |
1128 | #[test] |
1129 | fn connect_send_recv() { | |
1130 | let addr = next_test_ip4(); | |
1131 | ||
1132 | let socket = t!(UdpSocket::bind(&addr)); | |
1133 | t!(socket.connect(addr)); | |
1134 | ||
1135 | t!(socket.send(b"hello world")); | |
1136 | ||
1137 | let mut buf = [0; 11]; | |
1138 | t!(socket.recv(&mut buf)); | |
1139 | assert_eq!(b"hello world", &buf[..]); | |
1140 | } | |
1141 | ||
8bb4bdeb XL |
1142 | #[test] |
1143 | fn connect_send_peek_recv() { | |
1144 | each_ip(&mut |addr, _| { | |
1145 | let socket = t!(UdpSocket::bind(&addr)); | |
1146 | t!(socket.connect(addr)); | |
1147 | ||
1148 | t!(socket.send(b"hello world")); | |
1149 | ||
1150 | for _ in 1..3 { | |
1151 | let mut buf = [0; 11]; | |
1152 | let size = t!(socket.peek(&mut buf)); | |
1153 | assert_eq!(b"hello world", &buf[..]); | |
1154 | assert_eq!(size, 11); | |
1155 | } | |
1156 | ||
1157 | let mut buf = [0; 11]; | |
1158 | let size = t!(socket.recv(&mut buf)); | |
1159 | assert_eq!(b"hello world", &buf[..]); | |
1160 | assert_eq!(size, 11); | |
1161 | }) | |
1162 | } | |
1163 | ||
1164 | #[test] | |
1165 | fn peek_from() { | |
1166 | each_ip(&mut |addr, _| { | |
1167 | let socket = t!(UdpSocket::bind(&addr)); | |
1168 | t!(socket.send_to(b"hello world", &addr)); | |
1169 | ||
1170 | for _ in 1..3 { | |
1171 | let mut buf = [0; 11]; | |
1172 | let (size, _) = t!(socket.peek_from(&mut buf)); | |
1173 | assert_eq!(b"hello world", &buf[..]); | |
1174 | assert_eq!(size, 11); | |
1175 | } | |
1176 | ||
1177 | let mut buf = [0; 11]; | |
1178 | let (size, _) = t!(socket.recv_from(&mut buf)); | |
1179 | assert_eq!(b"hello world", &buf[..]); | |
1180 | assert_eq!(size, 11); | |
1181 | }) | |
1182 | } | |
1183 | ||
54a0048b SL |
1184 | #[test] |
1185 | fn ttl() { | |
1186 | let ttl = 100; | |
1187 | ||
1188 | let addr = next_test_ip4(); | |
1189 | ||
1190 | let stream = t!(UdpSocket::bind(&addr)); | |
1191 | ||
1192 | t!(stream.set_ttl(ttl)); | |
1193 | assert_eq!(ttl, t!(stream.ttl())); | |
1194 | } | |
1195 | ||
1196 | #[test] | |
1197 | fn set_nonblocking() { | |
32a655c1 SL |
1198 | each_ip(&mut |addr, _| { |
1199 | let socket = t!(UdpSocket::bind(&addr)); | |
54a0048b | 1200 | |
32a655c1 SL |
1201 | t!(socket.set_nonblocking(true)); |
1202 | t!(socket.set_nonblocking(false)); | |
1203 | ||
1204 | t!(socket.connect(addr)); | |
54a0048b | 1205 | |
32a655c1 SL |
1206 | t!(socket.set_nonblocking(false)); |
1207 | t!(socket.set_nonblocking(true)); | |
1208 | ||
1209 | let mut buf = [0]; | |
1210 | match socket.recv(&mut buf) { | |
1211 | Ok(_) => panic!("expected error"), | |
1212 | Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} | |
1213 | Err(e) => panic!("unexpected error {}", e), | |
1214 | } | |
1215 | }) | |
54a0048b | 1216 | } |
85aaf69f | 1217 | } |