1
1
#[ cfg( feature = "metrics" ) ]
2
2
use super :: metrics;
3
3
use super :: settings:: TelemetrySettings ;
4
+ use crate :: addr:: ListenAddr ;
4
5
use crate :: telemetry:: log;
5
6
use crate :: BootstrapResult ;
6
7
use anyhow:: Context as _;
@@ -14,18 +15,127 @@ use std::net::SocketAddr;
14
15
use std:: pin:: Pin ;
15
16
use std:: sync:: Arc ;
16
17
use std:: task:: { Context , Poll } ;
18
+ use tokio:: io:: { AsyncRead , AsyncWrite } ;
17
19
use tokio:: net:: TcpListener ;
20
+ #[ cfg( unix) ]
21
+ use tokio:: net:: { TcpStream , UnixListener , UnixStream } ;
18
22
use tokio:: sync:: watch;
19
23
20
24
mod router;
21
25
22
26
use router:: Router ;
27
+
28
+ enum TelemetryStream {
29
+ Tcp ( TcpStream ) ,
30
+ #[ cfg( unix) ]
31
+ Unix ( UnixStream ) ,
32
+ }
33
+
34
+ impl AsyncRead for TelemetryStream {
35
+ fn poll_read (
36
+ self : Pin < & mut Self > ,
37
+ cx : & mut Context < ' _ > ,
38
+ buf : & mut tokio:: io:: ReadBuf < ' _ > ,
39
+ ) -> Poll < std:: io:: Result < ( ) > > {
40
+ match self . get_mut ( ) {
41
+ TelemetryStream :: Tcp ( stream) => Pin :: new ( stream) . poll_read ( cx, buf) ,
42
+ #[ cfg( unix) ]
43
+ TelemetryStream :: Unix ( stream) => Pin :: new ( stream) . poll_read ( cx, buf) ,
44
+ }
45
+ }
46
+ }
47
+
48
+ impl AsyncWrite for TelemetryStream {
49
+ fn poll_write (
50
+ self : Pin < & mut Self > ,
51
+ cx : & mut Context < ' _ > ,
52
+ buf : & [ u8 ] ,
53
+ ) -> Poll < Result < usize , std:: io:: Error > > {
54
+ match self . get_mut ( ) {
55
+ TelemetryStream :: Tcp ( stream) => Pin :: new ( stream) . poll_write ( cx, buf) ,
56
+ #[ cfg( unix) ]
57
+ TelemetryStream :: Unix ( stream) => Pin :: new ( stream) . poll_write ( cx, buf) ,
58
+ }
59
+ }
60
+
61
+ fn poll_flush ( self : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < Result < ( ) , std:: io:: Error > > {
62
+ match self . get_mut ( ) {
63
+ TelemetryStream :: Tcp ( stream) => Pin :: new ( stream) . poll_flush ( cx) ,
64
+ #[ cfg( unix) ]
65
+ TelemetryStream :: Unix ( stream) => Pin :: new ( stream) . poll_flush ( cx) ,
66
+ }
67
+ }
68
+
69
+ fn poll_shutdown (
70
+ self : Pin < & mut Self > ,
71
+ cx : & mut Context < ' _ > ,
72
+ ) -> Poll < Result < ( ) , std:: io:: Error > > {
73
+ match self . get_mut ( ) {
74
+ TelemetryStream :: Tcp ( stream) => Pin :: new ( stream) . poll_shutdown ( cx) ,
75
+ #[ cfg( unix) ]
76
+ TelemetryStream :: Unix ( stream) => Pin :: new ( stream) . poll_shutdown ( cx) ,
77
+ }
78
+ }
79
+ }
80
+
81
+ enum TelemetryListener {
82
+ Tcp ( TcpListener ) ,
83
+ #[ cfg( unix) ]
84
+ Unix ( UnixListener ) ,
85
+ }
86
+
87
+ impl TelemetryListener {
88
+ pub ( crate ) fn local_addr ( & self ) -> BootstrapResult < ListenAddr > {
89
+ match self {
90
+ TelemetryListener :: Tcp ( listener) => Ok ( listener. local_addr ( ) ?. into ( ) ) ,
91
+ #[ cfg( unix) ]
92
+ TelemetryListener :: Unix ( listener) => match listener. local_addr ( ) ?. as_pathname ( ) {
93
+ Some ( path) => Ok ( path. to_path_buf ( ) . into ( ) ) ,
94
+ None => Err ( anyhow:: anyhow!( "unix socket listener has no pathname" ) ) ,
95
+ } ,
96
+ }
97
+ }
98
+
99
+ pub ( crate ) async fn accept ( & self ) -> std:: io:: Result < TelemetryStream > {
100
+ match self {
101
+ TelemetryListener :: Tcp ( listener) => listener
102
+ . accept ( )
103
+ . await
104
+ . map ( |( conn, _) | TelemetryStream :: Tcp ( conn) ) ,
105
+ #[ cfg( unix) ]
106
+ TelemetryListener :: Unix ( listener) => listener
107
+ . accept ( )
108
+ . await
109
+ . map ( |( conn, _) | TelemetryStream :: Unix ( conn) ) ,
110
+ }
111
+ }
112
+
113
+ pub ( crate ) fn poll_accept (
114
+ & mut self ,
115
+ cx : & mut std:: task:: Context < ' _ > ,
116
+ ) -> std:: task:: Poll < std:: io:: Result < TelemetryStream > > {
117
+ match self {
118
+ TelemetryListener :: Tcp ( listener) => match std:: task:: ready!( listener. poll_accept( cx) ) {
119
+ Ok ( ( conn, _) ) => std:: task:: Poll :: Ready ( Ok ( TelemetryStream :: Tcp ( conn) ) ) ,
120
+ Err ( e) => std:: task:: Poll :: Ready ( Err ( e) ) ,
121
+ } ,
122
+ #[ cfg( unix) ]
123
+ TelemetryListener :: Unix ( listener) => {
124
+ match std:: task:: ready!( listener. poll_accept( cx) ) {
125
+ Ok ( ( conn, _) ) => std:: task:: Poll :: Ready ( Ok ( TelemetryStream :: Unix ( conn) ) ) ,
126
+ Err ( e) => std:: task:: Poll :: Ready ( Err ( e) ) ,
127
+ }
128
+ }
129
+ }
130
+ }
131
+ }
132
+
23
133
pub use router:: {
24
134
BoxError , TelemetryRouteHandler , TelemetryRouteHandlerFuture , TelemetryServerRoute ,
25
135
} ;
26
136
27
137
pub ( super ) struct TelemetryServerFuture {
28
- listener : TcpListener ,
138
+ listener : TelemetryListener ,
29
139
router : Router ,
30
140
}
31
141
@@ -47,27 +157,38 @@ impl TelemetryServerFuture {
47
157
. map_err ( |err| anyhow:: anyhow!( err) ) ?;
48
158
}
49
159
50
- let addr = settings. server . addr ;
51
-
52
- #[ cfg( feature = "settings" ) ]
53
- let addr = SocketAddr :: from ( addr) ;
54
-
55
- let router = Router :: new ( custom_routes, settings) ;
56
-
57
- let listener = {
58
- let std_listener = std:: net:: TcpListener :: from (
59
- bind_socket ( addr) . with_context ( || format ! ( "binding to socket {addr:?}" ) ) ?,
60
- ) ;
61
-
62
- std_listener. set_nonblocking ( true ) ?;
160
+ let router = Router :: new ( custom_routes, Arc :: clone ( & settings) ) ;
161
+
162
+ let listener = match & settings. server . addr {
163
+ ListenAddr :: Tcp ( addr) => {
164
+ let std_listener = std:: net:: TcpListener :: from (
165
+ bind_socket ( * addr)
166
+ . with_context ( || format ! ( "binding to TCP socket {addr:?}" ) ) ?,
167
+ ) ;
168
+ std_listener. set_nonblocking ( true ) ?;
169
+ let tokio_listener = tokio:: net:: TcpListener :: from_std ( std_listener) ?;
170
+ TelemetryListener :: Tcp ( tokio_listener)
171
+ }
172
+ #[ cfg( unix) ]
173
+ ListenAddr :: Unix ( path) => {
174
+ // Remove existing socket file if it exists to avoid bind errors
175
+ if path. exists ( ) {
176
+ if let Err ( e) = std:: fs:: remove_file ( path) {
177
+ log:: warn!( "failed to remove existing Unix socket file" ; "path" => %path. display( ) , "error" => e) ;
178
+ }
179
+ }
63
180
64
- tokio:: net:: TcpListener :: from_std ( std_listener) ?
181
+ let unix_listener = UnixListener :: bind ( path)
182
+ . with_context ( || format ! ( "binding to Unix socket {path:?}" ) ) ?;
183
+ TelemetryListener :: Unix ( unix_listener)
184
+ }
65
185
} ;
66
186
67
187
Ok ( Some ( TelemetryServerFuture { listener, router } ) )
68
188
}
69
- pub ( super ) fn local_addr ( & self ) -> SocketAddr {
70
- self . listener . local_addr ( ) . unwrap ( )
189
+
190
+ pub ( super ) fn local_addr ( & self ) -> BootstrapResult < ListenAddr > {
191
+ self . listener . local_addr ( )
71
192
}
72
193
73
194
// Adapted from Hyper 0.14 Server stuff and axum::serve::serve.
@@ -87,15 +208,12 @@ impl TelemetryServerFuture {
87
208
let ( close_tx, close_rx) = watch:: channel ( ( ) ) ;
88
209
let listener = self . listener ;
89
210
90
- pin_mut ! ( listener) ;
91
-
92
211
loop {
93
212
let socket = tokio:: select! {
94
213
conn = listener. accept( ) => match conn {
95
- Ok ( ( conn, _ ) ) => TokioIo :: new( conn) ,
214
+ Ok ( conn) => TokioIo :: new( conn) ,
96
215
Err ( e) => {
97
216
log:: warn!( "failed to accept connection" ; "error" => e) ;
98
-
99
217
continue ;
100
218
}
101
219
} ,
@@ -140,11 +258,10 @@ impl Future for TelemetryServerFuture {
140
258
let this = & mut * self ;
141
259
142
260
loop {
143
- let socket = match ready ! ( Pin :: new ( & mut this. listener) . poll_accept( cx) ) {
144
- Ok ( ( conn, _ ) ) => TokioIo :: new ( conn) ,
261
+ let socket = match ready ! ( this. listener. poll_accept( cx) ) {
262
+ Ok ( conn) => TokioIo :: new ( conn) ,
145
263
Err ( e) => {
146
264
log:: warn!( "failed to accept connection" ; "error" => e) ;
147
-
148
265
continue ;
149
266
}
150
267
} ;
0 commit comments