]>
Commit | Line | Data |
---|---|---|
fc512014 XL |
1 | src/socket.rs |
2 | src/sys/unix.rs | |
3 | src/sys/windows.rs | |
4 | ||
5 | ||
6 | ||
7 | ||
8 | commit 9f0fbf2ed487668e4e2b5357a8e4a167e7ec903a | |
9 | Author: Thomas de Zeeuw <thomasdezeeuw@gmail.com> | |
10 | Date: Sat Jan 18 16:43:21 2020 +0100 | |
11 | ||
12 | Part 1 of the rewrite | |
13 | ||
14 | Currently not functional on Windows and a lot of methods are removed, | |
15 | but its a start. | |
16 | ||
17 | diff --git a/src/socket.rs b/src/socket.rs | |
18 | index 354c5cf..424e094 100644 | |
19 | --- a/src/socket.rs | |
20 | +++ b/src/socket.rs | |
21 | @@ -8,201 +8,107 @@ | |
22 | // option. This file may not be copied, modified, or distributed | |
23 | // except according to those terms. | |
24 | ||
25 | -use std::fmt; | |
26 | -use std::io::{self, Read, Write}; | |
27 | -use std::net::{self, Ipv4Addr, Ipv6Addr, Shutdown}; | |
28 | -#[cfg(all(unix, feature = "unix"))] | |
29 | -use std::os::unix::net::{UnixDatagram, UnixListener, UnixStream}; | |
30 | -use std::time::Duration; | |
31 | +use std::net::{Shutdown, TcpListener, TcpStream, UdpSocket}; | |
32 | +#[cfg(unix)] | |
33 | +use std::os::unix::io::{FromRawFd, IntoRawFd}; | |
34 | +use std::{fmt, io}; | |
35 | ||
36 | -use crate::sys; | |
37 | +use crate::sys::{self, c_int}; | |
38 | use crate::{Domain, Protocol, SockAddr, Type}; | |
39 | ||
40 | -/// Newtype, owned, wrapper around a system socket. | |
41 | +/// An owned system socket. | |
42 | /// | |
43 | -/// This type simply wraps an instance of a file descriptor (`c_int`) on Unix | |
44 | -/// and an instance of `SOCKET` on Windows. This is the main type exported by | |
45 | -/// this crate and is intended to mirror the raw semantics of sockets on | |
46 | -/// platforms as closely as possible. Almost all methods correspond to | |
47 | -/// precisely one libc or OS API call which is essentially just a "Rustic | |
48 | -/// translation" of what's below. | |
49 | +/// This type simply wraps an instance of a file descriptor (`int`) on Unix and | |
50 | +/// an instance of `SOCKET` on Windows. This is the main type exported by this | |
51 | +/// crate and is intended to mirror the raw semantics of sockets on platforms as | |
52 | +/// closely as possible. All methods correspond to precisely one libc or OS API | |
53 | +/// call which is essentially just a "Rustic translation" of what's below. | |
54 | +/// | |
55 | +/// # Notes | |
56 | +/// | |
57 | +/// This type can be converted to and from all network types provided by the | |
58 | +/// standard library using the [`From`] and [`Into`] traits. Is up to the user | |
59 | +/// to ensure the socket is setup correctly for a given type! | |
60 | /// | |
61 | /// # Examples | |
62 | /// | |
63 | -/// ```no_run | |
64 | -/// use std::net::SocketAddr; | |
65 | -/// use socket2::{Socket, Domain, Type, SockAddr}; | |
66 | +/// ``` | |
67 | +/// # fn main() -> std::io::Result<()> { | |
68 | +/// use std::net::{SocketAddr, TcpListener}; | |
69 | +/// use socket2::{Socket, Domain, Type}; | |
70 | /// | |
71 | -/// // create a TCP listener bound to two addresses | |
72 | -/// let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); | |
73 | +/// // Create a new `Socket`. | |
74 | +/// let socket = Socket::new(Domain::ipv4(), Type::stream(), None)?; | |
75 | /// | |
76 | -/// socket.bind(&"127.0.0.1:12345".parse::<SocketAddr>().unwrap().into()).unwrap(); | |
77 | -/// socket.bind(&"127.0.0.1:12346".parse::<SocketAddr>().unwrap().into()).unwrap(); | |
78 | -/// socket.listen(128).unwrap(); | |
79 | +/// // Bind the socket to an addresses. | |
80 | +/// let addr1: SocketAddr = "127.0.0.1:15123".parse().unwrap(); | |
81 | +/// socket.bind(&addr1.into())?; | |
82 | /// | |
83 | -/// let listener = socket.into_tcp_listener(); | |
84 | -/// // ... | |
85 | +/// // Start listening on the socket. | |
86 | +/// socket.listen(128)?; | |
87 | +/// | |
88 | +/// // Finally convert it to `TcpListener` from the standard library. Now it can | |
89 | +/// // be used like any other `TcpListener`. | |
90 | +/// let listener: TcpListener = socket.into(); | |
91 | +/// # drop(listener); | |
92 | +/// # Ok(()) | |
93 | +/// # } | |
94 | /// ``` | |
95 | pub struct Socket { | |
96 | - // The `sys` module most have access to the socket. | |
97 | - pub(crate) inner: sys::Socket, | |
98 | + // The `sys` module must have access to the raw socket to implement OS | |
99 | + // specific additional methods, e.g. Unix Domain sockets (UDS). | |
100 | + pub(crate) inner: sys::RawSocket, | |
101 | } | |
102 | ||
103 | impl Socket { | |
104 | /// Creates a new socket ready to be configured. | |
105 | /// | |
106 | - /// This function corresponds to `socket(2)` and simply creates a new | |
107 | - /// socket, no other configuration is done and further functions must be | |
108 | - /// invoked to configure this socket. | |
109 | + /// This function corresponds to `socket(2)`. | |
110 | pub fn new(domain: Domain, type_: Type, protocol: Option<Protocol>) -> io::Result<Socket> { | |
111 | - let protocol = protocol.map(|p| p.0).unwrap_or(0); | |
112 | - Ok(Socket { | |
113 | - inner: sys::Socket::new(domain.0, type_.0, protocol)?, | |
114 | - }) | |
115 | - } | |
116 | - | |
117 | - /// Creates a pair of sockets which are connected to each other. | |
118 | - /// | |
119 | - /// This function corresponds to `socketpair(2)`. | |
120 | - /// | |
121 | - /// This function is only available on Unix when the `pair` feature is | |
122 | - /// enabled. | |
123 | - #[cfg(all(unix, feature = "pair"))] | |
124 | - pub fn pair( | |
125 | - domain: Domain, | |
126 | - type_: Type, | |
127 | - protocol: Option<Protocol>, | |
128 | - ) -> io::Result<(Socket, Socket)> { | |
129 | - let protocol = protocol.map(|p| p.0).unwrap_or(0); | |
130 | - let sockets = sys::Socket::pair(domain.0, type_.0, protocol)?; | |
131 | - Ok((Socket { inner: sockets.0 }, Socket { inner: sockets.1 })) | |
132 | - } | |
133 | - | |
134 | - /// Consumes this `Socket`, converting it to a `TcpStream`. | |
135 | - pub fn into_tcp_stream(self) -> net::TcpStream { | |
136 | - self.into() | |
137 | - } | |
138 | - | |
139 | - /// Consumes this `Socket`, converting it to a `TcpListener`. | |
140 | - pub fn into_tcp_listener(self) -> net::TcpListener { | |
141 | - self.into() | |
142 | - } | |
143 | - | |
144 | - /// Consumes this `Socket`, converting it to a `UdpSocket`. | |
145 | - pub fn into_udp_socket(self) -> net::UdpSocket { | |
146 | - self.into() | |
147 | - } | |
148 | - | |
149 | - /// Consumes this `Socket`, converting it into a `UnixStream`. | |
150 | - /// | |
151 | - /// This function is only available on Unix when the `unix` feature is | |
152 | - /// enabled. | |
153 | - #[cfg(all(unix, feature = "unix"))] | |
154 | - pub fn into_unix_stream(self) -> UnixStream { | |
155 | - self.into() | |
156 | - } | |
157 | - | |
158 | - /// Consumes this `Socket`, converting it into a `UnixListener`. | |
159 | - /// | |
160 | - /// This function is only available on Unix when the `unix` feature is | |
161 | - /// enabled. | |
162 | - #[cfg(all(unix, feature = "unix"))] | |
163 | - pub fn into_unix_listener(self) -> UnixListener { | |
164 | - self.into() | |
165 | - } | |
166 | - | |
167 | - /// Consumes this `Socket`, converting it into a `UnixDatagram`. | |
168 | - /// | |
169 | - /// This function is only available on Unix when the `unix` feature is | |
170 | - /// enabled. | |
171 | - #[cfg(all(unix, feature = "unix"))] | |
172 | - pub fn into_unix_datagram(self) -> UnixDatagram { | |
173 | - self.into() | |
174 | + sys::socket(domain.0, type_.0, protocol.map(|p| p.0).unwrap_or(0)) | |
175 | } | |
176 | ||
177 | /// Initiate a connection on this socket to the specified address. | |
178 | /// | |
179 | - /// This function directly corresponds to the connect(2) function on Windows | |
180 | - /// and Unix. | |
181 | - /// | |
182 | - /// An error will be returned if `listen` or `connect` has already been | |
183 | - /// called on this builder. | |
184 | + /// This function directly corresponds to the `connect(2)` function. | |
185 | pub fn connect(&self, addr: &SockAddr) -> io::Result<()> { | |
186 | - self.inner.connect(addr) | |
187 | - } | |
188 | - | |
189 | - /// Initiate a connection on this socket to the specified address, only | |
190 | - /// only waiting for a certain period of time for the connection to be | |
191 | - /// established. | |
192 | - /// | |
193 | - /// Unlike many other methods on `Socket`, this does *not* correspond to a | |
194 | - /// single C function. It sets the socket to nonblocking mode, connects via | |
195 | - /// connect(2), and then waits for the connection to complete with poll(2) | |
196 | - /// on Unix and select on Windows. When the connection is complete, the | |
197 | - /// socket is set back to blocking mode. On Unix, this will loop over | |
198 | - /// `EINTR` errors. | |
199 | - /// | |
200 | - /// # Warnings | |
201 | - /// | |
202 | - /// The nonblocking state of the socket is overridden by this function - | |
203 | - /// it will be returned in blocking mode on success, and in an indeterminate | |
204 | - /// state on failure. | |
205 | - /// | |
206 | - /// If the connection request times out, it may still be processing in the | |
207 | - /// background - a second call to `connect` or `connect_timeout` may fail. | |
208 | - pub fn connect_timeout(&self, addr: &SockAddr, timeout: Duration) -> io::Result<()> { | |
209 | - self.inner.connect_timeout(addr, timeout) | |
210 | + sys::connect(self.inner, addr.as_ptr(), addr.len()) | |
211 | } | |
212 | ||
213 | /// Binds this socket to the specified address. | |
214 | /// | |
215 | - /// This function directly corresponds to the bind(2) function on Windows | |
216 | - /// and Unix. | |
217 | + /// This function directly corresponds to the `bind(2)` function. | |
218 | pub fn bind(&self, addr: &SockAddr) -> io::Result<()> { | |
219 | - self.inner.bind(addr) | |
220 | + sys::bind(self.inner, addr.as_ptr(), addr.len()) | |
221 | } | |
222 | ||
223 | - /// Mark a socket as ready to accept incoming connection requests using | |
224 | - /// accept() | |
225 | + /// Returns the socket address of the local half of this connection. | |
226 | /// | |
227 | - /// This function directly corresponds to the listen(2) function on Windows | |
228 | - /// and Unix. | |
229 | - /// | |
230 | - /// An error will be returned if `listen` or `connect` has already been | |
231 | - /// called on this builder. | |
232 | - pub fn listen(&self, backlog: i32) -> io::Result<()> { | |
233 | - self.inner.listen(backlog) | |
234 | + /// This function directly corresponds to the `getsockname(2)` function. | |
235 | + pub fn local_addr(&self) -> io::Result<SockAddr> { | |
236 | + sys::getsockname(self.inner) | |
237 | } | |
238 | ||
239 | - /// Accept a new incoming connection from this listener. | |
240 | + /// Returns the socket address of the remote peer of this connection. | |
241 | /// | |
242 | - /// This function will block the calling thread until a new connection is | |
243 | - /// established. When established, the corresponding `Socket` and the | |
244 | - /// remote peer's address will be returned. | |
245 | - pub fn accept(&self) -> io::Result<(Socket, SockAddr)> { | |
246 | - self.inner | |
247 | - .accept() | |
248 | - .map(|(socket, addr)| (Socket { inner: socket }, addr)) | |
249 | - } | |
250 | - | |
251 | - /// Returns the socket address of the local half of this TCP connection. | |
252 | - pub fn local_addr(&self) -> io::Result<SockAddr> { | |
253 | - self.inner.local_addr() | |
254 | + /// This function directly corresponds to the `getpeername(2)` function. | |
255 | + pub fn peer_addr(&self) -> io::Result<SockAddr> { | |
256 | + sys::getpeername(self.inner) | |
257 | } | |
258 | ||
259 | - /// Returns the socket address of the remote peer of this TCP connection. | |
260 | - pub fn peer_addr(&self) -> io::Result<SockAddr> { | |
261 | - self.inner.peer_addr() | |
262 | + /// Mark a socket as ready to accept incoming connection requests using | |
263 | + /// `accept(2)`. | |
264 | + /// | |
265 | + /// This function directly corresponds to the `listen(2)` function. | |
266 | + pub fn listen(&self, backlog: c_int) -> io::Result<()> { | |
267 | + sys::listen(self.inner, backlog) | |
268 | } | |
269 | ||
270 | - /// Creates a new independently owned handle to the underlying socket. | |
271 | + /// Accept a new incoming connection from this listener. | |
272 | /// | |
273 | - /// The returned `TcpStream` is a reference to the same stream that this | |
274 | - /// object references. Both handles will read and write the same stream of | |
275 | - /// data, and options set on one stream will be propagated to the other | |
276 | - /// stream. | |
277 | - pub fn try_clone(&self) -> io::Result<Socket> { | |
278 | - self.inner.try_clone().map(|s| Socket { inner: s }) | |
279 | + /// This function directly corresponds to the `accept(2)` function. | |
280 | + pub fn accept(&self) -> io::Result<(Socket, SockAddr)> { | |
281 | + sys::accept(self.inner) | |
282 | } | |
283 | ||
284 | /// Get the value of the `SO_ERROR` option on this socket. | |
285 | @@ -211,15 +117,14 @@ impl Socket { | |
286 | /// the field in the process. This can be useful for checking errors between | |
287 | /// calls. | |
288 | pub fn take_error(&self) -> io::Result<Option<io::Error>> { | |
289 | - self.inner.take_error() | |
290 | - } | |
291 | - | |
292 | - /// Moves this TCP stream into or out of nonblocking mode. | |
293 | - /// | |
294 | - /// On Unix this corresponds to calling fcntl, and on Windows this | |
295 | - /// corresponds to calling ioctlsocket. | |
296 | - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { | |
297 | - self.inner.set_nonblocking(nonblocking) | |
298 | + self.getsockopt::<c_int>(libc::SOL_SOCKET, libc::SO_ERROR) | |
299 | + .map(|errno| { | |
300 | + if errno == 0 { | |
301 | + None | |
302 | + } else { | |
303 | + Some(io::Error::from_raw_os_error(errno)) | |
304 | + } | |
305 | + }) | |
306 | } | |
307 | ||
308 | /// Shuts down the read, write, or both halves of this connection. | |
309 | @@ -227,689 +132,110 @@ impl Socket { | |
310 | /// This function will cause all pending and future I/O on the specified | |
311 | /// portions to return immediately with an appropriate value. | |
312 | pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { | |
313 | - self.inner.shutdown(how) | |
314 | - } | |
315 | - | |
316 | - /// Receives data on the socket from the remote address to which it is | |
317 | - /// connected. | |
318 | - /// | |
319 | - /// The [`connect`] method will connect this socket to a remote address. This | |
320 | - /// method will fail if the socket is not connected. | |
321 | - /// | |
322 | - /// [`connect`]: #method.connect | |
323 | - pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> { | |
324 | - self.inner.recv(buf) | |
325 | - } | |
326 | - | |
327 | - /// Receives data on the socket from the remote adress to which it is | |
328 | - /// connected, without removing that data from the queue. On success, | |
329 | - /// returns the number of bytes peeked. | |
330 | - /// | |
331 | - /// Successive calls return the same data. This is accomplished by passing | |
332 | - /// `MSG_PEEK` as a flag to the underlying `recv` system call. | |
333 | - pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> { | |
334 | - self.inner.peek(buf) | |
335 | - } | |
336 | - | |
337 | - /// Receives data from the socket. On success, returns the number of bytes | |
338 | - /// read and the address from whence the data came. | |
339 | - pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SockAddr)> { | |
340 | - self.inner.recv_from(buf) | |
341 | - } | |
342 | - | |
343 | - /// Receives data from the socket, without removing it from the queue. | |
344 | - /// | |
345 | - /// Successive calls return the same data. This is accomplished by passing | |
346 | - /// `MSG_PEEK` as a flag to the underlying `recvfrom` system call. | |
347 | - /// | |
348 | - /// On success, returns the number of bytes peeked and the address from | |
349 | - /// whence the data came. | |
350 | - pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SockAddr)> { | |
351 | - self.inner.peek_from(buf) | |
352 | - } | |
353 | - | |
354 | - /// Sends data on the socket to a connected peer. | |
355 | - /// | |
356 | - /// This is typically used on TCP sockets or datagram sockets which have | |
357 | - /// been connected. | |
358 | - /// | |
359 | - /// On success returns the number of bytes that were sent. | |
360 | - pub fn send(&self, buf: &[u8]) -> io::Result<usize> { | |
361 | - self.inner.send(buf) | |
362 | - } | |
363 | - | |
364 | - /// Sends data on the socket to the given address. On success, returns the | |
365 | - /// number of bytes written. | |
366 | - /// | |
367 | - /// This is typically used on UDP or datagram-oriented sockets. On success | |
368 | - /// returns the number of bytes that were sent. | |
369 | - pub fn send_to(&self, buf: &[u8], addr: &SockAddr) -> io::Result<usize> { | |
370 | - self.inner.send_to(buf, addr) | |
371 | - } | |
372 | - | |
373 | - // ================================================ | |
374 | - | |
375 | - /// Gets the value of the `IP_TTL` option for this socket. | |
376 | - /// | |
377 | - /// For more information about this option, see [`set_ttl`][link]. | |
378 | - /// | |
379 | - /// [link]: #method.set_ttl | |
380 | - pub fn ttl(&self) -> io::Result<u32> { | |
381 | - self.inner.ttl() | |
382 | - } | |
383 | - | |
384 | - /// Sets the value for the `IP_TTL` option on this socket. | |
385 | - /// | |
386 | - /// This value sets the time-to-live field that is used in every packet sent | |
387 | - /// from this socket. | |
388 | - pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { | |
389 | - self.inner.set_ttl(ttl) | |
390 | - } | |
391 | - | |
392 | - /// Gets the value of the `IPV6_UNICAST_HOPS` option for this socket. | |
393 | - /// | |
394 | - /// Specifies the hop limit for ipv6 unicast packets | |
395 | - pub fn unicast_hops_v6(&self) -> io::Result<u32> { | |
396 | - self.inner.unicast_hops_v6() | |
397 | - } | |
398 | - | |
399 | - /// Sets the value for the `IPV6_UNICAST_HOPS` option on this socket. | |
400 | - /// | |
401 | - /// Specifies the hop limit for ipv6 unicast packets | |
402 | - pub fn set_unicast_hops_v6(&self, ttl: u32) -> io::Result<()> { | |
403 | - self.inner.set_unicast_hops_v6(ttl) | |
404 | - } | |
405 | - | |
406 | - /// Gets the value of the `IPV6_V6ONLY` option for this socket. | |
407 | - /// | |
408 | - /// For more information about this option, see [`set_only_v6`][link]. | |
409 | - /// | |
410 | - /// [link]: #method.set_only_v6 | |
411 | - pub fn only_v6(&self) -> io::Result<bool> { | |
412 | - self.inner.only_v6() | |
413 | - } | |
414 | - | |
415 | - /// Sets the value for the `IPV6_V6ONLY` option on this socket. | |
416 | - /// | |
417 | - /// If this is set to `true` then the socket is restricted to sending and | |
418 | - /// receiving IPv6 packets only. In this case two IPv4 and IPv6 applications | |
419 | - /// can bind the same port at the same time. | |
420 | - /// | |
421 | - /// If this is set to `false` then the socket can be used to send and | |
422 | - /// receive packets from an IPv4-mapped IPv6 address. | |
423 | - pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> { | |
424 | - self.inner.set_only_v6(only_v6) | |
425 | - } | |
426 | - | |
427 | - /// Returns the read timeout of this socket. | |
428 | - /// | |
429 | - /// If the timeout is `None`, then `read` calls will block indefinitely. | |
430 | - pub fn read_timeout(&self) -> io::Result<Option<Duration>> { | |
431 | - self.inner.read_timeout() | |
432 | - } | |
433 | - | |
434 | - /// Sets the read timeout to the timeout specified. | |
435 | - /// | |
436 | - /// If the value specified is `None`, then `read` calls will block | |
437 | - /// indefinitely. It is an error to pass the zero `Duration` to this | |
438 | - /// method. | |
439 | - pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> { | |
440 | - self.inner.set_read_timeout(dur) | |
441 | - } | |
442 | - | |
443 | - /// Returns the write timeout of this socket. | |
444 | - /// | |
445 | - /// If the timeout is `None`, then `write` calls will block indefinitely. | |
446 | - pub fn write_timeout(&self) -> io::Result<Option<Duration>> { | |
447 | - self.inner.write_timeout() | |
448 | - } | |
449 | - | |
450 | - /// Sets the write timeout to the timeout specified. | |
451 | - /// | |
452 | - /// If the value specified is `None`, then `write` calls will block | |
453 | - /// indefinitely. It is an error to pass the zero `Duration` to this | |
454 | - /// method. | |
455 | - pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> { | |
456 | - self.inner.set_write_timeout(dur) | |
457 | - } | |
458 | - | |
459 | - /// Gets the value of the `TCP_NODELAY` option on this socket. | |
460 | - /// | |
461 | - /// For more information about this option, see [`set_nodelay`][link]. | |
462 | - /// | |
463 | - /// [link]: #method.set_nodelay | |
464 | - pub fn nodelay(&self) -> io::Result<bool> { | |
465 | - self.inner.nodelay() | |
466 | - } | |
467 | - | |
468 | - /// Sets the value of the `TCP_NODELAY` option on this socket. | |
469 | - /// | |
470 | - /// If set, this option disables the Nagle algorithm. This means that | |
471 | - /// segments are always sent as soon as possible, even if there is only a | |
472 | - /// small amount of data. When not set, data is buffered until there is a | |
473 | - /// sufficient amount to send out, thereby avoiding the frequent sending of | |
474 | - /// small packets. | |
475 | - pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { | |
476 | - self.inner.set_nodelay(nodelay) | |
477 | - } | |
478 | - | |
479 | - /// Sets the value of the `SO_BROADCAST` option for this socket. | |
480 | - /// | |
481 | - /// When enabled, this socket is allowed to send packets to a broadcast | |
482 | - /// address. | |
483 | - pub fn broadcast(&self) -> io::Result<bool> { | |
484 | - self.inner.broadcast() | |
485 | - } | |
486 | - | |
487 | - /// Gets the value of the `SO_BROADCAST` option for this socket. | |
488 | - /// | |
489 | - /// For more information about this option, see | |
490 | - /// [`set_broadcast`][link]. | |
491 | - /// | |
492 | - /// [link]: #method.set_broadcast | |
493 | - pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> { | |
494 | - self.inner.set_broadcast(broadcast) | |
495 | - } | |
496 | - | |
497 | - /// Gets the value of the `IP_MULTICAST_LOOP` option for this socket. | |
498 | - /// | |
499 | - /// For more information about this option, see | |
500 | - /// [`set_multicast_loop_v4`][link]. | |
501 | - /// | |
502 | - /// [link]: #method.set_multicast_loop_v4 | |
503 | - pub fn multicast_loop_v4(&self) -> io::Result<bool> { | |
504 | - self.inner.multicast_loop_v4() | |
505 | - } | |
506 | - | |
507 | - /// Sets the value of the `IP_MULTICAST_LOOP` option for this socket. | |
508 | - /// | |
509 | - /// If enabled, multicast packets will be looped back to the local socket. | |
510 | - /// Note that this may not have any affect on IPv6 sockets. | |
511 | - pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> { | |
512 | - self.inner.set_multicast_loop_v4(multicast_loop_v4) | |
513 | - } | |
514 | - | |
515 | - /// Gets the value of the `IP_MULTICAST_TTL` option for this socket. | |
516 | - /// | |
517 | - /// For more information about this option, see | |
518 | - /// [`set_multicast_ttl_v4`][link]. | |
519 | - /// | |
520 | - /// [link]: #method.set_multicast_ttl_v4 | |
521 | - pub fn multicast_ttl_v4(&self) -> io::Result<u32> { | |
522 | - self.inner.multicast_ttl_v4() | |
523 | - } | |
524 | - | |
525 | - /// Sets the value of the `IP_MULTICAST_TTL` option for this socket. | |
526 | - /// | |
527 | - /// Indicates the time-to-live value of outgoing multicast packets for | |
528 | - /// this socket. The default value is 1 which means that multicast packets | |
529 | - /// don't leave the local network unless explicitly requested. | |
530 | - /// | |
531 | - /// Note that this may not have any affect on IPv6 sockets. | |
532 | - pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> { | |
533 | - self.inner.set_multicast_ttl_v4(multicast_ttl_v4) | |
534 | - } | |
535 | - | |
536 | - /// Gets the value of the `IPV6_MULTICAST_HOPS` option for this socket | |
537 | - /// | |
538 | - /// For more information about this option, see | |
539 | - /// [`set_multicast_hops_v6`][link]. | |
540 | - /// | |
541 | - /// [link]: #method.set_multicast_hops_v6 | |
542 | - pub fn multicast_hops_v6(&self) -> io::Result<u32> { | |
543 | - self.inner.multicast_hops_v6() | |
544 | - } | |
545 | - | |
546 | - /// Sets the value of the `IPV6_MULTICAST_HOPS` option for this socket | |
547 | - /// | |
548 | - /// Indicates the number of "routers" multicast packets will transit for | |
549 | - /// this socket. The default value is 1 which means that multicast packets | |
550 | - /// don't leave the local network unless explicitly requested. | |
551 | - pub fn set_multicast_hops_v6(&self, hops: u32) -> io::Result<()> { | |
552 | - self.inner.set_multicast_hops_v6(hops) | |
553 | - } | |
554 | - | |
555 | - /// Gets the value of the `IP_MULTICAST_IF` option for this socket. | |
556 | - /// | |
557 | - /// For more information about this option, see | |
558 | - /// [`set_multicast_if_v4`][link]. | |
559 | - /// | |
560 | - /// [link]: #method.set_multicast_if_v4 | |
561 | - /// | |
562 | - /// Returns the interface to use for routing multicast packets. | |
563 | - pub fn multicast_if_v4(&self) -> io::Result<Ipv4Addr> { | |
564 | - self.inner.multicast_if_v4() | |
565 | - } | |
566 | - | |
567 | - /// Sets the value of the `IP_MULTICAST_IF` option for this socket. | |
568 | - /// | |
569 | - /// Specifies the interface to use for routing multicast packets. | |
570 | - pub fn set_multicast_if_v4(&self, interface: &Ipv4Addr) -> io::Result<()> { | |
571 | - self.inner.set_multicast_if_v4(interface) | |
572 | - } | |
573 | - | |
574 | - /// Gets the value of the `IPV6_MULTICAST_IF` option for this socket. | |
575 | - /// | |
576 | - /// For more information about this option, see | |
577 | - /// [`set_multicast_if_v6`][link]. | |
578 | - /// | |
579 | - /// [link]: #method.set_multicast_if_v6 | |
580 | - /// | |
581 | - /// Returns the interface to use for routing multicast packets. | |
582 | - pub fn multicast_if_v6(&self) -> io::Result<u32> { | |
583 | - self.inner.multicast_if_v6() | |
584 | - } | |
585 | - | |
586 | - /// Sets the value of the `IPV6_MULTICAST_IF` option for this socket. | |
587 | - /// | |
588 | - /// Specifies the interface to use for routing multicast packets. Unlike ipv4, this | |
589 | - /// is generally required in ipv6 contexts where network routing prefixes may | |
590 | - /// overlap. | |
591 | - pub fn set_multicast_if_v6(&self, interface: u32) -> io::Result<()> { | |
592 | - self.inner.set_multicast_if_v6(interface) | |
593 | - } | |
594 | - | |
595 | - /// Gets the value of the `IPV6_MULTICAST_LOOP` option for this socket. | |
596 | - /// | |
597 | - /// For more information about this option, see | |
598 | - /// [`set_multicast_loop_v6`][link]. | |
599 | - /// | |
600 | - /// [link]: #method.set_multicast_loop_v6 | |
601 | - pub fn multicast_loop_v6(&self) -> io::Result<bool> { | |
602 | - self.inner.multicast_loop_v6() | |
603 | - } | |
604 | - | |
605 | - /// Sets the value of the `IPV6_MULTICAST_LOOP` option for this socket. | |
606 | - /// | |
607 | - /// Controls whether this socket sees the multicast packets it sends itself. | |
608 | - /// Note that this may not have any affect on IPv4 sockets. | |
609 | - pub fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> { | |
610 | - self.inner.set_multicast_loop_v6(multicast_loop_v6) | |
611 | - } | |
612 | - | |
613 | - /// Executes an operation of the `IP_ADD_MEMBERSHIP` type. | |
614 | - /// | |
615 | - /// This function specifies a new multicast group for this socket to join. | |
616 | - /// The address must be a valid multicast address, and `interface` is the | |
617 | - /// address of the local interface with which the system should join the | |
618 | - /// multicast group. If it's equal to `INADDR_ANY` then an appropriate | |
619 | - /// interface is chosen by the system. | |
620 | - pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { | |
621 | - self.inner.join_multicast_v4(multiaddr, interface) | |
622 | - } | |
623 | - | |
624 | - /// Executes an operation of the `IPV6_ADD_MEMBERSHIP` type. | |
625 | - /// | |
626 | - /// This function specifies a new multicast group for this socket to join. | |
627 | - /// The address must be a valid multicast address, and `interface` is the | |
628 | - /// index of the interface to join/leave (or 0 to indicate any interface). | |
629 | - pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { | |
630 | - self.inner.join_multicast_v6(multiaddr, interface) | |
631 | - } | |
632 | - | |
633 | - /// Executes an operation of the `IP_DROP_MEMBERSHIP` type. | |
634 | - /// | |
635 | - /// For more information about this option, see | |
636 | - /// [`join_multicast_v4`][link]. | |
637 | - /// | |
638 | - /// [link]: #method.join_multicast_v4 | |
639 | - pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { | |
640 | - self.inner.leave_multicast_v4(multiaddr, interface) | |
641 | - } | |
642 | - | |
643 | - /// Executes an operation of the `IPV6_DROP_MEMBERSHIP` type. | |
644 | - /// | |
645 | - /// For more information about this option, see | |
646 | - /// [`join_multicast_v6`][link]. | |
647 | - /// | |
648 | - /// [link]: #method.join_multicast_v6 | |
649 | - pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { | |
650 | - self.inner.leave_multicast_v6(multiaddr, interface) | |
651 | - } | |
652 | - | |
653 | - /// Reads the linger duration for this socket by getting the SO_LINGER | |
654 | - /// option | |
655 | - pub fn linger(&self) -> io::Result<Option<Duration>> { | |
656 | - self.inner.linger() | |
657 | - } | |
658 | - | |
659 | - /// Sets the linger duration of this socket by setting the SO_LINGER option | |
660 | - pub fn set_linger(&self, dur: Option<Duration>) -> io::Result<()> { | |
661 | - self.inner.set_linger(dur) | |
662 | - } | |
663 | - | |
664 | - /// Check the `SO_REUSEADDR` option on this socket. | |
665 | - pub fn reuse_address(&self) -> io::Result<bool> { | |
666 | - self.inner.reuse_address() | |
667 | + sys::shutdown(self.inner, how) | |
668 | } | |
669 | +} | |
670 | ||
671 | - /// Set value for the `SO_REUSEADDR` option on this socket. | |
672 | +impl Socket { | |
673 | + /// Set a socket option. | |
674 | /// | |
675 | - /// This indicates that futher calls to `bind` may allow reuse of local | |
676 | - /// addresses. For IPv4 sockets this means that a socket may bind even when | |
677 | - /// there's a socket already listening on this port. | |
678 | - pub fn set_reuse_address(&self, reuse: bool) -> io::Result<()> { | |
679 | - self.inner.set_reuse_address(reuse) | |
680 | + /// This function directly corresponds to the `setsockopt(2)` function. As | |
681 | + /// different options use different option types the user must define the | |
682 | + /// correct type `T`! | |
683 | + pub fn setsockopt<T>(&self, level: c_int, optname: c_int, opt: &T) -> io::Result<()> { | |
684 | + sys::setsockopt(self.inner, level, optname, opt) | |
685 | } | |
686 | ||
687 | - /// Gets the value of the `SO_RCVBUF` option on this socket. | |
688 | - /// | |
689 | - /// For more information about this option, see | |
690 | - /// [`set_recv_buffer_size`][link]. | |
691 | + /// Get a socket option. | |
692 | /// | |
693 | - /// [link]: #method.set_recv_buffer_size | |
694 | - pub fn recv_buffer_size(&self) -> io::Result<usize> { | |
695 | - self.inner.recv_buffer_size() | |
696 | - } | |
697 | - | |
698 | - /// Sets the value of the `SO_RCVBUF` option on this socket. | |
699 | + /// This function directly corresponds to the `getsockopt(2)` function. As | |
700 | + /// different options have different return types the user must define the | |
701 | + /// return type `T` correctly! | |
702 | /// | |
703 | - /// Changes the size of the operating system's receive buffer associated | |
704 | - /// with the socket. | |
705 | - pub fn set_recv_buffer_size(&self, size: usize) -> io::Result<()> { | |
706 | - self.inner.set_recv_buffer_size(size) | |
707 | - } | |
708 | - | |
709 | - /// Gets the value of the `SO_SNDBUF` option on this socket. | |
710 | + /// For an example usage see [`Socket::take_error`]. | |
711 | /// | |
712 | - /// For more information about this option, see [`set_send_buffer`][link]. | |
713 | + /// # Notes | |
714 | /// | |
715 | - /// [link]: #method.set_send_buffer | |
716 | - pub fn send_buffer_size(&self) -> io::Result<usize> { | |
717 | - self.inner.send_buffer_size() | |
718 | + /// Currently this will panic (in debug mode) if `T` isn't completely | |
719 | + /// written to, it doesn't support options which partly write to `T`. | |
720 | + pub fn getsockopt<T>(&self, level: c_int, optname: c_int) -> io::Result<T> { | |
721 | + sys::getsockopt(self.inner, level, optname) | |
722 | } | |
723 | ||
724 | - /// Sets the value of the `SO_SNDBUF` option on this socket. | |
725 | + /// Manipulate the file descriptor options of the socket. | |
726 | /// | |
727 | - /// Changes the size of the operating system's send buffer associated with | |
728 | - /// the socket. | |
729 | - pub fn set_send_buffer_size(&self, size: usize) -> io::Result<()> { | |
730 | - self.inner.set_send_buffer_size(size) | |
731 | - } | |
732 | - | |
733 | - /// Returns whether keepalive messages are enabled on this socket, and if so | |
734 | - /// the duration of time between them. | |
735 | + /// This function directly corresponds to the `fcntl(2)` function. As | |
736 | + /// different command have different options the user must defined the | |
737 | + /// correct type `T`! | |
738 | /// | |
739 | - /// For more information about this option, see [`set_keepalive`][link]. | |
740 | + /// # Examples | |
741 | /// | |
742 | - /// [link]: #method.set_keepalive | |
743 | - pub fn keepalive(&self) -> io::Result<Option<Duration>> { | |
744 | - self.inner.keepalive() | |
745 | - } | |
746 | - | |
747 | - /// Sets whether keepalive messages are enabled to be sent on this socket. | |
748 | + /// The following example retrieves and sets the file descriptor flags. | |
749 | /// | |
750 | - /// On Unix, this option will set the `SO_KEEPALIVE` as well as the | |
751 | - /// `TCP_KEEPALIVE` or `TCP_KEEPIDLE` option (depending on your platform). | |
752 | - /// On Windows, this will set the `SIO_KEEPALIVE_VALS` option. | |
753 | + /// ``` | |
754 | + /// use std::io; | |
755 | + /// use socket2::{Domain, Socket, Type}; | |
756 | /// | |
757 | - /// If `None` is specified then keepalive messages are disabled, otherwise | |
758 | - /// the duration specified will be the time to remain idle before sending a | |
759 | - /// TCP keepalive probe. | |
760 | + /// # fn main() -> io::Result<()> { | |
761 | + /// let socket = Socket::new(Domain::ipv4(), Type::stream(), None)?; | |
762 | /// | |
763 | - /// Some platforms specify this value in seconds, so sub-second | |
764 | - /// specifications may be omitted. | |
765 | - pub fn set_keepalive(&self, keepalive: Option<Duration>) -> io::Result<()> { | |
766 | - self.inner.set_keepalive(keepalive) | |
767 | - } | |
768 | - | |
769 | - /// Check the value of the `SO_REUSEPORT` option on this socket. | |
770 | + /// // Retrieve the flags, using nothing `()` as argument. | |
771 | + /// let flags = socket.fcntl(libc::F_GETFD, ())?; | |
772 | + /// assert!((flags & libc::FD_CLOEXEC) == 0); | |
773 | /// | |
774 | - /// This function is only available on Unix. | |
775 | - #[cfg(all(unix, not(target_os = "solaris")))] | |
776 | - pub fn reuse_port(&self) -> io::Result<bool> { | |
777 | - self.inner.reuse_port() | |
778 | - } | |
779 | - | |
780 | - /// Set value for the `SO_REUSEPORT` option on this socket. | |
781 | + /// // Now we set the `FD_CLOEXEC` flag. | |
782 | + /// socket.fcntl(libc::F_SETFD, flags | libc::FD_CLOEXEC)?; | |
783 | /// | |
784 | - /// This indicates that further calls to `bind` may allow reuse of local | |
785 | - /// addresses. For IPv4 sockets this means that a socket may bind even when | |
786 | - /// there's a socket already listening on this port. | |
787 | + /// // Now the flag should be set. | |
788 | + /// let flags = socket.fcntl(libc::F_GETFD, ())?; | |
789 | + /// assert!((flags & libc::FD_CLOEXEC) != 0); | |
790 | /// | |
791 | - /// This function is only available on Unix. | |
792 | - #[cfg(all(unix, not(target_os = "solaris")))] | |
793 | - pub fn set_reuse_port(&self, reuse: bool) -> io::Result<()> { | |
794 | - self.inner.set_reuse_port(reuse) | |
795 | + /// # Ok(()) | |
796 | + /// # } | |
797 | + /// ``` | |
798 | + pub fn fcntl<T>(&self, cmd: c_int, arg: T) -> io::Result<c_int> { | |
799 | + sys::fcntl(self.inner, cmd, arg) | |
800 | } | |
801 | } | |
802 | ||
803 | -impl Read for Socket { | |
804 | - fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | |
805 | - self.inner.read(buf) | |
806 | +impl From<TcpStream> for Socket { | |
807 | + fn from(socket: TcpStream) -> Socket { | |
808 | + unsafe { Socket::from_raw_fd(socket.into_raw_fd()) } | |
809 | } | |
810 | } | |
811 | ||
812 | -impl<'a> Read for &'a Socket { | |
813 | - fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | |
814 | - (&self.inner).read(buf) | |
815 | +impl Into<TcpStream> for Socket { | |
816 | + fn into(self) -> TcpStream { | |
817 | + unsafe { TcpStream::from_raw_fd(self.into_raw_fd()) } | |
818 | } | |
819 | } | |
820 | ||
821 | -impl Write for Socket { | |
822 | - fn write(&mut self, buf: &[u8]) -> io::Result<usize> { | |
823 | - self.inner.write(buf) | |
824 | - } | |
825 | - | |
826 | - fn flush(&mut self) -> io::Result<()> { | |
827 | - self.inner.flush() | |
828 | +impl From<TcpListener> for Socket { | |
829 | + fn from(socket: TcpListener) -> Socket { | |
830 | + unsafe { Socket::from_raw_fd(socket.into_raw_fd()) } | |
831 | } | |
832 | } | |
833 | ||
834 | -impl<'a> Write for &'a Socket { | |
835 | - fn write(&mut self, buf: &[u8]) -> io::Result<usize> { | |
836 | - (&self.inner).write(buf) | |
837 | - } | |
838 | - | |
839 | - fn flush(&mut self) -> io::Result<()> { | |
840 | - (&self.inner).flush() | |
841 | +impl Into<TcpListener> for Socket { | |
842 | + fn into(self) -> TcpListener { | |
843 | + unsafe { TcpListener::from_raw_fd(self.into_raw_fd()) } | |
844 | } | |
845 | } | |
846 | ||
847 | -impl fmt::Debug for Socket { | |
848 | - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
849 | - self.inner.fmt(f) | |
850 | +impl From<UdpSocket> for Socket { | |
851 | + fn from(socket: UdpSocket) -> Socket { | |
852 | + unsafe { Socket::from_raw_fd(socket.into_raw_fd()) } | |
853 | } | |
854 | } | |
855 | ||
856 | -impl From<net::TcpStream> for Socket { | |
857 | - fn from(socket: net::TcpStream) -> Socket { | |
858 | - Socket { | |
859 | - inner: socket.into(), | |
860 | - } | |
861 | +impl Into<UdpSocket> for Socket { | |
862 | + fn into(self) -> UdpSocket { | |
863 | + unsafe { UdpSocket::from_raw_fd(self.into_raw_fd()) } | |
864 | } | |
865 | } | |
866 | ||
867 | -impl From<net::TcpListener> for Socket { | |
868 | - fn from(socket: net::TcpListener) -> Socket { | |
869 | - Socket { | |
870 | - inner: socket.into(), | |
871 | - } | |
872 | - } | |
873 | -} | |
874 | - | |
875 | -impl From<net::UdpSocket> for Socket { | |
876 | - fn from(socket: net::UdpSocket) -> Socket { | |
877 | - Socket { | |
878 | - inner: socket.into(), | |
879 | - } | |
880 | - } | |
881 | -} | |
882 | - | |
883 | -#[cfg(all(unix, feature = "unix"))] | |
884 | -impl From<UnixStream> for Socket { | |
885 | - fn from(socket: UnixStream) -> Socket { | |
886 | - Socket { | |
887 | - inner: socket.into(), | |
888 | - } | |
889 | - } | |
890 | -} | |
891 | - | |
892 | -#[cfg(all(unix, feature = "unix"))] | |
893 | -impl From<UnixListener> for Socket { | |
894 | - fn from(socket: UnixListener) -> Socket { | |
895 | - Socket { | |
896 | - inner: socket.into(), | |
897 | - } | |
898 | - } | |
899 | -} | |
900 | - | |
901 | -#[cfg(all(unix, feature = "unix"))] | |
902 | -impl From<UnixDatagram> for Socket { | |
903 | - fn from(socket: UnixDatagram) -> Socket { | |
904 | - Socket { | |
905 | - inner: socket.into(), | |
906 | - } | |
907 | - } | |
908 | -} | |
909 | - | |
910 | -impl From<Socket> for net::TcpStream { | |
911 | - fn from(socket: Socket) -> net::TcpStream { | |
912 | - socket.inner.into() | |
913 | - } | |
914 | -} | |
915 | - | |
916 | -impl From<Socket> for net::TcpListener { | |
917 | - fn from(socket: Socket) -> net::TcpListener { | |
918 | - socket.inner.into() | |
919 | - } | |
920 | -} | |
921 | - | |
922 | -impl From<Socket> for net::UdpSocket { | |
923 | - fn from(socket: Socket) -> net::UdpSocket { | |
924 | - socket.inner.into() | |
925 | - } | |
926 | -} | |
927 | - | |
928 | -#[cfg(all(unix, feature = "unix"))] | |
929 | -impl From<Socket> for UnixStream { | |
930 | - fn from(socket: Socket) -> UnixStream { | |
931 | - socket.inner.into() | |
932 | - } | |
933 | -} | |
934 | - | |
935 | -#[cfg(all(unix, feature = "unix"))] | |
936 | -impl From<Socket> for UnixListener { | |
937 | - fn from(socket: Socket) -> UnixListener { | |
938 | - socket.inner.into() | |
939 | - } | |
940 | -} | |
941 | - | |
942 | -#[cfg(all(unix, feature = "unix"))] | |
943 | -impl From<Socket> for UnixDatagram { | |
944 | - fn from(socket: Socket) -> UnixDatagram { | |
945 | - socket.inner.into() | |
946 | - } | |
947 | -} | |
948 | - | |
949 | -#[cfg(test)] | |
950 | -mod test { | |
951 | - use std::net::SocketAddr; | |
952 | - | |
953 | - use super::*; | |
954 | - | |
955 | - #[test] | |
956 | - fn connect_timeout_unrouteable() { | |
957 | - // this IP is unroutable, so connections should always time out | |
958 | - let addr = "10.255.255.1:80".parse::<SocketAddr>().unwrap().into(); | |
959 | - | |
960 | - let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); | |
961 | - match socket.connect_timeout(&addr, Duration::from_millis(250)) { | |
962 | - Ok(_) => panic!("unexpected success"), | |
963 | - Err(ref e) if e.kind() == io::ErrorKind::TimedOut => {} | |
964 | - Err(e) => panic!("unexpected error {}", e), | |
965 | - } | |
966 | - } | |
967 | - | |
968 | - #[test] | |
969 | - fn connect_timeout_unbound() { | |
970 | - // bind and drop a socket to track down a "probably unassigned" port | |
971 | - let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); | |
972 | - let addr = "127.0.0.1:0".parse::<SocketAddr>().unwrap().into(); | |
973 | - socket.bind(&addr).unwrap(); | |
974 | - let addr = socket.local_addr().unwrap(); | |
975 | - drop(socket); | |
976 | - | |
977 | - let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); | |
978 | - match socket.connect_timeout(&addr, Duration::from_millis(250)) { | |
979 | - Ok(_) => panic!("unexpected success"), | |
980 | - Err(ref e) | |
981 | - if e.kind() == io::ErrorKind::ConnectionRefused | |
982 | - || e.kind() == io::ErrorKind::TimedOut => {} | |
983 | - Err(e) => panic!("unexpected error {}", e), | |
984 | - } | |
985 | - } | |
986 | - | |
987 | - #[test] | |
988 | - fn connect_timeout_valid() { | |
989 | - let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); | |
990 | - socket | |
991 | - .bind(&"127.0.0.1:0".parse::<SocketAddr>().unwrap().into()) | |
992 | - .unwrap(); | |
993 | - socket.listen(128).unwrap(); | |
994 | - | |
995 | - let addr = socket.local_addr().unwrap(); | |
996 | - | |
997 | - let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); | |
998 | - socket | |
999 | - .connect_timeout(&addr, Duration::from_millis(250)) | |
1000 | - .unwrap(); | |
1001 | - } | |
1002 | - | |
1003 | - #[test] | |
1004 | - #[cfg(all(unix, feature = "pair", feature = "unix"))] | |
1005 | - fn pair() { | |
1006 | - let (mut a, mut b) = Socket::pair(Domain::unix(), Type::stream(), None).unwrap(); | |
1007 | - a.write_all(b"hello world").unwrap(); | |
1008 | - let mut buf = [0; 11]; | |
1009 | - b.read_exact(&mut buf).unwrap(); | |
1010 | - assert_eq!(buf, &b"hello world"[..]); | |
1011 | - } | |
1012 | - | |
1013 | - #[test] | |
1014 | - #[cfg(all(unix, feature = "unix"))] | |
1015 | - fn unix() { | |
1016 | - use tempdir::TempDir; | |
1017 | - | |
1018 | - let dir = TempDir::new("unix").unwrap(); | |
1019 | - let addr = SockAddr::unix(dir.path().join("sock")).unwrap(); | |
1020 | - | |
1021 | - let listener = Socket::new(Domain::unix(), Type::stream(), None).unwrap(); | |
1022 | - listener.bind(&addr).unwrap(); | |
1023 | - listener.listen(10).unwrap(); | |
1024 | - | |
1025 | - let mut a = Socket::new(Domain::unix(), Type::stream(), None).unwrap(); | |
1026 | - a.connect(&addr).unwrap(); | |
1027 | - | |
1028 | - let mut b = listener.accept().unwrap().0; | |
1029 | - | |
1030 | - a.write_all(b"hello world").unwrap(); | |
1031 | - let mut buf = [0; 11]; | |
1032 | - b.read_exact(&mut buf).unwrap(); | |
1033 | - assert_eq!(buf, &b"hello world"[..]); | |
1034 | - } | |
1035 | - | |
1036 | - #[test] | |
1037 | - fn keepalive() { | |
1038 | - let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); | |
1039 | - socket.set_keepalive(Some(Duration::from_secs(7))).unwrap(); | |
1040 | - // socket.keepalive() doesn't work on Windows #24 | |
1041 | - #[cfg(unix)] | |
1042 | - assert_eq!(socket.keepalive().unwrap(), Some(Duration::from_secs(7))); | |
1043 | - socket.set_keepalive(None).unwrap(); | |
1044 | - #[cfg(unix)] | |
1045 | - assert_eq!(socket.keepalive().unwrap(), None); | |
1046 | - } | |
1047 | - | |
1048 | - #[test] | |
1049 | - fn nodelay() { | |
1050 | - let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); | |
1051 | - | |
1052 | - assert!(socket.set_nodelay(true).is_ok()); | |
1053 | - | |
1054 | - let result = socket.nodelay(); | |
1055 | - | |
1056 | - assert!(result.is_ok()); | |
1057 | - assert!(result.unwrap()); | |
1058 | +impl fmt::Debug for Socket { | |
1059 | + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
1060 | + self.inner.fmt(f) | |
1061 | } | |
1062 | } | |
1063 | diff --git a/src/sys/unix.rs b/src/sys/unix.rs | |
1064 | index 3612f77..3cc08f6 100644 | |
1065 | --- a/src/sys/unix.rs | |
1066 | +++ b/src/sys/unix.rs | |
1067 | @@ -8,23 +8,13 @@ | |
1068 | // option. This file may not be copied, modified, or distributed | |
1069 | // except according to those terms. | |
1070 | ||
1071 | -use std::cmp; | |
1072 | -use std::fmt; | |
1073 | use std::io; | |
1074 | -use std::io::{ErrorKind, Read, Write}; | |
1075 | -use std::mem; | |
1076 | +use std::mem::{self, size_of, MaybeUninit}; | |
1077 | use std::net::Shutdown; | |
1078 | -use std::net::{self, Ipv4Addr, Ipv6Addr}; | |
1079 | -use std::ops::Neg; | |
1080 | -#[cfg(feature = "unix")] | |
1081 | +use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; | |
1082 | use std::os::unix::net::{UnixDatagram, UnixListener, UnixStream}; | |
1083 | -use std::os::unix::prelude::*; | |
1084 | -use std::sync::atomic::{AtomicBool, Ordering}; | |
1085 | -use std::time::{Duration, Instant}; | |
1086 | ||
1087 | -use libc::{self, c_void, socklen_t, ssize_t}; | |
1088 | - | |
1089 | -use crate::{Domain, Type}; | |
1090 | +use crate::{Domain, Protocol, SockAddr, Socket, Type}; | |
1091 | ||
1092 | // Used in conversions for `Domain`, `Type` and `Protocol`. | |
1093 | #[allow(non_camel_case_types)] | |
1094 | @@ -36,43 +26,8 @@ pub(crate) use libc::{AF_INET, AF_INET6}; | |
1095 | pub(crate) use libc::{SOCK_DGRAM, SOCK_RAW, SOCK_SEQPACKET, SOCK_STREAM}; | |
1096 | // Used in `Protocol`. | |
1097 | pub(crate) use libc::{IPPROTO_ICMP, IPPROTO_ICMPV6, IPPROTO_TCP, IPPROTO_UDP}; | |
1098 | - | |
1099 | -cfg_if::cfg_if! { | |
1100 | - if #[cfg(any(target_os = "dragonfly", target_os = "freebsd", | |
1101 | - target_os = "ios", target_os = "macos", | |
1102 | - target_os = "openbsd", target_os = "netbsd", | |
1103 | - target_os = "solaris", target_os = "haiku"))] { | |
1104 | - use libc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP; | |
1105 | - use libc::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP; | |
1106 | - } else { | |
1107 | - use libc::IPV6_ADD_MEMBERSHIP; | |
1108 | - use libc::IPV6_DROP_MEMBERSHIP; | |
1109 | - } | |
1110 | -} | |
1111 | - | |
1112 | -cfg_if::cfg_if! { | |
1113 | - if #[cfg(any(target_os = "linux", target_os = "android", | |
1114 | - target_os = "dragonfly", target_os = "freebsd", | |
1115 | - target_os = "openbsd", target_os = "netbsd", | |
1116 | - target_os = "haiku", target_os = "bitrig"))] { | |
1117 | - use libc::MSG_NOSIGNAL; | |
1118 | - } else { | |
1119 | - const MSG_NOSIGNAL: c_int = 0x0; | |
1120 | - } | |
1121 | -} | |
1122 | - | |
1123 | -cfg_if::cfg_if! { | |
1124 | - if #[cfg(any(target_os = "macos", target_os = "ios"))] { | |
1125 | - use libc::TCP_KEEPALIVE as KEEPALIVE_OPTION; | |
1126 | - } else if #[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "haiku"))] { | |
1127 | - use libc::SO_KEEPALIVE as KEEPALIVE_OPTION; | |
1128 | - } else { | |
1129 | - use libc::TCP_KEEPIDLE as KEEPALIVE_OPTION; | |
1130 | - } | |
1131 | -} | |
1132 | - | |
1133 | -use crate::utils::One; | |
1134 | -use crate::SockAddr; | |
1135 | +// Used in `Socket`. | |
1136 | +pub(crate) use std::os::unix::io::RawFd as RawSocket; | |
1137 | ||
1138 | /// Unix only API. | |
1139 | impl Domain { | |
1140 | @@ -131,1036 +86,241 @@ impl Type { | |
1141 | } | |
1142 | } | |
1143 | ||
1144 | -pub struct Socket { | |
1145 | - fd: c_int, | |
1146 | +/// Helper macro to execute a system call that returns an `io::Result`. | |
1147 | +macro_rules! syscall { | |
1148 | + ($fn: ident ( $($arg: expr),* $(,)* ) ) => {{ | |
1149 | + let res = unsafe { libc::$fn($($arg, )*) }; | |
1150 | + if res == -1 { | |
1151 | + Err(std::io::Error::last_os_error()) | |
1152 | + } else { | |
1153 | + Ok(res) | |
1154 | + } | |
1155 | + }}; | |
1156 | +} | |
1157 | + | |
1158 | +pub(crate) fn socket(domain: c_int, type_: c_int, protocol: c_int) -> io::Result<Socket> { | |
1159 | + syscall!(socket(domain, type_, protocol)).map(|fd| Socket { inner: fd }) | |
1160 | +} | |
1161 | + | |
1162 | +pub(crate) fn connect( | |
1163 | + sockfd: RawSocket, | |
1164 | + addr: *const libc::sockaddr_storage, | |
1165 | + addrlen: libc::socklen_t, | |
1166 | +) -> io::Result<()> { | |
1167 | + // Most OSes don't actually use `sockaddr_storage` in the `connect(2)` call, | |
1168 | + // but `sockaddr_storage` can be converted safely into the correct type. | |
1169 | + syscall!(connect(sockfd, addr as *const _, addrlen)).map(|_| ()) | |
1170 | +} | |
1171 | + | |
1172 | +pub(crate) fn bind( | |
1173 | + sockfd: RawSocket, | |
1174 | + addr: *const libc::sockaddr_storage, | |
1175 | + addrlen: libc::socklen_t, | |
1176 | +) -> io::Result<()> { | |
1177 | + // Most OSes don't actually use `sockaddr_storage` in the `bind(2)` call, | |
1178 | + // but `sockaddr_storage` can be converted safely into the correct type. | |
1179 | + syscall!(bind(sockfd, addr as *const _, addrlen)).map(|_| ()) | |
1180 | +} | |
1181 | + | |
1182 | +pub(crate) fn listen(sockfd: RawSocket, backlog: c_int) -> io::Result<()> { | |
1183 | + syscall!(listen(sockfd, backlog)).map(|_| ()) | |
1184 | +} | |
1185 | + | |
1186 | +pub(crate) fn accept(sockfd: RawSocket) -> io::Result<(Socket, SockAddr)> { | |
1187 | + let mut addr: MaybeUninit<libc::sockaddr_storage> = MaybeUninit::uninit(); | |
1188 | + let mut addrlen = size_of::<libc::sockaddr_storage>() as libc::socklen_t; | |
1189 | + syscall!(accept(sockfd, addr.as_mut_ptr() as *mut _, &mut addrlen)).map(|stream_fd| { | |
1190 | + // This is safe because `accept(2)` filled in the address for us. | |
1191 | + let addr = unsafe { SockAddr::from_raw_parts(addr.assume_init(), addrlen) }; | |
1192 | + (Socket { inner: stream_fd }, addr) | |
1193 | + }) | |
1194 | +} | |
1195 | + | |
1196 | +pub(crate) fn getsockname(sockfd: RawSocket) -> io::Result<SockAddr> { | |
1197 | + let mut addr: MaybeUninit<libc::sockaddr_storage> = MaybeUninit::uninit(); | |
1198 | + let mut addrlen = size_of::<libc::sockaddr_storage>() as libc::socklen_t; | |
1199 | + syscall!(getsockname( | |
1200 | + sockfd, | |
1201 | + addr.as_mut_ptr() as *mut _, | |
1202 | + &mut addrlen | |
1203 | + )) | |
1204 | + .map(|_| { | |
1205 | + // This is safe because `getsockname(2)` filled in the address for us. | |
1206 | + unsafe { SockAddr::from_raw_parts(addr.assume_init(), addrlen) } | |
1207 | + }) | |
1208 | +} | |
1209 | + | |
1210 | +pub(crate) fn getpeername(sockfd: RawSocket) -> io::Result<SockAddr> { | |
1211 | + let mut addr: MaybeUninit<libc::sockaddr_storage> = MaybeUninit::uninit(); | |
1212 | + let mut addrlen = size_of::<libc::sockaddr_storage>() as libc::socklen_t; | |
1213 | + syscall!(getpeername( | |
1214 | + sockfd, | |
1215 | + addr.as_mut_ptr() as *mut _, | |
1216 | + &mut addrlen | |
1217 | + )) | |
1218 | + .map(|_| { | |
1219 | + // This is safe because `getpeername(2)` filled in the address for us. | |
1220 | + unsafe { SockAddr::from_raw_parts(addr.assume_init(), addrlen) } | |
1221 | + }) | |
1222 | +} | |
1223 | + | |
1224 | +pub(crate) fn shutdown(sockfd: RawSocket, how: Shutdown) -> io::Result<()> { | |
1225 | + let how = match how { | |
1226 | + Shutdown::Write => libc::SHUT_WR, | |
1227 | + Shutdown::Read => libc::SHUT_RD, | |
1228 | + Shutdown::Both => libc::SHUT_RDWR, | |
1229 | + }; | |
1230 | + syscall!(shutdown(sockfd, how)).map(|_| ()) | |
1231 | +} | |
1232 | + | |
1233 | +pub(crate) fn setsockopt<T>( | |
1234 | + sockfd: RawSocket, | |
1235 | + level: c_int, | |
1236 | + optname: c_int, | |
1237 | + opt: &T, | |
1238 | +) -> io::Result<()> { | |
1239 | + syscall!(setsockopt( | |
1240 | + sockfd, | |
1241 | + level, | |
1242 | + optname, | |
1243 | + opt as *const _ as *const _, | |
1244 | + size_of::<T>() as libc::socklen_t, | |
1245 | + )) | |
1246 | + .map(|_| ()) | |
1247 | +} | |
1248 | + | |
1249 | +pub(crate) fn getsockopt<T>(sockfd: RawSocket, level: c_int, optname: c_int) -> io::Result<T> { | |
1250 | + let mut optval: MaybeUninit<T> = MaybeUninit::uninit(); | |
1251 | + let mut optlen = size_of::<T>() as libc::socklen_t; | |
1252 | + syscall!(getsockopt( | |
1253 | + sockfd, | |
1254 | + level, | |
1255 | + optname, | |
1256 | + optval.as_mut_ptr() as *mut _, | |
1257 | + &mut optlen | |
1258 | + )) | |
1259 | + .map(|_| unsafe { | |
1260 | + // Safe because `getsockopt(2)` initialised the value for us. | |
1261 | + debug_assert_eq!(optlen as usize, size_of::<T>()); | |
1262 | + optval.assume_init() | |
1263 | + }) | |
1264 | +} | |
1265 | + | |
1266 | +pub(crate) fn fcntl<T>(sockfd: RawSocket, cmd: c_int, arg: T) -> io::Result<c_int> { | |
1267 | + syscall!(fcntl(sockfd, cmd, arg)) | |
1268 | } | |
1269 | ||
1270 | +/// Unix only API. | |
1271 | impl Socket { | |
1272 | - pub fn new(family: c_int, ty: c_int, protocol: c_int) -> io::Result<Socket> { | |
1273 | - unsafe { | |
1274 | - // On linux we first attempt to pass the SOCK_CLOEXEC flag to | |
1275 | - // atomically create the socket and set it as CLOEXEC. Support for | |
1276 | - // this option, however, was added in 2.6.27, and we still support | |
1277 | - // 2.6.18 as a kernel, so if the returned error is EINVAL we | |
1278 | - // fallthrough to the fallback. | |
1279 | - #[cfg(target_os = "linux")] | |
1280 | - { | |
1281 | - match cvt(libc::socket(family, ty | libc::SOCK_CLOEXEC, protocol)) { | |
1282 | - Ok(fd) => return Ok(Socket::from_raw_fd(fd)), | |
1283 | - Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {} | |
1284 | - Err(e) => return Err(e), | |
1285 | - } | |
1286 | - } | |
1287 | - | |
1288 | - let fd = cvt(libc::socket(family, ty, protocol))?; | |
1289 | - let fd = Socket::from_raw_fd(fd); | |
1290 | - set_cloexec(fd.as_raw_fd())?; | |
1291 | - #[cfg(target_os = "macos")] | |
1292 | - { | |
1293 | - fd.setsockopt(libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1i32)?; | |
1294 | - } | |
1295 | - Ok(fd) | |
1296 | - } | |
1297 | - } | |
1298 | - | |
1299 | - pub fn pair(family: c_int, ty: c_int, protocol: c_int) -> io::Result<(Socket, Socket)> { | |
1300 | - unsafe { | |
1301 | - let mut fds = [0, 0]; | |
1302 | - cvt(libc::socketpair(family, ty, protocol, fds.as_mut_ptr()))?; | |
1303 | - let fds = (Socket::from_raw_fd(fds[0]), Socket::from_raw_fd(fds[1])); | |
1304 | - set_cloexec(fds.0.as_raw_fd())?; | |
1305 | - set_cloexec(fds.1.as_raw_fd())?; | |
1306 | - #[cfg(target_os = "macos")] | |
1307 | - { | |
1308 | - fds.0 | |
1309 | - .setsockopt(libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1i32)?; | |
1310 | - fds.1 | |
1311 | - .setsockopt(libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1i32)?; | |
1312 | - } | |
1313 | - Ok(fds) | |
1314 | - } | |
1315 | - } | |
1316 | - | |
1317 | - pub fn bind(&self, addr: &SockAddr) -> io::Result<()> { | |
1318 | - unsafe { cvt(libc::bind(self.fd, addr.as_ptr(), addr.len() as _)).map(|_| ()) } | |
1319 | - } | |
1320 | - | |
1321 | - pub fn listen(&self, backlog: i32) -> io::Result<()> { | |
1322 | - unsafe { cvt(libc::listen(self.fd, backlog)).map(|_| ()) } | |
1323 | - } | |
1324 | - | |
1325 | - pub fn connect(&self, addr: &SockAddr) -> io::Result<()> { | |
1326 | - unsafe { cvt(libc::connect(self.fd, addr.as_ptr(), addr.len())).map(|_| ()) } | |
1327 | - } | |
1328 | - | |
1329 | - pub fn connect_timeout(&self, addr: &SockAddr, timeout: Duration) -> io::Result<()> { | |
1330 | - self.set_nonblocking(true)?; | |
1331 | - let r = self.connect(addr); | |
1332 | - self.set_nonblocking(false)?; | |
1333 | - | |
1334 | - match r { | |
1335 | - Ok(()) => return Ok(()), | |
1336 | - // there's no io::ErrorKind conversion registered for EINPROGRESS :( | |
1337 | - Err(ref e) if e.raw_os_error() == Some(libc::EINPROGRESS) => {} | |
1338 | - Err(e) => return Err(e), | |
1339 | - } | |
1340 | - | |
1341 | - let mut pollfd = libc::pollfd { | |
1342 | - fd: self.fd, | |
1343 | - events: libc::POLLOUT, | |
1344 | - revents: 0, | |
1345 | - }; | |
1346 | - | |
1347 | - if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { | |
1348 | - return Err(io::Error::new( | |
1349 | - io::ErrorKind::InvalidInput, | |
1350 | - "cannot set a 0 duration timeout", | |
1351 | - )); | |
1352 | - } | |
1353 | - | |
1354 | - let start = Instant::now(); | |
1355 | - | |
1356 | - loop { | |
1357 | - let elapsed = start.elapsed(); | |
1358 | - if elapsed >= timeout { | |
1359 | - return Err(io::Error::new( | |
1360 | - io::ErrorKind::TimedOut, | |
1361 | - "connection timed out", | |
1362 | - )); | |
1363 | - } | |
1364 | - | |
1365 | - let timeout = timeout - elapsed; | |
1366 | - let mut timeout = timeout | |
1367 | - .as_secs() | |
1368 | - .saturating_mul(1_000) | |
1369 | - .saturating_add(timeout.subsec_nanos() as u64 / 1_000_000); | |
1370 | - if timeout == 0 { | |
1371 | - timeout = 1; | |
1372 | - } | |
1373 | - | |
1374 | - let timeout = cmp::min(timeout, c_int::max_value() as u64) as c_int; | |
1375 | - | |
1376 | - match unsafe { libc::poll(&mut pollfd, 1, timeout) } { | |
1377 | - -1 => { | |
1378 | - let err = io::Error::last_os_error(); | |
1379 | - if err.kind() != io::ErrorKind::Interrupted { | |
1380 | - return Err(err); | |
1381 | - } | |
1382 | - } | |
1383 | - 0 => { | |
1384 | - return Err(io::Error::new( | |
1385 | - io::ErrorKind::TimedOut, | |
1386 | - "connection timed out", | |
1387 | - )) | |
1388 | - } | |
1389 | - _ => { | |
1390 | - // linux returns POLLOUT|POLLERR|POLLHUP for refused connections (!), so look | |
1391 | - // for POLLHUP rather than read readiness | |
1392 | - if pollfd.revents & libc::POLLHUP != 0 { | |
1393 | - let e = self.take_error()?.unwrap_or_else(|| { | |
1394 | - io::Error::new(io::ErrorKind::Other, "no error set after POLLHUP") | |
1395 | - }); | |
1396 | - return Err(e); | |
1397 | - } | |
1398 | - return Ok(()); | |
1399 | - } | |
1400 | - } | |
1401 | - } | |
1402 | - } | |
1403 | - | |
1404 | - pub fn local_addr(&self) -> io::Result<SockAddr> { | |
1405 | - unsafe { | |
1406 | - let mut storage: libc::sockaddr_storage = mem::zeroed(); | |
1407 | - let mut len = mem::size_of_val(&storage) as libc::socklen_t; | |
1408 | - cvt(libc::getsockname( | |
1409 | - self.fd, | |
1410 | - &mut storage as *mut _ as *mut _, | |
1411 | - &mut len, | |
1412 | - ))?; | |
1413 | - Ok(SockAddr::from_raw_parts( | |
1414 | - &storage as *const _ as *const _, | |
1415 | - len, | |
1416 | - )) | |
1417 | - } | |
1418 | - } | |
1419 | - | |
1420 | - pub fn peer_addr(&self) -> io::Result<SockAddr> { | |
1421 | - unsafe { | |
1422 | - let mut storage: libc::sockaddr_storage = mem::zeroed(); | |
1423 | - let mut len = mem::size_of_val(&storage) as libc::socklen_t; | |
1424 | - cvt(libc::getpeername( | |
1425 | - self.fd, | |
1426 | - &mut storage as *mut _ as *mut _, | |
1427 | - &mut len, | |
1428 | - ))?; | |
1429 | - Ok(SockAddr::from_raw_parts( | |
1430 | - &storage as *const _ as *const _, | |
1431 | - len, | |
1432 | - )) | |
1433 | - } | |
1434 | - } | |
1435 | - | |
1436 | - pub fn try_clone(&self) -> io::Result<Socket> { | |
1437 | - // implementation lifted from libstd | |
1438 | - #[cfg(any(target_os = "android", target_os = "haiku"))] | |
1439 | - use libc::F_DUPFD as F_DUPFD_CLOEXEC; | |
1440 | - #[cfg(not(any(target_os = "android", target_os = "haiku")))] | |
1441 | - use libc::F_DUPFD_CLOEXEC; | |
1442 | - | |
1443 | - static CLOEXEC_FAILED: AtomicBool = AtomicBool::new(false); | |
1444 | - unsafe { | |
1445 | - if !CLOEXEC_FAILED.load(Ordering::Relaxed) { | |
1446 | - match cvt(libc::fcntl(self.fd, F_DUPFD_CLOEXEC, 0)) { | |
1447 | - Ok(fd) => { | |
1448 | - let fd = Socket::from_raw_fd(fd); | |
1449 | - if cfg!(target_os = "linux") { | |
1450 | - set_cloexec(fd.as_raw_fd())?; | |
1451 | - } | |
1452 | - return Ok(fd); | |
1453 | - } | |
1454 | - Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => { | |
1455 | - CLOEXEC_FAILED.store(true, Ordering::Relaxed); | |
1456 | - } | |
1457 | - Err(e) => return Err(e), | |
1458 | - } | |
1459 | - } | |
1460 | - let fd = cvt(libc::fcntl(self.fd, libc::F_DUPFD, 0))?; | |
1461 | - let fd = Socket::from_raw_fd(fd); | |
1462 | - set_cloexec(fd.as_raw_fd())?; | |
1463 | - Ok(fd) | |
1464 | - } | |
1465 | - } | |
1466 | - | |
1467 | - #[allow(unused_mut)] | |
1468 | - pub fn accept(&self) -> io::Result<(Socket, SockAddr)> { | |
1469 | - let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() }; | |
1470 | - let mut len = mem::size_of_val(&storage) as socklen_t; | |
1471 | - | |
1472 | - let mut socket = None; | |
1473 | - #[cfg(target_os = "linux")] | |
1474 | - { | |
1475 | - let res = cvt_r(|| unsafe { | |
1476 | - libc::syscall( | |
1477 | - libc::SYS_accept4, | |
1478 | - self.fd as libc::c_long, | |
1479 | - &mut storage as *mut _ as libc::c_long, | |
1480 | - &mut len, | |
1481 | - libc::SOCK_CLOEXEC as libc::c_long, | |
1482 | - ) as libc::c_int | |
1483 | - }); | |
1484 | - match res { | |
1485 | - Ok(fd) => socket = Some(Socket { fd: fd }), | |
1486 | - Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {} | |
1487 | - Err(e) => return Err(e), | |
1488 | - } | |
1489 | - } | |
1490 | - | |
1491 | - let socket = match socket { | |
1492 | - Some(socket) => socket, | |
1493 | - None => unsafe { | |
1494 | - let fd = | |
1495 | - cvt_r(|| libc::accept(self.fd, &mut storage as *mut _ as *mut _, &mut len))?; | |
1496 | - let fd = Socket::from_raw_fd(fd); | |
1497 | - set_cloexec(fd.as_raw_fd())?; | |
1498 | - fd | |
1499 | - }, | |
1500 | - }; | |
1501 | - let addr = unsafe { SockAddr::from_raw_parts(&storage as *const _ as *const _, len) }; | |
1502 | - Ok((socket, addr)) | |
1503 | - } | |
1504 | - | |
1505 | - pub fn take_error(&self) -> io::Result<Option<io::Error>> { | |
1506 | - unsafe { | |
1507 | - let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_ERROR)?; | |
1508 | - if raw == 0 { | |
1509 | - Ok(None) | |
1510 | - } else { | |
1511 | - Ok(Some(io::Error::from_raw_os_error(raw as i32))) | |
1512 | - } | |
1513 | - } | |
1514 | - } | |
1515 | - | |
1516 | - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { | |
1517 | - unsafe { | |
1518 | - let previous = cvt(libc::fcntl(self.fd, libc::F_GETFL))?; | |
1519 | - let new = if nonblocking { | |
1520 | - previous | libc::O_NONBLOCK | |
1521 | - } else { | |
1522 | - previous & !libc::O_NONBLOCK | |
1523 | - }; | |
1524 | - if new != previous { | |
1525 | - cvt(libc::fcntl(self.fd, libc::F_SETFL, new))?; | |
1526 | - } | |
1527 | - Ok(()) | |
1528 | - } | |
1529 | - } | |
1530 | - | |
1531 | - pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { | |
1532 | - let how = match how { | |
1533 | - Shutdown::Write => libc::SHUT_WR, | |
1534 | - Shutdown::Read => libc::SHUT_RD, | |
1535 | - Shutdown::Both => libc::SHUT_RDWR, | |
1536 | - }; | |
1537 | - cvt(unsafe { libc::shutdown(self.fd, how) })?; | |
1538 | - Ok(()) | |
1539 | - } | |
1540 | - | |
1541 | - pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> { | |
1542 | - unsafe { | |
1543 | - let n = cvt({ | |
1544 | - libc::recv( | |
1545 | - self.fd, | |
1546 | - buf.as_mut_ptr() as *mut c_void, | |
1547 | - cmp::min(buf.len(), max_len()), | |
1548 | - 0, | |
1549 | - ) | |
1550 | - })?; | |
1551 | - Ok(n as usize) | |
1552 | - } | |
1553 | - } | |
1554 | - | |
1555 | - pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> { | |
1556 | - unsafe { | |
1557 | - let n = cvt({ | |
1558 | - libc::recv( | |
1559 | - self.fd, | |
1560 | - buf.as_mut_ptr() as *mut c_void, | |
1561 | - cmp::min(buf.len(), max_len()), | |
1562 | - libc::MSG_PEEK, | |
1563 | - ) | |
1564 | - })?; | |
1565 | - Ok(n as usize) | |
1566 | - } | |
1567 | - } | |
1568 | - | |
1569 | - pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SockAddr)> { | |
1570 | - self.recvfrom(buf, 0) | |
1571 | - } | |
1572 | - | |
1573 | - pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SockAddr)> { | |
1574 | - self.recvfrom(buf, libc::MSG_PEEK) | |
1575 | - } | |
1576 | - | |
1577 | - fn recvfrom(&self, buf: &mut [u8], flags: c_int) -> io::Result<(usize, SockAddr)> { | |
1578 | - unsafe { | |
1579 | - let mut storage: libc::sockaddr_storage = mem::zeroed(); | |
1580 | - let mut addrlen = mem::size_of_val(&storage) as socklen_t; | |
1581 | - | |
1582 | - let n = cvt({ | |
1583 | - libc::recvfrom( | |
1584 | - self.fd, | |
1585 | - buf.as_mut_ptr() as *mut c_void, | |
1586 | - cmp::min(buf.len(), max_len()), | |
1587 | - flags, | |
1588 | - &mut storage as *mut _ as *mut _, | |
1589 | - &mut addrlen, | |
1590 | - ) | |
1591 | - })?; | |
1592 | - let addr = SockAddr::from_raw_parts(&storage as *const _ as *const _, addrlen); | |
1593 | - Ok((n as usize, addr)) | |
1594 | - } | |
1595 | - } | |
1596 | - | |
1597 | - pub fn send(&self, buf: &[u8]) -> io::Result<usize> { | |
1598 | - unsafe { | |
1599 | - let n = cvt({ | |
1600 | - libc::send( | |
1601 | - self.fd, | |
1602 | - buf.as_ptr() as *const c_void, | |
1603 | - cmp::min(buf.len(), max_len()), | |
1604 | - MSG_NOSIGNAL, | |
1605 | - ) | |
1606 | - })?; | |
1607 | - Ok(n as usize) | |
1608 | - } | |
1609 | - } | |
1610 | - | |
1611 | - pub fn send_to(&self, buf: &[u8], addr: &SockAddr) -> io::Result<usize> { | |
1612 | - unsafe { | |
1613 | - let n = cvt({ | |
1614 | - libc::sendto( | |
1615 | - self.fd, | |
1616 | - buf.as_ptr() as *const c_void, | |
1617 | - cmp::min(buf.len(), max_len()), | |
1618 | - MSG_NOSIGNAL, | |
1619 | - addr.as_ptr(), | |
1620 | - addr.len(), | |
1621 | - ) | |
1622 | - })?; | |
1623 | - Ok(n as usize) | |
1624 | - } | |
1625 | - } | |
1626 | - | |
1627 | - // ================================================ | |
1628 | - | |
1629 | - pub fn ttl(&self) -> io::Result<u32> { | |
1630 | - unsafe { | |
1631 | - let raw: c_int = self.getsockopt(libc::IPPROTO_IP, libc::IP_TTL)?; | |
1632 | - Ok(raw as u32) | |
1633 | - } | |
1634 | - } | |
1635 | - | |
1636 | - pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { | |
1637 | - unsafe { self.setsockopt(libc::IPPROTO_IP, libc::IP_TTL, ttl as c_int) } | |
1638 | - } | |
1639 | - | |
1640 | - pub fn unicast_hops_v6(&self) -> io::Result<u32> { | |
1641 | - unsafe { | |
1642 | - let raw: c_int = self.getsockopt(libc::IPPROTO_IPV6, libc::IPV6_UNICAST_HOPS)?; | |
1643 | - Ok(raw as u32) | |
1644 | - } | |
1645 | - } | |
1646 | - | |
1647 | - pub fn set_unicast_hops_v6(&self, hops: u32) -> io::Result<()> { | |
1648 | - unsafe { | |
1649 | - self.setsockopt( | |
1650 | - libc::IPPROTO_IPV6 as c_int, | |
1651 | - libc::IPV6_UNICAST_HOPS, | |
1652 | - hops as c_int, | |
1653 | - ) | |
1654 | - } | |
1655 | - } | |
1656 | - | |
1657 | - pub fn only_v6(&self) -> io::Result<bool> { | |
1658 | - unsafe { | |
1659 | - let raw: c_int = self.getsockopt(libc::IPPROTO_IPV6, libc::IPV6_V6ONLY)?; | |
1660 | - Ok(raw != 0) | |
1661 | - } | |
1662 | - } | |
1663 | - | |
1664 | - pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> { | |
1665 | - unsafe { self.setsockopt(libc::IPPROTO_IPV6, libc::IPV6_V6ONLY, only_v6 as c_int) } | |
1666 | - } | |
1667 | - | |
1668 | - pub fn read_timeout(&self) -> io::Result<Option<Duration>> { | |
1669 | - unsafe { | |
1670 | - Ok(timeval2dur( | |
1671 | - self.getsockopt(libc::SOL_SOCKET, libc::SO_RCVTIMEO)?, | |
1672 | - )) | |
1673 | - } | |
1674 | - } | |
1675 | - | |
1676 | - pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> { | |
1677 | - unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_RCVTIMEO, dur2timeval(dur)?) } | |
1678 | - } | |
1679 | - | |
1680 | - pub fn write_timeout(&self) -> io::Result<Option<Duration>> { | |
1681 | - unsafe { | |
1682 | - Ok(timeval2dur( | |
1683 | - self.getsockopt(libc::SOL_SOCKET, libc::SO_SNDTIMEO)?, | |
1684 | - )) | |
1685 | - } | |
1686 | - } | |
1687 | - | |
1688 | - pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> { | |
1689 | - unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_SNDTIMEO, dur2timeval(dur)?) } | |
1690 | - } | |
1691 | - | |
1692 | - pub fn nodelay(&self) -> io::Result<bool> { | |
1693 | - unsafe { | |
1694 | - let raw: c_int = self.getsockopt(libc::IPPROTO_TCP, libc::TCP_NODELAY)?; | |
1695 | - Ok(raw != 0) | |
1696 | - } | |
1697 | - } | |
1698 | - | |
1699 | - pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { | |
1700 | - unsafe { self.setsockopt(libc::IPPROTO_TCP, libc::TCP_NODELAY, nodelay as c_int) } | |
1701 | - } | |
1702 | - | |
1703 | - pub fn broadcast(&self) -> io::Result<bool> { | |
1704 | - unsafe { | |
1705 | - let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_BROADCAST)?; | |
1706 | - Ok(raw != 0) | |
1707 | - } | |
1708 | - } | |
1709 | - | |
1710 | - pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> { | |
1711 | - unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_BROADCAST, broadcast as c_int) } | |
1712 | - } | |
1713 | - | |
1714 | - pub fn multicast_loop_v4(&self) -> io::Result<bool> { | |
1715 | - unsafe { | |
1716 | - let raw: c_int = self.getsockopt(libc::IPPROTO_IP, libc::IP_MULTICAST_LOOP)?; | |
1717 | - Ok(raw != 0) | |
1718 | - } | |
1719 | - } | |
1720 | - | |
1721 | - pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> { | |
1722 | - unsafe { | |
1723 | - self.setsockopt( | |
1724 | - libc::IPPROTO_IP, | |
1725 | - libc::IP_MULTICAST_LOOP, | |
1726 | - multicast_loop_v4 as c_int, | |
1727 | - ) | |
1728 | - } | |
1729 | - } | |
1730 | - | |
1731 | - pub fn multicast_ttl_v4(&self) -> io::Result<u32> { | |
1732 | - unsafe { | |
1733 | - let raw: c_int = self.getsockopt(libc::IPPROTO_IP, libc::IP_MULTICAST_TTL)?; | |
1734 | - Ok(raw as u32) | |
1735 | - } | |
1736 | - } | |
1737 | - | |
1738 | - pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> { | |
1739 | - unsafe { | |
1740 | - self.setsockopt( | |
1741 | - libc::IPPROTO_IP, | |
1742 | - libc::IP_MULTICAST_TTL, | |
1743 | - multicast_ttl_v4 as c_int, | |
1744 | - ) | |
1745 | - } | |
1746 | - } | |
1747 | - | |
1748 | - pub fn multicast_hops_v6(&self) -> io::Result<u32> { | |
1749 | - unsafe { | |
1750 | - let raw: c_int = self.getsockopt(libc::IPPROTO_IPV6, libc::IPV6_MULTICAST_HOPS)?; | |
1751 | - Ok(raw as u32) | |
1752 | - } | |
1753 | - } | |
1754 | - | |
1755 | - pub fn set_multicast_hops_v6(&self, hops: u32) -> io::Result<()> { | |
1756 | - unsafe { self.setsockopt(libc::IPPROTO_IPV6, libc::IPV6_MULTICAST_HOPS, hops as c_int) } | |
1757 | - } | |
1758 | - | |
1759 | - pub fn multicast_if_v4(&self) -> io::Result<Ipv4Addr> { | |
1760 | - unsafe { | |
1761 | - let imr_interface: libc::in_addr = | |
1762 | - self.getsockopt(libc::IPPROTO_IP, libc::IP_MULTICAST_IF)?; | |
1763 | - Ok(from_s_addr(imr_interface.s_addr)) | |
1764 | - } | |
1765 | - } | |
1766 | - | |
1767 | - pub fn set_multicast_if_v4(&self, interface: &Ipv4Addr) -> io::Result<()> { | |
1768 | - let interface = to_s_addr(interface); | |
1769 | - let imr_interface = libc::in_addr { s_addr: interface }; | |
1770 | - | |
1771 | - unsafe { self.setsockopt(libc::IPPROTO_IP, libc::IP_MULTICAST_IF, imr_interface) } | |
1772 | - } | |
1773 | - | |
1774 | - pub fn multicast_if_v6(&self) -> io::Result<u32> { | |
1775 | - unsafe { | |
1776 | - let raw: c_int = self.getsockopt(libc::IPPROTO_IPV6, libc::IPV6_MULTICAST_IF)?; | |
1777 | - Ok(raw as u32) | |
1778 | - } | |
1779 | - } | |
1780 | - | |
1781 | - pub fn set_multicast_if_v6(&self, interface: u32) -> io::Result<()> { | |
1782 | - unsafe { | |
1783 | - self.setsockopt( | |
1784 | - libc::IPPROTO_IPV6, | |
1785 | - libc::IPV6_MULTICAST_IF, | |
1786 | - interface as c_int, | |
1787 | - ) | |
1788 | - } | |
1789 | - } | |
1790 | - | |
1791 | - pub fn multicast_loop_v6(&self) -> io::Result<bool> { | |
1792 | - unsafe { | |
1793 | - let raw: c_int = self.getsockopt(libc::IPPROTO_IPV6, libc::IPV6_MULTICAST_LOOP)?; | |
1794 | - Ok(raw != 0) | |
1795 | - } | |
1796 | - } | |
1797 | - | |
1798 | - pub fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> { | |
1799 | - unsafe { | |
1800 | - self.setsockopt( | |
1801 | - libc::IPPROTO_IPV6, | |
1802 | - libc::IPV6_MULTICAST_LOOP, | |
1803 | - multicast_loop_v6 as c_int, | |
1804 | - ) | |
1805 | - } | |
1806 | - } | |
1807 | - | |
1808 | - pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { | |
1809 | - let multiaddr = to_s_addr(multiaddr); | |
1810 | - let interface = to_s_addr(interface); | |
1811 | - let mreq = libc::ip_mreq { | |
1812 | - imr_multiaddr: libc::in_addr { s_addr: multiaddr }, | |
1813 | - imr_interface: libc::in_addr { s_addr: interface }, | |
1814 | - }; | |
1815 | - unsafe { self.setsockopt(libc::IPPROTO_IP, libc::IP_ADD_MEMBERSHIP, mreq) } | |
1816 | - } | |
1817 | - | |
1818 | - pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { | |
1819 | - let multiaddr = to_in6_addr(multiaddr); | |
1820 | - let mreq = libc::ipv6_mreq { | |
1821 | - ipv6mr_multiaddr: multiaddr, | |
1822 | - ipv6mr_interface: to_ipv6mr_interface(interface), | |
1823 | - }; | |
1824 | - unsafe { self.setsockopt(libc::IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, mreq) } | |
1825 | - } | |
1826 | - | |
1827 | - pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { | |
1828 | - let multiaddr = to_s_addr(multiaddr); | |
1829 | - let interface = to_s_addr(interface); | |
1830 | - let mreq = libc::ip_mreq { | |
1831 | - imr_multiaddr: libc::in_addr { s_addr: multiaddr }, | |
1832 | - imr_interface: libc::in_addr { s_addr: interface }, | |
1833 | - }; | |
1834 | - unsafe { self.setsockopt(libc::IPPROTO_IP, libc::IP_DROP_MEMBERSHIP, mreq) } | |
1835 | - } | |
1836 | - | |
1837 | - pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { | |
1838 | - let multiaddr = to_in6_addr(multiaddr); | |
1839 | - let mreq = libc::ipv6_mreq { | |
1840 | - ipv6mr_multiaddr: multiaddr, | |
1841 | - ipv6mr_interface: to_ipv6mr_interface(interface), | |
1842 | - }; | |
1843 | - unsafe { self.setsockopt(libc::IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, mreq) } | |
1844 | - } | |
1845 | - | |
1846 | - pub fn linger(&self) -> io::Result<Option<Duration>> { | |
1847 | - unsafe { | |
1848 | - Ok(linger2dur( | |
1849 | - self.getsockopt(libc::SOL_SOCKET, libc::SO_LINGER)?, | |
1850 | - )) | |
1851 | - } | |
1852 | - } | |
1853 | - | |
1854 | - pub fn set_linger(&self, dur: Option<Duration>) -> io::Result<()> { | |
1855 | - unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_LINGER, dur2linger(dur)) } | |
1856 | - } | |
1857 | - | |
1858 | - pub fn set_reuse_address(&self, reuse: bool) -> io::Result<()> { | |
1859 | - unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_REUSEADDR, reuse as c_int) } | |
1860 | - } | |
1861 | - | |
1862 | - pub fn reuse_address(&self) -> io::Result<bool> { | |
1863 | - unsafe { | |
1864 | - let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_REUSEADDR)?; | |
1865 | - Ok(raw != 0) | |
1866 | - } | |
1867 | - } | |
1868 | - | |
1869 | - pub fn recv_buffer_size(&self) -> io::Result<usize> { | |
1870 | - unsafe { | |
1871 | - let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_RCVBUF)?; | |
1872 | - Ok(raw as usize) | |
1873 | - } | |
1874 | - } | |
1875 | - | |
1876 | - pub fn set_recv_buffer_size(&self, size: usize) -> io::Result<()> { | |
1877 | - unsafe { | |
1878 | - // TODO: casting usize to a c_int should be a checked cast | |
1879 | - self.setsockopt(libc::SOL_SOCKET, libc::SO_RCVBUF, size as c_int) | |
1880 | - } | |
1881 | - } | |
1882 | - | |
1883 | - pub fn send_buffer_size(&self) -> io::Result<usize> { | |
1884 | - unsafe { | |
1885 | - let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_SNDBUF)?; | |
1886 | - Ok(raw as usize) | |
1887 | - } | |
1888 | - } | |
1889 | - | |
1890 | - pub fn set_send_buffer_size(&self, size: usize) -> io::Result<()> { | |
1891 | - unsafe { | |
1892 | - // TODO: casting usize to a c_int should be a checked cast | |
1893 | - self.setsockopt(libc::SOL_SOCKET, libc::SO_SNDBUF, size as c_int) | |
1894 | - } | |
1895 | - } | |
1896 | - | |
1897 | - pub fn keepalive(&self) -> io::Result<Option<Duration>> { | |
1898 | - unsafe { | |
1899 | - let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_KEEPALIVE)?; | |
1900 | - if raw == 0 { | |
1901 | - return Ok(None); | |
1902 | - } | |
1903 | - let secs: c_int = self.getsockopt(libc::IPPROTO_TCP, KEEPALIVE_OPTION)?; | |
1904 | - Ok(Some(Duration::new(secs as u64, 0))) | |
1905 | - } | |
1906 | - } | |
1907 | - | |
1908 | - pub fn set_keepalive(&self, keepalive: Option<Duration>) -> io::Result<()> { | |
1909 | - unsafe { | |
1910 | - self.setsockopt( | |
1911 | - libc::SOL_SOCKET, | |
1912 | - libc::SO_KEEPALIVE, | |
1913 | - keepalive.is_some() as c_int, | |
1914 | - )?; | |
1915 | - if let Some(dur) = keepalive { | |
1916 | - // TODO: checked cast here | |
1917 | - self.setsockopt(libc::IPPROTO_TCP, KEEPALIVE_OPTION, dur.as_secs() as c_int)?; | |
1918 | - } | |
1919 | - Ok(()) | |
1920 | - } | |
1921 | - } | |
1922 | - | |
1923 | - #[cfg(all(unix, not(target_os = "solaris")))] | |
1924 | - pub fn reuse_port(&self) -> io::Result<bool> { | |
1925 | - unsafe { | |
1926 | - let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_REUSEPORT)?; | |
1927 | - Ok(raw != 0) | |
1928 | - } | |
1929 | - } | |
1930 | - | |
1931 | - #[cfg(all(unix, not(target_os = "solaris")))] | |
1932 | - pub fn set_reuse_port(&self, reuse: bool) -> io::Result<()> { | |
1933 | - unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_REUSEPORT, reuse as c_int) } | |
1934 | - } | |
1935 | - | |
1936 | - unsafe fn setsockopt<T>(&self, opt: c_int, val: c_int, payload: T) -> io::Result<()> | |
1937 | - where | |
1938 | - T: Copy, | |
1939 | - { | |
1940 | - let payload = &payload as *const T as *const c_void; | |
1941 | - cvt(libc::setsockopt( | |
1942 | - self.fd, | |
1943 | - opt, | |
1944 | - val, | |
1945 | - payload, | |
1946 | - mem::size_of::<T>() as libc::socklen_t, | |
1947 | - ))?; | |
1948 | - Ok(()) | |
1949 | - } | |
1950 | - | |
1951 | - unsafe fn getsockopt<T: Copy>(&self, opt: c_int, val: c_int) -> io::Result<T> { | |
1952 | - let mut slot: T = mem::zeroed(); | |
1953 | - let mut len = mem::size_of::<T>() as libc::socklen_t; | |
1954 | - cvt(libc::getsockopt( | |
1955 | - self.fd, | |
1956 | - opt, | |
1957 | - val, | |
1958 | - &mut slot as *mut _ as *mut _, | |
1959 | - &mut len, | |
1960 | - ))?; | |
1961 | - assert_eq!(len as usize, mem::size_of::<T>()); | |
1962 | - Ok(slot) | |
1963 | - } | |
1964 | -} | |
1965 | - | |
1966 | -impl Read for Socket { | |
1967 | - fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | |
1968 | - <&Socket>::read(&mut &*self, buf) | |
1969 | - } | |
1970 | -} | |
1971 | - | |
1972 | -impl<'a> Read for &'a Socket { | |
1973 | - fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | |
1974 | - unsafe { | |
1975 | - let n = cvt({ | |
1976 | - libc::read( | |
1977 | - self.fd, | |
1978 | - buf.as_mut_ptr() as *mut c_void, | |
1979 | - cmp::min(buf.len(), max_len()), | |
1980 | - ) | |
1981 | - })?; | |
1982 | - Ok(n as usize) | |
1983 | - } | |
1984 | - } | |
1985 | -} | |
1986 | - | |
1987 | -impl Write for Socket { | |
1988 | - fn write(&mut self, buf: &[u8]) -> io::Result<usize> { | |
1989 | - <&Socket>::write(&mut &*self, buf) | |
1990 | - } | |
1991 | - | |
1992 | - fn flush(&mut self) -> io::Result<()> { | |
1993 | - <&Socket>::flush(&mut &*self) | |
1994 | - } | |
1995 | -} | |
1996 | - | |
1997 | -impl<'a> Write for &'a Socket { | |
1998 | - fn write(&mut self, buf: &[u8]) -> io::Result<usize> { | |
1999 | - self.send(buf) | |
2000 | - } | |
2001 | - | |
2002 | - fn flush(&mut self) -> io::Result<()> { | |
2003 | - Ok(()) | |
2004 | - } | |
2005 | -} | |
2006 | - | |
2007 | -impl fmt::Debug for Socket { | |
2008 | - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
2009 | - let mut f = f.debug_struct("Socket"); | |
2010 | - f.field("fd", &self.fd); | |
2011 | - if let Ok(addr) = self.local_addr() { | |
2012 | - f.field("local_addr", &addr); | |
2013 | - } | |
2014 | - if let Ok(addr) = self.peer_addr() { | |
2015 | - f.field("peer_addr", &addr); | |
2016 | - } | |
2017 | - f.finish() | |
2018 | - } | |
2019 | -} | |
2020 | - | |
2021 | -impl AsRawFd for Socket { | |
2022 | - fn as_raw_fd(&self) -> c_int { | |
2023 | - self.fd | |
2024 | - } | |
2025 | -} | |
2026 | - | |
2027 | -impl IntoRawFd for Socket { | |
2028 | - fn into_raw_fd(self) -> c_int { | |
2029 | - let fd = self.fd; | |
2030 | - mem::forget(self); | |
2031 | - return fd; | |
2032 | - } | |
2033 | -} | |
2034 | - | |
2035 | -impl FromRawFd for Socket { | |
2036 | - unsafe fn from_raw_fd(fd: c_int) -> Socket { | |
2037 | - Socket { fd: fd } | |
2038 | - } | |
2039 | -} | |
2040 | - | |
2041 | -impl AsRawFd for crate::Socket { | |
2042 | - fn as_raw_fd(&self) -> c_int { | |
2043 | - self.inner.as_raw_fd() | |
2044 | - } | |
2045 | -} | |
2046 | - | |
2047 | -impl IntoRawFd for crate::Socket { | |
2048 | - fn into_raw_fd(self) -> c_int { | |
2049 | - self.inner.into_raw_fd() | |
2050 | - } | |
2051 | -} | |
2052 | - | |
2053 | -impl FromRawFd for crate::Socket { | |
2054 | - unsafe fn from_raw_fd(fd: c_int) -> crate::Socket { | |
2055 | - crate::Socket { | |
2056 | - inner: Socket::from_raw_fd(fd), | |
2057 | - } | |
2058 | - } | |
2059 | -} | |
2060 | - | |
2061 | -impl Drop for Socket { | |
2062 | - fn drop(&mut self) { | |
2063 | - unsafe { | |
2064 | - let _ = libc::close(self.fd); | |
2065 | - } | |
2066 | - } | |
2067 | -} | |
2068 | - | |
2069 | -impl From<Socket> for net::TcpStream { | |
2070 | - fn from(socket: Socket) -> net::TcpStream { | |
2071 | - unsafe { net::TcpStream::from_raw_fd(socket.into_raw_fd()) } | |
2072 | - } | |
2073 | -} | |
2074 | - | |
2075 | -impl From<Socket> for net::TcpListener { | |
2076 | - fn from(socket: Socket) -> net::TcpListener { | |
2077 | - unsafe { net::TcpListener::from_raw_fd(socket.into_raw_fd()) } | |
2078 | - } | |
2079 | -} | |
2080 | - | |
2081 | -impl From<Socket> for net::UdpSocket { | |
2082 | - fn from(socket: Socket) -> net::UdpSocket { | |
2083 | - unsafe { net::UdpSocket::from_raw_fd(socket.into_raw_fd()) } | |
2084 | - } | |
2085 | -} | |
2086 | - | |
2087 | -#[cfg(all(unix, feature = "unix"))] | |
2088 | -impl From<Socket> for UnixStream { | |
2089 | - fn from(socket: Socket) -> UnixStream { | |
2090 | - unsafe { UnixStream::from_raw_fd(socket.into_raw_fd()) } | |
2091 | - } | |
2092 | -} | |
2093 | - | |
2094 | -#[cfg(all(unix, feature = "unix"))] | |
2095 | -impl From<Socket> for UnixListener { | |
2096 | - fn from(socket: Socket) -> UnixListener { | |
2097 | - unsafe { UnixListener::from_raw_fd(socket.into_raw_fd()) } | |
2098 | - } | |
2099 | -} | |
2100 | - | |
2101 | -#[cfg(all(unix, feature = "unix"))] | |
2102 | -impl From<Socket> for UnixDatagram { | |
2103 | - fn from(socket: Socket) -> UnixDatagram { | |
2104 | - unsafe { UnixDatagram::from_raw_fd(socket.into_raw_fd()) } | |
2105 | - } | |
2106 | -} | |
2107 | - | |
2108 | -impl From<net::TcpStream> for Socket { | |
2109 | - fn from(socket: net::TcpStream) -> Socket { | |
2110 | - unsafe { Socket::from_raw_fd(socket.into_raw_fd()) } | |
2111 | + /// Creates a pair of sockets which are connected to each other. | |
2112 | + /// | |
2113 | + /// This function corresponds to `socketpair(2)`. | |
2114 | + pub fn pair( | |
2115 | + domain: Domain, | |
2116 | + type_: Type, | |
2117 | + protocol: Option<Protocol>, | |
2118 | + ) -> io::Result<(Socket, Socket)> { | |
2119 | + let mut fds = [0, 0]; | |
2120 | + let protocol = protocol.map(|p| p.0).unwrap_or(0); | |
2121 | + syscall!(socketpair(domain.0, type_.0, protocol, fds.as_mut_ptr())) | |
2122 | + .map(|_| (Socket { inner: fds[0] }, Socket { inner: fds[1] })) | |
2123 | + } | |
2124 | + | |
2125 | + /// Accept a new incoming connection from this listener. | |
2126 | + /// | |
2127 | + /// This function directly corresponds to the `accept4(2)` function. | |
2128 | + /// | |
2129 | + /// # Notes | |
2130 | + /// | |
2131 | + /// This only available on Android, DragonFlyBSD, FreeBSD, Linux and | |
2132 | + /// OpenBSD. Once https://github.com/rust-lang/libc/issues/1636 is fixed | |
2133 | + /// NetBSD will also support it. | |
2134 | + #[cfg(any( | |
2135 | + target_os = "android", | |
2136 | + target_os = "dragonfly", | |
2137 | + target_os = "freebsd", | |
2138 | + target_os = "linux", | |
2139 | + // NetBSD 8.0 actually has `accept4(2)`, but libc doesn't expose it | |
2140 | + // (yet). See https://github.com/rust-lang/libc/issues/1636. | |
2141 | + //target_os = "netbsd", | |
2142 | + target_os = "openbsd" | |
2143 | + ))] | |
2144 | + pub fn accept4(&self, flags: c_int) -> io::Result<(Socket, SockAddr)> { | |
2145 | + let mut addr: MaybeUninit<libc::sockaddr_storage> = MaybeUninit::uninit(); | |
2146 | + let mut addrlen = size_of::<libc::sockaddr_storage>() as libc::socklen_t; | |
2147 | + syscall!(accept4( | |
2148 | + self.inner, | |
2149 | + addr.as_mut_ptr() as *mut _, | |
2150 | + &mut addrlen, | |
2151 | + flags | |
2152 | + )) | |
2153 | + .map(|stream_fd| { | |
2154 | + // This is safe because `accept(2)` filled in the address for us. | |
2155 | + let addr = unsafe { SockAddr::from_raw_parts(addr.assume_init(), addrlen) }; | |
2156 | + (Socket { inner: stream_fd }, addr) | |
2157 | + }) | |
2158 | } | |
2159 | } | |
2160 | ||
2161 | -impl From<net::TcpListener> for Socket { | |
2162 | - fn from(socket: net::TcpListener) -> Socket { | |
2163 | +impl From<UnixStream> for Socket { | |
2164 | + fn from(socket: UnixStream) -> Socket { | |
2165 | unsafe { Socket::from_raw_fd(socket.into_raw_fd()) } | |
2166 | } | |
2167 | } | |
2168 | ||
2169 | -impl From<net::UdpSocket> for Socket { | |
2170 | - fn from(socket: net::UdpSocket) -> Socket { | |
2171 | - unsafe { Socket::from_raw_fd(socket.into_raw_fd()) } | |
2172 | +impl Into<UnixStream> for Socket { | |
2173 | + fn into(self) -> UnixStream { | |
2174 | + unsafe { UnixStream::from_raw_fd(self.into_raw_fd()) } | |
2175 | } | |
2176 | } | |
2177 | ||
2178 | -#[cfg(all(unix, feature = "unix"))] | |
2179 | -impl From<UnixStream> for Socket { | |
2180 | - fn from(socket: UnixStream) -> Socket { | |
2181 | +impl From<UnixListener> for Socket { | |
2182 | + fn from(socket: UnixListener) -> Socket { | |
2183 | unsafe { Socket::from_raw_fd(socket.into_raw_fd()) } | |
2184 | } | |
2185 | } | |
2186 | ||
2187 | -#[cfg(all(unix, feature = "unix"))] | |
2188 | -impl From<UnixListener> for Socket { | |
2189 | - fn from(socket: UnixListener) -> Socket { | |
2190 | - unsafe { Socket::from_raw_fd(socket.into_raw_fd()) } | |
2191 | +impl Into<UnixListener> for Socket { | |
2192 | + fn into(self) -> UnixListener { | |
2193 | + unsafe { UnixListener::from_raw_fd(self.into_raw_fd()) } | |
2194 | } | |
2195 | } | |
2196 | ||
2197 | -#[cfg(all(unix, feature = "unix"))] | |
2198 | impl From<UnixDatagram> for Socket { | |
2199 | fn from(socket: UnixDatagram) -> Socket { | |
2200 | unsafe { Socket::from_raw_fd(socket.into_raw_fd()) } | |
2201 | } | |
2202 | } | |
2203 | ||
2204 | -fn max_len() -> usize { | |
2205 | - // The maximum read limit on most posix-like systems is `SSIZE_MAX`, | |
2206 | - // with the man page quoting that if the count of bytes to read is | |
2207 | - // greater than `SSIZE_MAX` the result is "unspecified". | |
2208 | - // | |
2209 | - // On macOS, however, apparently the 64-bit libc is either buggy or | |
2210 | - // intentionally showing odd behavior by rejecting any read with a size | |
2211 | - // larger than or equal to INT_MAX. To handle both of these the read | |
2212 | - // size is capped on both platforms. | |
2213 | - if cfg!(target_os = "macos") { | |
2214 | - <c_int>::max_value() as usize - 1 | |
2215 | - } else { | |
2216 | - <ssize_t>::max_value() as usize | |
2217 | - } | |
2218 | -} | |
2219 | - | |
2220 | -fn cvt<T: One + PartialEq + Neg<Output = T>>(t: T) -> io::Result<T> { | |
2221 | - let one: T = T::one(); | |
2222 | - if t == -one { | |
2223 | - Err(io::Error::last_os_error()) | |
2224 | - } else { | |
2225 | - Ok(t) | |
2226 | +impl Into<UnixDatagram> for Socket { | |
2227 | + fn into(self) -> UnixDatagram { | |
2228 | + unsafe { UnixDatagram::from_raw_fd(self.into_raw_fd()) } | |
2229 | } | |
2230 | } | |
2231 | ||
2232 | -fn cvt_r<F, T>(mut f: F) -> io::Result<T> | |
2233 | -where | |
2234 | - F: FnMut() -> T, | |
2235 | - T: One + PartialEq + Neg<Output = T>, | |
2236 | -{ | |
2237 | - loop { | |
2238 | - match cvt(f()) { | |
2239 | - Err(ref e) if e.kind() == ErrorKind::Interrupted => {} | |
2240 | - other => return other, | |
2241 | - } | |
2242 | - } | |
2243 | -} | |
2244 | - | |
2245 | -fn set_cloexec(fd: c_int) -> io::Result<()> { | |
2246 | - unsafe { | |
2247 | - let previous = cvt(libc::fcntl(fd, libc::F_GETFD))?; | |
2248 | - let new = previous | libc::FD_CLOEXEC; | |
2249 | - if new != previous { | |
2250 | - cvt(libc::fcntl(fd, libc::F_SETFD, new))?; | |
2251 | - } | |
2252 | - Ok(()) | |
2253 | - } | |
2254 | -} | |
2255 | - | |
2256 | -fn dur2timeval(dur: Option<Duration>) -> io::Result<libc::timeval> { | |
2257 | - match dur { | |
2258 | - Some(dur) => { | |
2259 | - if dur.as_secs() == 0 && dur.subsec_nanos() == 0 { | |
2260 | - return Err(io::Error::new( | |
2261 | - io::ErrorKind::InvalidInput, | |
2262 | - "cannot set a 0 duration timeout", | |
2263 | - )); | |
2264 | - } | |
2265 | - | |
2266 | - let secs = if dur.as_secs() > libc::time_t::max_value() as u64 { | |
2267 | - libc::time_t::max_value() | |
2268 | - } else { | |
2269 | - dur.as_secs() as libc::time_t | |
2270 | - }; | |
2271 | - let mut timeout = libc::timeval { | |
2272 | - tv_sec: secs, | |
2273 | - tv_usec: (dur.subsec_nanos() / 1000) as libc::suseconds_t, | |
2274 | - }; | |
2275 | - if timeout.tv_sec == 0 && timeout.tv_usec == 0 { | |
2276 | - timeout.tv_usec = 1; | |
2277 | - } | |
2278 | - Ok(timeout) | |
2279 | - } | |
2280 | - None => Ok(libc::timeval { | |
2281 | - tv_sec: 0, | |
2282 | - tv_usec: 0, | |
2283 | - }), | |
2284 | +impl FromRawFd for Socket { | |
2285 | + unsafe fn from_raw_fd(fd: RawFd) -> Socket { | |
2286 | + Socket { inner: fd } | |
2287 | } | |
2288 | } | |
2289 | ||
2290 | -fn timeval2dur(raw: libc::timeval) -> Option<Duration> { | |
2291 | - if raw.tv_sec == 0 && raw.tv_usec == 0 { | |
2292 | - None | |
2293 | - } else { | |
2294 | - let sec = raw.tv_sec as u64; | |
2295 | - let nsec = (raw.tv_usec as u32) * 1000; | |
2296 | - Some(Duration::new(sec, nsec)) | |
2297 | +impl AsRawFd for Socket { | |
2298 | + fn as_raw_fd(&self) -> RawFd { | |
2299 | + self.inner | |
2300 | } | |
2301 | } | |
2302 | ||
2303 | -fn to_s_addr(addr: &Ipv4Addr) -> libc::in_addr_t { | |
2304 | - let octets = addr.octets(); | |
2305 | - crate::hton( | |
2306 | - ((octets[0] as libc::in_addr_t) << 24) | |
2307 | - | ((octets[1] as libc::in_addr_t) << 16) | |
2308 | - | ((octets[2] as libc::in_addr_t) << 8) | |
2309 | - | ((octets[3] as libc::in_addr_t) << 0), | |
2310 | - ) | |
2311 | -} | |
2312 | - | |
2313 | -fn from_s_addr(in_addr: libc::in_addr_t) -> Ipv4Addr { | |
2314 | - let h_addr = crate::ntoh(in_addr); | |
2315 | - | |
2316 | - let a: u8 = (h_addr >> 24) as u8; | |
2317 | - let b: u8 = (h_addr >> 16) as u8; | |
2318 | - let c: u8 = (h_addr >> 8) as u8; | |
2319 | - let d: u8 = (h_addr >> 0) as u8; | |
2320 | - | |
2321 | - Ipv4Addr::new(a, b, c, d) | |
2322 | -} | |
2323 | - | |
2324 | -fn to_in6_addr(addr: &Ipv6Addr) -> libc::in6_addr { | |
2325 | - let mut ret: libc::in6_addr = unsafe { mem::zeroed() }; | |
2326 | - ret.s6_addr = addr.octets(); | |
2327 | - return ret; | |
2328 | -} | |
2329 | - | |
2330 | -#[cfg(target_os = "android")] | |
2331 | -fn to_ipv6mr_interface(value: u32) -> c_int { | |
2332 | - value as c_int | |
2333 | -} | |
2334 | - | |
2335 | -#[cfg(not(target_os = "android"))] | |
2336 | -fn to_ipv6mr_interface(value: u32) -> libc::c_uint { | |
2337 | - value as libc::c_uint | |
2338 | -} | |
2339 | - | |
2340 | -fn linger2dur(linger_opt: libc::linger) -> Option<Duration> { | |
2341 | - if linger_opt.l_onoff == 0 { | |
2342 | - None | |
2343 | - } else { | |
2344 | - Some(Duration::from_secs(linger_opt.l_linger as u64)) | |
2345 | +impl IntoRawFd for Socket { | |
2346 | + fn into_raw_fd(self) -> RawFd { | |
2347 | + let fd = self.inner; | |
2348 | + mem::forget(self); | |
2349 | + fd | |
2350 | } | |
2351 | } | |
2352 | ||
2353 | -fn dur2linger(dur: Option<Duration>) -> libc::linger { | |
2354 | - match dur { | |
2355 | - Some(d) => libc::linger { | |
2356 | - l_onoff: 1, | |
2357 | - l_linger: d.as_secs() as c_int, | |
2358 | - }, | |
2359 | - None => libc::linger { | |
2360 | - l_onoff: 0, | |
2361 | - l_linger: 0, | |
2362 | - }, | |
2363 | +impl Drop for Socket { | |
2364 | + fn drop(&mut self) { | |
2365 | + // Can't handle the error here, nor can we do much with it. | |
2366 | + let _ = unsafe { libc::close(self.inner) }; | |
2367 | } | |
2368 | } | |
2369 | - | |
2370 | -#[test] | |
2371 | -fn test_ip() { | |
2372 | - let ip = Ipv4Addr::new(127, 0, 0, 1); | |
2373 | - assert_eq!(ip, from_s_addr(to_s_addr(&ip))); | |
2374 | -} | |
2375 | diff --git a/tests/socket.rs b/tests/socket.rs | |
2376 | new file mode 100644 | |
2377 | index 0000000..66058e1 | |
2378 | --- /dev/null | |
2379 | +++ b/tests/socket.rs | |
2380 | @@ -0,0 +1,122 @@ | |
2381 | +use std::net::{TcpListener, TcpStream, UdpSocket}; | |
2382 | + | |
2383 | +use socket2::{Domain, Socket, Type}; | |
2384 | + | |
2385 | +mod util; | |
2386 | +use util::any_local_ipv4_addr; | |
2387 | + | |
2388 | +#[test] | |
2389 | +fn from_std_tcp_stream() { | |
2390 | + let listener = TcpListener::bind(any_local_ipv4_addr()).unwrap(); | |
2391 | + let tcp_socket = TcpStream::connect(listener.local_addr().unwrap()).unwrap(); | |
2392 | + let socket: Socket = tcp_socket.into(); | |
2393 | + drop(socket); | |
2394 | +} | |
2395 | + | |
2396 | +#[test] | |
2397 | +fn from_std_tcp_listener() { | |
2398 | + let tcp_socket = TcpListener::bind(any_local_ipv4_addr()).unwrap(); | |
2399 | + let socket: Socket = tcp_socket.into(); | |
2400 | + drop(socket); | |
2401 | +} | |
2402 | + | |
2403 | +#[test] | |
2404 | +fn from_std_udp_socket() { | |
2405 | + let udp_socket = UdpSocket::bind(any_local_ipv4_addr()).unwrap(); | |
2406 | + let socket: Socket = udp_socket.into(); | |
2407 | + drop(socket); | |
2408 | +} | |
2409 | + | |
2410 | +#[test] | |
2411 | +fn into_std_tcp_stream() { | |
2412 | + let socket: Socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); | |
2413 | + let tcp_socket: TcpStream = socket.into(); | |
2414 | + drop(tcp_socket); | |
2415 | +} | |
2416 | + | |
2417 | +#[test] | |
2418 | +fn into_std_tcp_listener() { | |
2419 | + let socket: Socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); | |
2420 | + let tcp_socket: TcpListener = socket.into(); | |
2421 | + drop(tcp_socket); | |
2422 | +} | |
2423 | + | |
2424 | +#[test] | |
2425 | +fn into_std_udp_socket() { | |
2426 | + let socket: Socket = Socket::new(Domain::ipv4(), Type::dgram(), None).unwrap(); | |
2427 | + let udp_socket: UdpSocket = socket.into(); | |
2428 | + drop(udp_socket); | |
2429 | +} | |
2430 | + | |
2431 | +#[test] | |
2432 | +fn socket_connect_tcp() { | |
2433 | + let listener = TcpListener::bind(any_local_ipv4_addr()).unwrap(); | |
2434 | + let addr = listener.local_addr().unwrap(); | |
2435 | + | |
2436 | + let socket: TcpStream = Socket::new(Domain::ipv4(), Type::stream(), None) | |
2437 | + .and_then(|socket| socket.connect(&addr.into()).map(|()| socket.into())) | |
2438 | + .unwrap(); | |
2439 | + assert_eq!(socket.peer_addr().unwrap(), addr); | |
2440 | + | |
2441 | + let (stream, peer_addr) = listener.accept().unwrap(); | |
2442 | + let socket_local_addr = socket.local_addr().unwrap(); | |
2443 | + assert_eq!(peer_addr, socket_local_addr); | |
2444 | + assert_eq!(stream.peer_addr().unwrap(), socket_local_addr); | |
2445 | +} | |
2446 | + | |
2447 | +#[test] | |
2448 | +fn socket_bind_tcp() { | |
2449 | + let socket: TcpListener = Socket::new(Domain::ipv4(), Type::stream(), None) | |
2450 | + .and_then(|socket| { | |
2451 | + socket | |
2452 | + .bind(&any_local_ipv4_addr().into()) | |
2453 | + .map(|()| socket.into()) | |
2454 | + }) | |
2455 | + .unwrap(); | |
2456 | + | |
2457 | + assert!(socket.local_addr().unwrap().ip().is_loopback()) | |
2458 | +} | |
2459 | + | |
2460 | +#[test] | |
2461 | +fn socket_listen_tcp() { | |
2462 | + let socket: TcpListener = Socket::new(Domain::ipv4(), Type::stream(), None) | |
2463 | + .and_then(|socket| { | |
2464 | + socket.bind(&any_local_ipv4_addr().into())?; | |
2465 | + socket.listen(1024)?; | |
2466 | + Ok(socket.into()) | |
2467 | + }) | |
2468 | + .unwrap(); | |
2469 | + let addr = socket.local_addr().unwrap(); | |
2470 | + | |
2471 | + let stream = TcpStream::connect(addr).unwrap(); | |
2472 | + let stream_addr = stream.local_addr().unwrap(); | |
2473 | + | |
2474 | + let (accepted_stream, peer_addr) = socket.accept().unwrap(); | |
2475 | + assert_eq!(peer_addr, stream_addr); | |
2476 | + assert_eq!(accepted_stream.peer_addr().unwrap(), stream_addr); | |
2477 | +} | |
2478 | + | |
2479 | +// Also tests `local_addr` and `peer_addr`. | |
2480 | +#[test] | |
2481 | +fn socket_accept_tcp() { | |
2482 | + let socket: Socket = Socket::new(Domain::ipv4(), Type::stream(), None) | |
2483 | + .and_then(|socket| { | |
2484 | + socket.bind(&any_local_ipv4_addr().into())?; | |
2485 | + socket.listen(1024)?; | |
2486 | + Ok(socket.into()) | |
2487 | + }) | |
2488 | + .unwrap(); | |
2489 | + let addr = socket.local_addr().unwrap(); | |
2490 | + let addr = addr.as_std().unwrap(); | |
2491 | + | |
2492 | + let stream = TcpStream::connect(addr).unwrap(); | |
2493 | + let stream_addr = stream.local_addr().unwrap(); | |
2494 | + | |
2495 | + let (accepted_socket, peer_addr) = socket.accept().unwrap(); | |
2496 | + let peer_addr = peer_addr.as_std().unwrap(); | |
2497 | + assert_eq!(peer_addr, stream_addr); | |
2498 | + assert_eq!( | |
2499 | + accepted_socket.peer_addr().unwrap().as_std().unwrap(), | |
2500 | + stream_addr | |
2501 | + ); | |
2502 | +} | |
2503 | diff --git a/tests/unix.rs b/tests/unix.rs | |
2504 | new file mode 100644 | |
2505 | index 0000000..3af40f6 | |
2506 | --- /dev/null | |
2507 | +++ b/tests/unix.rs | |
2508 | @@ -0,0 +1,60 @@ | |
2509 | +//! Tests for Unix only API. | |
2510 | + | |
2511 | +#![cfg(unix)] | |
2512 | + | |
2513 | +use std::os::unix::net::{UnixDatagram, UnixListener, UnixStream}; | |
2514 | + | |
2515 | +use socket2::{Domain, Socket, Type}; | |
2516 | + | |
2517 | +mod util; | |
2518 | +use util::temp_file; | |
2519 | + | |
2520 | +#[test] | |
2521 | +fn from_std_unix_stream() { | |
2522 | + let path = temp_file("from_std_unix_stream"); | |
2523 | + let listener = UnixListener::bind(&path).unwrap(); | |
2524 | + let stream = UnixStream::connect(&path).unwrap(); | |
2525 | + let socket: Socket = stream.into(); | |
2526 | + drop(socket); | |
2527 | + drop(listener); | |
2528 | +} | |
2529 | + | |
2530 | +#[test] | |
2531 | +fn from_std_unix_listener() { | |
2532 | + let path = temp_file("from_std_unix_listener"); | |
2533 | + let listener = UnixListener::bind(&path).unwrap(); | |
2534 | + let socket: Socket = listener.into(); | |
2535 | + drop(socket); | |
2536 | +} | |
2537 | + | |
2538 | +#[test] | |
2539 | +fn from_std_unix_socket() { | |
2540 | + let path = temp_file("from_std_unix_socket"); | |
2541 | + let datagram = UnixDatagram::bind(&path).unwrap(); | |
2542 | + let socket: Socket = datagram.into(); | |
2543 | + drop(socket); | |
2544 | +} | |
2545 | + | |
2546 | +#[test] | |
2547 | +fn into_std_unix_stream() { | |
2548 | + let socket: Socket = Socket::new(Domain::unix(), Type::stream(), None).unwrap(); | |
2549 | + let unix_socket: UnixStream = socket.into(); | |
2550 | + drop(unix_socket); | |
2551 | +} | |
2552 | + | |
2553 | +#[test] | |
2554 | +fn into_std_tcp_listener() { | |
2555 | + let socket: Socket = Socket::new(Domain::unix(), Type::stream(), None).unwrap(); | |
2556 | + let unix_socket: UnixListener = socket.into(); | |
2557 | + drop(unix_socket); | |
2558 | +} | |
2559 | + | |
2560 | +#[test] | |
2561 | +fn into_std_udp_socket() { | |
2562 | + let socket: Socket = Socket::new(Domain::unix(), Type::dgram(), None).unwrap(); | |
2563 | + let unix_socket: UnixDatagram = socket.into(); | |
2564 | + drop(unix_socket); | |
2565 | +} | |
2566 | + | |
2567 | +// TODO: test accept4. | |
2568 | +// TODO: test pair. | |
2569 | diff --git a/tests/util/mod.rs b/tests/util/mod.rs | |
2570 | new file mode 100644 | |
2571 | index 0000000..1744e40 | |
2572 | --- /dev/null | |
2573 | +++ b/tests/util/mod.rs | |
2574 | @@ -0,0 +1,49 @@ | |
2575 | +// Not all tests use all functions. | |
2576 | +#![allow(dead_code)] | |
2577 | + | |
2578 | +use std::net::SocketAddr; | |
2579 | +use std::path::PathBuf; | |
2580 | +use std::sync::Once; | |
2581 | +use std::{env, fs}; | |
2582 | + | |
2583 | +/// Bind to any port on localhost. | |
2584 | +pub fn any_local_ipv4_addr() -> SocketAddr { | |
2585 | + "127.0.0.1:0".parse().unwrap() | |
2586 | +} | |
2587 | + | |
2588 | +/* TODO: needed? | |
2589 | +/// Bind to any port on localhost, using a IPv6 address. | |
2590 | +pub fn any_local_ipv6_addr() -> SocketAddr { | |
2591 | + "[::1]:0".parse().unwrap() | |
2592 | +} | |
2593 | +*/ | |
2594 | + | |
2595 | +/// Returns a path to a temporary file using `name` as filename. | |
2596 | +pub fn temp_file(name: &'static str) -> PathBuf { | |
2597 | + init(); | |
2598 | + let mut path = temp_dir(); | |
2599 | + path.push(name); | |
2600 | + path | |
2601 | +} | |
2602 | + | |
2603 | +pub fn init() { | |
2604 | + static INIT: Once = Once::new(); | |
2605 | + | |
2606 | + INIT.call_once(|| { | |
2607 | + // Remove all temporary files from previous test runs. | |
2608 | + let dir = temp_dir(); | |
2609 | + let _ = fs::remove_dir_all(&dir); | |
2610 | + fs::create_dir_all(&dir).expect("unable to create temporary directory"); | |
2611 | + }) | |
2612 | +} | |
2613 | + | |
2614 | +/// Returns the temporary directory for test files. | |
2615 | +/// | |
2616 | +/// # Notes | |
2617 | +/// | |
2618 | +/// `init` must be called before this. | |
2619 | +fn temp_dir() -> PathBuf { | |
2620 | + let mut path = env::temp_dir(); | |
2621 | + path.push("socket_tests"); | |
2622 | + path | |
2623 | +} |