]>
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 | ||
c34b1796 AL |
11 | #![unstable(feature = "udp", reason = "remaining functions have not been \ |
12 | scrutinized enough to be stabilized")] | |
13 | ||
85aaf69f SL |
14 | use prelude::v1::*; |
15 | ||
d9579d0f | 16 | use fmt; |
85aaf69f SL |
17 | use io::{self, Error, ErrorKind}; |
18 | use net::{ToSocketAddrs, SocketAddr, IpAddr}; | |
d9579d0f | 19 | use sys_common::net as net_imp; |
c1a9b12d | 20 | use sys_common::{AsInner, FromInner, IntoInner}; |
62682a34 | 21 | use time::Duration; |
85aaf69f SL |
22 | |
23 | /// A User Datagram Protocol socket. | |
24 | /// | |
25 | /// This is an implementation of a bound UDP socket. This supports both IPv4 and | |
26 | /// IPv6 addresses, and there is no corresponding notion of a server because UDP | |
27 | /// is a datagram protocol. | |
28 | /// | |
c34b1796 | 29 | /// # Examples |
85aaf69f SL |
30 | /// |
31 | /// ```no_run | |
32 | /// use std::net::UdpSocket; | |
33 | /// | |
34 | /// # fn foo() -> std::io::Result<()> { | |
35 | /// let mut socket = try!(UdpSocket::bind("127.0.0.1:34254")); | |
36 | /// | |
37 | /// let mut buf = [0; 10]; | |
38 | /// let (amt, src) = try!(socket.recv_from(&mut buf)); | |
39 | /// | |
40 | /// // Send a reply to the socket we received data from | |
41 | /// let buf = &mut buf[..amt]; | |
42 | /// buf.reverse(); | |
43 | /// try!(socket.send_to(buf, &src)); | |
44 | /// | |
45 | /// drop(socket); // close the socket | |
46 | /// # Ok(()) | |
47 | /// # } | |
48 | /// ``` | |
c34b1796 | 49 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
50 | pub struct UdpSocket(net_imp::UdpSocket); |
51 | ||
52 | impl UdpSocket { | |
53 | /// Creates a UDP socket from the given address. | |
54 | /// | |
bd371182 AL |
55 | /// The address type can be any implementor of `ToSocketAddr` trait. See |
56 | /// its documentation for concrete examples. | |
c34b1796 AL |
57 | #[stable(feature = "rust1", since = "1.0.0")] |
58 | pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<UdpSocket> { | |
85aaf69f SL |
59 | super::each_addr(addr, net_imp::UdpSocket::bind).map(UdpSocket) |
60 | } | |
61 | ||
62 | /// Receives data from the socket. On success, returns the number of bytes | |
63 | /// read and the address from whence the data came. | |
c34b1796 | 64 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
65 | pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { |
66 | self.0.recv_from(buf) | |
67 | } | |
68 | ||
bd371182 AL |
69 | /// Sends data on the socket to the given address. On success, returns the |
70 | /// number of bytes written. | |
85aaf69f SL |
71 | /// |
72 | /// Address type can be any implementor of `ToSocketAddrs` trait. See its | |
73 | /// documentation for concrete examples. | |
c34b1796 AL |
74 | #[stable(feature = "rust1", since = "1.0.0")] |
75 | pub fn send_to<A: ToSocketAddrs>(&self, buf: &[u8], addr: A) | |
76 | -> io::Result<usize> { | |
85aaf69f SL |
77 | match try!(addr.to_socket_addrs()).next() { |
78 | Some(addr) => self.0.send_to(buf, &addr), | |
79 | None => Err(Error::new(ErrorKind::InvalidInput, | |
c34b1796 | 80 | "no addresses to send data to")), |
85aaf69f SL |
81 | } |
82 | } | |
83 | ||
84 | /// Returns the socket address that this socket was created from. | |
c34b1796 AL |
85 | #[stable(feature = "rust1", since = "1.0.0")] |
86 | pub fn local_addr(&self) -> io::Result<SocketAddr> { | |
85aaf69f SL |
87 | self.0.socket_addr() |
88 | } | |
89 | ||
9346a6ac | 90 | /// Creates a new independently owned handle to the underlying socket. |
85aaf69f SL |
91 | /// |
92 | /// The returned `UdpSocket` is a reference to the same socket that this | |
93 | /// object references. Both handles will read and write the same port, and | |
94 | /// options set on one socket will be propagated to the other. | |
c34b1796 | 95 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
96 | pub fn try_clone(&self) -> io::Result<UdpSocket> { |
97 | self.0.duplicate().map(UdpSocket) | |
98 | } | |
99 | ||
bd371182 | 100 | /// Sets the broadcast flag on or off. |
c1a9b12d SL |
101 | #[deprecated(since = "1.3.0", |
102 | reason = "available through the `net2` crate on crates.io")] | |
103 | #[unstable(feature = "udp_extras", reason = "available externally")] | |
85aaf69f SL |
104 | pub fn set_broadcast(&self, on: bool) -> io::Result<()> { |
105 | self.0.set_broadcast(on) | |
106 | } | |
107 | ||
bd371182 | 108 | /// Sets the multicast loop flag to the specified value. |
85aaf69f SL |
109 | /// |
110 | /// This lets multicast packets loop back to local sockets (if enabled) | |
c1a9b12d SL |
111 | #[deprecated(since = "1.3.0", |
112 | reason = "available through the `net2` crate on crates.io")] | |
113 | #[unstable(feature = "udp_extras", reason = "available externally")] | |
85aaf69f SL |
114 | pub fn set_multicast_loop(&self, on: bool) -> io::Result<()> { |
115 | self.0.set_multicast_loop(on) | |
116 | } | |
117 | ||
bd371182 | 118 | /// Joins a multicast IP address (becomes a member of it). |
c1a9b12d SL |
119 | #[deprecated(since = "1.3.0", |
120 | reason = "available through the `net2` crate on crates.io")] | |
121 | #[unstable(feature = "udp_extras", reason = "available externally")] | |
85aaf69f SL |
122 | pub fn join_multicast(&self, multi: &IpAddr) -> io::Result<()> { |
123 | self.0.join_multicast(multi) | |
124 | } | |
125 | ||
bd371182 | 126 | /// Leaves a multicast IP address (drops membership from it). |
c1a9b12d SL |
127 | #[deprecated(since = "1.3.0", |
128 | reason = "available through the `net2` crate on crates.io")] | |
129 | #[unstable(feature = "udp_extras", reason = "available externally")] | |
85aaf69f SL |
130 | pub fn leave_multicast(&self, multi: &IpAddr) -> io::Result<()> { |
131 | self.0.leave_multicast(multi) | |
132 | } | |
133 | ||
bd371182 | 134 | /// Sets the multicast TTL. |
c1a9b12d SL |
135 | #[deprecated(since = "1.3.0", |
136 | reason = "available through the `net2` crate on crates.io")] | |
137 | #[unstable(feature = "udp_extras", reason = "available externally")] | |
85aaf69f SL |
138 | pub fn set_multicast_time_to_live(&self, ttl: i32) -> io::Result<()> { |
139 | self.0.multicast_time_to_live(ttl) | |
140 | } | |
141 | ||
bd371182 | 142 | /// Sets this socket's TTL. |
c1a9b12d SL |
143 | #[deprecated(since = "1.3.0", |
144 | reason = "available through the `net2` crate on crates.io")] | |
145 | #[unstable(feature = "udp_extras", reason = "available externally")] | |
85aaf69f SL |
146 | pub fn set_time_to_live(&self, ttl: i32) -> io::Result<()> { |
147 | self.0.time_to_live(ttl) | |
148 | } | |
62682a34 SL |
149 | |
150 | /// Sets the read timeout to the timeout specified. | |
151 | /// | |
152 | /// If the value specified is `None`, then `read` calls will block | |
153 | /// indefinitely. It is an error to pass the zero `Duration` to this | |
154 | /// method. | |
155 | #[unstable(feature = "socket_timeout", reason = "RFC 1047 - recently added")] | |
156 | pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> { | |
157 | self.0.set_read_timeout(dur) | |
158 | } | |
159 | ||
160 | /// Sets the write timeout to the timeout specified. | |
161 | /// | |
162 | /// If the value specified is `None`, then `write` calls will block | |
163 | /// indefinitely. It is an error to pass the zero `Duration` to this | |
164 | /// method. | |
165 | #[unstable(feature = "socket_timeout", reason = "RFC 1047 - recently added")] | |
166 | pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> { | |
167 | self.0.set_write_timeout(dur) | |
168 | } | |
169 | ||
170 | /// Returns the read timeout of this socket. | |
171 | /// | |
172 | /// If the timeout is `None`, then `read` calls will block indefinitely. | |
173 | #[unstable(feature = "socket_timeout", reason = "RFC 1047 - recently added")] | |
174 | pub fn read_timeout(&self) -> io::Result<Option<Duration>> { | |
175 | self.0.read_timeout() | |
176 | } | |
177 | ||
178 | /// Returns the write timeout of this socket. | |
179 | /// | |
180 | /// If the timeout is `None`, then `write` calls will block indefinitely. | |
181 | #[unstable(feature = "socket_timeout", reason = "RFC 1047 - recently added")] | |
182 | pub fn write_timeout(&self) -> io::Result<Option<Duration>> { | |
183 | self.0.write_timeout() | |
184 | } | |
85aaf69f SL |
185 | } |
186 | ||
187 | impl AsInner<net_imp::UdpSocket> for UdpSocket { | |
188 | fn as_inner(&self) -> &net_imp::UdpSocket { &self.0 } | |
189 | } | |
190 | ||
c34b1796 AL |
191 | impl FromInner<net_imp::UdpSocket> for UdpSocket { |
192 | fn from_inner(inner: net_imp::UdpSocket) -> UdpSocket { UdpSocket(inner) } | |
193 | } | |
194 | ||
c1a9b12d SL |
195 | impl IntoInner<net_imp::UdpSocket> for UdpSocket { |
196 | fn into_inner(self) -> net_imp::UdpSocket { self.0 } | |
197 | } | |
198 | ||
d9579d0f AL |
199 | impl fmt::Debug for UdpSocket { |
200 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
201 | self.0.fmt(f) | |
202 | } | |
203 | } | |
204 | ||
85aaf69f SL |
205 | #[cfg(test)] |
206 | mod tests { | |
207 | use prelude::v1::*; | |
208 | ||
209 | use io::ErrorKind; | |
210 | use net::*; | |
211 | use net::test::{next_test_ip4, next_test_ip6}; | |
212 | use sync::mpsc::channel; | |
d9579d0f | 213 | use sys_common::AsInner; |
62682a34 | 214 | use time::Duration; |
85aaf69f SL |
215 | use thread; |
216 | ||
217 | fn each_ip(f: &mut FnMut(SocketAddr, SocketAddr)) { | |
218 | f(next_test_ip4(), next_test_ip4()); | |
219 | f(next_test_ip6(), next_test_ip6()); | |
220 | } | |
221 | ||
222 | macro_rules! t { | |
223 | ($e:expr) => { | |
224 | match $e { | |
225 | Ok(t) => t, | |
226 | Err(e) => panic!("received error for `{}`: {}", stringify!($e), e), | |
227 | } | |
228 | } | |
229 | } | |
230 | ||
231 | // FIXME #11530 this fails on android because tests are run as root | |
232 | #[cfg_attr(any(windows, target_os = "android"), ignore)] | |
233 | #[test] | |
234 | fn bind_error() { | |
c34b1796 | 235 | let addr = SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), 1); |
85aaf69f SL |
236 | match UdpSocket::bind(&addr) { |
237 | Ok(..) => panic!(), | |
238 | Err(e) => assert_eq!(e.kind(), ErrorKind::PermissionDenied), | |
239 | } | |
240 | } | |
241 | ||
242 | #[test] | |
243 | fn socket_smoke_test_ip4() { | |
244 | each_ip(&mut |server_ip, client_ip| { | |
245 | let (tx1, rx1) = channel(); | |
246 | let (tx2, rx2) = channel(); | |
247 | ||
248 | let _t = thread::spawn(move|| { | |
249 | let client = t!(UdpSocket::bind(&client_ip)); | |
250 | rx1.recv().unwrap(); | |
251 | t!(client.send_to(&[99], &server_ip)); | |
252 | tx2.send(()).unwrap(); | |
253 | }); | |
254 | ||
255 | let server = t!(UdpSocket::bind(&server_ip)); | |
256 | tx1.send(()).unwrap(); | |
257 | let mut buf = [0]; | |
258 | let (nread, src) = t!(server.recv_from(&mut buf)); | |
259 | assert_eq!(nread, 1); | |
260 | assert_eq!(buf[0], 99); | |
261 | assert_eq!(src, client_ip); | |
262 | rx2.recv().unwrap(); | |
263 | }) | |
264 | } | |
265 | ||
266 | #[test] | |
267 | fn socket_name_ip4() { | |
268 | each_ip(&mut |addr, _| { | |
269 | let server = t!(UdpSocket::bind(&addr)); | |
c34b1796 | 270 | assert_eq!(addr, t!(server.local_addr())); |
85aaf69f SL |
271 | }) |
272 | } | |
273 | ||
274 | #[test] | |
275 | fn udp_clone_smoke() { | |
276 | each_ip(&mut |addr1, addr2| { | |
277 | let sock1 = t!(UdpSocket::bind(&addr1)); | |
278 | let sock2 = t!(UdpSocket::bind(&addr2)); | |
279 | ||
280 | let _t = thread::spawn(move|| { | |
281 | let mut buf = [0, 0]; | |
c34b1796 | 282 | assert_eq!(sock2.recv_from(&mut buf).unwrap(), (1, addr1)); |
85aaf69f SL |
283 | assert_eq!(buf[0], 1); |
284 | t!(sock2.send_to(&[2], &addr1)); | |
285 | }); | |
286 | ||
287 | let sock3 = t!(sock1.try_clone()); | |
288 | ||
289 | let (tx1, rx1) = channel(); | |
290 | let (tx2, rx2) = channel(); | |
291 | let _t = thread::spawn(move|| { | |
292 | rx1.recv().unwrap(); | |
293 | t!(sock3.send_to(&[1], &addr2)); | |
294 | tx2.send(()).unwrap(); | |
295 | }); | |
296 | tx1.send(()).unwrap(); | |
297 | let mut buf = [0, 0]; | |
c34b1796 | 298 | assert_eq!(sock1.recv_from(&mut buf).unwrap(), (1, addr2)); |
85aaf69f SL |
299 | rx2.recv().unwrap(); |
300 | }) | |
301 | } | |
302 | ||
303 | #[test] | |
304 | fn udp_clone_two_read() { | |
305 | each_ip(&mut |addr1, addr2| { | |
306 | let sock1 = t!(UdpSocket::bind(&addr1)); | |
307 | let sock2 = t!(UdpSocket::bind(&addr2)); | |
308 | let (tx1, rx) = channel(); | |
309 | let tx2 = tx1.clone(); | |
310 | ||
311 | let _t = thread::spawn(move|| { | |
312 | t!(sock2.send_to(&[1], &addr1)); | |
313 | rx.recv().unwrap(); | |
314 | t!(sock2.send_to(&[2], &addr1)); | |
315 | rx.recv().unwrap(); | |
316 | }); | |
317 | ||
318 | let sock3 = t!(sock1.try_clone()); | |
319 | ||
320 | let (done, rx) = channel(); | |
321 | let _t = thread::spawn(move|| { | |
322 | let mut buf = [0, 0]; | |
323 | t!(sock3.recv_from(&mut buf)); | |
324 | tx2.send(()).unwrap(); | |
325 | done.send(()).unwrap(); | |
326 | }); | |
327 | let mut buf = [0, 0]; | |
328 | t!(sock1.recv_from(&mut buf)); | |
329 | tx1.send(()).unwrap(); | |
330 | ||
331 | rx.recv().unwrap(); | |
332 | }) | |
333 | } | |
334 | ||
335 | #[test] | |
336 | fn udp_clone_two_write() { | |
337 | each_ip(&mut |addr1, addr2| { | |
338 | let sock1 = t!(UdpSocket::bind(&addr1)); | |
339 | let sock2 = t!(UdpSocket::bind(&addr2)); | |
340 | ||
341 | let (tx, rx) = channel(); | |
342 | let (serv_tx, serv_rx) = channel(); | |
343 | ||
344 | let _t = thread::spawn(move|| { | |
345 | let mut buf = [0, 1]; | |
346 | rx.recv().unwrap(); | |
347 | t!(sock2.recv_from(&mut buf)); | |
348 | serv_tx.send(()).unwrap(); | |
349 | }); | |
350 | ||
351 | let sock3 = t!(sock1.try_clone()); | |
352 | ||
353 | let (done, rx) = channel(); | |
354 | let tx2 = tx.clone(); | |
355 | let _t = thread::spawn(move|| { | |
356 | match sock3.send_to(&[1], &addr2) { | |
357 | Ok(..) => { let _ = tx2.send(()); } | |
358 | Err(..) => {} | |
359 | } | |
360 | done.send(()).unwrap(); | |
361 | }); | |
362 | match sock1.send_to(&[2], &addr2) { | |
363 | Ok(..) => { let _ = tx.send(()); } | |
364 | Err(..) => {} | |
365 | } | |
366 | drop(tx); | |
367 | ||
368 | rx.recv().unwrap(); | |
369 | serv_rx.recv().unwrap(); | |
370 | }) | |
371 | } | |
d9579d0f AL |
372 | |
373 | #[test] | |
374 | fn debug() { | |
375 | let name = if cfg!(windows) {"socket"} else {"fd"}; | |
376 | let socket_addr = next_test_ip4(); | |
377 | ||
378 | let udpsock = t!(UdpSocket::bind(&socket_addr)); | |
379 | let udpsock_inner = udpsock.0.socket().as_inner(); | |
380 | let compare = format!("UdpSocket {{ addr: {:?}, {}: {:?} }}", | |
381 | socket_addr, name, udpsock_inner); | |
382 | assert_eq!(format!("{:?}", udpsock), compare); | |
383 | } | |
62682a34 | 384 | |
c1a9b12d | 385 | // FIXME: re-enabled bitrig/openbsd/netbsd tests once their socket timeout code |
62682a34 | 386 | // no longer has rounding errors. |
c1a9b12d | 387 | #[cfg_attr(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"), ignore)] |
62682a34 SL |
388 | #[test] |
389 | fn timeouts() { | |
390 | let addr = next_test_ip4(); | |
391 | ||
392 | let stream = t!(UdpSocket::bind(&addr)); | |
393 | let dur = Duration::new(15410, 0); | |
394 | ||
395 | assert_eq!(None, t!(stream.read_timeout())); | |
396 | ||
397 | t!(stream.set_read_timeout(Some(dur))); | |
398 | assert_eq!(Some(dur), t!(stream.read_timeout())); | |
399 | ||
400 | assert_eq!(None, t!(stream.write_timeout())); | |
401 | ||
402 | t!(stream.set_write_timeout(Some(dur))); | |
403 | assert_eq!(Some(dur), t!(stream.write_timeout())); | |
404 | ||
405 | t!(stream.set_read_timeout(None)); | |
406 | assert_eq!(None, t!(stream.read_timeout())); | |
407 | ||
408 | t!(stream.set_write_timeout(None)); | |
409 | assert_eq!(None, t!(stream.write_timeout())); | |
410 | } | |
411 | ||
412 | #[test] | |
413 | fn test_read_timeout() { | |
414 | let addr = next_test_ip4(); | |
415 | ||
416 | let mut stream = t!(UdpSocket::bind(&addr)); | |
417 | t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); | |
418 | ||
419 | let mut buf = [0; 10]; | |
420 | let wait = Duration::span(|| { | |
421 | let kind = stream.recv_from(&mut buf).err().expect("expected error").kind(); | |
422 | assert!(kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut); | |
423 | }); | |
424 | assert!(wait > Duration::from_millis(400)); | |
425 | assert!(wait < Duration::from_millis(1600)); | |
426 | } | |
427 | ||
428 | #[test] | |
429 | fn test_read_with_timeout() { | |
430 | let addr = next_test_ip4(); | |
431 | ||
432 | let mut stream = t!(UdpSocket::bind(&addr)); | |
433 | t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); | |
434 | ||
435 | t!(stream.send_to(b"hello world", &addr)); | |
436 | ||
437 | let mut buf = [0; 11]; | |
438 | t!(stream.recv_from(&mut buf)); | |
439 | assert_eq!(b"hello world", &buf[..]); | |
440 | ||
441 | let wait = Duration::span(|| { | |
442 | let kind = stream.recv_from(&mut buf).err().expect("expected error").kind(); | |
443 | assert!(kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut); | |
444 | }); | |
445 | assert!(wait > Duration::from_millis(400)); | |
446 | assert!(wait < Duration::from_millis(1600)); | |
447 | } | |
85aaf69f | 448 | } |