Skip to content

Commit efd78e3

Browse files
committed
Housekeeping
1 parent 56fea74 commit efd78e3

14 files changed

Lines changed: 242 additions & 282 deletions

File tree

Cargo.lock

Lines changed: 5 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/slipstream-client/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ slipstream-dns = { path = "../slipstream-dns" }
1717
slipstream-ffi = { path = "../slipstream-ffi" }
1818
tokio = { version = "1.37", features = ["io-util", "macros", "net", "rt", "sync", "time"] }
1919
tracing = { workspace = true }
20-
tracing-subscriber = { workspace = true }
2120

2221
[features]
2322
default = []

crates/slipstream-client/src/main.rs

Lines changed: 53 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ mod streams;
77

88
use clap::{parser::ValueSource, ArgGroup, CommandFactory, FromArgMatches, Parser};
99
use slipstream_core::{
10+
cli::{exit_with_error, exit_with_message, init_logging, unwrap_or_exit},
1011
normalize_domain, parse_host_port, parse_host_port_parts, sip003, AddressKind, HostPort,
1112
};
1213
use slipstream_ffi::{ClientConfig, ResolverMode, ResolverSpec};
1314
use tokio::runtime::Builder;
14-
use tracing_subscriber::EnvFilter;
1515

1616
use runtime::run_client;
1717

@@ -64,96 +64,89 @@ fn main() {
6464
init_logging();
6565
let matches = Args::command().get_matches();
6666
let args = Args::from_arg_matches(&matches).unwrap_or_else(|err| err.exit());
67-
let sip003_env = sip003::read_sip003_env().unwrap_or_else(|err| {
68-
tracing::error!("SIP003 env error: {}", err);
69-
std::process::exit(2);
70-
});
67+
let sip003_env = unwrap_or_exit(sip003::read_sip003_env(), "SIP003 env error", 2);
7168
if sip003_env.is_present() {
7269
tracing::info!("SIP003 env detected; applying SS_* overrides with CLI precedence");
7370
}
7471

7572
let tcp_listen_host_provided = cli_provided(&matches, "tcp_listen_host");
7673
let tcp_listen_port_provided = cli_provided(&matches, "tcp_listen_port");
77-
let (tcp_listen_host, tcp_listen_port) = sip003::select_host_port(
78-
&args.tcp_listen_host,
79-
args.tcp_listen_port,
80-
tcp_listen_host_provided,
81-
tcp_listen_port_provided,
82-
sip003_env.local_host.as_deref(),
83-
sip003_env.local_port.as_deref(),
84-
"SS_LOCAL",
85-
)
86-
.unwrap_or_else(|err| {
87-
tracing::error!("SIP003 env error: {}", err);
88-
std::process::exit(2);
89-
});
74+
let (tcp_listen_host, tcp_listen_port) = unwrap_or_exit(
75+
sip003::select_host_port(
76+
&args.tcp_listen_host,
77+
args.tcp_listen_port,
78+
tcp_listen_host_provided,
79+
tcp_listen_port_provided,
80+
sip003_env.local_host.as_deref(),
81+
sip003_env.local_port.as_deref(),
82+
"SS_LOCAL",
83+
),
84+
"SIP003 env error",
85+
2,
86+
);
9087

9188
let domain = if let Some(domain) = args.domain.clone() {
9289
domain
9390
} else {
94-
let option_domain = parse_domain_option(&sip003_env.plugin_options).unwrap_or_else(|err| {
95-
tracing::error!("SIP003 env error: {}", err);
96-
std::process::exit(2);
97-
});
91+
let option_domain = unwrap_or_exit(
92+
parse_domain_option(&sip003_env.plugin_options),
93+
"SIP003 env error",
94+
2,
95+
);
9896
if let Some(domain) = option_domain {
9997
domain
10098
} else {
101-
tracing::error!("A domain is required");
102-
std::process::exit(2);
99+
exit_with_message("A domain is required", 2);
103100
}
104101
};
105102

106103
let cli_has_resolvers = has_cli_resolvers(&matches);
107104
let resolvers = if cli_has_resolvers {
108-
build_resolvers(&matches, true).unwrap_or_else(|err| {
109-
tracing::error!("Resolver error: {}", err);
110-
std::process::exit(2);
111-
})
105+
unwrap_or_exit(build_resolvers(&matches, true), "Resolver error", 2)
112106
} else {
113-
let resolver_options = parse_resolvers_from_options(&sip003_env.plugin_options)
114-
.unwrap_or_else(|err| {
115-
tracing::error!("SIP003 env error: {}", err);
116-
std::process::exit(2);
117-
});
107+
let resolver_options = unwrap_or_exit(
108+
parse_resolvers_from_options(&sip003_env.plugin_options),
109+
"SIP003 env error",
110+
2,
111+
);
118112
if !resolver_options.resolvers.is_empty() {
119113
resolver_options.resolvers
120114
} else {
121-
let sip003_remote = sip003::parse_endpoint(
122-
sip003_env.remote_host.as_deref(),
123-
sip003_env.remote_port.as_deref(),
124-
"SS_REMOTE",
125-
)
126-
.unwrap_or_else(|err| {
127-
tracing::error!("SIP003 env error: {}", err);
128-
std::process::exit(2);
129-
});
115+
let sip003_remote = unwrap_or_exit(
116+
sip003::parse_endpoint(
117+
sip003_env.remote_host.as_deref(),
118+
sip003_env.remote_port.as_deref(),
119+
"SS_REMOTE",
120+
),
121+
"SIP003 env error",
122+
2,
123+
);
130124
if let Some(endpoint) = &sip003_remote {
131125
let mode = if resolver_options.authoritative_remote {
132126
ResolverMode::Authoritative
133127
} else {
134128
ResolverMode::Recursive
135129
};
136-
let resolver =
137-
parse_host_port_parts(&endpoint.host, endpoint.port, AddressKind::Resolver)
138-
.unwrap_or_else(|err| {
139-
tracing::error!("SIP003 env error: {}", err);
140-
std::process::exit(2);
141-
});
130+
let resolver = unwrap_or_exit(
131+
parse_host_port_parts(&endpoint.host, endpoint.port, AddressKind::Resolver),
132+
"SIP003 env error",
133+
2,
134+
);
142135
vec![ResolverSpec { resolver, mode }]
143136
} else {
144-
tracing::error!("At least one resolver is required");
145-
std::process::exit(2);
137+
exit_with_message("At least one resolver is required", 2);
146138
}
147139
}
148140
};
149141

150142
let congestion_control = if args.congestion_control.is_some() {
151143
args.congestion_control.clone()
152144
} else {
153-
parse_congestion_control(&sip003_env.plugin_options).unwrap_or_else(|err| {
154-
tracing::error!("SIP003 env error: {}", err);
155-
std::process::exit(2);
156-
})
145+
unwrap_or_exit(
146+
parse_congestion_control(&sip003_env.plugin_options),
147+
"SIP003 env error",
148+
2,
149+
)
157150
};
158151

159152
let cert = if args.cert.is_some() {
@@ -170,11 +163,11 @@ fn main() {
170163
let keep_alive_interval = if cli_provided(&matches, "keep_alive_interval") {
171164
args.keep_alive_interval
172165
} else {
173-
let keep_alive_override = parse_keep_alive_interval(&sip003_env.plugin_options)
174-
.unwrap_or_else(|err| {
175-
tracing::error!("SIP003 env error: {}", err);
176-
std::process::exit(2);
177-
});
166+
let keep_alive_override = unwrap_or_exit(
167+
parse_keep_alive_interval(&sip003_env.plugin_options),
168+
"SIP003 env error",
169+
2,
170+
);
178171
keep_alive_override.unwrap_or(args.keep_alive_interval)
179172
};
180173

@@ -198,22 +191,10 @@ fn main() {
198191
.expect("Failed to build Tokio runtime");
199192
match runtime.block_on(run_client(&config)) {
200193
Ok(code) => std::process::exit(code),
201-
Err(err) => {
202-
tracing::error!("Client error: {}", err);
203-
std::process::exit(1);
204-
}
194+
Err(err) => exit_with_error("Client error", err, 1),
205195
}
206196
}
207197

208-
fn init_logging() {
209-
let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
210-
let _ = tracing_subscriber::fmt()
211-
.with_env_filter(filter)
212-
.with_target(false)
213-
.without_time()
214-
.try_init();
215-
}
216-
217198
fn parse_domain(input: &str) -> Result<String, String> {
218199
normalize_domain(input).map_err(|err| err.to_string())
219200
}

crates/slipstream-client/src/runtime/setup.rs

Lines changed: 6 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
use crate::error::ClientError;
2-
use socket2::{Domain, Protocol, SockAddr, Socket, Type};
2+
use slipstream_core::net::{bind_first_resolved, bind_tcp_listener_addr, bind_udp_socket_addr};
33
use std::net::{Ipv6Addr, SocketAddr, SocketAddrV6};
4-
use tokio::net::{lookup_host, TcpListener as TokioTcpListener, UdpSocket as TokioUdpSocket};
5-
use tracing::warn;
4+
use tokio::net::{TcpListener as TokioTcpListener, UdpSocket as TokioUdpSocket};
65

76
pub(crate) fn compute_mtu(domain_len: usize) -> Result<u32, ClientError> {
87
if domain_len >= 240 {
@@ -21,77 +20,16 @@ pub(crate) fn compute_mtu(domain_len: usize) -> Result<u32, ClientError> {
2120

2221
pub(crate) async fn bind_udp_socket() -> Result<TokioUdpSocket, ClientError> {
2322
let bind_addr = SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::UNSPECIFIED, 0, 0, 0));
24-
bind_udp_socket_addr(bind_addr)
23+
bind_udp_socket_addr(bind_addr, "UDP socket").map_err(map_io)
2524
}
2625

2726
pub(crate) async fn bind_tcp_listener(
2827
host: &str,
2928
port: u16,
3029
) -> Result<TokioTcpListener, ClientError> {
31-
let addrs: Vec<SocketAddr> = lookup_host((host, port)).await.map_err(map_io)?.collect();
32-
if addrs.is_empty() {
33-
return Err(ClientError::new(format!(
34-
"No addresses resolved for {}:{}",
35-
host, port
36-
)));
37-
}
38-
let mut last_err = None;
39-
for addr in addrs {
40-
match bind_tcp_listener_addr(addr) {
41-
Ok(listener) => return Ok(listener),
42-
Err(err) => last_err = Some(err),
43-
}
44-
}
45-
Err(last_err.unwrap_or_else(|| {
46-
ClientError::new(format!("Failed to bind TCP listener on {}:{}", host, port))
47-
}))
48-
}
49-
50-
fn bind_tcp_listener_addr(addr: SocketAddr) -> Result<TokioTcpListener, ClientError> {
51-
let domain = match addr {
52-
SocketAddr::V4(_) => Domain::IPV4,
53-
SocketAddr::V6(_) => Domain::IPV6,
54-
};
55-
let socket = Socket::new(domain, Type::STREAM, Some(Protocol::TCP)).map_err(map_io)?;
56-
#[cfg(not(windows))]
57-
if let Err(err) = socket.set_reuse_address(true) {
58-
warn!("Failed to enable SO_REUSEADDR on {}: {}", addr, err);
59-
}
60-
if let SocketAddr::V6(_) = addr {
61-
if let Err(err) = socket.set_only_v6(false) {
62-
warn!(
63-
"Failed to enable dual-stack TCP listener on {}: {}",
64-
addr, err
65-
);
66-
}
67-
}
68-
let sock_addr = SockAddr::from(addr);
69-
socket.bind(&sock_addr).map_err(map_io)?;
70-
socket.listen(1024).map_err(map_io)?;
71-
socket.set_nonblocking(true).map_err(map_io)?;
72-
let std_listener: std::net::TcpListener = socket.into();
73-
TokioTcpListener::from_std(std_listener).map_err(map_io)
74-
}
75-
76-
fn bind_udp_socket_addr(addr: SocketAddr) -> Result<TokioUdpSocket, ClientError> {
77-
let domain = match addr {
78-
SocketAddr::V4(_) => Domain::IPV4,
79-
SocketAddr::V6(_) => Domain::IPV6,
80-
};
81-
let socket = Socket::new(domain, Type::DGRAM, Some(Protocol::UDP)).map_err(map_io)?;
82-
if let SocketAddr::V6(_) = addr {
83-
if let Err(err) = socket.set_only_v6(false) {
84-
warn!(
85-
"Failed to enable dual-stack UDP socket on {}: {}",
86-
addr, err
87-
);
88-
}
89-
}
90-
let sock_addr = SockAddr::from(addr);
91-
socket.bind(&sock_addr).map_err(map_io)?;
92-
socket.set_nonblocking(true).map_err(map_io)?;
93-
let std_socket: std::net::UdpSocket = socket.into();
94-
TokioUdpSocket::from_std(std_socket).map_err(map_io)
30+
bind_first_resolved(host, port, bind_tcp_listener_addr, "TCP listener")
31+
.await
32+
.map_err(map_io)
9533
}
9634

9735
pub(crate) fn map_io(err: std::io::Error) -> ClientError {

crates/slipstream-core/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ readme = "../../README.md"
99

1010
[dependencies]
1111
libc = "0.2"
12+
socket2 = "0.6"
13+
tokio = { version = "1.37", features = ["net"] }
14+
tracing = { workspace = true }
15+
tracing-subscriber = { workspace = true }
1216

1317
[features]
1418
default = []

crates/slipstream-core/src/cli.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
use std::fmt::Display;
2+
use tracing_subscriber::EnvFilter;
3+
4+
pub fn init_logging() {
5+
let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
6+
let _ = tracing_subscriber::fmt()
7+
.with_env_filter(filter)
8+
.with_target(false)
9+
.without_time()
10+
.try_init();
11+
}
12+
13+
pub fn unwrap_or_exit<T, E>(result: Result<T, E>, context: &str, code: i32) -> T
14+
where
15+
E: Display,
16+
{
17+
result.unwrap_or_else(|err| exit_with_error(context, err, code))
18+
}
19+
20+
pub fn exit_with_error(context: &str, err: impl Display, code: i32) -> ! {
21+
tracing::error!("{}: {}", context, err);
22+
std::process::exit(code);
23+
}
24+
25+
pub fn exit_with_message(message: &str, code: i32) -> ! {
26+
tracing::error!("{}", message);
27+
std::process::exit(code);
28+
}

crates/slipstream-core/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::fmt;
22

3+
pub mod cli;
34
pub mod flow_control;
45
pub mod invariants;
56
mod macros;

0 commit comments

Comments
 (0)