Skip to main content

ntex_server/net/
accept.rs

1#![allow(clippy::missing_panics_doc)]
2use std::sync::{Arc, mpsc};
3use std::time::{Duration, Instant};
4use std::{cell::Cell, fmt, io, thread};
5use std::{collections::VecDeque, num::NonZeroUsize};
6
7use ntex_polling::{Event, Events, Notifier, Poller};
8use ntex_rt::System;
9use ntex_util::{future::Either, time::Millis, time::sleep};
10use parking_lot::Mutex;
11
12use super::socket::{Connection, Listener, SocketAddr};
13use super::{Server, Token};
14use crate::metrics::AcceptSlot;
15
16const EXIT_TIMEOUT: Duration = Duration::from_millis(100);
17const ERR_TIMEOUT: Duration = Duration::from_millis(500);
18const ERR_SLEEP_TIMEOUT: Millis = Millis(525);
19const DEFAULT_BACKLOG: i32 = 2048;
20
21/// Command sent to the accept loop.
22#[derive(Debug)]
23pub enum AcceptorCommand {
24    /// Stops accepting and closes the listeners, then signals the sender.
25    Stop(oneshot::Sender<()>),
26    /// Stops accepting and closes the listeners immediately.
27    Terminate,
28    /// Stops accepting connections.
29    Pause,
30    /// Resumes accepting connections.
31    Resume,
32    /// Re-registers listeners that were paused after an accept error.
33    Timer,
34}
35
36/// Command delivered to a single accept thread.
37#[derive(Debug, Clone)]
38enum Command {
39    Stop(Arc<StopSignal>),
40    Terminate,
41    Pause,
42    Resume,
43    Timer,
44}
45
46/// Completes a stop request once every accept thread has released it.
47#[derive(Debug)]
48struct StopSignal(Option<oneshot::Sender<()>>);
49
50impl Drop for StopSignal {
51    fn drop(&mut self) {
52        if let Some(tx) = self.0.take() {
53            let _ = tx.send(());
54        }
55    }
56}
57
58#[derive(Debug)]
59struct ServerSocketInfo {
60    addr: SocketAddr,
61    token: Token,
62    sock: Listener,
63    /// Listener index used for metrics, shared by replicated sockets.
64    idx: usize,
65    registered: Cell<bool>,
66    timeout: Cell<Option<Instant>>,
67}
68
69/// Command channel of a single accept thread.
70#[derive(Debug, Clone)]
71struct AcceptHandle(Notifier, mpsc::Sender<Command>);
72
73impl AcceptHandle {
74    fn send(&self, cmd: Command) {
75        let _ = self.1.send(cmd);
76        let _ = self.0.notify();
77    }
78}
79
80/// Handle for sending commands to the accept loop.
81///
82/// Commands are delivered to every accept thread.
83#[derive(Debug, Clone)]
84pub struct AcceptNotify(Arc<Mutex<Vec<AcceptHandle>>>);
85
86impl AcceptNotify {
87    /// Sends a command and wakes the accept loop.
88    ///
89    /// A `Stop` command is signaled after every accept thread has stopped.
90    pub fn send(&self, cmd: AcceptorCommand) {
91        let handles = self.0.lock().clone();
92        let cmd = match cmd {
93            AcceptorCommand::Stop(tx) => Command::Stop(Arc::new(StopSignal(Some(tx)))),
94            AcceptorCommand::Terminate => Command::Terminate,
95            AcceptorCommand::Pause => Command::Pause,
96            AcceptorCommand::Resume => Command::Resume,
97            AcceptorCommand::Timer => Command::Timer,
98        };
99        for h in &handles {
100            h.send(cmd.clone());
101        }
102    }
103}
104
105/// Accept loop for network listeners.
106///
107/// The loop runs on its own threads and passes accepted connections to the
108/// server.
109pub struct AcceptLoop {
110    name: String,
111    testing: bool,
112    backlog: i32,
113    notify: AcceptNotify,
114    inner: Vec<(mpsc::Receiver<Command>, Poller)>,
115}
116
117impl Default for AcceptLoop {
118    fn default() -> Self {
119        Self::new()
120    }
121}
122
123impl AcceptLoop {
124    /// Creates an accept loop with one accept thread.
125    ///
126    /// # Panics
127    ///
128    /// Panics if the poller cannot be created.
129    pub fn new() -> AcceptLoop {
130        let mut slf = AcceptLoop {
131            notify: AcceptNotify(Arc::new(Mutex::new(Vec::new()))),
132            name: "ntex:accept".to_string(),
133            inner: Vec::new(),
134            testing: false,
135            backlog: DEFAULT_BACKLOG,
136        };
137        slf.add_acceptor();
138        slf
139    }
140
141    fn add_acceptor(&mut self) {
142        let poll = Poller::new()
143            .map_err(|e| panic!("Cannot create Poller {e}"))
144            .unwrap();
145        let (tx, rx) = mpsc::channel();
146        self.notify.0.lock().push(AcceptHandle(poll.notifier(), tx));
147        self.inner.push((rx, poll));
148    }
149
150    /// Sets the server name.
151    ///
152    /// The first accept thread is named `{name}:accept`, additional threads
153    /// are named `{name}:accept{n}`.
154    pub fn name<T: AsRef<str>>(&mut self, name: T) {
155        self.name = format!("{}:accept", name.as_ref());
156    }
157
158    /// Sets the number of accept threads.
159    ///
160    /// Every TCP listener is replicated with `SO_REUSEPORT`, so each accept
161    /// thread has its own socket for the same address and the kernel spreads
162    /// incoming connections between them. Unix domain listeners are served
163    /// by the first thread only.
164    ///
165    /// Multiple accept threads are supported on Linux and Android. On other
166    /// platforms, a single thread is used.
167    ///
168    /// # Panics
169    ///
170    /// Panics if a poller cannot be created.
171    pub fn acceptors(&mut self, num: usize) {
172        let num = if cfg!(any(target_os = "linux", target_os = "android")) {
173            num.max(1)
174        } else {
175            if num > 1 {
176                log::warn!("Multiple accept threads are not supported on this platform");
177            }
178            1
179        };
180        while self.inner.len() < num {
181            self.add_acceptor();
182        }
183        self.inner.truncate(num);
184        self.notify.0.lock().truncate(num);
185    }
186
187    /// Sets the listen backlog for replicated listeners.
188    pub(crate) fn backlog(&mut self, num: i32) {
189        self.backlog = num;
190    }
191
192    /// Returns a handle for sending commands to the loop.
193    pub fn notify(&self) -> AcceptNotify {
194        self.notify.clone()
195    }
196
197    /// Enables test mode, which skips the exit delay on stop.
198    pub fn testing(&mut self) {
199        self.testing = true;
200    }
201
202    /// Starts the accept loop on new threads.
203    ///
204    /// Blocks until the listeners are registered.
205    #[allow(clippy::needless_pass_by_value)]
206    pub fn start(self, socks: Vec<(Token, Listener)>, srv: Server) {
207        // the builder registers named listeners, others only have an address
208        srv.metrics_ref().listeners(
209            socks
210                .iter()
211                .map(|(_, lst)| (String::new(), lst.local_addr().to_string())),
212        );
213
214        let num = self.inner.len();
215        let mut groups: Vec<Vec<(usize, Token, Listener)>> = (0..num).map(|_| Vec::new()).collect();
216        for (idx, (token, lst)) in socks.into_iter().enumerate() {
217            if num > 1 {
218                for (n, lst) in replicate(&lst, num - 1, self.backlog)
219                    .into_iter()
220                    .enumerate()
221                {
222                    groups[n + 1].push((idx, token, lst));
223                }
224            }
225            groups[0].push((idx, token, lst));
226        }
227
228        let handles = self.notify.0.lock().clone();
229        let mut started = Vec::new();
230        for (n, ((rx, poll), socks)) in self.inner.into_iter().zip(groups).enumerate() {
231            // the first thread always runs, others only serve replicated sockets
232            if n > 0 && socks.is_empty() {
233                continue;
234            }
235            let name = if n == 0 {
236                self.name.clone()
237            } else {
238                format!("{}{n}", self.name)
239            };
240            let (tx, rx_start) = oneshot::channel();
241            Accept::start(
242                tx,
243                rx,
244                poll,
245                handles[n].clone(),
246                socks,
247                srv.clone(),
248                name,
249                self.testing,
250            );
251            started.push(rx_start);
252        }
253
254        for rx in started {
255            let _ = rx.recv();
256        }
257    }
258}
259
260/// Creates `num` more listeners bound to the address of `lst`.
261///
262/// `SO_REUSEPORT` is enabled on `lst` and on the new listeners, so the
263/// kernel balances incoming connections between all of them.
264fn replicate(lst: &Listener, num: usize, backlog: i32) -> Vec<Listener> {
265    #[cfg(any(target_os = "linux", target_os = "android"))]
266    if let Listener::Tcp(lst) = lst {
267        use socket2::{Domain, SockAddr, SockRef, Socket, Type};
268
269        let create = || -> io::Result<std::net::TcpListener> {
270            let addr = lst.local_addr()?;
271            let sock = Socket::new(Domain::for_address(addr), Type::STREAM, None)?;
272            sock.set_reuse_address(true)?;
273            sock.set_reuse_port(true)?;
274            if addr.is_ipv6() {
275                sock.set_only_v6(SockRef::from(lst).only_v6()?)?;
276            }
277            sock.bind(&SockAddr::from(addr))?;
278            sock.listen(backlog)?;
279            Ok(sock.into())
280        };
281
282        if let Err(e) = SockRef::from(lst).set_reuse_port(true) {
283            log::warn!("Cannot enable SO_REUSEPORT for {lst:?}: {e}");
284            return Vec::new();
285        }
286        let mut items = Vec::with_capacity(num);
287        for _ in 0..num {
288            match create() {
289                Ok(item) => items.push(Listener::from_tcp(item)),
290                Err(e) => {
291                    log::warn!("Cannot replicate listener {lst:?}: {e}");
292                    break;
293                }
294            }
295        }
296        return items;
297    }
298    let _ = (lst, num, backlog);
299    Vec::new()
300}
301
302impl fmt::Debug for AcceptLoop {
303    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
304        f.debug_struct("AcceptLoop")
305            .field("name", &self.name)
306            .field("acceptors", &self.inner.len())
307            .field("notify", &self.notify)
308            .finish()
309    }
310}
311
312struct Accept {
313    name: String,
314    poller: Poller,
315    rx: mpsc::Receiver<Command>,
316    tx: Option<oneshot::Sender<()>>,
317    sockets: Vec<ServerSocketInfo>,
318    srv: Server,
319    notify: AcceptHandle,
320    testing: bool,
321    backpressure: bool,
322    backlog: VecDeque<Connection>,
323    /// Backlog length last added to the shared metrics.
324    backlog_reported: usize,
325    /// Whether this thread is counted as paused in the shared metrics.
326    paused_reported: bool,
327}
328
329impl Accept {
330    #[allow(clippy::too_many_arguments)]
331    fn start(
332        tx: oneshot::Sender<()>,
333        rx: mpsc::Receiver<Command>,
334        poller: Poller,
335        notify: AcceptHandle,
336        socks: Vec<(usize, Token, Listener)>,
337        srv: Server,
338        name: String,
339        testing: bool,
340    ) {
341        log::info!("Starting {name:?} accept loop");
342
343        // start accept thread
344        let sys = System::current();
345        let _ = thread::Builder::new().name(name.clone()).spawn(move || {
346            System::set_current(sys);
347            Accept::new(name, tx, rx, poller, notify, socks, srv, testing).poll();
348        });
349    }
350
351    #[allow(clippy::too_many_arguments)]
352    fn new(
353        name: String,
354        tx: oneshot::Sender<()>,
355        rx: mpsc::Receiver<Command>,
356        poller: Poller,
357        notify: AcceptHandle,
358        socks: Vec<(usize, Token, Listener)>,
359        srv: Server,
360        testing: bool,
361    ) -> Accept {
362        let sockets = socks
363            .into_iter()
364            .map(|(idx, token, sock)| ServerSocketInfo {
365                addr: sock.local_addr(),
366                sock,
367                idx,
368                token,
369                registered: Cell::new(false),
370                timeout: Cell::new(None),
371            })
372            .collect();
373
374        Accept {
375            name,
376            poller,
377            rx,
378            sockets,
379            notify,
380            srv,
381            testing,
382            tx: Some(tx),
383            backpressure: true,
384            backlog: VecDeque::new(),
385            backlog_reported: 0,
386            paused_reported: false,
387        }
388    }
389
390    fn report_paused(&mut self, paused: bool) {
391        if self.paused_reported != paused {
392            self.paused_reported = paused;
393            self.metrics().paused(paused);
394        }
395    }
396
397    fn report_backlog(&mut self) {
398        let len = self.backlog.len();
399        self.metrics().backlog(self.backlog_reported, len);
400        self.backlog_reported = len;
401    }
402
403    fn metrics(&self) -> &AcceptSlot {
404        self.srv.metrics_ref().listeners([])
405    }
406
407    fn poll(mut self) {
408        // Create storage for events
409        let mut events = Events::with_capacity(NonZeroUsize::new(512).unwrap());
410
411        // notify start
412        for idx in 0..self.sockets.len() {
413            self.add_source(idx);
414        }
415        if let Some(tx) = self.tx.take() {
416            thread::sleep(Duration::from_millis(25));
417            let _ = tx.send(());
418        }
419
420        loop {
421            for idx in 0..self.sockets.len() {
422                // paused sockets and sockets in error timeout must not be
423                // polled, a wakeup would re-register them
424                let info = &self.sockets[idx];
425                if !self.backpressure && info.registered.get() && info.timeout.get().is_none() {
426                    let readd = self.accept(idx);
427                    if readd {
428                        self.add_source(idx);
429                    }
430                }
431            }
432
433            if let Either::Right(rx) = self.process_cmd() {
434                // cleanup
435                for info in self.sockets.drain(..) {
436                    delete_source(&self.poller, &info);
437                    info.sock.remove_source();
438                }
439                log::info!("Accept loop {:?} has been stopped", self.name);
440
441                // the stop request completes when every accept thread releases it
442                if let Some(signal) = rx {
443                    if !self.testing {
444                        thread::sleep(EXIT_TIMEOUT);
445                    }
446                    drop(signal);
447                }
448
449                break;
450            }
451
452            events.clear();
453            if let Err(e) = self.poller.wait(&mut events, None) {
454                assert!(
455                    e.kind() == io::ErrorKind::Interrupted,
456                    "Cannot wait for events in poller: {e}"
457                );
458            }
459        }
460    }
461
462    fn add_source(&self, idx: usize) {
463        let info = &self.sockets[idx];
464
465        loop {
466            // try to register poller source
467            let result = if info.registered.get() {
468                self.poller.modify(&info.sock, Event::readable(idx))
469            } else {
470                unsafe { self.poller.add(&info.sock, Event::readable(idx)) }
471            };
472            if let Err(err) = result {
473                if err.kind() == io::ErrorKind::WouldBlock {
474                    continue;
475                }
476                log::error!("Cannot register socket listener: {err}");
477
478                // sleep after error
479                info.timeout.set(Some(Instant::now() + ERR_TIMEOUT));
480
481                let notify = self.notify.clone();
482                System::current().handle().spawn_detached(async move {
483                    sleep(ERR_SLEEP_TIMEOUT).await;
484                    notify.send(Command::Timer);
485                });
486            } else {
487                info.registered.set(true);
488            }
489
490            break;
491        }
492    }
493
494    fn remove_source(&self, key: usize) {
495        let info = &self.sockets[key];
496
497        let result = if info.registered.get() {
498            self.poller.modify(&info.sock, Event::none(key))
499        } else {
500            return;
501        };
502
503        // stop listening for incoming connections
504        if let Err(err) = result {
505            log::error!("Cannot stop socket listener for {} err: {}", info.addr, err);
506        }
507    }
508
509    fn process_timer(&mut self) {
510        let now = Instant::now();
511        for key in 0..self.sockets.len() {
512            let info = &mut self.sockets[key];
513            if let Some(inst) = info.timeout.get()
514                && now > inst
515                && !self.backpressure
516            {
517                log::info!("Resuming socket listener on {} after timeout", info.addr);
518                info.timeout.take();
519                self.add_source(key);
520            }
521        }
522    }
523
524    fn process_cmd(&mut self) -> Either<(), Option<Arc<StopSignal>>> {
525        loop {
526            match self.rx.try_recv() {
527                Ok(cmd) => match cmd {
528                    Command::Stop(rx) => {
529                        if !self.backpressure {
530                            log::info!("Stopping accept loop {:?}", self.name);
531                            self.backpressure(true);
532                        }
533                        break Either::Right(Some(rx));
534                    }
535                    Command::Terminate => {
536                        log::info!("Stopping accept loop {:?}", self.name);
537                        self.backpressure(true);
538                        break Either::Right(None);
539                    }
540                    Command::Pause => {
541                        if !self.backpressure {
542                            log::info!("Pausing accept loop {:?}", self.name);
543                            self.backpressure(true);
544                        }
545                    }
546                    Command::Resume => {
547                        if self.backpressure {
548                            log::info!("Resuming accept loop {:?}", self.name);
549                            self.backpressure(false);
550                        }
551                    }
552                    Command::Timer => {
553                        self.process_timer();
554                    }
555                },
556                Err(err) => {
557                    break match err {
558                        mpsc::TryRecvError::Empty => Either::Left(()),
559                        mpsc::TryRecvError::Disconnected => {
560                            log::error!("Dropping accept loop {:?}", self.name);
561                            self.backpressure(true);
562                            Either::Right(None)
563                        }
564                    };
565                }
566            }
567        }
568    }
569
570    fn backpressure(&mut self, on: bool) {
571        if self.backpressure && !on {
572            // handle backlog
573            while let Some(msg) = self.backlog.pop_front() {
574                if let Err(msg) = self.srv.process_with(msg, Connection::incoming_cpu) {
575                    log::trace!("Server is unavailable");
576                    self.backlog.push_front(msg);
577                    self.report_backlog();
578                    return;
579                }
580            }
581            self.report_backlog();
582            self.report_paused(false);
583
584            // re-enable acceptors
585            self.backpressure = false;
586            for (key, info) in self.sockets.iter().enumerate() {
587                if info.timeout.get().is_none() {
588                    // socket with timeout will re-register itself after timeout
589                    log::info!(
590                        "Resuming socket listener on {} after back-pressure",
591                        info.addr
592                    );
593                    self.add_source(key);
594                }
595            }
596        } else if !self.backpressure && on {
597            self.backpressure = true;
598            self.report_paused(true);
599            for key in 0..self.sockets.len() {
600                // disable err timeout
601                let info = &mut self.sockets[key];
602                if info.timeout.take().is_none() {
603                    log::info!("Stopping socket listener on {}", info.addr);
604                    self.remove_source(key);
605                }
606            }
607        }
608    }
609
610    fn accept(&mut self, token: usize) -> bool {
611        loop {
612            if let Some(info) = self.sockets.get_mut(token) {
613                let idx = info.idx;
614                match info.sock.accept() {
615                    Ok(Some(io)) => {
616                        self.srv.metrics_ref().listeners([]).accepted(idx);
617                        let msg = Connection {
618                            io,
619                            token: info.token,
620                        };
621                        if let Err(msg) = self.srv.process_with(msg, Connection::incoming_cpu) {
622                            log::trace!("Server is unavailable");
623                            self.backlog.push_back(msg);
624                            self.report_backlog();
625                            self.backpressure(true);
626                            return false;
627                        }
628                    }
629                    Ok(None) => return true,
630                    Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => return true,
631                    Err(ref e) if connection_error(e) => {
632                        self.srv.metrics_ref().listeners([]).connection_error(idx);
633                    }
634                    Err(e) => {
635                        log::error!("Error accepting socket: {e}");
636                        self.srv.metrics_ref().listeners([]).resource_error(idx);
637
638                        // sleep after error
639                        info.timeout.set(Some(Instant::now() + ERR_TIMEOUT));
640
641                        let notify = self.notify.clone();
642                        System::current().handle().spawn_detached(async move {
643                            sleep(ERR_SLEEP_TIMEOUT).await;
644                            notify.send(Command::Timer);
645                        });
646                        return false;
647                    }
648                }
649            }
650        }
651    }
652}
653
654impl Drop for Accept {
655    fn drop(&mut self) {
656        // the normal shutdown path drains the sockets, this covers panics
657        for info in &self.sockets {
658            delete_source(&self.poller, info);
659        }
660    }
661}
662
663/// Deletes a registered listener from the poller, as `Poller::add` requires
664/// before the listener is dropped.
665fn delete_source(poller: &Poller, info: &ServerSocketInfo) {
666    if info.registered.replace(false)
667        && let Err(err) = poller.delete(&info.sock)
668    {
669        log::error!(
670            "Cannot delete socket listener for {} err: {}",
671            info.addr,
672            err
673        );
674    }
675}
676
677/// This function defines errors that are per-connection. Which basically
678/// means that if we get this error from `accept()` system call it means
679/// next connection might be ready to be accepted.
680///
681/// All other errors will incur a timeout before next `accept()` is performed.
682/// The timeout is useful to handle resource exhaustion errors like ENFILE
683/// and EMFILE. Otherwise, could enter into tight loop.
684fn connection_error(e: &io::Error) -> bool {
685    matches!(
686        e.kind(),
687        io::ErrorKind::ConnectionRefused
688            | io::ErrorKind::ConnectionAborted
689            | io::ErrorKind::ConnectionReset
690    )
691}