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 {
205 self.pool = self.pool.graceful_shutdown();
206 self
207 }
208
209 #[must_use]
210 pub fn graceful_shutdown_timeout<T: Into<Millis>>(mut self, timeout: T) -> Self {
223 self.pool = self.pool.graceful_shutdown_timeout(timeout);
224 self
225 }
226
227 pub async fn configure<F>(mut self, f: F) -> io::Result<Self>
235 where
236 F: AsyncFnOnce(ServiceConfig<Cfg>) -> io::Result<()>,
237 {
238 let cfg = ServiceConfig::new(self.token, self.backlog);
239
240 f(cfg.clone()).await?;
241
242 let (token, sockets, factory) = cfg.into_factory();
243 self.token = token;
244 self.sockets.extend(sockets);
245 self.services.push(factory);
246
247 Ok(self)
248 }
249
250 #[allow(clippy::needless_pass_by_value)]
251 pub fn bind<F, S, I>(
261 mut self,
262 name: impl AsRef<str>,
263 addr: impl net::ToSocketAddrs,
264 cfg: impl Into<SharedCfg>,
265 factory: F,
266 ) -> io::Result<Self>
267 where
268 F: AsyncFn(&Cfg::State) -> I + Send + Clone + 'static,
269 S: Service<Cfg::State, Io> + 'static,
270 I: IntoService<S, Cfg::State, Io> + 'static,
271 {
272 let cfg = cfg.into();
273 let sockets = bind_addr(addr, self.backlog)?;
274
275 let mut tokens = Vec::new();
276 for lst in sockets {
277 let token = self.token.next();
278 self.sockets
279 .push((token, name.as_ref().to_string(), Listener::from_tcp(lst)));
280 tokens.push((token, cfg.clone()));
281 }
282
283 self.services.push(factory::create_factory_service(
284 name.as_ref().to_string(),
285 tokens,
286 factory,
287 ));
288
289 Ok(self)
290 }
291
292 #[cfg(unix)]
293 pub fn bind_uds<F, I, S>(
299 self,
300 name: impl AsRef<str>,
301 addr: impl AsRef<std::path::Path>,
302 cfg: impl Into<SharedCfg>,
303 factory: F,
304 ) -> io::Result<Self>
305 where
306 F: AsyncFn(&Cfg::State) -> I + Send + Clone + 'static,
307 I: IntoService<S, Cfg::State, Io> + 'static,
308 S: Service<Cfg::State, Io> + 'static,
309 {
310 use std::os::unix::net::UnixListener;
311
312 if let Err(e) = std::fs::remove_file(addr.as_ref()) {
315 if e.kind() != std::io::ErrorKind::NotFound {
317 return Err(e);
318 }
319 }
320
321 let lst = UnixListener::bind(addr)?;
322 self.listen_uds(name, lst, cfg.into(), factory)
323 }
324
325 #[cfg(unix)]
326 pub fn listen_uds<F, I, S>(
332 mut self,
333 name: impl AsRef<str>,
334 lst: std::os::unix::net::UnixListener,
335 cfg: impl Into<SharedCfg>,
336 factory: F,
337 ) -> io::Result<Self>
338 where
339 F: AsyncFn(&Cfg::State) -> I + Send + Clone + 'static,
340 I: IntoService<S, Cfg::State, Io> + 'static,
341 S: Service<Cfg::State, Io> + 'static,
342 {
343 let token = self.token.next();
344 self.services.push(factory::create_factory_service(
345 name.as_ref().to_string(),
346 vec![(token, cfg.into())],
347 factory,
348 ));
349 self.sockets
350 .push((token, name.as_ref().to_string(), Listener::from_uds(lst)));
351 Ok(self)
352 }
353
354 pub fn listen<F, S, I>(
359 mut self,
360 name: impl AsRef<str>,
361 lst: net::TcpListener,
362 cfg: impl Into<SharedCfg>,
363 factory: F,
364 ) -> io::Result<Self>
365 where
366 F: AsyncFn(&Cfg::State) -> I + Send + Clone + 'static,
367 S: Service<Cfg::State, Io> + 'static,
368 I: IntoService<S, Cfg::State, Io> + 'static,
369 {
370 let token = self.token.next();
371 self.services.push(factory::create_factory_service(
372 name.as_ref().to_string(),
373 vec![(token, cfg.into())],
374 factory,
375 ));
376 self.sockets
377 .push((token, name.as_ref().to_string(), Listener::from_tcp(lst)));
378 Ok(self)
379 }
380
381 pub fn run(mut self) -> Server<Connection> {
387 assert!(
388 !self.sockets.is_empty(),
389 "Server should have at least one bound socket"
390 );
391 self.accept.acceptors(self.acceptors);
392 let srv = StreamServer::new(
393 self.accept.notify(),
394 self.state,
395 self.services,
396 self.max_conns,
397 );
398 let svc = self.pool.run(srv);
399
400 svc.metrics_ref().listeners(
401 self.sockets
402 .iter()
403 .map(|sock| (sock.1.clone(), sock.2.local_addr().to_string())),
404 );
405 let sockets = self
406 .sockets
407 .into_iter()
408 .map(|sock| {
409 log::info!("Starting \"{}\" service on {}", sock.1, sock.2);
410 (sock.0, sock.2)
411 })
412 .collect();
413 self.accept.start(sockets, svc.clone());
414
415 svc
416 }
417}
418
419impl<Cfg> fmt::Debug for ServerBuilder<Cfg> {
420 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
421 f.debug_struct("ServerBuilder")
422 .field("name", &self.name)
423 .field("token", &self.token)
424 .field("backlog", &self.backlog)
425 .field("sockets", &self.sockets)
426 .field("accept", &self.accept)
427 .field("acceptors", &self.acceptors)
428 .field("max_conns", &self.max_conns)
429 .field("worker-pool", &self.pool)
430 .finish()
431 }
432}
433
434pub fn bind_addr<S: net::ToSocketAddrs>(
439 addr: S,
440 backlog: i32,
441) -> io::Result<Vec<net::TcpListener>> {
442 let mut err = None;
443 let mut succ = false;
444 let mut sockets = Vec::new();
445 for addr in addr.to_socket_addrs()? {
446 match create_tcp_listener(addr, backlog) {
447 Ok(lst) => {
448 succ = true;
449 sockets.push(lst);
450 }
451 Err(e) => err = Some(e),
452 }
453 }
454
455 if succ {
456 Ok(sockets)
457 } else if let Some(e) = err.take() {
458 Err(e)
459 } else {
460 Err(io::Error::new(
461 io::ErrorKind::InvalidInput,
462 "Cannot bind to address.",
463 ))
464 }
465}
466
467pub fn create_tcp_listener(addr: net::SocketAddr, backlog: i32) -> io::Result<net::TcpListener> {
469 let builder = match addr {
470 net::SocketAddr::V4(_) => Socket::new(Domain::IPV4, Type::STREAM, None)?,
471 net::SocketAddr::V6(_) => Socket::new(Domain::IPV6, Type::STREAM, None)?,
472 };
473
474 #[cfg(not(windows))]
478 builder.set_reuse_address(true)?;
479
480 builder.bind(&SockAddr::from(addr))?;
481 builder.listen(backlog)?;
482 Ok(net::TcpListener::from(builder))
483}
484
485#[cfg(test)]
486mod tests {
487 use super::*;
488
489 #[test]
490 fn test_bind_addr() {
491 let addrs: Vec<net::SocketAddr> = Vec::new();
492 assert!(bind_addr(&addrs[..], 10).is_err());
493 }
494
495 #[ntex::test]
496 async fn test_debug() {
497 let builder = ServerBuilder::default();
498 assert!(format!("{builder:?}").contains("ServerBuilder"));
499 }
500
501 #[ntex::test]
511 async fn test_paused_wakeup_does_not_accept() {
512 use crate::ServerStatus;
513 use crate::net::AcceptorCommand;
514 use ntex_service::{cfg::SharedCfg, fn_service};
515
516 let lst = net::TcpListener::bind("127.0.0.1:0").unwrap();
517 let addr = lst.local_addr().unwrap();
518 let builder = ServerBuilder::default()
519 .workers(1)
520 .acceptors(1)
521 .disable_signals()
522 .listen("test", lst, SharedCfg::default(), async |&()| {
523 fn_service(async |_: ntex_io::Io| Ok::<_, ()>(()))
524 })
525 .unwrap();
526 let notify = builder.accept.notify();
527 let srv = builder.run();
528 ntex_util::time::timeout(Millis(3000), async {
529 while srv.status() != ServerStatus::Ready {
530 srv.status_changed().await;
531 }
532 })
533 .await
534 .unwrap();
535
536 srv.pause().await;
537 ntex_util::time::sleep(Millis(100)).await;
538 notify.send(AcceptorCommand::Timer);
539 ntex_util::time::sleep(Millis(100)).await;
540
541 let _conn = net::TcpStream::connect(addr).unwrap();
542 ntex_util::time::sleep(Millis(200)).await;
543 assert_eq!(srv.metrics().listeners[0].accepted, 0);
544
545 srv.resume().await;
546 ntex_util::time::timeout(Millis(3000), async {
547 while srv.metrics().listeners[0].accepted == 0 {
548 ntex_util::time::sleep(Millis(10)).await;
549 }
550 })
551 .await
552 .unwrap();
553 srv.stop(false).await;
554 }
555}