Skip to main content

ntex_server/net/
accept.rs

1#![allow(clippy::missing_panics_doc)]
2use std::time::{Duration, Instant};
3use std::{cell::Cell, fmt, io, sync::mpsc, thread};
4use std::{collections::VecDeque, num::NonZeroUsize};
5
6use ntex_polling::{Event, Events, Notifier, Poller};
7use ntex_rt::System;
8use ntex_util::{future::Either, time::Millis, time::sleep};
9
10use super::socket::{Connection, Listener, SocketAddr};
11use super::{Server, Token};
12use crate::metrics::AcceptSlot;
13
14const EXIT_TIMEOUT: Duration = Duration::from_millis(100);
15const ERR_TIMEOUT: Duration = Duration::from_millis(500);
16const ERR_SLEEP_TIMEOUT: Millis = Millis(525);
17
18/// Command sent to the accept loop.
19#[derive(Debug)]
20pub enum AcceptorCommand {
21    /// Stops accepting and closes the listeners, then signals the sender.
22    Stop(oneshot::Sender<()>),
23    /// Stops accepting and closes the listeners immediately.
24    Terminate,
25    /// Stops accepting connections.
26    Pause,
27    /// Resumes accepting connections.
28    Resume,
29    /// Re-registers listeners that were paused after an accept error.
30    Timer,
31}
32
33#[derive(Debug)]
34struct ServerSocketInfo {
35    addr: SocketAddr,
36    token: Token,
37    sock: Listener,
38    registered: Cell<bool>,
39    timeout: Cell<Option<Instant>>,
40}
41
42/// Handle for sending commands to the accept loop.
43#[derive(Debug, Clone)]
44pub struct AcceptNotify(Notifier, mpsc::Sender<AcceptorCommand>);
45
46impl AcceptNotify {
47    fn new(waker: Notifier, tx: mpsc::Sender<AcceptorCommand>) -> Self {
48        AcceptNotify(waker, tx)
49    }
50
51    /// Sends a command and wakes the accept loop.
52    pub fn send(&self, cmd: AcceptorCommand) {
53        let _ = self.1.send(cmd);
54        let _ = self.0.notify();
55    }
56}
57
58/// Accept loop for network listeners.
59///
60/// The loop runs on its own thread and passes accepted connections to the
61/// server.
62pub struct AcceptLoop {
63    name: String,
64    testing: bool,
65    notify: AcceptNotify,
66    inner: Option<(mpsc::Receiver<AcceptorCommand>, Poller)>,
67}
68
69impl Default for AcceptLoop {
70    fn default() -> Self {
71        Self::new()
72    }
73}
74
75impl AcceptLoop {
76    /// Creates an accept loop.
77    ///
78    /// # Panics
79    ///
80    /// Panics if the poller cannot be created.
81    pub fn new() -> AcceptLoop {
82        // Create a poller instance
83        let poll = Poller::new()
84            .map_err(|e| panic!("Cannot create Poller {e}"))
85            .unwrap();
86
87        let (tx, rx) = mpsc::channel();
88        let notify = AcceptNotify::new(poll.notifier(), tx);
89
90        AcceptLoop {
91            notify,
92            name: "ntex:accept".to_string(),
93            inner: Some((rx, poll)),
94            testing: false,
95        }
96    }
97
98    /// Sets the server name.
99    ///
100    /// The accept thread is named `{name}:accept`.
101    pub fn name<T: AsRef<str>>(&mut self, name: T) {
102        self.name = format!("{}:accept", name.as_ref());
103    }
104
105    /// Returns a handle for sending commands to the loop.
106    pub fn notify(&self) -> AcceptNotify {
107        self.notify.clone()
108    }
109
110    /// Enables test mode, which skips the exit delay on stop.
111    pub fn testing(&mut self) {
112        self.testing = true;
113    }
114
115    /// Starts the accept loop on a new thread.
116    ///
117    /// Blocks until the listeners are registered.
118    pub fn start(mut self, socks: Vec<(Token, Listener)>, srv: Server) {
119        let (tx, rx_start) = oneshot::channel();
120        let (rx, poll) = self
121            .inner
122            .take()
123            .expect("AcceptLoop cannot be used multiple times");
124
125        Accept::start(
126            tx,
127            rx,
128            poll,
129            socks,
130            srv,
131            self.name.clone(),
132            self.notify.clone(),
133            self.testing,
134        );
135
136        let _ = rx_start.recv();
137    }
138}
139
140impl fmt::Debug for AcceptLoop {
141    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
142        f.debug_struct("AcceptLoop")
143            .field("name", &self.name)
144            .field("notify", &self.notify)
145            .field("inner", &self.inner)
146            .finish()
147    }
148}
149
150struct Accept {
151    name: String,
152    poller: Poller,
153    rx: mpsc::Receiver<AcceptorCommand>,
154    tx: Option<oneshot::Sender<()>>,
155    sockets: Vec<ServerSocketInfo>,
156    srv: Server,
157    notify: AcceptNotify,
158    testing: bool,
159    backpressure: bool,
160    backlog: VecDeque<Connection>,
161}
162
163impl Accept {
164    #[allow(clippy::too_many_arguments)]
165    fn start(
166        tx: oneshot::Sender<()>,
167        rx: mpsc::Receiver<AcceptorCommand>,
168        poller: Poller,
169        socks: Vec<(Token, Listener)>,
170        srv: Server,
171        name: String,
172        notify: AcceptNotify,
173        testing: bool,
174    ) {
175        log::info!("Starting {name:?} accept loop");
176
177        // start accept thread
178        let sys = System::current();
179        let _ = thread::Builder::new().name(name.clone()).spawn(move || {
180            System::set_current(sys);
181            Accept::new(name, tx, rx, poller, socks, srv, notify, testing).poll();
182        });
183    }
184
185    #[allow(clippy::too_many_arguments)]
186    fn new(
187        name: String,
188        tx: oneshot::Sender<()>,
189        rx: mpsc::Receiver<AcceptorCommand>,
190        poller: Poller,
191        socks: Vec<(Token, Listener)>,
192        srv: Server,
193        notify: AcceptNotify,
194        testing: bool,
195    ) -> Accept {
196        let mut sockets = Vec::new();
197        // the builder registers named listeners, others only have an address
198        srv.metrics_ref().listeners(
199            socks
200                .iter()
201                .map(|(_, lst)| (String::new(), lst.local_addr().to_string())),
202        );
203        for (hnd_token, lst) in socks {
204            sockets.push(ServerSocketInfo {
205                addr: lst.local_addr(),
206                sock: lst,
207                token: hnd_token,
208                registered: Cell::new(false),
209                timeout: Cell::new(None),
210            });
211        }
212
213        Accept {
214            name,
215            poller,
216            rx,
217            sockets,
218            notify,
219            srv,
220            testing,
221            tx: Some(tx),
222            backpressure: true,
223            backlog: VecDeque::new(),
224        }
225    }
226
227    fn metrics(&self) -> &AcceptSlot {
228        self.srv.metrics_ref().listeners([])
229    }
230
231    fn poll(mut self) {
232        // Create storage for events
233        let mut events = Events::with_capacity(NonZeroUsize::new(512).unwrap());
234
235        // notify start
236        for idx in 0..self.sockets.len() {
237            self.add_source(idx);
238        }
239        if let Some(tx) = self.tx.take() {
240            thread::sleep(Duration::from_millis(25));
241            let _ = tx.send(());
242        }
243
244        loop {
245            for idx in 0..self.sockets.len() {
246                if self.sockets[idx].registered.get() {
247                    let readd = self.accept(idx);
248                    if readd {
249                        self.add_source(idx);
250                    }
251                }
252            }
253
254            if let Either::Right(rx) = self.process_cmd() {
255                // cleanup
256                for info in self.sockets.drain(..) {
257                    info.sock.remove_source();
258                }
259                log::info!("Accept loop {:?} has been stopped", self.name);
260
261                if let Some(rx) = rx {
262                    if !self.testing {
263                        thread::sleep(EXIT_TIMEOUT);
264                    }
265                    let _ = rx.send(());
266                }
267
268                break;
269            }
270
271            events.clear();
272            if let Err(e) = self.poller.wait(&mut events, None) {
273                assert!(
274                    e.kind() == io::ErrorKind::Interrupted,
275                    "Cannot wait for events in poller: {e}"
276                );
277            }
278        }
279    }
280
281    fn add_source(&self, idx: usize) {
282        let info = &self.sockets[idx];
283
284        loop {
285            // try to register poller source
286            let result = if info.registered.get() {
287                self.poller.modify(&info.sock, Event::readable(idx))
288            } else {
289                unsafe { self.poller.add(&info.sock, Event::readable(idx)) }
290            };
291            if let Err(err) = result {
292                if err.kind() == io::ErrorKind::WouldBlock {
293                    continue;
294                }
295                log::error!("Cannot register socket listener: {err}");
296
297                // sleep after error
298                info.timeout.set(Some(Instant::now() + ERR_TIMEOUT));
299
300                let notify = self.notify.clone();
301                System::current().handle().spawn_detached(async move {
302                    sleep(ERR_SLEEP_TIMEOUT).await;
303                    notify.send(AcceptorCommand::Timer);
304                });
305            } else {
306                info.registered.set(true);
307            }
308
309            break;
310        }
311    }
312
313    fn remove_source(&self, key: usize) {
314        let info = &self.sockets[key];
315
316        let result = if info.registered.get() {
317            self.poller.modify(&info.sock, Event::none(key))
318        } else {
319            return;
320        };
321
322        // stop listening for incoming connections
323        if let Err(err) = result {
324            log::error!("Cannot stop socket listener for {} err: {}", info.addr, err);
325        }
326    }
327
328    fn process_timer(&mut self) {
329        let now = Instant::now();
330        for key in 0..self.sockets.len() {
331            let info = &mut self.sockets[key];
332            if let Some(inst) = info.timeout.get()
333                && now > inst
334                && !self.backpressure
335            {
336                log::info!("Resuming socket listener on {} after timeout", info.addr);
337                info.timeout.take();
338                self.add_source(key);
339            }
340        }
341    }
342
343    fn process_cmd(&mut self) -> Either<(), Option<oneshot::Sender<()>>> {
344        loop {
345            match self.rx.try_recv() {
346                Ok(cmd) => match cmd {
347                    AcceptorCommand::Stop(rx) => {
348                        if !self.backpressure {
349                            log::info!("Stopping accept loop {:?}", self.name);
350                            self.backpressure(true);
351                        }
352                        break Either::Right(Some(rx));
353                    }
354                    AcceptorCommand::Terminate => {
355                        log::info!("Stopping accept loop {:?}", self.name);
356                        self.backpressure(true);
357                        break Either::Right(None);
358                    }
359                    AcceptorCommand::Pause => {
360                        if !self.backpressure {
361                            log::info!("Pausing accept loop {:?}", self.name);
362                            self.backpressure(true);
363                        }
364                    }
365                    AcceptorCommand::Resume => {
366                        if self.backpressure {
367                            log::info!("Resuming accept loop {:?}", self.name);
368                            self.backpressure(false);
369                        }
370                    }
371                    AcceptorCommand::Timer => {
372                        self.process_timer();
373                    }
374                },
375                Err(err) => {
376                    break match err {
377                        mpsc::TryRecvError::Empty => Either::Left(()),
378                        mpsc::TryRecvError::Disconnected => {
379                            log::error!("Dropping accept loop {:?}", self.name);
380                            self.backpressure(true);
381                            Either::Right(None)
382                        }
383                    };
384                }
385            }
386        }
387    }
388
389    fn backpressure(&mut self, on: bool) {
390        if self.backpressure && !on {
391            // handle backlog
392            while let Some(msg) = self.backlog.pop_front() {
393                if let Err(msg) = self.srv.process(msg) {
394                    log::trace!("Server is unavailable");
395                    self.backlog.push_front(msg);
396                    self.metrics().backlog(self.backlog.len());
397                    return;
398                }
399            }
400            self.metrics().backlog(0);
401            self.metrics().paused(false);
402
403            // re-enable acceptors
404            self.backpressure = false;
405            for (key, info) in self.sockets.iter().enumerate() {
406                if info.timeout.get().is_none() {
407                    // socket with timeout will re-register itself after timeout
408                    log::info!(
409                        "Resuming socket listener on {} after back-pressure",
410                        info.addr
411                    );
412                    self.add_source(key);
413                }
414            }
415        } else if !self.backpressure && on {
416            self.backpressure = true;
417            self.metrics().paused(true);
418            for key in 0..self.sockets.len() {
419                // disable err timeout
420                let info = &mut self.sockets[key];
421                if info.timeout.take().is_none() {
422                    log::info!("Stopping socket listener on {}", info.addr);
423                    self.remove_source(key);
424                }
425            }
426        }
427    }
428
429    fn accept(&mut self, token: usize) -> bool {
430        loop {
431            if let Some(info) = self.sockets.get_mut(token) {
432                match info.sock.accept() {
433                    Ok(Some(io)) => {
434                        self.srv.metrics_ref().listeners([]).accepted(token);
435                        let msg = Connection {
436                            io,
437                            token: info.token,
438                        };
439                        if let Err(msg) = self.srv.process(msg) {
440                            log::trace!("Server is unavailable");
441                            self.backlog.push_back(msg);
442                            self.metrics().backlog(self.backlog.len());
443                            self.backpressure(true);
444                            return false;
445                        }
446                    }
447                    Ok(None) => return true,
448                    Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => return true,
449                    Err(ref e) if connection_error(e) => {
450                        self.srv.metrics_ref().listeners([]).connection_error(token);
451                    }
452                    Err(e) => {
453                        log::error!("Error accepting socket: {e}");
454                        self.srv.metrics_ref().listeners([]).resource_error(token);
455
456                        // sleep after error
457                        info.timeout.set(Some(Instant::now() + ERR_TIMEOUT));
458
459                        let notify = self.notify.clone();
460                        System::current().handle().spawn_detached(async move {
461                            sleep(ERR_SLEEP_TIMEOUT).await;
462                            notify.send(AcceptorCommand::Timer);
463                        });
464                        return false;
465                    }
466                }
467            }
468        }
469    }
470}
471
472/// This function defines errors that are per-connection. Which basically
473/// means that if we get this error from `accept()` system call it means
474/// next connection might be ready to be accepted.
475///
476/// All other errors will incur a timeout before next `accept()` is performed.
477/// The timeout is useful to handle resource exhaustion errors like ENFILE
478/// and EMFILE. Otherwise, could enter into tight loop.
479fn connection_error(e: &io::Error) -> bool {
480    matches!(
481        e.kind(),
482        io::ErrorKind::ConnectionRefused
483            | io::ErrorKind::ConnectionAborted
484            | io::ErrorKind::ConnectionReset
485    )
486}