1use std::{fmt, io, net, sync::Arc};
2
3use ntex_io::Io;
4use ntex_rt::System;
5use ntex_service::{IntoService, Service, cfg::SharedCfg};
6use ntex_util::time::Millis;
7use socket2::{Domain, SockAddr, Socket, Type};
8
9use crate::{Affinity, LoadBalancing, NoConfig, Server, ServerAppConfig, WorkerPool};
10
11use super::accept::AcceptLoop;
12use super::config::ServiceConfig;
13use super::factory::{self, FactoryServiceType};
14use super::{Connection, StreamServer, Token, socket::Listener};
15
16pub struct ServerBuilder<Cfg = NoConfig> {
21 name: String,
22 token: Token,
23 backlog: i32,
24 state: Arc<Cfg>,
25 services: Vec<FactoryServiceType<Cfg>>,
26 sockets: Vec<(Token, String, Listener)>,
27 accept: AcceptLoop,
28 acceptors: usize,
29 max_conns: usize,
30 pool: WorkerPool,
31}
32
33impl Default for ServerBuilder {
34 fn default() -> Self {
35 Self::new(NoConfig)
36 }
37}
38
39impl<Cfg> ServerBuilder<Cfg>
40where
41 Cfg: ServerAppConfig,
42{
43 #[must_use]
44 pub fn new(cfg: Cfg) -> ServerBuilder<Cfg> {
46 let sys = System::current();
47 let mut accept = AcceptLoop::default();
48 accept.name(sys.name());
49 if sys.testing() {
50 accept.testing();
51 }
52
53 ServerBuilder {
54 accept,
55 acceptors: 1,
56 max_conns: super::DEFAULT_MAX_CONNS,
57 name: sys.name().to_string(),
58 token: Token(0),
59 state: Arc::new(cfg),
60 services: Vec::new(),
61 sockets: Vec::new(),
62 backlog: 2048,
63 pool: WorkerPool::default().name(sys.name()),
64 }
65 }
66
67 #[must_use]
68 pub fn name<T: AsRef<str>>(mut self, name: T) -> Self {
73 self.name = name.as_ref().to_string();
74 self.accept.name(self.name.as_str());
75 self.pool = self.pool.name(self.name.as_str());
76 self
77 }
78
79 #[must_use]
80 pub fn workers(mut self, num: usize) -> Self {
88 self.pool = self.pool.workers(num);
89 self
90 }
91
92 #[must_use]
93 pub fn backlog(mut self, num: i32) -> Self {
106 self.backlog = num;
107 self.accept.backlog(num);
108 self
109 }
110
111 #[must_use]
112 pub fn acceptors(mut self, num: usize) -> Self {
127 self.acceptors = num;
128 self
129 }
130
131 #[must_use]
132 pub fn max_connections(mut self, num: usize) -> Self {
143 self.max_conns = num;
144 self
145 }
146
147 #[must_use]
148 pub fn stop_runtime(mut self) -> Self {
152 self.pool = self.pool.stop_runtime();
153 self
154 }
155
156 #[must_use]
157 pub fn stop_on_panic(mut self) -> Self {
165 self.pool = self.pool.stop_on_panic();
166 self
167 }
168
169 #[must_use]
170 pub fn disable_signals(mut self) -> Self {
174 self.pool = self.pool.disable_signals();
175 self
176 }
177
178 #[must_use]
179 pub fn affinity(mut self, affinity: Affinity) -> Self {
183 self.pool = self.pool.affinity(affinity);
184 self
185 }
186
187 #[must_use]
188 pub fn load_balancing(mut self, balancing: LoadBalancing) -> Self {
192 self.pool = self.pool.load_balancing(balancing);
193 self
194 }
195
196 #[must_use]
197 pub fn graceful_shutdown(mut self) -> Self {
207 self.pool = self.pool.graceful_shutdown();
208 self
209 }
210
211 #[must_use]
212 pub fn graceful_shutdown_timeout<T: Into<Millis>>(mut self, timeout: T) -> Self {
225 self.pool = self.pool.graceful_shutdown_timeout(timeout);
226 self
227 }
228
229 pub async fn configure<F>(mut self, f: F) -> io::Result<Self>
237 where
238 F: AsyncFnOnce(ServiceConfig<Cfg>) -> io::Result<()>,
239 {
240 let cfg = ServiceConfig::new(self.token, self.backlog);
241
242 f(cfg.clone()).await?;
243
244 let (token, sockets, factory) = cfg.into_factory();
245 self.token = token;
246 self.sockets.extend(sockets);
247 self.services.push(factory);
248
249 Ok(self)
250 }
251
252 #[allow(clippy::needless_pass_by_value)]
253 pub fn bind<F, S, I>(
263 mut self,
264 name: impl AsRef<str>,
265 addr: impl net::ToSocketAddrs,
266 cfg: impl Into<SharedCfg>,
267 factory: F,
268 ) -> io::Result<Self>
269 where
270 F: AsyncFn(&Cfg::State) -> I + Send + Clone + 'static,
271 S: Service<Cfg::State, Io> + 'static,
272 I: IntoService<S, Cfg::State, Io> + 'static,
273 {
274 let cfg = cfg.into();
275 let sockets = bind_addr(addr, self.backlog)?;
276
277 let mut tokens = Vec::new();
278 for lst in sockets {
279 let token = self.token.next();
280 self.sockets
281 .push((token, name.as_ref().to_string(), Listener::from_tcp(lst)));
282 tokens.push((token, cfg.clone()));
283 }
284
285 self.services.push(factory::create_factory_service(
286 name.as_ref().to_string(),
287 tokens,
288 factory,
289 ));
290
291 Ok(self)
292 }
293
294 #[cfg(unix)]
295 pub fn bind_uds<F, I, S>(
301 self,
302 name: impl AsRef<str>,
303 addr: impl AsRef<std::path::Path>,
304 cfg: impl Into<SharedCfg>,
305 factory: F,
306 ) -> io::Result<Self>
307 where
308 F: AsyncFn(&Cfg::State) -> I + Send + Clone + 'static,
309 I: IntoService<S, Cfg::State, Io> + 'static,
310 S: Service<Cfg::State, Io> + 'static,
311 {
312 use std::os::unix::net::UnixListener;
313
314 if let Err(e) = std::fs::remove_file(addr.as_ref()) {
317 if e.kind() != std::io::ErrorKind::NotFound {
319 return Err(e);
320 }
321 }
322
323 let lst = UnixListener::bind(addr)?;
324 self.listen_uds(name, lst, cfg.into(), factory)
325 }
326
327 #[cfg(unix)]
328 pub fn listen_uds<F, I, S>(
334 mut self,
335 name: impl AsRef<str>,
336 lst: std::os::unix::net::UnixListener,
337 cfg: impl Into<SharedCfg>,
338 factory: F,
339 ) -> io::Result<Self>
340 where
341 F: AsyncFn(&Cfg::State) -> I + Send + Clone + 'static,
342 I: IntoService<S, Cfg::State, Io> + 'static,
343 S: Service<Cfg::State, Io> + 'static,
344 {
345 let token = self.token.next();
346 self.services.push(factory::create_factory_service(
347 name.as_ref().to_string(),
348 vec![(token, cfg.into())],
349 factory,
350 ));
351 self.sockets
352 .push((token, name.as_ref().to_string(), Listener::from_uds(lst)));
353 Ok(self)
354 }
355
356 pub fn listen<F, S, I>(
361 mut self,
362 name: impl AsRef<str>,
363 lst: net::TcpListener,
364 cfg: impl Into<SharedCfg>,
365 factory: F,
366 ) -> io::Result<Self>
367 where
368 F: AsyncFn(&Cfg::State) -> I + Send + Clone + 'static,
369 S: Service<Cfg::State, Io> + 'static,
370 I: IntoService<S, Cfg::State, Io> + 'static,
371 {
372 let token = self.token.next();
373 self.services.push(factory::create_factory_service(
374 name.as_ref().to_string(),
375 vec![(token, cfg.into())],
376 factory,
377 ));
378 self.sockets
379 .push((token, name.as_ref().to_string(), Listener::from_tcp(lst)));
380 Ok(self)
381 }
382
383 pub fn run(mut self) -> Server<Connection> {
389 assert!(
390 !self.sockets.is_empty(),
391 "Server should have at least one bound socket"
392 );
393 self.accept.acceptors(self.acceptors);
394 let srv = StreamServer::new(
395 self.accept.notify(),
396 self.state,
397 self.services,
398 self.max_conns,
399 );
400 let svc = self.pool.run(srv);
401
402 svc.metrics_ref().listeners(
403 self.sockets
404 .iter()
405 .map(|sock| (sock.1.clone(), sock.2.local_addr().to_string())),
406 );
407 let sockets = self
408 .sockets
409 .into_iter()
410 .map(|sock| {
411 log::info!("Starting \"{}\" service on {}", sock.1, sock.2);
412 (sock.0, sock.2)
413 })
414 .collect();
415 self.accept.start(sockets, svc.clone());
416
417 svc
418 }
419}
420
421impl<Cfg> fmt::Debug for ServerBuilder<Cfg> {
422 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
423 f.debug_struct("ServerBuilder")
424 .field("name", &self.name)
425 .field("token", &self.token)
426 .field("backlog", &self.backlog)
427 .field("sockets", &self.sockets)
428 .field("accept", &self.accept)
429 .field("acceptors", &self.acceptors)
430 .field("max_conns", &self.max_conns)
431 .field("worker-pool", &self.pool)
432 .finish()
433 }
434}
435
436pub fn bind_addr<S: net::ToSocketAddrs>(
441 addr: S,
442 backlog: i32,
443) -> io::Result<Vec<net::TcpListener>> {
444 let mut err = None;
445 let mut succ = false;
446 let mut sockets = Vec::new();
447 for addr in addr.to_socket_addrs()? {
448 match create_tcp_listener(addr, backlog) {
449 Ok(lst) => {
450 succ = true;
451 sockets.push(lst);
452 }
453 Err(e) => err = Some(e),
454 }
455 }
456
457 if succ {
458 Ok(sockets)
459 } else if let Some(e) = err.take() {
460 Err(e)
461 } else {
462 Err(io::Error::new(
463 io::ErrorKind::InvalidInput,
464 "Cannot bind to address.",
465 ))
466 }
467}
468
469pub fn create_tcp_listener(addr: net::SocketAddr, backlog: i32) -> io::Result<net::TcpListener> {
471 let builder = match addr {
472 net::SocketAddr::V4(_) => Socket::new(Domain::IPV4, Type::STREAM, None)?,
473 net::SocketAddr::V6(_) => Socket::new(Domain::IPV6, Type::STREAM, None)?,
474 };
475
476 #[cfg(not(windows))]
480 builder.set_reuse_address(true)?;
481
482 builder.bind(&SockAddr::from(addr))?;
483 builder.listen(backlog)?;
484 Ok(net::TcpListener::from(builder))
485}
486
487#[cfg(test)]
488mod tests {
489 use super::*;
490
491 #[test]
492 fn test_bind_addr() {
493 let addrs: Vec<net::SocketAddr> = Vec::new();
494 assert!(bind_addr(&addrs[..], 10).is_err());
495 }
496
497 #[ntex::test]
498 async fn test_debug() {
499 let builder = ServerBuilder::default();
500 assert!(format!("{builder:?}").contains("ServerBuilder"));
501 }
502
503 #[ntex::test]
513 async fn test_paused_wakeup_does_not_accept() {
514 use crate::ServerStatus;
515 use crate::net::AcceptorCommand;
516 use ntex_service::{cfg::SharedCfg, fn_service};
517
518 let lst = net::TcpListener::bind("127.0.0.1:0").unwrap();
519 let addr = lst.local_addr().unwrap();
520 let builder = ServerBuilder::default()
521 .workers(1)
522 .acceptors(1)
523 .disable_signals()
524 .listen("test", lst, SharedCfg::default(), async |&()| {
525 fn_service(async |_: ntex_io::Io| Ok::<_, ()>(()))
526 })
527 .unwrap();
528 let notify = builder.accept.notify();
529 let srv = builder.run();
530 ntex_util::time::timeout(Millis(3000), async {
531 while srv.status() != ServerStatus::Ready {
532 srv.status_changed().await;
533 }
534 })
535 .await
536 .unwrap();
537
538 srv.pause().await;
539 ntex_util::time::sleep(Millis(100)).await;
540 notify.send(AcceptorCommand::Timer);
541 ntex_util::time::sleep(Millis(100)).await;
542
543 let _conn = net::TcpStream::connect(addr).unwrap();
544 ntex_util::time::sleep(Millis(200)).await;
545 assert_eq!(srv.metrics().listeners[0].accepted, 0);
546
547 srv.resume().await;
548 ntex_util::time::timeout(Millis(3000), async {
549 while srv.metrics().listeners[0].accepted == 0 {
550 ntex_util::time::sleep(Millis(10)).await;
551 }
552 })
553 .await
554 .unwrap();
555 srv.stop(false).await;
556 }
557}