Skip to content

Commit edd807c

Browse files
Merge pull request #12 from quackitsquinn/socket-config
Add Socket config
2 parents 857cc0b + f99697e commit edd807c

File tree

4 files changed

+113
-10
lines changed

4 files changed

+113
-10
lines changed

lazuli_core/src/client/client.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ use log::trace;
99

1010
use crate::{hash_type_id, stream::Stream, ArcMutex, Result, Sendable};
1111

12-
use super::{connector::StreamConnector, input, listener::SocketListener, StreamCollection};
12+
use super::{
13+
config::SocketConfig, connector::StreamConnector, input, listener::SocketListener,
14+
StreamCollection,
15+
};
1316
/// A client for sending and receiving data.
1417
pub struct Client {
1518
socket: ArcMutex<TcpStream>,
@@ -55,6 +58,12 @@ impl Client {
5558
))
5659
}
5760

61+
/// Applies the configuration to the socket.
62+
pub fn with_config(self, config: &SocketConfig) -> Result<Self> {
63+
config.apply_stream(&mut self.socket.lock().unwrap())?;
64+
Ok(self)
65+
}
66+
5867
/// Sends data to the socket.
5968
#[inline]
6069
pub fn send<T>(&mut self, data: &T) -> Result<()>

lazuli_core/src/client/config.rs

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/// Config flags for the underlying socket of a client.
2+
pub struct SocketConfig {
3+
/// Whether the socket should be blocking.
4+
pub blocking: Option<bool>,
5+
/// The read timeout for the socket.
6+
pub read_timeout: Option<std::time::Duration>,
7+
/// The write timeout for the socket.
8+
pub write_timeout: Option<std::time::Duration>,
9+
/// The time-to-live for the socket.
10+
pub ttl: Option<u32>,
11+
/// Whether the socket should have the Nagle algorithm disabled
12+
pub nodelay: Option<bool>,
13+
}
14+
15+
impl Default for SocketConfig {
16+
fn default() -> Self {
17+
Self {
18+
blocking: None,
19+
read_timeout: None,
20+
write_timeout: None,
21+
ttl: None,
22+
nodelay: None,
23+
}
24+
}
25+
}
26+
27+
impl SocketConfig {
28+
/// Creates a new `SocketConfig` with all fields set to `None`.
29+
/// This is equivalent to `SocketConfig::default()`.
30+
pub fn new() -> Self {
31+
Self::default()
32+
}
33+
34+
/// Applies the configuration to the given socket. Any fields that are `None` are ignored.
35+
pub fn apply_stream(&self, socket: &std::net::TcpStream) -> std::io::Result<()> {
36+
if let Some(blocking) = self.blocking {
37+
socket.set_nonblocking(!blocking)?;
38+
}
39+
if let Some(read_timeout) = self.read_timeout {
40+
socket.set_read_timeout(Some(read_timeout))?;
41+
}
42+
if let Some(write_timeout) = self.write_timeout {
43+
socket.set_write_timeout(Some(write_timeout))?;
44+
}
45+
if let Some(ttl) = self.ttl {
46+
socket.set_ttl(ttl)?;
47+
}
48+
if let Some(nodelay) = self.nodelay {
49+
socket.set_nodelay(nodelay)?;
50+
}
51+
Ok(())
52+
}
53+
54+
/// Applies the configuration to the given listener. Any fields that are `None` are ignored.
55+
pub fn apply_listener(&self, listener: &std::net::TcpListener) -> std::io::Result<()> {
56+
if let Some(blocking) = self.blocking {
57+
listener.set_nonblocking(!blocking)?;
58+
}
59+
if let Some(ttl) = self.ttl {
60+
listener.set_ttl(ttl)?;
61+
}
62+
Ok(())
63+
}
64+
65+
/// Sets the blocking flag for the socket.
66+
pub fn blocking(mut self, blocking: bool) -> Self {
67+
self.blocking = Some(blocking);
68+
self
69+
}
70+
71+
/// Sets the read timeout for the socket.
72+
pub fn read_timeout(mut self, read_timeout: std::time::Duration) -> Self {
73+
self.read_timeout = Some(read_timeout);
74+
self
75+
}
76+
77+
/// Sets the write timeout for the socket.
78+
pub fn write_timeout(mut self, write_timeout: std::time::Duration) -> Self {
79+
self.write_timeout = Some(write_timeout);
80+
self
81+
}
82+
83+
/// Sets the time-to-live for the socket.
84+
pub fn ttl(mut self, ttl: u32) -> Self {
85+
self.ttl = Some(ttl);
86+
self
87+
}
88+
89+
/// Sets the nodelay flag for the socket.
90+
pub fn nodelay(mut self, nodelay: bool) -> Self {
91+
self.nodelay = Some(nodelay);
92+
self
93+
}
94+
}

lazuli_core/src/client/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
mod client;
2+
mod config;
23
mod connector;
34
mod input;
45
mod listener;

lazuli_core/src/client/server.rs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ use std::{
55

66
use crate::{ArcMutex, Client, Result, Sendable};
77

8+
use super::config::{self, SocketConfig};
9+
810
pub struct Server {
911
listener: TcpListener,
1012
streams: Vec<ArcMutex<Client>>,
@@ -19,14 +21,10 @@ impl Server {
1921
streams: vec![],
2022
})
2123
}
22-
/// Creates a new non-blocking server.
23-
pub fn new_nonblocking<T: ToSocketAddrs>(addrs: T) -> Result<Self> {
24-
let listener = TcpListener::bind(addrs)?;
25-
listener.set_nonblocking(true)?;
26-
Ok(Server {
27-
listener,
28-
streams: vec![],
29-
})
24+
/// Adds a configuration to the server.
25+
pub fn with_config(self, config: SocketConfig) -> Result<Self> {
26+
config.apply_listener(&self.listener)?;
27+
Ok(self)
3028
}
3129
/// Accepts a connection.
3230
pub fn accept(&mut self) -> Result<ArcMutex<Client>> {
@@ -116,7 +114,8 @@ mod test {
116114
}
117115
#[test]
118116
fn test_nonblocking_server() -> Result<()> {
119-
let mut server = Server::new_nonblocking((Ipv4Addr::LOCALHOST, 0))?;
117+
let mut server = Server::new((Ipv4Addr::LOCALHOST, 0))?
118+
.with_config(SocketConfig::new().blocking(false))?;
120119
assert!(server.accept().is_err());
121120
if let Err(e) = server.accept() {
122121
assert_eq!(e.kind(), std::io::ErrorKind::WouldBlock);

0 commit comments

Comments
 (0)