]>
Commit | Line | Data |
---|---|---|
85aaf69f SL |
1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
d9579d0f | 11 | use fmt; |
85aaf69f | 12 | use io::{self, Error, ErrorKind}; |
54a0048b | 13 | use net::{ToSocketAddrs, SocketAddr, Ipv4Addr, Ipv6Addr}; |
d9579d0f | 14 | use sys_common::net as net_imp; |
c1a9b12d | 15 | use sys_common::{AsInner, FromInner, IntoInner}; |
62682a34 | 16 | use time::Duration; |
85aaf69f SL |
17 | |
18 | /// A User Datagram Protocol socket. | |
19 | /// | |
20 | /// This is an implementation of a bound UDP socket. This supports both IPv4 and | |
21 | /// IPv6 addresses, and there is no corresponding notion of a server because UDP | |
22 | /// is a datagram protocol. | |
23 | /// | |
c34b1796 | 24 | /// # Examples |
85aaf69f SL |
25 | /// |
26 | /// ```no_run | |
27 | /// use std::net::UdpSocket; | |
28 | /// | |
29 | /// # fn foo() -> std::io::Result<()> { | |
9cc50fc6 SL |
30 | /// { |
31 | /// let mut socket = try!(UdpSocket::bind("127.0.0.1:34254")); | |
85aaf69f | 32 | /// |
9cc50fc6 SL |
33 | /// // read from the socket |
34 | /// let mut buf = [0; 10]; | |
35 | /// let (amt, src) = try!(socket.recv_from(&mut buf)); | |
85aaf69f | 36 | /// |
9cc50fc6 SL |
37 | /// // send a reply to the socket we received data from |
38 | /// let buf = &mut buf[..amt]; | |
39 | /// buf.reverse(); | |
40 | /// try!(socket.send_to(buf, &src)); | |
41 | /// # Ok(()) | |
42 | /// } // the socket is closed here | |
85aaf69f SL |
43 | /// # } |
44 | /// ``` | |
c34b1796 | 45 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
46 | pub struct UdpSocket(net_imp::UdpSocket); |
47 | ||
48 | impl UdpSocket { | |
49 | /// Creates a UDP socket from the given address. | |
50 | /// | |
bd371182 AL |
51 | /// The address type can be any implementor of `ToSocketAddr` trait. See |
52 | /// its documentation for concrete examples. | |
c34b1796 AL |
53 | #[stable(feature = "rust1", since = "1.0.0")] |
54 | pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<UdpSocket> { | |
85aaf69f SL |
55 | super::each_addr(addr, net_imp::UdpSocket::bind).map(UdpSocket) |
56 | } | |
57 | ||
58 | /// Receives data from the socket. On success, returns the number of bytes | |
59 | /// read and the address from whence the data came. | |
c34b1796 | 60 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
61 | pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { |
62 | self.0.recv_from(buf) | |
63 | } | |
64 | ||
bd371182 AL |
65 | /// Sends data on the socket to the given address. On success, returns the |
66 | /// number of bytes written. | |
85aaf69f SL |
67 | /// |
68 | /// Address type can be any implementor of `ToSocketAddrs` trait. See its | |
69 | /// documentation for concrete examples. | |
c34b1796 AL |
70 | #[stable(feature = "rust1", since = "1.0.0")] |
71 | pub fn send_to<A: ToSocketAddrs>(&self, buf: &[u8], addr: A) | |
72 | -> io::Result<usize> { | |
54a0048b | 73 | match addr.to_socket_addrs()?.next() { |
85aaf69f SL |
74 | Some(addr) => self.0.send_to(buf, &addr), |
75 | None => Err(Error::new(ErrorKind::InvalidInput, | |
c34b1796 | 76 | "no addresses to send data to")), |
85aaf69f SL |
77 | } |
78 | } | |
79 | ||
80 | /// Returns the socket address that this socket was created from. | |
c34b1796 AL |
81 | #[stable(feature = "rust1", since = "1.0.0")] |
82 | pub fn local_addr(&self) -> io::Result<SocketAddr> { | |
85aaf69f SL |
83 | self.0.socket_addr() |
84 | } | |
85 | ||
9346a6ac | 86 | /// Creates a new independently owned handle to the underlying socket. |
85aaf69f SL |
87 | /// |
88 | /// The returned `UdpSocket` is a reference to the same socket that this | |
89 | /// object references. Both handles will read and write the same port, and | |
90 | /// options set on one socket will be propagated to the other. | |
c34b1796 | 91 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
92 | pub fn try_clone(&self) -> io::Result<UdpSocket> { |
93 | self.0.duplicate().map(UdpSocket) | |
94 | } | |
95 | ||
62682a34 SL |
96 | /// Sets the read timeout to the timeout specified. |
97 | /// | |
98 | /// If the value specified is `None`, then `read` calls will block | |
99 | /// indefinitely. It is an error to pass the zero `Duration` to this | |
100 | /// method. | |
e9174d1e SL |
101 | /// |
102 | /// # Note | |
103 | /// | |
104 | /// Platforms may return a different error code whenever a read times out as | |
105 | /// a result of setting this option. For example Unix typically returns an | |
106 | /// error of the kind `WouldBlock`, but Windows may return `TimedOut`. | |
107 | #[stable(feature = "socket_timeout", since = "1.4.0")] | |
62682a34 SL |
108 | pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> { |
109 | self.0.set_read_timeout(dur) | |
110 | } | |
111 | ||
112 | /// Sets the write timeout to the timeout specified. | |
113 | /// | |
114 | /// If the value specified is `None`, then `write` calls will block | |
115 | /// indefinitely. It is an error to pass the zero `Duration` to this | |
116 | /// method. | |
e9174d1e SL |
117 | /// |
118 | /// # Note | |
119 | /// | |
120 | /// Platforms may return a different error code whenever a write times out | |
121 | /// as a result of setting this option. For example Unix typically returns | |
122 | /// an error of the kind `WouldBlock`, but Windows may return `TimedOut`. | |
123 | #[stable(feature = "socket_timeout", since = "1.4.0")] | |
62682a34 SL |
124 | pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> { |
125 | self.0.set_write_timeout(dur) | |
126 | } | |
127 | ||
128 | /// Returns the read timeout of this socket. | |
129 | /// | |
130 | /// If the timeout is `None`, then `read` calls will block indefinitely. | |
e9174d1e | 131 | #[stable(feature = "socket_timeout", since = "1.4.0")] |
62682a34 SL |
132 | pub fn read_timeout(&self) -> io::Result<Option<Duration>> { |
133 | self.0.read_timeout() | |
134 | } | |
135 | ||
136 | /// Returns the write timeout of this socket. | |
137 | /// | |
138 | /// If the timeout is `None`, then `write` calls will block indefinitely. | |
e9174d1e | 139 | #[stable(feature = "socket_timeout", since = "1.4.0")] |
62682a34 SL |
140 | pub fn write_timeout(&self) -> io::Result<Option<Duration>> { |
141 | self.0.write_timeout() | |
142 | } | |
54a0048b SL |
143 | |
144 | /// Sets the value of the `SO_BROADCAST` option for this socket. | |
145 | /// | |
146 | /// When enabled, this socket is allowed to send packets to a broadcast | |
147 | /// address. | |
148 | #[stable(feature = "net2_mutators", since = "1.9.0")] | |
149 | pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> { | |
150 | self.0.set_broadcast(broadcast) | |
151 | } | |
152 | ||
153 | /// Gets the value of the `SO_BROADCAST` option for this socket. | |
154 | /// | |
155 | /// For more information about this option, see | |
156 | /// [`set_broadcast`][link]. | |
157 | /// | |
158 | /// [link]: #method.set_broadcast | |
159 | #[stable(feature = "net2_mutators", since = "1.9.0")] | |
160 | pub fn broadcast(&self) -> io::Result<bool> { | |
161 | self.0.broadcast() | |
162 | } | |
163 | ||
164 | /// Sets the value of the `IP_MULTICAST_LOOP` option for this socket. | |
165 | /// | |
166 | /// If enabled, multicast packets will be looped back to the local socket. | |
167 | /// Note that this may not have any affect on IPv6 sockets. | |
168 | #[stable(feature = "net2_mutators", since = "1.9.0")] | |
169 | pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> { | |
170 | self.0.set_multicast_loop_v4(multicast_loop_v4) | |
171 | } | |
172 | ||
173 | /// Gets the value of the `IP_MULTICAST_LOOP` option for this socket. | |
174 | /// | |
175 | /// For more information about this option, see | |
176 | /// [`set_multicast_loop_v4`][link]. | |
177 | /// | |
178 | /// [link]: #method.set_multicast_loop_v4 | |
179 | #[stable(feature = "net2_mutators", since = "1.9.0")] | |
180 | pub fn multicast_loop_v4(&self) -> io::Result<bool> { | |
181 | self.0.multicast_loop_v4() | |
182 | } | |
183 | ||
184 | /// Sets the value of the `IP_MULTICAST_TTL` option for this socket. | |
185 | /// | |
186 | /// Indicates the time-to-live value of outgoing multicast packets for | |
187 | /// this socket. The default value is 1 which means that multicast packets | |
188 | /// don't leave the local network unless explicitly requested. | |
189 | /// | |
190 | /// Note that this may not have any affect on IPv6 sockets. | |
191 | #[stable(feature = "net2_mutators", since = "1.9.0")] | |
192 | pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> { | |
193 | self.0.set_multicast_ttl_v4(multicast_ttl_v4) | |
194 | } | |
195 | ||
196 | /// Gets the value of the `IP_MULTICAST_TTL` option for this socket. | |
197 | /// | |
198 | /// For more information about this option, see | |
199 | /// [`set_multicast_ttl_v4`][link]. | |
200 | /// | |
201 | /// [link]: #method.set_multicast_ttl_v4 | |
202 | #[stable(feature = "net2_mutators", since = "1.9.0")] | |
203 | pub fn multicast_ttl_v4(&self) -> io::Result<u32> { | |
204 | self.0.multicast_ttl_v4() | |
205 | } | |
206 | ||
207 | /// Sets the value of the `IPV6_MULTICAST_LOOP` option for this socket. | |
208 | /// | |
209 | /// Controls whether this socket sees the multicast packets it sends itself. | |
210 | /// Note that this may not have any affect on IPv4 sockets. | |
211 | #[stable(feature = "net2_mutators", since = "1.9.0")] | |
212 | pub fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> { | |
213 | self.0.set_multicast_loop_v6(multicast_loop_v6) | |
214 | } | |
215 | ||
216 | /// Gets the value of the `IPV6_MULTICAST_LOOP` option for this socket. | |
217 | /// | |
218 | /// For more information about this option, see | |
219 | /// [`set_multicast_loop_v6`][link]. | |
220 | /// | |
221 | /// [link]: #method.set_multicast_loop_v6 | |
222 | #[stable(feature = "net2_mutators", since = "1.9.0")] | |
223 | pub fn multicast_loop_v6(&self) -> io::Result<bool> { | |
224 | self.0.multicast_loop_v6() | |
225 | } | |
226 | ||
227 | /// Sets the value for the `IP_TTL` option on this socket. | |
228 | /// | |
229 | /// This value sets the time-to-live field that is used in every packet sent | |
230 | /// from this socket. | |
231 | #[stable(feature = "net2_mutators", since = "1.9.0")] | |
232 | pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { | |
233 | self.0.set_ttl(ttl) | |
234 | } | |
235 | ||
236 | /// Gets the value of the `IP_TTL` option for this socket. | |
237 | /// | |
238 | /// For more information about this option, see [`set_ttl`][link]. | |
239 | /// | |
240 | /// [link]: #method.set_ttl | |
241 | #[stable(feature = "net2_mutators", since = "1.9.0")] | |
242 | pub fn ttl(&self) -> io::Result<u32> { | |
243 | self.0.ttl() | |
244 | } | |
245 | ||
246 | /// Executes an operation of the `IP_ADD_MEMBERSHIP` type. | |
247 | /// | |
248 | /// This function specifies a new multicast group for this socket to join. | |
249 | /// The address must be a valid multicast address, and `interface` is the | |
250 | /// address of the local interface with which the system should join the | |
251 | /// multicast group. If it's equal to `INADDR_ANY` then an appropriate | |
252 | /// interface is chosen by the system. | |
253 | #[stable(feature = "net2_mutators", since = "1.9.0")] | |
254 | pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { | |
255 | self.0.join_multicast_v4(multiaddr, interface) | |
256 | } | |
257 | ||
258 | /// Executes an operation of the `IPV6_ADD_MEMBERSHIP` type. | |
259 | /// | |
260 | /// This function specifies a new multicast group for this socket to join. | |
261 | /// The address must be a valid multicast address, and `interface` is the | |
262 | /// index of the interface to join/leave (or 0 to indicate any interface). | |
263 | #[stable(feature = "net2_mutators", since = "1.9.0")] | |
264 | pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { | |
265 | self.0.join_multicast_v6(multiaddr, interface) | |
266 | } | |
267 | ||
268 | /// Executes an operation of the `IP_DROP_MEMBERSHIP` type. | |
269 | /// | |
270 | /// For more information about this option, see | |
271 | /// [`join_multicast_v4`][link]. | |
272 | /// | |
273 | /// [link]: #method.join_multicast_v4 | |
274 | #[stable(feature = "net2_mutators", since = "1.9.0")] | |
275 | pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { | |
276 | self.0.leave_multicast_v4(multiaddr, interface) | |
277 | } | |
278 | ||
279 | /// Executes an operation of the `IPV6_DROP_MEMBERSHIP` type. | |
280 | /// | |
281 | /// For more information about this option, see | |
282 | /// [`join_multicast_v6`][link]. | |
283 | /// | |
284 | /// [link]: #method.join_multicast_v6 | |
285 | #[stable(feature = "net2_mutators", since = "1.9.0")] | |
286 | pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { | |
287 | self.0.leave_multicast_v6(multiaddr, interface) | |
288 | } | |
289 | ||
290 | /// Get the value of the `SO_ERROR` option on this socket. | |
291 | /// | |
292 | /// This will retrieve the stored error in the underlying socket, clearing | |
293 | /// the field in the process. This can be useful for checking errors between | |
294 | /// calls. | |
295 | #[stable(feature = "net2_mutators", since = "1.9.0")] | |
296 | pub fn take_error(&self) -> io::Result<Option<io::Error>> { | |
297 | self.0.take_error() | |
298 | } | |
299 | ||
300 | /// Connects this UDP socket to a remote address, allowing the `send` and | |
301 | /// `recv` syscalls to be used to send data and also applies filters to only | |
302 | /// receive data from the specified address. | |
303 | #[stable(feature = "net2_mutators", since = "1.9.0")] | |
304 | pub fn connect<A: ToSocketAddrs>(&self, addr: A) -> io::Result<()> { | |
305 | super::each_addr(addr, |addr| self.0.connect(addr)) | |
306 | } | |
307 | ||
308 | /// Sends data on the socket to the remote address to which it is connected. | |
309 | /// | |
310 | /// The `connect` method will connect this socket to a remote address. This | |
311 | /// method will fail if the socket is not connected. | |
312 | #[stable(feature = "net2_mutators", since = "1.9.0")] | |
313 | pub fn send(&self, buf: &[u8]) -> io::Result<usize> { | |
314 | self.0.send(buf) | |
315 | } | |
316 | ||
317 | /// Receives data on the socket from the remote address to which it is | |
318 | /// connected. | |
319 | /// | |
320 | /// The `connect` method will connect this socket to a remote address. This | |
321 | /// method will fail if the socket is not connected. | |
322 | #[stable(feature = "net2_mutators", since = "1.9.0")] | |
323 | pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> { | |
324 | self.0.recv(buf) | |
325 | } | |
326 | ||
a7813a04 | 327 | /// Moves this UDP socket into or out of nonblocking mode. |
54a0048b SL |
328 | /// |
329 | /// On Unix this corresponds to calling fcntl, and on Windows this | |
330 | /// corresponds to calling ioctlsocket. | |
331 | #[stable(feature = "net2_mutators", since = "1.9.0")] | |
332 | pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { | |
333 | self.0.set_nonblocking(nonblocking) | |
334 | } | |
85aaf69f SL |
335 | } |
336 | ||
337 | impl AsInner<net_imp::UdpSocket> for UdpSocket { | |
338 | fn as_inner(&self) -> &net_imp::UdpSocket { &self.0 } | |
339 | } | |
340 | ||
c34b1796 AL |
341 | impl FromInner<net_imp::UdpSocket> for UdpSocket { |
342 | fn from_inner(inner: net_imp::UdpSocket) -> UdpSocket { UdpSocket(inner) } | |
343 | } | |
344 | ||
c1a9b12d SL |
345 | impl IntoInner<net_imp::UdpSocket> for UdpSocket { |
346 | fn into_inner(self) -> net_imp::UdpSocket { self.0 } | |
347 | } | |
348 | ||
92a42be0 | 349 | #[stable(feature = "rust1", since = "1.0.0")] |
d9579d0f AL |
350 | impl fmt::Debug for UdpSocket { |
351 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
352 | self.0.fmt(f) | |
353 | } | |
354 | } | |
355 | ||
c30ab7b3 | 356 | #[cfg(all(test, not(target_os = "emscripten")))] |
85aaf69f | 357 | mod tests { |
85aaf69f SL |
358 | use io::ErrorKind; |
359 | use net::*; | |
360 | use net::test::{next_test_ip4, next_test_ip6}; | |
361 | use sync::mpsc::channel; | |
d9579d0f | 362 | use sys_common::AsInner; |
9cc50fc6 | 363 | use time::{Instant, Duration}; |
85aaf69f SL |
364 | use thread; |
365 | ||
366 | fn each_ip(f: &mut FnMut(SocketAddr, SocketAddr)) { | |
367 | f(next_test_ip4(), next_test_ip4()); | |
368 | f(next_test_ip6(), next_test_ip6()); | |
369 | } | |
370 | ||
371 | macro_rules! t { | |
372 | ($e:expr) => { | |
373 | match $e { | |
374 | Ok(t) => t, | |
375 | Err(e) => panic!("received error for `{}`: {}", stringify!($e), e), | |
376 | } | |
377 | } | |
378 | } | |
379 | ||
85aaf69f SL |
380 | #[test] |
381 | fn bind_error() { | |
b039eaaf | 382 | match UdpSocket::bind("1.1.1.1:9999") { |
85aaf69f | 383 | Ok(..) => panic!(), |
b039eaaf SL |
384 | Err(e) => { |
385 | assert_eq!(e.kind(), ErrorKind::AddrNotAvailable) | |
386 | } | |
85aaf69f SL |
387 | } |
388 | } | |
389 | ||
390 | #[test] | |
391 | fn socket_smoke_test_ip4() { | |
392 | each_ip(&mut |server_ip, client_ip| { | |
393 | let (tx1, rx1) = channel(); | |
394 | let (tx2, rx2) = channel(); | |
395 | ||
396 | let _t = thread::spawn(move|| { | |
397 | let client = t!(UdpSocket::bind(&client_ip)); | |
398 | rx1.recv().unwrap(); | |
399 | t!(client.send_to(&[99], &server_ip)); | |
400 | tx2.send(()).unwrap(); | |
401 | }); | |
402 | ||
403 | let server = t!(UdpSocket::bind(&server_ip)); | |
404 | tx1.send(()).unwrap(); | |
405 | let mut buf = [0]; | |
406 | let (nread, src) = t!(server.recv_from(&mut buf)); | |
407 | assert_eq!(nread, 1); | |
408 | assert_eq!(buf[0], 99); | |
409 | assert_eq!(src, client_ip); | |
410 | rx2.recv().unwrap(); | |
411 | }) | |
412 | } | |
413 | ||
414 | #[test] | |
415 | fn socket_name_ip4() { | |
416 | each_ip(&mut |addr, _| { | |
417 | let server = t!(UdpSocket::bind(&addr)); | |
c34b1796 | 418 | assert_eq!(addr, t!(server.local_addr())); |
85aaf69f SL |
419 | }) |
420 | } | |
421 | ||
422 | #[test] | |
423 | fn udp_clone_smoke() { | |
424 | each_ip(&mut |addr1, addr2| { | |
425 | let sock1 = t!(UdpSocket::bind(&addr1)); | |
426 | let sock2 = t!(UdpSocket::bind(&addr2)); | |
427 | ||
428 | let _t = thread::spawn(move|| { | |
429 | let mut buf = [0, 0]; | |
c34b1796 | 430 | assert_eq!(sock2.recv_from(&mut buf).unwrap(), (1, addr1)); |
85aaf69f SL |
431 | assert_eq!(buf[0], 1); |
432 | t!(sock2.send_to(&[2], &addr1)); | |
433 | }); | |
434 | ||
435 | let sock3 = t!(sock1.try_clone()); | |
436 | ||
437 | let (tx1, rx1) = channel(); | |
438 | let (tx2, rx2) = channel(); | |
439 | let _t = thread::spawn(move|| { | |
440 | rx1.recv().unwrap(); | |
441 | t!(sock3.send_to(&[1], &addr2)); | |
442 | tx2.send(()).unwrap(); | |
443 | }); | |
444 | tx1.send(()).unwrap(); | |
445 | let mut buf = [0, 0]; | |
c34b1796 | 446 | assert_eq!(sock1.recv_from(&mut buf).unwrap(), (1, addr2)); |
85aaf69f SL |
447 | rx2.recv().unwrap(); |
448 | }) | |
449 | } | |
450 | ||
451 | #[test] | |
452 | fn udp_clone_two_read() { | |
453 | each_ip(&mut |addr1, addr2| { | |
454 | let sock1 = t!(UdpSocket::bind(&addr1)); | |
455 | let sock2 = t!(UdpSocket::bind(&addr2)); | |
456 | let (tx1, rx) = channel(); | |
457 | let tx2 = tx1.clone(); | |
458 | ||
459 | let _t = thread::spawn(move|| { | |
460 | t!(sock2.send_to(&[1], &addr1)); | |
461 | rx.recv().unwrap(); | |
462 | t!(sock2.send_to(&[2], &addr1)); | |
463 | rx.recv().unwrap(); | |
464 | }); | |
465 | ||
466 | let sock3 = t!(sock1.try_clone()); | |
467 | ||
468 | let (done, rx) = channel(); | |
469 | let _t = thread::spawn(move|| { | |
470 | let mut buf = [0, 0]; | |
471 | t!(sock3.recv_from(&mut buf)); | |
472 | tx2.send(()).unwrap(); | |
473 | done.send(()).unwrap(); | |
474 | }); | |
475 | let mut buf = [0, 0]; | |
476 | t!(sock1.recv_from(&mut buf)); | |
477 | tx1.send(()).unwrap(); | |
478 | ||
479 | rx.recv().unwrap(); | |
480 | }) | |
481 | } | |
482 | ||
483 | #[test] | |
484 | fn udp_clone_two_write() { | |
485 | each_ip(&mut |addr1, addr2| { | |
486 | let sock1 = t!(UdpSocket::bind(&addr1)); | |
487 | let sock2 = t!(UdpSocket::bind(&addr2)); | |
488 | ||
489 | let (tx, rx) = channel(); | |
490 | let (serv_tx, serv_rx) = channel(); | |
491 | ||
492 | let _t = thread::spawn(move|| { | |
493 | let mut buf = [0, 1]; | |
494 | rx.recv().unwrap(); | |
495 | t!(sock2.recv_from(&mut buf)); | |
496 | serv_tx.send(()).unwrap(); | |
497 | }); | |
498 | ||
499 | let sock3 = t!(sock1.try_clone()); | |
500 | ||
501 | let (done, rx) = channel(); | |
502 | let tx2 = tx.clone(); | |
503 | let _t = thread::spawn(move|| { | |
504 | match sock3.send_to(&[1], &addr2) { | |
505 | Ok(..) => { let _ = tx2.send(()); } | |
506 | Err(..) => {} | |
507 | } | |
508 | done.send(()).unwrap(); | |
509 | }); | |
510 | match sock1.send_to(&[2], &addr2) { | |
511 | Ok(..) => { let _ = tx.send(()); } | |
512 | Err(..) => {} | |
513 | } | |
514 | drop(tx); | |
515 | ||
516 | rx.recv().unwrap(); | |
517 | serv_rx.recv().unwrap(); | |
518 | }) | |
519 | } | |
d9579d0f AL |
520 | |
521 | #[test] | |
522 | fn debug() { | |
523 | let name = if cfg!(windows) {"socket"} else {"fd"}; | |
524 | let socket_addr = next_test_ip4(); | |
525 | ||
526 | let udpsock = t!(UdpSocket::bind(&socket_addr)); | |
527 | let udpsock_inner = udpsock.0.socket().as_inner(); | |
528 | let compare = format!("UdpSocket {{ addr: {:?}, {}: {:?} }}", | |
529 | socket_addr, name, udpsock_inner); | |
530 | assert_eq!(format!("{:?}", udpsock), compare); | |
531 | } | |
62682a34 | 532 | |
c1a9b12d | 533 | // FIXME: re-enabled bitrig/openbsd/netbsd tests once their socket timeout code |
62682a34 | 534 | // no longer has rounding errors. |
c1a9b12d | 535 | #[cfg_attr(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"), ignore)] |
62682a34 SL |
536 | #[test] |
537 | fn timeouts() { | |
538 | let addr = next_test_ip4(); | |
539 | ||
540 | let stream = t!(UdpSocket::bind(&addr)); | |
541 | let dur = Duration::new(15410, 0); | |
542 | ||
543 | assert_eq!(None, t!(stream.read_timeout())); | |
544 | ||
545 | t!(stream.set_read_timeout(Some(dur))); | |
546 | assert_eq!(Some(dur), t!(stream.read_timeout())); | |
547 | ||
548 | assert_eq!(None, t!(stream.write_timeout())); | |
549 | ||
550 | t!(stream.set_write_timeout(Some(dur))); | |
551 | assert_eq!(Some(dur), t!(stream.write_timeout())); | |
552 | ||
553 | t!(stream.set_read_timeout(None)); | |
554 | assert_eq!(None, t!(stream.read_timeout())); | |
555 | ||
556 | t!(stream.set_write_timeout(None)); | |
557 | assert_eq!(None, t!(stream.write_timeout())); | |
558 | } | |
559 | ||
560 | #[test] | |
561 | fn test_read_timeout() { | |
562 | let addr = next_test_ip4(); | |
563 | ||
9cc50fc6 | 564 | let stream = t!(UdpSocket::bind(&addr)); |
62682a34 SL |
565 | t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); |
566 | ||
567 | let mut buf = [0; 10]; | |
9cc50fc6 SL |
568 | |
569 | let start = Instant::now(); | |
570 | let kind = stream.recv_from(&mut buf).err().expect("expected error").kind(); | |
571 | assert!(kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut); | |
572 | assert!(start.elapsed() > Duration::from_millis(400)); | |
62682a34 SL |
573 | } |
574 | ||
575 | #[test] | |
576 | fn test_read_with_timeout() { | |
577 | let addr = next_test_ip4(); | |
578 | ||
9cc50fc6 | 579 | let stream = t!(UdpSocket::bind(&addr)); |
62682a34 SL |
580 | t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); |
581 | ||
582 | t!(stream.send_to(b"hello world", &addr)); | |
583 | ||
584 | let mut buf = [0; 11]; | |
585 | t!(stream.recv_from(&mut buf)); | |
586 | assert_eq!(b"hello world", &buf[..]); | |
587 | ||
9cc50fc6 SL |
588 | let start = Instant::now(); |
589 | let kind = stream.recv_from(&mut buf).err().expect("expected error").kind(); | |
590 | assert!(kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut); | |
591 | assert!(start.elapsed() > Duration::from_millis(400)); | |
62682a34 | 592 | } |
54a0048b SL |
593 | |
594 | #[test] | |
595 | fn connect_send_recv() { | |
596 | let addr = next_test_ip4(); | |
597 | ||
598 | let socket = t!(UdpSocket::bind(&addr)); | |
599 | t!(socket.connect(addr)); | |
600 | ||
601 | t!(socket.send(b"hello world")); | |
602 | ||
603 | let mut buf = [0; 11]; | |
604 | t!(socket.recv(&mut buf)); | |
605 | assert_eq!(b"hello world", &buf[..]); | |
606 | } | |
607 | ||
608 | #[test] | |
609 | fn ttl() { | |
610 | let ttl = 100; | |
611 | ||
612 | let addr = next_test_ip4(); | |
613 | ||
614 | let stream = t!(UdpSocket::bind(&addr)); | |
615 | ||
616 | t!(stream.set_ttl(ttl)); | |
617 | assert_eq!(ttl, t!(stream.ttl())); | |
618 | } | |
619 | ||
620 | #[test] | |
621 | fn set_nonblocking() { | |
622 | let addr = next_test_ip4(); | |
623 | ||
624 | let stream = t!(UdpSocket::bind(&addr)); | |
625 | ||
626 | t!(stream.set_nonblocking(true)); | |
627 | t!(stream.set_nonblocking(false)); | |
628 | } | |
85aaf69f | 629 | } |