First API tests.

This commit is contained in:
Mauro D
2023-04-19 16:55:37 +00:00
parent 0264890595
commit f8acc4fe5a
57 changed files with 2243 additions and 664 deletions

View File

@@ -4,7 +4,7 @@ use tokio::{net::TcpListener, sync::watch};
use tokio_rustls::TlsAcceptor;
use crate::{
config::{Listener, Server, ServerProtocol, Servers},
config::{Config, Listener, Server, ServerProtocol, Servers},
failed,
listener::SessionData,
UnwrapFailure,
@@ -13,12 +13,7 @@ use crate::{
use super::{limiter::ConcurrencyLimiter, ServerInstance, SessionManager};
impl Server {
pub fn spawn(
self,
manager: impl SessionManager,
max_concurrent: u64,
shutdown_rx: watch::Receiver<bool>,
) -> Result<(), String> {
pub fn spawn(self, manager: impl SessionManager, shutdown_rx: watch::Receiver<bool>) {
// Prepare instance
let instance = Arc::new(ServerInstance {
data: if matches!(self.protocol, ServerProtocol::Smtp | ServerProtocol::Lmtp) {
@@ -32,11 +27,10 @@ impl Server {
hostname: self.hostname,
tls_acceptor: self.tls.map(|config| TlsAcceptor::from(Arc::new(config))),
is_tls_implicit: self.tls_implicit,
limiter: ConcurrencyLimiter::new(manager.max_concurrent()),
shutdown_rx,
});
// Start concurrency limiter
let limiter = Arc::new(ConcurrencyLimiter::new(max_concurrent));
// Spawn listeners
for listener in self.listeners {
tracing::info!(
@@ -53,10 +47,9 @@ impl Server {
let listener = listener.listen();
// Spawn listener
let mut shutdown_rx = shutdown_rx.clone();
let mut shutdown_rx = instance.shutdown_rx.clone();
let manager = manager.clone();
let instance = instance.clone();
let limiter = limiter.clone();
tokio::spawn(async move {
loop {
tokio::select! {
@@ -64,7 +57,7 @@ impl Server {
match stream {
Ok((stream, remote_addr)) => {
// Enforce concurrency
if let Some(in_flight) = limiter.is_allowed() {
if let Some(in_flight) = instance.limiter.is_allowed() {
let span = tracing::info_span!(
"session",
instance = instance.id,
@@ -81,7 +74,6 @@ impl Server {
span,
in_flight,
instance: instance.clone(),
shutdown_rx: shutdown_rx.clone(),
});
} else {
tracing::info!(
@@ -91,7 +83,7 @@ impl Server {
protocol = ?instance.protocol,
remote.ip = remote_addr.ip().to_string(),
remote.port = remote_addr.port(),
max_concurrent = max_concurrent,
max_concurrent = instance.limiter.max_concurrent,
"Too many concurrent connections."
);
};
@@ -117,13 +109,16 @@ impl Server {
}
});
}
Ok(())
}
}
impl Servers {
pub fn bind(&self) {
pub fn spawn(
self,
config: &Config,
spawn: impl Fn(Server, watch::Receiver<bool>),
) -> watch::Sender<bool> {
// Bind as root
for server in &self.inner {
for listener in &server.listeners {
listener
@@ -132,6 +127,26 @@ impl Servers {
.failed(&format!("Failed to bind to {}", listener.addr));
}
}
// Drop privileges
#[cfg(not(target_env = "msvc"))]
{
if let Some(run_as_user) = config.value("server.run-as.user") {
let mut pd = privdrop::PrivDrop::default().user(run_as_user);
if let Some(run_as_group) = config.value("server.run-as.group") {
pd = pd.group(run_as_group);
}
pd.apply().failed("Failed to drop privileges");
}
}
// Spawn listeners
let (shutdown_tx, shutdown_rx) = watch::channel(false);
for server in self.inner {
spawn(server, shutdown_rx.clone());
}
shutdown_tx
}
}

View File

@@ -9,7 +9,7 @@ use tokio_rustls::TlsAcceptor;
use crate::config::ServerProtocol;
use self::limiter::InFlight;
use self::limiter::{ConcurrencyLimiter, InFlight};
pub mod limiter;
pub mod listen;
@@ -22,6 +22,8 @@ pub struct ServerInstance {
pub data: String,
pub tls_acceptor: Option<TlsAcceptor>,
pub is_tls_implicit: bool,
pub limiter: ConcurrencyLimiter,
pub shutdown_rx: watch::Receiver<bool>,
}
pub struct SessionData<T: AsyncRead + AsyncWrite + Unpin + 'static> {
@@ -31,9 +33,9 @@ pub struct SessionData<T: AsyncRead + AsyncWrite + Unpin + 'static> {
pub span: tracing::Span,
pub in_flight: InFlight,
pub instance: Arc<ServerInstance>,
pub shutdown_rx: watch::Receiver<bool>,
}
pub trait SessionManager: Sync + Send + 'static + Clone {
fn spawn(&self, session: SessionData<TcpStream>);
fn max_concurrent(&self) -> u64;
}