]>
Commit | Line | Data |
---|---|---|
54a0048b SL |
1 | // Copyright 2016 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. | |
a7813a04 XL |
10 | |
11 | #![stable(feature = "unix_socket", since = "1.10.0")] | |
54a0048b SL |
12 | |
13 | //! Unix-specific networking functionality | |
14 | ||
15 | use libc; | |
16 | ||
54a0048b SL |
17 | use ascii; |
18 | use ffi::OsStr; | |
19 | use fmt; | |
20 | use io; | |
21 | use mem; | |
22 | use net::Shutdown; | |
23 | use os::unix::ffi::OsStrExt; | |
24 | use os::unix::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd}; | |
25 | use path::Path; | |
26 | use time::Duration; | |
27 | use sys::cvt; | |
28 | use sys::net::Socket; | |
29 | use sys_common::{AsInner, FromInner, IntoInner}; | |
30 | ||
c30ab7b3 SL |
31 | #[cfg(any(target_os = "linux", target_os = "android", |
32 | target_os = "dragonfly", target_os = "freebsd", | |
33 | target_os = "openbsd", target_os = "netbsd", | |
34 | target_os = "haiku", target_os = "bitrig"))] | |
35 | use libc::MSG_NOSIGNAL; | |
36 | #[cfg(not(any(target_os = "linux", target_os = "android", | |
37 | target_os = "dragonfly", target_os = "freebsd", | |
38 | target_os = "openbsd", target_os = "netbsd", | |
39 | target_os = "haiku", target_os = "bitrig")))] | |
40 | const MSG_NOSIGNAL: libc::c_int = 0x0; | |
41 | ||
54a0048b SL |
42 | fn sun_path_offset() -> usize { |
43 | unsafe { | |
44 | // Work with an actual instance of the type since using a null pointer is UB | |
45 | let addr: libc::sockaddr_un = mem::uninitialized(); | |
46 | let base = &addr as *const _ as usize; | |
47 | let path = &addr.sun_path as *const _ as usize; | |
48 | path - base | |
49 | } | |
50 | } | |
51 | ||
52 | unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> { | |
53 | let mut addr: libc::sockaddr_un = mem::zeroed(); | |
54 | addr.sun_family = libc::AF_UNIX as libc::sa_family_t; | |
55 | ||
56 | let bytes = path.as_os_str().as_bytes(); | |
57 | ||
58 | if bytes.contains(&0) { | |
59 | return Err(io::Error::new(io::ErrorKind::InvalidInput, | |
60 | "paths may not contain interior null bytes")); | |
61 | } | |
62 | ||
63 | if bytes.len() >= addr.sun_path.len() { | |
64 | return Err(io::Error::new(io::ErrorKind::InvalidInput, | |
65 | "path must be shorter than SUN_LEN")); | |
66 | } | |
67 | for (dst, src) in addr.sun_path.iter_mut().zip(bytes.iter()) { | |
68 | *dst = *src as libc::c_char; | |
69 | } | |
70 | // null byte for pathname addresses is already there because we zeroed the | |
71 | // struct | |
72 | ||
73 | let mut len = sun_path_offset() + bytes.len(); | |
74 | match bytes.get(0) { | |
75 | Some(&0) | None => {} | |
76 | Some(_) => len += 1, | |
77 | } | |
78 | Ok((addr, len as libc::socklen_t)) | |
79 | } | |
80 | ||
81 | enum AddressKind<'a> { | |
82 | Unnamed, | |
83 | Pathname(&'a Path), | |
84 | Abstract(&'a [u8]), | |
85 | } | |
86 | ||
87 | /// An address associated with a Unix socket. | |
88 | #[derive(Clone)] | |
a7813a04 | 89 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
90 | pub struct SocketAddr { |
91 | addr: libc::sockaddr_un, | |
92 | len: libc::socklen_t, | |
93 | } | |
94 | ||
95 | impl SocketAddr { | |
96 | fn new<F>(f: F) -> io::Result<SocketAddr> | |
97 | where F: FnOnce(*mut libc::sockaddr, *mut libc::socklen_t) -> libc::c_int | |
98 | { | |
99 | unsafe { | |
100 | let mut addr: libc::sockaddr_un = mem::zeroed(); | |
101 | let mut len = mem::size_of::<libc::sockaddr_un>() as libc::socklen_t; | |
102 | cvt(f(&mut addr as *mut _ as *mut _, &mut len))?; | |
103 | SocketAddr::from_parts(addr, len) | |
104 | } | |
105 | } | |
106 | ||
107 | fn from_parts(addr: libc::sockaddr_un, mut len: libc::socklen_t) -> io::Result<SocketAddr> { | |
108 | if len == 0 { | |
109 | // When there is a datagram from unnamed unix socket | |
110 | // linux returns zero bytes of address | |
111 | len = sun_path_offset() as libc::socklen_t; // i.e. zero-length address | |
112 | } else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t { | |
113 | return Err(io::Error::new(io::ErrorKind::InvalidInput, | |
114 | "file descriptor did not correspond to a Unix socket")); | |
115 | } | |
116 | ||
117 | Ok(SocketAddr { | |
118 | addr: addr, | |
119 | len: len, | |
120 | }) | |
121 | } | |
122 | ||
5bcae85e | 123 | /// Returns true if and only if the address is unnamed. |
a7813a04 | 124 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
125 | pub fn is_unnamed(&self) -> bool { |
126 | if let AddressKind::Unnamed = self.address() { | |
127 | true | |
128 | } else { | |
129 | false | |
130 | } | |
131 | } | |
132 | ||
133 | /// Returns the contents of this address if it is a `pathname` address. | |
a7813a04 | 134 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
135 | pub fn as_pathname(&self) -> Option<&Path> { |
136 | if let AddressKind::Pathname(path) = self.address() { | |
137 | Some(path) | |
138 | } else { | |
139 | None | |
140 | } | |
141 | } | |
142 | ||
143 | fn address<'a>(&'a self) -> AddressKind<'a> { | |
144 | let len = self.len as usize - sun_path_offset(); | |
145 | let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) }; | |
146 | ||
147 | // OSX seems to return a len of 16 and a zeroed sun_path for unnamed addresses | |
148 | if len == 0 || (cfg!(not(target_os = "linux")) && self.addr.sun_path[0] == 0) { | |
149 | AddressKind::Unnamed | |
150 | } else if self.addr.sun_path[0] == 0 { | |
151 | AddressKind::Abstract(&path[1..len]) | |
152 | } else { | |
153 | AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref()) | |
154 | } | |
155 | } | |
156 | } | |
157 | ||
a7813a04 | 158 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
159 | impl fmt::Debug for SocketAddr { |
160 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | |
161 | match self.address() { | |
162 | AddressKind::Unnamed => write!(fmt, "(unnamed)"), | |
163 | AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)), | |
164 | AddressKind::Pathname(path) => write!(fmt, "{:?} (pathname)", path), | |
165 | } | |
166 | } | |
167 | } | |
168 | ||
169 | struct AsciiEscaped<'a>(&'a [u8]); | |
170 | ||
171 | impl<'a> fmt::Display for AsciiEscaped<'a> { | |
172 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | |
173 | write!(fmt, "\"")?; | |
174 | for byte in self.0.iter().cloned().flat_map(ascii::escape_default) { | |
175 | write!(fmt, "{}", byte as char)?; | |
176 | } | |
177 | write!(fmt, "\"") | |
178 | } | |
179 | } | |
180 | ||
181 | /// A Unix stream socket. | |
182 | /// | |
183 | /// # Examples | |
184 | /// | |
185 | /// ```rust,no_run | |
54a0048b SL |
186 | /// use std::os::unix::net::UnixStream; |
187 | /// use std::io::prelude::*; | |
188 | /// | |
189 | /// let mut stream = UnixStream::connect("/path/to/my/socket").unwrap(); | |
190 | /// stream.write_all(b"hello world").unwrap(); | |
191 | /// let mut response = String::new(); | |
192 | /// stream.read_to_string(&mut response).unwrap(); | |
193 | /// println!("{}", response); | |
194 | /// ``` | |
a7813a04 | 195 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
196 | pub struct UnixStream(Socket); |
197 | ||
a7813a04 | 198 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
199 | impl fmt::Debug for UnixStream { |
200 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | |
201 | let mut builder = fmt.debug_struct("UnixStream"); | |
202 | builder.field("fd", self.0.as_inner()); | |
203 | if let Ok(addr) = self.local_addr() { | |
204 | builder.field("local", &addr); | |
205 | } | |
206 | if let Ok(addr) = self.peer_addr() { | |
207 | builder.field("peer", &addr); | |
208 | } | |
209 | builder.finish() | |
210 | } | |
211 | } | |
212 | ||
213 | impl UnixStream { | |
214 | /// Connects to the socket named by `path`. | |
a7813a04 | 215 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
216 | pub fn connect<P: AsRef<Path>>(path: P) -> io::Result<UnixStream> { |
217 | fn inner(path: &Path) -> io::Result<UnixStream> { | |
218 | unsafe { | |
219 | let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; | |
220 | let (addr, len) = sockaddr_un(path)?; | |
221 | ||
222 | cvt(libc::connect(*inner.as_inner(), &addr as *const _ as *const _, len))?; | |
223 | Ok(UnixStream(inner)) | |
224 | } | |
225 | } | |
226 | inner(path.as_ref()) | |
227 | } | |
228 | ||
229 | /// Creates an unnamed pair of connected sockets. | |
230 | /// | |
231 | /// Returns two `UnixStream`s which are connected to each other. | |
a7813a04 | 232 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
233 | pub fn pair() -> io::Result<(UnixStream, UnixStream)> { |
234 | let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_STREAM)?; | |
235 | Ok((UnixStream(i1), UnixStream(i2))) | |
236 | } | |
237 | ||
238 | /// Creates a new independently owned handle to the underlying socket. | |
239 | /// | |
240 | /// The returned `UnixStream` is a reference to the same stream that this | |
241 | /// object references. Both handles will read and write the same stream of | |
242 | /// data, and options set on one stream will be propogated to the other | |
243 | /// stream. | |
a7813a04 | 244 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
245 | pub fn try_clone(&self) -> io::Result<UnixStream> { |
246 | self.0.duplicate().map(UnixStream) | |
247 | } | |
248 | ||
249 | /// Returns the socket address of the local half of this connection. | |
a7813a04 | 250 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
251 | pub fn local_addr(&self) -> io::Result<SocketAddr> { |
252 | SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) | |
253 | } | |
254 | ||
255 | /// Returns the socket address of the remote half of this connection. | |
a7813a04 | 256 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
257 | pub fn peer_addr(&self) -> io::Result<SocketAddr> { |
258 | SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) | |
259 | } | |
260 | ||
261 | /// Sets the read timeout for the socket. | |
262 | /// | |
263 | /// If the provided value is `None`, then `read` calls will block | |
264 | /// indefinitely. It is an error to pass the zero `Duration` to this | |
265 | /// method. | |
a7813a04 | 266 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
267 | pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> { |
268 | self.0.set_timeout(timeout, libc::SO_RCVTIMEO) | |
269 | } | |
270 | ||
271 | /// Sets the write timeout for the socket. | |
272 | /// | |
273 | /// If the provided value is `None`, then `write` calls will block | |
274 | /// indefinitely. It is an error to pass the zero `Duration` to this | |
275 | /// method. | |
a7813a04 | 276 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
277 | pub fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> { |
278 | self.0.set_timeout(timeout, libc::SO_SNDTIMEO) | |
279 | } | |
280 | ||
281 | /// Returns the read timeout of this socket. | |
a7813a04 | 282 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
283 | pub fn read_timeout(&self) -> io::Result<Option<Duration>> { |
284 | self.0.timeout(libc::SO_RCVTIMEO) | |
285 | } | |
286 | ||
287 | /// Returns the write timeout of this socket. | |
a7813a04 | 288 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
289 | pub fn write_timeout(&self) -> io::Result<Option<Duration>> { |
290 | self.0.timeout(libc::SO_SNDTIMEO) | |
291 | } | |
292 | ||
293 | /// Moves the socket into or out of nonblocking mode. | |
a7813a04 | 294 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
295 | pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { |
296 | self.0.set_nonblocking(nonblocking) | |
297 | } | |
298 | ||
299 | /// Returns the value of the `SO_ERROR` option. | |
a7813a04 | 300 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
301 | pub fn take_error(&self) -> io::Result<Option<io::Error>> { |
302 | self.0.take_error() | |
303 | } | |
304 | ||
305 | /// Shuts down the read, write, or both halves of this connection. | |
306 | /// | |
307 | /// This function will cause all pending and future I/O calls on the | |
308 | /// specified portions to immediately return with an appropriate value | |
309 | /// (see the documentation of `Shutdown`). | |
a7813a04 | 310 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
311 | pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { |
312 | self.0.shutdown(how) | |
313 | } | |
314 | } | |
315 | ||
a7813a04 | 316 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
317 | impl io::Read for UnixStream { |
318 | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | |
319 | io::Read::read(&mut &*self, buf) | |
320 | } | |
321 | ||
322 | fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { | |
323 | io::Read::read_to_end(&mut &*self, buf) | |
324 | } | |
325 | } | |
326 | ||
a7813a04 | 327 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
328 | impl<'a> io::Read for &'a UnixStream { |
329 | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | |
330 | self.0.read(buf) | |
331 | } | |
332 | ||
333 | fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { | |
334 | self.0.read_to_end(buf) | |
335 | } | |
336 | } | |
337 | ||
a7813a04 | 338 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
339 | impl io::Write for UnixStream { |
340 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { | |
341 | io::Write::write(&mut &*self, buf) | |
342 | } | |
343 | ||
344 | fn flush(&mut self) -> io::Result<()> { | |
345 | io::Write::flush(&mut &*self) | |
346 | } | |
347 | } | |
348 | ||
a7813a04 | 349 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
350 | impl<'a> io::Write for &'a UnixStream { |
351 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { | |
352 | self.0.write(buf) | |
353 | } | |
354 | ||
355 | fn flush(&mut self) -> io::Result<()> { | |
356 | Ok(()) | |
357 | } | |
358 | } | |
359 | ||
a7813a04 | 360 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
361 | impl AsRawFd for UnixStream { |
362 | fn as_raw_fd(&self) -> RawFd { | |
363 | *self.0.as_inner() | |
364 | } | |
365 | } | |
366 | ||
a7813a04 | 367 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
368 | impl FromRawFd for UnixStream { |
369 | unsafe fn from_raw_fd(fd: RawFd) -> UnixStream { | |
370 | UnixStream(Socket::from_inner(fd)) | |
371 | } | |
372 | } | |
373 | ||
a7813a04 | 374 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
375 | impl IntoRawFd for UnixStream { |
376 | fn into_raw_fd(self) -> RawFd { | |
377 | self.0.into_inner() | |
378 | } | |
379 | } | |
380 | ||
381 | /// A structure representing a Unix domain socket server. | |
382 | /// | |
383 | /// # Examples | |
384 | /// | |
385 | /// ```rust,no_run | |
54a0048b SL |
386 | /// use std::thread; |
387 | /// use std::os::unix::net::{UnixStream, UnixListener}; | |
388 | /// | |
389 | /// fn handle_client(stream: UnixStream) { | |
390 | /// // ... | |
391 | /// } | |
392 | /// | |
393 | /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); | |
394 | /// | |
395 | /// // accept connections and process them, spawning a new thread for each one | |
396 | /// for stream in listener.incoming() { | |
397 | /// match stream { | |
398 | /// Ok(stream) => { | |
399 | /// /* connection succeeded */ | |
400 | /// thread::spawn(|| handle_client(stream)); | |
401 | /// } | |
402 | /// Err(err) => { | |
403 | /// /* connection failed */ | |
404 | /// break; | |
405 | /// } | |
406 | /// } | |
407 | /// } | |
408 | /// | |
409 | /// // close the listener socket | |
410 | /// drop(listener); | |
411 | /// ``` | |
a7813a04 | 412 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
413 | pub struct UnixListener(Socket); |
414 | ||
a7813a04 | 415 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
416 | impl fmt::Debug for UnixListener { |
417 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | |
418 | let mut builder = fmt.debug_struct("UnixListener"); | |
419 | builder.field("fd", self.0.as_inner()); | |
420 | if let Ok(addr) = self.local_addr() { | |
421 | builder.field("local", &addr); | |
422 | } | |
423 | builder.finish() | |
424 | } | |
425 | } | |
426 | ||
427 | impl UnixListener { | |
428 | /// Creates a new `UnixListener` bound to the specified socket. | |
a7813a04 | 429 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
430 | pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixListener> { |
431 | fn inner(path: &Path) -> io::Result<UnixListener> { | |
432 | unsafe { | |
433 | let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; | |
434 | let (addr, len) = sockaddr_un(path)?; | |
435 | ||
436 | cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len))?; | |
437 | cvt(libc::listen(*inner.as_inner(), 128))?; | |
438 | ||
439 | Ok(UnixListener(inner)) | |
440 | } | |
441 | } | |
442 | inner(path.as_ref()) | |
443 | } | |
444 | ||
445 | /// Accepts a new incoming connection to this listener. | |
446 | /// | |
447 | /// This function will block the calling thread until a new Unix connection | |
448 | /// is established. When established, the corersponding `UnixStream` and | |
449 | /// the remote peer's address will be returned. | |
a7813a04 | 450 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
451 | pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { |
452 | let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() }; | |
453 | let mut len = mem::size_of_val(&storage) as libc::socklen_t; | |
454 | let sock = self.0.accept(&mut storage as *mut _ as *mut _, &mut len)?; | |
455 | let addr = SocketAddr::from_parts(storage, len)?; | |
456 | Ok((UnixStream(sock), addr)) | |
457 | } | |
458 | ||
459 | /// Creates a new independently owned handle to the underlying socket. | |
460 | /// | |
461 | /// The returned `UnixListener` is a reference to the same socket that this | |
462 | /// object references. Both handles can be used to accept incoming | |
463 | /// connections and options set on one listener will affect the other. | |
a7813a04 | 464 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
465 | pub fn try_clone(&self) -> io::Result<UnixListener> { |
466 | self.0.duplicate().map(UnixListener) | |
467 | } | |
468 | ||
469 | /// Returns the local socket address of this listener. | |
a7813a04 | 470 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
471 | pub fn local_addr(&self) -> io::Result<SocketAddr> { |
472 | SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) | |
473 | } | |
474 | ||
475 | /// Moves the socket into or out of nonblocking mode. | |
a7813a04 | 476 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
477 | pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { |
478 | self.0.set_nonblocking(nonblocking) | |
479 | } | |
480 | ||
481 | /// Returns the value of the `SO_ERROR` option. | |
a7813a04 | 482 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
483 | pub fn take_error(&self) -> io::Result<Option<io::Error>> { |
484 | self.0.take_error() | |
485 | } | |
486 | ||
487 | /// Returns an iterator over incoming connections. | |
488 | /// | |
489 | /// The iterator will never return `None` and will also not yield the | |
490 | /// peer's `SocketAddr` structure. | |
a7813a04 | 491 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
492 | pub fn incoming<'a>(&'a self) -> Incoming<'a> { |
493 | Incoming { listener: self } | |
494 | } | |
495 | } | |
496 | ||
a7813a04 | 497 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
498 | impl AsRawFd for UnixListener { |
499 | fn as_raw_fd(&self) -> RawFd { | |
500 | *self.0.as_inner() | |
501 | } | |
502 | } | |
503 | ||
a7813a04 | 504 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
505 | impl FromRawFd for UnixListener { |
506 | unsafe fn from_raw_fd(fd: RawFd) -> UnixListener { | |
507 | UnixListener(Socket::from_inner(fd)) | |
508 | } | |
509 | } | |
510 | ||
a7813a04 | 511 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
512 | impl IntoRawFd for UnixListener { |
513 | fn into_raw_fd(self) -> RawFd { | |
514 | self.0.into_inner() | |
515 | } | |
516 | } | |
517 | ||
a7813a04 | 518 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
519 | impl<'a> IntoIterator for &'a UnixListener { |
520 | type Item = io::Result<UnixStream>; | |
521 | type IntoIter = Incoming<'a>; | |
522 | ||
523 | fn into_iter(self) -> Incoming<'a> { | |
524 | self.incoming() | |
525 | } | |
526 | } | |
527 | ||
528 | /// An iterator over incoming connections to a `UnixListener`. | |
529 | /// | |
530 | /// It will never return `None`. | |
531 | #[derive(Debug)] | |
a7813a04 | 532 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
533 | pub struct Incoming<'a> { |
534 | listener: &'a UnixListener, | |
535 | } | |
536 | ||
a7813a04 | 537 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
538 | impl<'a> Iterator for Incoming<'a> { |
539 | type Item = io::Result<UnixStream>; | |
540 | ||
541 | fn next(&mut self) -> Option<io::Result<UnixStream>> { | |
542 | Some(self.listener.accept().map(|s| s.0)) | |
543 | } | |
544 | ||
545 | fn size_hint(&self) -> (usize, Option<usize>) { | |
546 | (usize::max_value(), None) | |
547 | } | |
548 | } | |
549 | ||
550 | /// A Unix datagram socket. | |
551 | /// | |
552 | /// # Examples | |
553 | /// | |
554 | /// ```rust,no_run | |
54a0048b SL |
555 | /// use std::os::unix::net::UnixDatagram; |
556 | /// | |
557 | /// let socket = UnixDatagram::bind("/path/to/my/socket").unwrap(); | |
558 | /// socket.send_to(b"hello world", "/path/to/other/socket").unwrap(); | |
559 | /// let mut buf = [0; 100]; | |
560 | /// let (count, address) = socket.recv_from(&mut buf).unwrap(); | |
561 | /// println!("socket {:?} sent {:?}", address, &buf[..count]); | |
562 | /// ``` | |
a7813a04 | 563 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
564 | pub struct UnixDatagram(Socket); |
565 | ||
a7813a04 | 566 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
567 | impl fmt::Debug for UnixDatagram { |
568 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | |
569 | let mut builder = fmt.debug_struct("UnixDatagram"); | |
570 | builder.field("fd", self.0.as_inner()); | |
571 | if let Ok(addr) = self.local_addr() { | |
572 | builder.field("local", &addr); | |
573 | } | |
574 | if let Ok(addr) = self.peer_addr() { | |
575 | builder.field("peer", &addr); | |
576 | } | |
577 | builder.finish() | |
578 | } | |
579 | } | |
580 | ||
581 | impl UnixDatagram { | |
582 | /// Creates a Unix datagram socket bound to the given path. | |
a7813a04 | 583 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
584 | pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixDatagram> { |
585 | fn inner(path: &Path) -> io::Result<UnixDatagram> { | |
586 | unsafe { | |
587 | let socket = UnixDatagram::unbound()?; | |
588 | let (addr, len) = sockaddr_un(path)?; | |
589 | ||
590 | cvt(libc::bind(*socket.0.as_inner(), &addr as *const _ as *const _, len))?; | |
591 | ||
592 | Ok(socket) | |
593 | } | |
594 | } | |
595 | inner(path.as_ref()) | |
596 | } | |
597 | ||
598 | /// Creates a Unix Datagram socket which is not bound to any address. | |
a7813a04 | 599 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
600 | pub fn unbound() -> io::Result<UnixDatagram> { |
601 | let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_DGRAM)?; | |
602 | Ok(UnixDatagram(inner)) | |
603 | } | |
604 | ||
605 | /// Create an unnamed pair of connected sockets. | |
606 | /// | |
607 | /// Returns two `UnixDatagrams`s which are connected to each other. | |
a7813a04 | 608 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
609 | pub fn pair() -> io::Result<(UnixDatagram, UnixDatagram)> { |
610 | let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_DGRAM)?; | |
611 | Ok((UnixDatagram(i1), UnixDatagram(i2))) | |
612 | } | |
613 | ||
614 | /// Connects the socket to the specified address. | |
615 | /// | |
616 | /// The `send` method may be used to send data to the specified address. | |
617 | /// `recv` and `recv_from` will only receive data from that address. | |
a7813a04 | 618 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
619 | pub fn connect<P: AsRef<Path>>(&self, path: P) -> io::Result<()> { |
620 | fn inner(d: &UnixDatagram, path: &Path) -> io::Result<()> { | |
621 | unsafe { | |
622 | let (addr, len) = sockaddr_un(path)?; | |
623 | ||
624 | cvt(libc::connect(*d.0.as_inner(), &addr as *const _ as *const _, len))?; | |
625 | ||
626 | Ok(()) | |
627 | } | |
628 | } | |
629 | inner(self, path.as_ref()) | |
630 | } | |
631 | ||
632 | /// Creates a new independently owned handle to the underlying socket. | |
633 | /// | |
634 | /// The returned `UnixListener` is a reference to the same socket that this | |
635 | /// object references. Both handles can be used to accept incoming | |
636 | /// connections and options set on one listener will affect the other. | |
a7813a04 | 637 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
638 | pub fn try_clone(&self) -> io::Result<UnixDatagram> { |
639 | self.0.duplicate().map(UnixDatagram) | |
640 | } | |
641 | ||
642 | /// Returns the address of this socket. | |
a7813a04 | 643 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
644 | pub fn local_addr(&self) -> io::Result<SocketAddr> { |
645 | SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) | |
646 | } | |
647 | ||
648 | /// Returns the address of this socket's peer. | |
649 | /// | |
650 | /// The `connect` method will connect the socket to a peer. | |
a7813a04 | 651 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
652 | pub fn peer_addr(&self) -> io::Result<SocketAddr> { |
653 | SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) | |
654 | } | |
655 | ||
656 | /// Receives data from the socket. | |
657 | /// | |
658 | /// On success, returns the number of bytes read and the address from | |
659 | /// whence the data came. | |
a7813a04 | 660 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
661 | pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { |
662 | let mut count = 0; | |
663 | let addr = SocketAddr::new(|addr, len| { | |
664 | unsafe { | |
665 | count = libc::recvfrom(*self.0.as_inner(), | |
666 | buf.as_mut_ptr() as *mut _, | |
667 | buf.len(), | |
668 | 0, | |
669 | addr, | |
670 | len); | |
671 | if count > 0 { | |
672 | 1 | |
673 | } else if count == 0 { | |
674 | 0 | |
675 | } else { | |
676 | -1 | |
677 | } | |
678 | } | |
679 | })?; | |
680 | ||
681 | Ok((count as usize, addr)) | |
682 | } | |
683 | ||
684 | /// Receives data from the socket. | |
685 | /// | |
686 | /// On success, returns the number of bytes read. | |
a7813a04 | 687 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
688 | pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> { |
689 | self.0.read(buf) | |
690 | } | |
691 | ||
692 | /// Sends data on the socket to the specified address. | |
693 | /// | |
694 | /// On success, returns the number of bytes written. | |
a7813a04 | 695 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
696 | pub fn send_to<P: AsRef<Path>>(&self, buf: &[u8], path: P) -> io::Result<usize> { |
697 | fn inner(d: &UnixDatagram, buf: &[u8], path: &Path) -> io::Result<usize> { | |
698 | unsafe { | |
699 | let (addr, len) = sockaddr_un(path)?; | |
700 | ||
701 | let count = cvt(libc::sendto(*d.0.as_inner(), | |
702 | buf.as_ptr() as *const _, | |
703 | buf.len(), | |
c30ab7b3 | 704 | MSG_NOSIGNAL, |
54a0048b SL |
705 | &addr as *const _ as *const _, |
706 | len))?; | |
707 | Ok(count as usize) | |
708 | } | |
709 | } | |
710 | inner(self, buf, path.as_ref()) | |
711 | } | |
712 | ||
713 | /// Sends data on the socket to the socket's peer. | |
714 | /// | |
715 | /// The peer address may be set by the `connect` method, and this method | |
716 | /// will return an error if the socket has not already been connected. | |
717 | /// | |
718 | /// On success, returns the number of bytes written. | |
a7813a04 | 719 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
720 | pub fn send(&self, buf: &[u8]) -> io::Result<usize> { |
721 | self.0.write(buf) | |
722 | } | |
723 | ||
724 | /// Sets the read timeout for the socket. | |
725 | /// | |
726 | /// If the provided value is `None`, then `recv` and `recv_from` calls will | |
727 | /// block indefinitely. It is an error to pass the zero `Duration` to this | |
728 | /// method. | |
a7813a04 | 729 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
730 | pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> { |
731 | self.0.set_timeout(timeout, libc::SO_RCVTIMEO) | |
732 | } | |
733 | ||
734 | /// Sets the write timeout for the socket. | |
735 | /// | |
736 | /// If the provided value is `None`, then `send` and `send_to` calls will | |
737 | /// block indefinitely. It is an error to pass the zero `Duration` to this | |
738 | /// method. | |
a7813a04 | 739 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
740 | pub fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> { |
741 | self.0.set_timeout(timeout, libc::SO_SNDTIMEO) | |
742 | } | |
743 | ||
744 | /// Returns the read timeout of this socket. | |
a7813a04 | 745 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
746 | pub fn read_timeout(&self) -> io::Result<Option<Duration>> { |
747 | self.0.timeout(libc::SO_RCVTIMEO) | |
748 | } | |
749 | ||
750 | /// Returns the write timeout of this socket. | |
a7813a04 | 751 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
752 | pub fn write_timeout(&self) -> io::Result<Option<Duration>> { |
753 | self.0.timeout(libc::SO_SNDTIMEO) | |
754 | } | |
755 | ||
756 | /// Moves the socket into or out of nonblocking mode. | |
a7813a04 | 757 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
758 | pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { |
759 | self.0.set_nonblocking(nonblocking) | |
760 | } | |
761 | ||
762 | /// Returns the value of the `SO_ERROR` option. | |
a7813a04 | 763 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
764 | pub fn take_error(&self) -> io::Result<Option<io::Error>> { |
765 | self.0.take_error() | |
766 | } | |
767 | ||
768 | /// Shut down the read, write, or both halves of this connection. | |
769 | /// | |
770 | /// This function will cause all pending and future I/O calls on the | |
771 | /// specified portions to immediately return with an appropriate value | |
772 | /// (see the documentation of `Shutdown`). | |
a7813a04 | 773 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
774 | pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { |
775 | self.0.shutdown(how) | |
776 | } | |
777 | } | |
778 | ||
a7813a04 | 779 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
780 | impl AsRawFd for UnixDatagram { |
781 | fn as_raw_fd(&self) -> RawFd { | |
782 | *self.0.as_inner() | |
783 | } | |
784 | } | |
785 | ||
a7813a04 | 786 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
787 | impl FromRawFd for UnixDatagram { |
788 | unsafe fn from_raw_fd(fd: RawFd) -> UnixDatagram { | |
789 | UnixDatagram(Socket::from_inner(fd)) | |
790 | } | |
791 | } | |
792 | ||
a7813a04 | 793 | #[stable(feature = "unix_socket", since = "1.10.0")] |
54a0048b SL |
794 | impl IntoRawFd for UnixDatagram { |
795 | fn into_raw_fd(self) -> RawFd { | |
796 | self.0.into_inner() | |
797 | } | |
798 | } | |
799 | ||
c30ab7b3 | 800 | #[cfg(all(test, not(target_os = "emscripten")))] |
54a0048b | 801 | mod test { |
54a0048b SL |
802 | use thread; |
803 | use io; | |
804 | use io::prelude::*; | |
805 | use time::Duration; | |
806 | use sys_common::io::test::tmpdir; | |
807 | ||
808 | use super::*; | |
809 | ||
810 | macro_rules! or_panic { | |
811 | ($e:expr) => { | |
812 | match $e { | |
813 | Ok(e) => e, | |
814 | Err(e) => panic!("{}", e), | |
815 | } | |
816 | } | |
817 | } | |
818 | ||
819 | #[test] | |
820 | fn basic() { | |
821 | let dir = tmpdir(); | |
822 | let socket_path = dir.path().join("sock"); | |
823 | let msg1 = b"hello"; | |
824 | let msg2 = b"world!"; | |
825 | ||
826 | let listener = or_panic!(UnixListener::bind(&socket_path)); | |
827 | let thread = thread::spawn(move || { | |
828 | let mut stream = or_panic!(listener.accept()).0; | |
829 | let mut buf = [0; 5]; | |
830 | or_panic!(stream.read(&mut buf)); | |
831 | assert_eq!(&msg1[..], &buf[..]); | |
832 | or_panic!(stream.write_all(msg2)); | |
833 | }); | |
834 | ||
835 | let mut stream = or_panic!(UnixStream::connect(&socket_path)); | |
836 | assert_eq!(Some(&*socket_path), | |
837 | stream.peer_addr().unwrap().as_pathname()); | |
838 | or_panic!(stream.write_all(msg1)); | |
839 | let mut buf = vec![]; | |
840 | or_panic!(stream.read_to_end(&mut buf)); | |
841 | assert_eq!(&msg2[..], &buf[..]); | |
842 | drop(stream); | |
843 | ||
844 | thread.join().unwrap(); | |
845 | } | |
846 | ||
847 | #[test] | |
848 | fn pair() { | |
849 | let msg1 = b"hello"; | |
850 | let msg2 = b"world!"; | |
851 | ||
852 | let (mut s1, mut s2) = or_panic!(UnixStream::pair()); | |
853 | let thread = thread::spawn(move || { | |
854 | // s1 must be moved in or the test will hang! | |
855 | let mut buf = [0; 5]; | |
856 | or_panic!(s1.read(&mut buf)); | |
857 | assert_eq!(&msg1[..], &buf[..]); | |
858 | or_panic!(s1.write_all(msg2)); | |
859 | }); | |
860 | ||
861 | or_panic!(s2.write_all(msg1)); | |
862 | let mut buf = vec![]; | |
863 | or_panic!(s2.read_to_end(&mut buf)); | |
864 | assert_eq!(&msg2[..], &buf[..]); | |
865 | drop(s2); | |
866 | ||
867 | thread.join().unwrap(); | |
868 | } | |
869 | ||
870 | #[test] | |
871 | fn try_clone() { | |
872 | let dir = tmpdir(); | |
873 | let socket_path = dir.path().join("sock"); | |
874 | let msg1 = b"hello"; | |
875 | let msg2 = b"world"; | |
876 | ||
877 | let listener = or_panic!(UnixListener::bind(&socket_path)); | |
878 | let thread = thread::spawn(move || { | |
879 | let mut stream = or_panic!(listener.accept()).0; | |
880 | or_panic!(stream.write_all(msg1)); | |
881 | or_panic!(stream.write_all(msg2)); | |
882 | }); | |
883 | ||
884 | let mut stream = or_panic!(UnixStream::connect(&socket_path)); | |
885 | let mut stream2 = or_panic!(stream.try_clone()); | |
886 | ||
887 | let mut buf = [0; 5]; | |
888 | or_panic!(stream.read(&mut buf)); | |
889 | assert_eq!(&msg1[..], &buf[..]); | |
890 | or_panic!(stream2.read(&mut buf)); | |
891 | assert_eq!(&msg2[..], &buf[..]); | |
892 | ||
893 | thread.join().unwrap(); | |
894 | } | |
895 | ||
896 | #[test] | |
897 | fn iter() { | |
898 | let dir = tmpdir(); | |
899 | let socket_path = dir.path().join("sock"); | |
900 | ||
901 | let listener = or_panic!(UnixListener::bind(&socket_path)); | |
902 | let thread = thread::spawn(move || { | |
903 | for stream in listener.incoming().take(2) { | |
904 | let mut stream = or_panic!(stream); | |
905 | let mut buf = [0]; | |
906 | or_panic!(stream.read(&mut buf)); | |
907 | } | |
908 | }); | |
909 | ||
910 | for _ in 0..2 { | |
911 | let mut stream = or_panic!(UnixStream::connect(&socket_path)); | |
912 | or_panic!(stream.write_all(&[0])); | |
913 | } | |
914 | ||
915 | thread.join().unwrap(); | |
916 | } | |
917 | ||
918 | #[test] | |
919 | fn long_path() { | |
920 | let dir = tmpdir(); | |
921 | let socket_path = dir.path() | |
922 | .join("asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfa\ | |
923 | sasdfasdfasdasdfasdfasdfadfasdfasdfasdfasdfasdf"); | |
924 | match UnixStream::connect(&socket_path) { | |
925 | Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {} | |
926 | Err(e) => panic!("unexpected error {}", e), | |
927 | Ok(_) => panic!("unexpected success"), | |
928 | } | |
929 | ||
930 | match UnixListener::bind(&socket_path) { | |
931 | Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {} | |
932 | Err(e) => panic!("unexpected error {}", e), | |
933 | Ok(_) => panic!("unexpected success"), | |
934 | } | |
935 | ||
936 | match UnixDatagram::bind(&socket_path) { | |
937 | Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {} | |
938 | Err(e) => panic!("unexpected error {}", e), | |
939 | Ok(_) => panic!("unexpected success"), | |
940 | } | |
941 | } | |
942 | ||
943 | #[test] | |
944 | fn timeouts() { | |
945 | let dir = tmpdir(); | |
946 | let socket_path = dir.path().join("sock"); | |
947 | ||
948 | let _listener = or_panic!(UnixListener::bind(&socket_path)); | |
949 | ||
950 | let stream = or_panic!(UnixStream::connect(&socket_path)); | |
951 | let dur = Duration::new(15410, 0); | |
952 | ||
953 | assert_eq!(None, or_panic!(stream.read_timeout())); | |
954 | ||
955 | or_panic!(stream.set_read_timeout(Some(dur))); | |
956 | assert_eq!(Some(dur), or_panic!(stream.read_timeout())); | |
957 | ||
958 | assert_eq!(None, or_panic!(stream.write_timeout())); | |
959 | ||
960 | or_panic!(stream.set_write_timeout(Some(dur))); | |
961 | assert_eq!(Some(dur), or_panic!(stream.write_timeout())); | |
962 | ||
963 | or_panic!(stream.set_read_timeout(None)); | |
964 | assert_eq!(None, or_panic!(stream.read_timeout())); | |
965 | ||
966 | or_panic!(stream.set_write_timeout(None)); | |
967 | assert_eq!(None, or_panic!(stream.write_timeout())); | |
968 | } | |
969 | ||
970 | #[test] | |
971 | fn test_read_timeout() { | |
972 | let dir = tmpdir(); | |
973 | let socket_path = dir.path().join("sock"); | |
974 | ||
975 | let _listener = or_panic!(UnixListener::bind(&socket_path)); | |
976 | ||
977 | let mut stream = or_panic!(UnixStream::connect(&socket_path)); | |
978 | or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); | |
979 | ||
980 | let mut buf = [0; 10]; | |
981 | let kind = stream.read(&mut buf).err().expect("expected error").kind(); | |
982 | assert!(kind == io::ErrorKind::WouldBlock || kind == io::ErrorKind::TimedOut); | |
983 | } | |
984 | ||
985 | #[test] | |
986 | fn test_read_with_timeout() { | |
987 | let dir = tmpdir(); | |
988 | let socket_path = dir.path().join("sock"); | |
989 | ||
990 | let listener = or_panic!(UnixListener::bind(&socket_path)); | |
991 | ||
992 | let mut stream = or_panic!(UnixStream::connect(&socket_path)); | |
993 | or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); | |
994 | ||
995 | let mut other_end = or_panic!(listener.accept()).0; | |
996 | or_panic!(other_end.write_all(b"hello world")); | |
997 | ||
998 | let mut buf = [0; 11]; | |
999 | or_panic!(stream.read(&mut buf)); | |
1000 | assert_eq!(b"hello world", &buf[..]); | |
1001 | ||
1002 | let kind = stream.read(&mut buf).err().expect("expected error").kind(); | |
1003 | assert!(kind == io::ErrorKind::WouldBlock || kind == io::ErrorKind::TimedOut); | |
1004 | } | |
1005 | ||
1006 | #[test] | |
1007 | fn test_unix_datagram() { | |
1008 | let dir = tmpdir(); | |
1009 | let path1 = dir.path().join("sock1"); | |
1010 | let path2 = dir.path().join("sock2"); | |
1011 | ||
1012 | let sock1 = or_panic!(UnixDatagram::bind(&path1)); | |
1013 | let sock2 = or_panic!(UnixDatagram::bind(&path2)); | |
1014 | ||
1015 | let msg = b"hello world"; | |
1016 | or_panic!(sock1.send_to(msg, &path2)); | |
1017 | let mut buf = [0; 11]; | |
1018 | or_panic!(sock2.recv_from(&mut buf)); | |
1019 | assert_eq!(msg, &buf[..]); | |
1020 | } | |
1021 | ||
1022 | #[test] | |
1023 | fn test_unnamed_unix_datagram() { | |
1024 | let dir = tmpdir(); | |
1025 | let path1 = dir.path().join("sock1"); | |
1026 | ||
1027 | let sock1 = or_panic!(UnixDatagram::bind(&path1)); | |
1028 | let sock2 = or_panic!(UnixDatagram::unbound()); | |
1029 | ||
1030 | let msg = b"hello world"; | |
1031 | or_panic!(sock2.send_to(msg, &path1)); | |
1032 | let mut buf = [0; 11]; | |
1033 | let (usize, addr) = or_panic!(sock1.recv_from(&mut buf)); | |
1034 | assert_eq!(usize, 11); | |
1035 | assert!(addr.is_unnamed()); | |
1036 | assert_eq!(msg, &buf[..]); | |
1037 | } | |
1038 | ||
1039 | #[test] | |
1040 | fn test_connect_unix_datagram() { | |
1041 | let dir = tmpdir(); | |
1042 | let path1 = dir.path().join("sock1"); | |
1043 | let path2 = dir.path().join("sock2"); | |
1044 | ||
1045 | let bsock1 = or_panic!(UnixDatagram::bind(&path1)); | |
1046 | let bsock2 = or_panic!(UnixDatagram::bind(&path2)); | |
1047 | let sock = or_panic!(UnixDatagram::unbound()); | |
1048 | or_panic!(sock.connect(&path1)); | |
1049 | ||
1050 | // Check send() | |
1051 | let msg = b"hello there"; | |
1052 | or_panic!(sock.send(msg)); | |
1053 | let mut buf = [0; 11]; | |
1054 | let (usize, addr) = or_panic!(bsock1.recv_from(&mut buf)); | |
1055 | assert_eq!(usize, 11); | |
1056 | assert!(addr.is_unnamed()); | |
1057 | assert_eq!(msg, &buf[..]); | |
1058 | ||
1059 | // Changing default socket works too | |
1060 | or_panic!(sock.connect(&path2)); | |
1061 | or_panic!(sock.send(msg)); | |
1062 | or_panic!(bsock2.recv_from(&mut buf)); | |
1063 | } | |
1064 | ||
1065 | #[test] | |
1066 | fn test_unix_datagram_recv() { | |
1067 | let dir = tmpdir(); | |
1068 | let path1 = dir.path().join("sock1"); | |
1069 | ||
1070 | let sock1 = or_panic!(UnixDatagram::bind(&path1)); | |
1071 | let sock2 = or_panic!(UnixDatagram::unbound()); | |
1072 | or_panic!(sock2.connect(&path1)); | |
1073 | ||
1074 | let msg = b"hello world"; | |
1075 | or_panic!(sock2.send(msg)); | |
1076 | let mut buf = [0; 11]; | |
1077 | let size = or_panic!(sock1.recv(&mut buf)); | |
1078 | assert_eq!(size, 11); | |
1079 | assert_eq!(msg, &buf[..]); | |
1080 | } | |
1081 | ||
1082 | #[test] | |
1083 | fn datagram_pair() { | |
1084 | let msg1 = b"hello"; | |
1085 | let msg2 = b"world!"; | |
1086 | ||
1087 | let (s1, s2) = or_panic!(UnixDatagram::pair()); | |
1088 | let thread = thread::spawn(move || { | |
1089 | // s1 must be moved in or the test will hang! | |
1090 | let mut buf = [0; 5]; | |
1091 | or_panic!(s1.recv(&mut buf)); | |
1092 | assert_eq!(&msg1[..], &buf[..]); | |
1093 | or_panic!(s1.send(msg2)); | |
1094 | }); | |
1095 | ||
1096 | or_panic!(s2.send(msg1)); | |
1097 | let mut buf = [0; 6]; | |
1098 | or_panic!(s2.recv(&mut buf)); | |
1099 | assert_eq!(&msg2[..], &buf[..]); | |
1100 | drop(s2); | |
1101 | ||
1102 | thread.join().unwrap(); | |
1103 | } | |
1104 | ||
1105 | #[test] | |
1106 | fn abstract_namespace_not_allowed() { | |
1107 | assert!(UnixStream::connect("\0asdf").is_err()); | |
1108 | } | |
1109 | } |