@@ -143,23 +143,37 @@ impl ApiServer {
143143 conf : Option < TLSConfig > ,
144144 api_chan : ( mpsc:: Sender < ( ) > , mpsc:: Receiver < ( ) > ) ,
145145 ) -> Result < thread:: JoinHandle < ( ) > , Error > {
146- let _ = rustls:: crypto:: ring:: default_provider ( ) . install_default ( ) ;
147-
148146 if self . shutdown_sender . is_some ( ) {
149147 return Err ( Error :: Internal (
150148 "Can't start API server, it's running already" . to_string ( ) ,
151149 ) ) ;
152150 }
153- self . shutdown_sender = Some ( api_chan. 0 ) ;
151+
152+ let _ = rustls:: crypto:: ring:: default_provider ( ) . install_default ( ) ;
153+
154+ // Check if provided address is free.
155+ let listener = match std:: net:: TcpListener :: bind ( addr) {
156+ Ok ( l) => {
157+ l. set_nonblocking ( true )
158+ . map_err ( |e| Error :: Internal ( format ! ( "API listener binding error: {}" , e) ) ) ?;
159+ l
160+ }
161+ Err ( e) => {
162+ error ! ( "API listener binding error: {}" , e) ;
163+ return Err ( Error :: Internal ( e. to_string ( ) ) ) ;
164+ }
165+ } ;
154166
155167 let tls = match conf {
156168 Some ( conf) => Some ( TlsAcceptor :: from ( conf. build_server_config ( ) ?) ) ,
157169 None => None ,
158170 } ;
159- thread:: Builder :: new ( )
171+ let res = thread:: Builder :: new ( )
160172 . name ( "apis" . to_string ( ) )
161- . spawn ( move || start_server ( addr, router, api_chan. 1 , tls) )
162- . map_err ( |_| Error :: Internal ( "failed to spawn API thread" . to_string ( ) ) )
173+ . spawn ( move || start_server ( listener, router, api_chan. 1 , tls) )
174+ . map_err ( |_| Error :: Internal ( "failed to spawn API thread" . to_string ( ) ) ) ?;
175+ self . shutdown_sender = Some ( api_chan. 0 ) ;
176+ Ok ( res)
163177 }
164178
165179 /// Stops the API server.
@@ -184,7 +198,7 @@ impl ApiServer {
184198
185199/// Start API server with optional TLS support.
186200fn start_server (
187- addr : SocketAddr ,
201+ l : std :: net :: TcpListener ,
188202 router : Router ,
189203 rx : mpsc:: Receiver < ( ) > ,
190204 tls : Option < TlsAcceptor > ,
@@ -194,77 +208,77 @@ fn start_server(
194208 // When this signal completes, start shutdown.
195209 let mut signal = std:: pin:: pin!( shutdown_signal( rx) ) ;
196210
197- // Start server loop.
198- match TcpListener :: bind ( addr) . await {
199- Ok ( l) => {
200- loop {
201- tokio:: select! {
202- Ok ( s) = async {
203- match l. accept( ) . await {
204- Ok ( ( s, _) ) => Ok :: <Option <tokio:: net:: TcpStream >, Error >( Some ( s) ) ,
205- Err ( e) => {
206- error!( "Failed to accept connection: {e:#}" ) ;
207- Ok ( None )
208- }
209- }
210- } => {
211- if let Some ( s) = s {
212- if let Some ( tls) = tls. clone( ) {
213- let router = router. clone( ) ;
214- let watcher = graceful. watcher( ) ;
215- tokio:: spawn( async move {
216- let handshake = timeout( TLS_HANDSHAKE_TIMEOUT , tls. accept( s) ) ;
217- let tls_stream = match handshake. await {
218- Ok ( Ok ( tls_stream) ) => tls_stream,
219- Ok ( Err ( err) ) => {
220- error!( "failed to perform TLS handshake: {err:#}" ) ;
221- return ;
222- }
223- Err ( _) => {
224- error!( "TLS handshake timed out" ) ;
225- return ;
226- }
227- } ;
228- let io = TokioIo :: new( tls_stream) ;
229- let conn = http1:: Builder :: new( ) . serve_connection( io, router) ;
230- if let Err ( e) = watcher. watch( conn) . await {
231- error!( "API TLS server error: {:?}" , e) ;
232- }
233- } ) ;
234- } else {
235- let io = TokioIo :: new( s) ;
236- let conn = http1:: Builder :: new( ) . serve_connection( io, router. clone( ) ) ;
237- let fut = graceful. watch( conn) ;
238- tokio:: spawn( async move {
239- if let Err ( e) = fut. await {
240- error!( "API HTTP server error: {:?}" , e) ;
241- }
242- } ) ;
243- } ;
244- } else {
245- continue ;
246- }
247- }
248- _ = & mut signal => {
249- drop( l) ;
250- break ;
211+ let l = match TcpListener :: from_std ( l) {
212+ Ok ( l) => l,
213+ Err ( e) => {
214+ error ! ( "HTTP API server error: {}" , e) ;
215+ return ;
216+ }
217+ } ;
218+
219+ loop {
220+ tokio:: select! {
221+ Ok ( s) = async {
222+ match l. accept( ) . await {
223+ Ok ( ( s, _) ) => Ok :: <Option <tokio:: net:: TcpStream >, Error >( Some ( s) ) ,
224+ Err ( e) => {
225+ error!( "Failed to accept connection: {e:#}" ) ;
226+ Ok ( None )
251227 }
252228 }
253- }
254-
255- // Now start the shutdown and wait for them to complete
256- // Also start a timeout to limit how long to wait.
257- tokio:: select! {
258- _ = graceful. shutdown( ) => {
259- warn!( "API server gracefully stopped" ) ;
260- } ,
261- _ = sleep( GRACEFUL_SHUTDOWN_TIMEOUT ) => {
262- warn!( "API server timed out wait for all connections to close" ) ;
229+ } => {
230+ if let Some ( s) = s {
231+ if let Some ( tls) = tls. clone( ) {
232+ let router = router. clone( ) ;
233+ let watcher = graceful. watcher( ) ;
234+ tokio:: spawn( async move {
235+ let handshake = timeout( TLS_HANDSHAKE_TIMEOUT , tls. accept( s) ) ;
236+ let tls_stream = match handshake. await {
237+ Ok ( Ok ( tls_stream) ) => tls_stream,
238+ Ok ( Err ( err) ) => {
239+ error!( "failed to perform TLS handshake: {err:#}" ) ;
240+ return ;
241+ }
242+ Err ( _) => {
243+ error!( "TLS handshake timed out" ) ;
244+ return ;
245+ }
246+ } ;
247+ let io = TokioIo :: new( tls_stream) ;
248+ let conn = http1:: Builder :: new( ) . serve_connection( io, router) ;
249+ if let Err ( e) = watcher. watch( conn) . await {
250+ error!( "API TLS server error: {:?}" , e) ;
251+ }
252+ } ) ;
253+ } else {
254+ let io = TokioIo :: new( s) ;
255+ let conn = http1:: Builder :: new( ) . serve_connection( io, router. clone( ) ) ;
256+ let fut = graceful. watch( conn) ;
257+ tokio:: spawn( async move {
258+ if let Err ( e) = fut. await {
259+ error!( "API HTTP server error: {:?}" , e) ;
260+ }
261+ } ) ;
262+ } ;
263+ } else {
264+ continue ;
263265 }
264266 }
267+ _ = & mut signal => {
268+ drop( l) ;
269+ break ;
270+ }
265271 }
266- Err ( e) => {
267- error ! ( "API listener binding error: {}" , e) ;
272+ }
273+
274+ // Now start the shutdown and wait for them to complete
275+ // Also start a timeout to limit how long to wait.
276+ tokio:: select! {
277+ _ = graceful. shutdown( ) => {
278+ warn!( "API server gracefully stopped" ) ;
279+ } ,
280+ _ = sleep( GRACEFUL_SHUTDOWN_TIMEOUT ) => {
281+ warn!( "API server timed out wait for all connections to close" ) ;
268282 }
269283 }
270284 } ;
0 commit comments