use std::net::SocketAddr;
use tracing::Instrument;
use crate::decode::DecodeLevel;
use crate::server::task::ServerSetting;
use crate::tcp::server::{ServerTask, TcpServerConnectionHandler};
mod address_filter;
pub(crate) mod handler;
pub(crate) mod request;
pub(crate) mod response;
pub(crate) mod task;
pub(crate) mod types;
pub(crate) const SERVER_SETTING_CHANNEL_CAPACITY: usize = 8;
use crate::error::Shutdown;
pub use address_filter::*;
pub use handler::*;
pub use types::*;
#[cfg(feature = "tls")]
pub use crate::tcp::tls::server::TlsServerConfig;
#[cfg(feature = "tls")]
pub use crate::tcp::tls::*;
#[derive(Debug)]
pub struct ServerHandle {
tx: tokio::sync::mpsc::Sender<ServerSetting>,
}
impl ServerHandle {
pub fn new(tx: tokio::sync::mpsc::Sender<ServerSetting>) -> Self {
ServerHandle { tx }
}
pub async fn set_decode_level(&mut self, level: DecodeLevel) -> Result<(), Shutdown> {
self.tx.send(ServerSetting::ChangeDecoding(level)).await?;
Ok(())
}
}
pub async fn spawn_tcp_server_task<T: RequestHandler>(
max_sessions: usize,
addr: SocketAddr,
handlers: ServerHandlerMap<T>,
filter: AddressFilter,
decode: DecodeLevel,
) -> Result<ServerHandle, std::io::Error> {
let listener = tokio::net::TcpListener::bind(addr).await?;
let (tx, rx) = tokio::sync::mpsc::channel(SERVER_SETTING_CHANNEL_CAPACITY);
let task = async move {
ServerTask::new(
max_sessions,
listener,
handlers,
TcpServerConnectionHandler::Tcp,
filter,
decode,
)
.run(rx)
.instrument(tracing::info_span!("Modbus-Server-TCP", "listen" = ?addr))
.await;
};
tokio::spawn(task);
Ok(ServerHandle::new(tx))
}
#[cfg(feature = "serial")]
pub fn spawn_rtu_server_task<T: RequestHandler>(
path: &str,
settings: crate::serial::SerialSettings,
retry: Box<dyn crate::retry::RetryStrategy>,
handlers: ServerHandlerMap<T>,
decode: DecodeLevel,
) -> Result<ServerHandle, std::io::Error> {
let (tx, rx) = tokio::sync::mpsc::channel(SERVER_SETTING_CHANNEL_CAPACITY);
let session = crate::server::task::SessionTask::new(
handlers,
crate::server::task::AuthorizationType::None,
crate::common::frame::FrameWriter::rtu(),
crate::common::frame::FramedReader::rtu_request(),
rx,
decode,
);
let mut rtu = crate::serial::server::RtuServerTask {
port: path.to_string(),
retry,
settings,
session,
};
let path = path.to_string();
let task = async move {
rtu.run()
.instrument(tracing::info_span!("Modbus-Server-RTU", "port" = ?path))
.await
};
tokio::spawn(task);
Ok(ServerHandle::new(tx))
}
#[cfg(feature = "tls")]
pub async fn spawn_tls_server_task<T: RequestHandler>(
max_sessions: usize,
addr: SocketAddr,
handlers: ServerHandlerMap<T>,
tls_config: TlsServerConfig,
filter: AddressFilter,
decode: DecodeLevel,
) -> Result<ServerHandle, std::io::Error> {
spawn_tls_server_task_impl(
max_sessions,
addr,
handlers,
None,
tls_config,
filter,
decode,
)
.await
}
#[cfg(feature = "tls")]
pub async fn spawn_tls_server_task_with_authz<T: RequestHandler>(
max_sessions: usize,
addr: SocketAddr,
handlers: ServerHandlerMap<T>,
auth_handler: std::sync::Arc<dyn AuthorizationHandler>,
tls_config: TlsServerConfig,
filter: AddressFilter,
decode: DecodeLevel,
) -> Result<ServerHandle, std::io::Error> {
spawn_tls_server_task_impl(
max_sessions,
addr,
handlers,
Some(auth_handler),
tls_config,
filter,
decode,
)
.await
}
#[cfg(feature = "tls")]
async fn spawn_tls_server_task_impl<T: RequestHandler>(
max_sessions: usize,
addr: SocketAddr,
handlers: ServerHandlerMap<T>,
auth_handler: Option<std::sync::Arc<dyn AuthorizationHandler>>,
tls_config: TlsServerConfig,
filter: AddressFilter,
decode: DecodeLevel,
) -> Result<ServerHandle, std::io::Error> {
let listener = tokio::net::TcpListener::bind(addr).await?;
let (tx, rx) = tokio::sync::mpsc::channel(SERVER_SETTING_CHANNEL_CAPACITY);
let task = async move {
ServerTask::new(
max_sessions,
listener,
handlers,
TcpServerConnectionHandler::Tls(tls_config, auth_handler),
filter,
decode,
)
.run(rx)
.instrument(tracing::info_span!("Modbus-Server-TLS", "listen" = ?addr))
.await
};
tokio::spawn(task);
Ok(ServerHandle::new(tx))
}