1
1
//! Utilities for use TCP servers & clients.
2
2
//!
3
- //! Uses unsafe code to interact with socket options for keepalive and SO_ORIGINAL_DST.
3
+ //! Uses unsafe code to interact with socket options for SO_ORIGINAL_DST.
4
4
5
5
#![ deny( warnings, rust_2018_idioms) ]
6
- //#![forbid(unsafe_code)]
6
+ // #![forbid(unsafe_code)]
7
7
8
8
pub mod addrs;
9
9
mod connect;
@@ -17,6 +17,7 @@ pub use self::{
17
17
listen:: { Bind , BindTcp } ,
18
18
orig_dst:: BindWithOrigDst ,
19
19
} ;
20
+ use linkerd_io as io;
20
21
use socket2:: TcpKeepalive ;
21
22
use std:: time:: Duration ;
22
23
use tokio:: net:: TcpStream ;
@@ -38,47 +39,20 @@ fn set_nodelay_or_warn(socket: &TcpStream) {
38
39
}
39
40
}
40
41
41
- fn set_keepalive_or_warn ( tcp : & TcpStream , keepalive_duration : Option < Duration > ) {
42
- // TODO(eliza): when https://github.com/tokio-rs/tokio/pull/3189 merges
43
- // upstream, we will be able to convert the Tokio `TcpStream` into a
44
- // `socket2::Socket` without unsafe, by converting it to a
45
- // `std::net::TcpStream` (as `socket2::Socket` has a
46
- // `From<std::net::TcpStream>`). What we're doing now is more or less
47
- // equivalent, but this would use a safe interface...
48
- #[ cfg( unix) ]
49
- let sock = unsafe {
50
- // Safety: `from_raw_fd` takes ownership of the underlying file
51
- // descriptor, and will close it when dropped. However, we obtain the
52
- // file descriptor via `as_raw_fd` rather than `into_raw_fd`, so the
53
- // Tokio `TcpStream` *also* retains ownership of the socket --- which is
54
- // what we want. Instead of letting the `socket2` socket returned by
55
- // `from_raw_fd` close the fd, we `mem::forget` the `Socket`, so that
56
- // its `Drop` impl will not run. This ensures the fd is not closed
57
- // prematurely.
58
- use std:: os:: unix:: io:: { AsRawFd , FromRawFd } ;
59
- socket2:: Socket :: from_raw_fd ( tcp. as_raw_fd ( ) )
42
+ fn set_keepalive_or_warn (
43
+ tcp : TcpStream ,
44
+ keepalive_duration : Option < Duration > ,
45
+ ) -> io:: Result < TcpStream > {
46
+ let sock = {
47
+ let stream = tokio:: net:: TcpStream :: into_std ( tcp) ?;
48
+ socket2:: Socket :: from ( stream)
60
49
} ;
61
- #[ cfg( windows) ]
62
- let sock = unsafe {
63
- // Safety: `from_raw_socket` takes ownership of the underlying Windows
64
- // SOCKET, and will close it when dropped. However, we obtain the
65
- // SOCKET via `as_raw_socket` rather than `into_raw_socket`, so the
66
- // Tokio `TcpStream` *also* retains ownership of the socket --- which is
67
- // what we want. Instead of letting the `socket2` socket returned by
68
- // `from_raw_socket` close the SOCKET, we `mem::forget` the `Socket`, so
69
- // that its `Drop` impl will not run. This ensures the socket is not
70
- // closed prematurely.
71
- use std:: os:: windows:: io:: { AsRawSocket , FromRawSocket } ;
72
- socket2:: Socket :: from_raw_socket ( tcp. as_raw_socket ( ) )
73
- } ;
74
-
75
50
let ka = keepalive_duration
76
51
. into_iter ( )
77
52
. fold ( TcpKeepalive :: new ( ) , |k, t| k. with_time ( t) ) ;
78
53
if let Err ( e) = sock. set_tcp_keepalive ( & ka) {
79
54
tracing:: warn!( "failed to set keepalive: {}" , e) ;
80
55
}
81
-
82
- // Don't let the socket2 socket close the fd on drop!
83
- std:: mem:: forget ( sock) ;
56
+ let stream: std:: net:: TcpStream = socket2:: Socket :: into ( sock) ;
57
+ tokio:: net:: TcpStream :: from_std ( stream)
84
58
}
0 commit comments