diff options
| author | Mroik <mroik@delayed.space> | 2026-04-12 21:16:17 +0200 |
|---|---|---|
| committer | Mroik <mroik@delayed.space> | 2026-04-13 06:56:12 +0200 |
| commit | 784bf87d6fbf59194412c1dafeb56b3ed3946106 (patch) | |
| tree | 0384213401f21c25996f8cbcff46126a2d04232e /src | |
| parent | e3854173d720fbbc4f98a7939ac667fcac007ec1 (diff) | |
Remove extra String alloc improving memory usage
Signed-off-by: Mroik <mroik@delayed.space>
Diffstat (limited to 'src')
| -rw-r--r-- | src/smtp_server.rs | 62 |
1 files changed, 30 insertions, 32 deletions
diff --git a/src/smtp_server.rs b/src/smtp_server.rs index 9e313f4..83a1093 100644 --- a/src/smtp_server.rs +++ b/src/smtp_server.rs @@ -10,18 +10,18 @@ use tokio::{ use crate::model::Mail; -const SERVER_NAME: &str = ""; - pub struct SmtpServer { listener: TcpListener, running: bool, + server_name: String, } impl SmtpServer { - pub async fn new(ip: [u8; 4], port: u16) -> Result<Self> { + pub async fn new(ip: [u8; 4], port: u16, server_name: &str) -> Result<Self> { Ok(Self { listener: TcpListener::bind((IpAddr::from(ip), port)).await?, running: false, + server_name: String::from(server_name), }) } @@ -46,6 +46,7 @@ impl SmtpServer { }; let session = SessionHandler { addr, + server_name: self.server_name.clone(), tx_processor: tx_processor.clone(), state: SessionState::default(), client_host: String::new(), @@ -61,6 +62,7 @@ impl SmtpServer { struct SessionHandler { addr: SocketAddr, + server_name: String, tx_processor: Sender<Mail>, state: SessionState, client_host: String, @@ -76,11 +78,7 @@ impl SessionHandler { let mut buffer = String::new(); writer - .write_all( - Reply::Ready(String::from(SERVER_NAME)) - .to_string() - .as_bytes(), - ) + .write_all(Reply::Ready(&self.server_name).to_string().as_bytes()) .await?; loop { @@ -129,7 +127,7 @@ impl SessionHandler { Ok(()) } - async fn apply(&mut self, command: Command) -> Result<Reply> { + async fn apply(&mut self, command: Command<'_>) -> Result<Reply<'_>> { match &command { Command::HELO(hostname) => self.helo(hostname).await, Command::MAIL(from) => self.mail(from).await, @@ -140,17 +138,17 @@ impl SessionHandler { } /// HELO resets buffers - async fn helo(&mut self, hostname: &str) -> Result<Reply> { + async fn helo(&mut self, hostname: &str) -> Result<Reply<'_>> { self.client_host = String::from(hostname); self.state = SessionState::Normal; self.from = None; self.to.clear(); - Ok(Reply::Completed(String::from(SERVER_NAME))) + Ok(Reply::Completed(&self.server_name)) } /// TODO: Validate email address /// MAIL resets buffers - async fn mail(&mut self, from: &str) -> Result<Reply> { + async fn mail(&mut self, from: &str) -> Result<Reply<'_>> { if from.is_empty() { return Ok(Reply::InvalidParameter); } @@ -159,12 +157,12 @@ impl SessionHandler { self.to.clear(); self.state = SessionState::MailTransaction; - Ok(Reply::Completed(String::from("Ok"))) + Ok(Reply::Completed("Ok")) } /// TODO: Validate email addresses /// Only after having started a mail transaction - async fn rcpt(&mut self, to: &str) -> Result<Reply> { + async fn rcpt(&mut self, to: &str) -> Result<Reply<'_>> { if self.state != SessionState::MailTransaction { return Ok(Reply::BadSequence); } @@ -174,11 +172,11 @@ impl SessionHandler { } self.to.push(String::from(to)); - Ok(Reply::Completed(String::from("Ok"))) + Ok(Reply::Completed("Ok")) } /// Only after having started a mail transaction - async fn start_data(&mut self) -> std::result::Result<Reply, anyhow::Error> { + async fn start_data(&mut self) -> Result<Reply<'_>> { if self.state != SessionState::MailTransaction { return Ok(Reply::BadSequence); } @@ -193,7 +191,7 @@ impl SessionHandler { Ok(Reply::StartMailInput) } - async fn process_mail(&mut self) -> Result<Reply> { + async fn process_mail(&mut self) -> Result<Reply<'_>> { if self.from.is_none() || self.to.is_empty() || self.data.trim().is_empty() { return Ok(Reply::InvalidCommand); } @@ -211,10 +209,10 @@ impl SessionHandler { self.to.clear(); self.data.clear(); - Ok(Reply::Completed(String::from("Ok"))) + Ok(Reply::Completed("Ok")) } - async fn quit(&self) -> Result<Reply> { + async fn quit(&self) -> Result<Reply<'_>> { Ok(Reply::EndTransmission) } } @@ -229,9 +227,9 @@ enum SessionState { } #[derive(PartialEq)] -enum Reply { - Ready(String), - Completed(String), +enum Reply<'a> { + Ready(&'a str), + Completed(&'a str), StartMailInput, InvalidCommand, InvalidParameter, @@ -239,7 +237,7 @@ enum Reply { EndTransmission, } -impl std::fmt::Display for Reply { +impl std::fmt::Display for Reply<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Reply::Ready(hostname) => write!(f, "220 {}\r\n", hostname), @@ -253,20 +251,20 @@ impl std::fmt::Display for Reply { } } -enum Command { - HELO(String), - MAIL(String), - RCPT(String), +enum Command<'a> { + HELO(&'a str), + MAIL(&'a str), + RCPT(&'a str), DATA, QUIT, } -impl TryFrom<&str> for Command { +impl<'a> TryFrom<&'a str> for Command<'a> { type Error = anyhow::Error; - fn try_from(value: &str) -> std::result::Result<Self, Self::Error> { + fn try_from(value: &'a str) -> std::result::Result<Self, Self::Error> { if value.len() >= 5 && value.to_lowercase().starts_with("helo ") { - return Ok(Command::HELO(String::from(&value[5..]))); + return Ok(Command::HELO(&value[5..])); } if value.len() >= 11 @@ -274,13 +272,13 @@ impl TryFrom<&str> for Command { && value.contains('>') { let from = &value[11..value.find('>').unwrap()]; - return Ok(Command::MAIL(String::from(from))); + return Ok(Command::MAIL(from)); } if value.len() >= 9 && value.to_lowercase().starts_with("rcpt to:<") && value.contains('>') { let to = &value[9..value.find('>').unwrap()]; - return Ok(Command::RCPT(String::from(to))); + return Ok(Command::RCPT(to)); } if value.to_lowercase().starts_with("data") { |
