itsi 0.1.0 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Cargo.lock +524 -44
- data/Rakefile +22 -33
- data/crates/itsi_error/Cargo.toml +2 -0
- data/crates/itsi_error/src/from.rs +70 -0
- data/crates/itsi_error/src/lib.rs +10 -37
- data/crates/itsi_instrument_entry/Cargo.toml +15 -0
- data/crates/itsi_instrument_entry/src/lib.rs +31 -0
- data/crates/itsi_rb_helpers/Cargo.toml +2 -0
- data/crates/itsi_rb_helpers/src/heap_value.rs +121 -0
- data/crates/itsi_rb_helpers/src/lib.rs +90 -10
- data/crates/itsi_scheduler/Cargo.toml +9 -1
- data/crates/itsi_scheduler/extconf.rb +1 -1
- data/crates/itsi_scheduler/src/itsi_scheduler/io_helpers.rs +56 -0
- data/crates/itsi_scheduler/src/itsi_scheduler/io_waiter.rs +44 -0
- data/crates/itsi_scheduler/src/itsi_scheduler/timer.rs +44 -0
- data/crates/itsi_scheduler/src/itsi_scheduler.rs +308 -0
- data/crates/itsi_scheduler/src/lib.rs +31 -10
- data/crates/itsi_server/Cargo.toml +14 -2
- data/crates/itsi_server/extconf.rb +1 -1
- data/crates/itsi_server/src/body_proxy/big_bytes.rs +104 -0
- data/crates/itsi_server/src/body_proxy/itsi_body_proxy.rs +122 -0
- data/crates/itsi_server/src/body_proxy/mod.rs +2 -0
- data/crates/itsi_server/src/lib.rs +58 -7
- data/crates/itsi_server/src/request/itsi_request.rs +238 -104
- data/crates/itsi_server/src/response/itsi_response.rs +347 -0
- data/crates/itsi_server/src/response/mod.rs +1 -0
- data/crates/itsi_server/src/server/bind.rs +50 -20
- data/crates/itsi_server/src/server/bind_protocol.rs +37 -0
- data/crates/itsi_server/src/server/io_stream.rs +104 -0
- data/crates/itsi_server/src/server/itsi_ca/itsi_ca.crt +11 -30
- data/crates/itsi_server/src/server/itsi_ca/itsi_ca.key +3 -50
- data/crates/itsi_server/src/server/itsi_server.rs +196 -134
- data/crates/itsi_server/src/server/lifecycle_event.rs +9 -0
- data/crates/itsi_server/src/server/listener.rs +184 -127
- data/crates/itsi_server/src/server/mod.rs +7 -1
- data/crates/itsi_server/src/server/process_worker.rs +196 -0
- data/crates/itsi_server/src/server/serve_strategy/cluster_mode.rs +254 -0
- data/crates/itsi_server/src/server/serve_strategy/mod.rs +27 -0
- data/crates/itsi_server/src/server/serve_strategy/single_mode.rs +241 -0
- data/crates/itsi_server/src/server/signal.rs +70 -0
- data/crates/itsi_server/src/server/thread_worker.rs +368 -0
- data/crates/itsi_server/src/server/tls.rs +42 -28
- data/crates/itsi_tracing/Cargo.toml +4 -0
- data/crates/itsi_tracing/src/lib.rs +36 -6
- data/gems/scheduler/Cargo.lock +219 -23
- data/gems/scheduler/Rakefile +7 -1
- data/gems/scheduler/ext/itsi_error/Cargo.toml +2 -0
- data/gems/scheduler/ext/itsi_error/src/from.rs +70 -0
- data/gems/scheduler/ext/itsi_error/src/lib.rs +10 -37
- data/gems/scheduler/ext/itsi_instrument_entry/Cargo.toml +15 -0
- data/gems/scheduler/ext/itsi_instrument_entry/src/lib.rs +31 -0
- data/gems/scheduler/ext/itsi_rb_helpers/Cargo.toml +2 -0
- data/gems/scheduler/ext/itsi_rb_helpers/src/heap_value.rs +121 -0
- data/gems/scheduler/ext/itsi_rb_helpers/src/lib.rs +90 -10
- data/gems/scheduler/ext/itsi_scheduler/Cargo.toml +9 -1
- data/gems/scheduler/ext/itsi_scheduler/extconf.rb +1 -1
- data/gems/scheduler/ext/itsi_scheduler/src/itsi_scheduler/io_helpers.rs +56 -0
- data/gems/scheduler/ext/itsi_scheduler/src/itsi_scheduler/io_waiter.rs +44 -0
- data/gems/scheduler/ext/itsi_scheduler/src/itsi_scheduler/timer.rs +44 -0
- data/gems/scheduler/ext/itsi_scheduler/src/itsi_scheduler.rs +308 -0
- data/gems/scheduler/ext/itsi_scheduler/src/lib.rs +31 -10
- data/gems/scheduler/ext/itsi_server/Cargo.toml +41 -0
- data/gems/scheduler/ext/itsi_server/extconf.rb +6 -0
- data/gems/scheduler/ext/itsi_server/src/body_proxy/big_bytes.rs +104 -0
- data/gems/scheduler/ext/itsi_server/src/body_proxy/itsi_body_proxy.rs +122 -0
- data/gems/scheduler/ext/itsi_server/src/body_proxy/mod.rs +2 -0
- data/gems/scheduler/ext/itsi_server/src/lib.rs +103 -0
- data/gems/scheduler/ext/itsi_server/src/request/itsi_request.rs +277 -0
- data/gems/scheduler/ext/itsi_server/src/request/mod.rs +1 -0
- data/gems/scheduler/ext/itsi_server/src/response/itsi_response.rs +347 -0
- data/gems/scheduler/ext/itsi_server/src/response/mod.rs +1 -0
- data/gems/scheduler/ext/itsi_server/src/server/bind.rs +168 -0
- data/gems/scheduler/ext/itsi_server/src/server/bind_protocol.rs +37 -0
- data/gems/scheduler/ext/itsi_server/src/server/io_stream.rs +104 -0
- data/gems/scheduler/ext/itsi_server/src/server/itsi_ca/itsi_ca.crt +13 -0
- data/gems/scheduler/ext/itsi_server/src/server/itsi_ca/itsi_ca.key +5 -0
- data/gems/scheduler/ext/itsi_server/src/server/itsi_server.rs +244 -0
- data/gems/scheduler/ext/itsi_server/src/server/lifecycle_event.rs +9 -0
- data/gems/scheduler/ext/itsi_server/src/server/listener.rs +275 -0
- data/gems/scheduler/ext/itsi_server/src/server/mod.rs +11 -0
- data/gems/scheduler/ext/itsi_server/src/server/process_worker.rs +196 -0
- data/gems/scheduler/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +254 -0
- data/gems/scheduler/ext/itsi_server/src/server/serve_strategy/mod.rs +27 -0
- data/gems/scheduler/ext/itsi_server/src/server/serve_strategy/single_mode.rs +241 -0
- data/gems/scheduler/ext/itsi_server/src/server/signal.rs +70 -0
- data/gems/scheduler/ext/itsi_server/src/server/thread_worker.rs +368 -0
- data/gems/scheduler/ext/itsi_server/src/server/tls.rs +152 -0
- data/gems/scheduler/ext/itsi_tracing/Cargo.toml +4 -0
- data/gems/scheduler/ext/itsi_tracing/src/lib.rs +36 -6
- data/gems/scheduler/itsi-scheduler.gemspec +2 -3
- data/gems/scheduler/lib/itsi/scheduler/version.rb +1 -1
- data/gems/scheduler/lib/itsi/scheduler.rb +137 -1
- data/gems/scheduler/test/helpers/test_helper.rb +24 -0
- data/gems/scheduler/test/test_active_record.rb +158 -0
- data/gems/scheduler/test/test_address_resolve.rb +23 -0
- data/gems/scheduler/test/test_block_unblock.rb +229 -0
- data/gems/scheduler/test/test_file_io.rb +193 -0
- data/gems/scheduler/test/test_itsi_scheduler.rb +24 -1
- data/gems/scheduler/test/test_kernel_sleep.rb +91 -0
- data/gems/scheduler/test/test_nested_fibers.rb +286 -0
- data/gems/scheduler/test/test_network_io.rb +274 -0
- data/gems/scheduler/test/test_process_wait.rb +26 -0
- data/gems/server/exe/itsi +88 -28
- data/gems/server/ext/itsi_error/Cargo.toml +2 -0
- data/gems/server/ext/itsi_error/src/from.rs +70 -0
- data/gems/server/ext/itsi_error/src/lib.rs +10 -37
- data/gems/server/ext/itsi_instrument_entry/Cargo.toml +15 -0
- data/gems/server/ext/itsi_instrument_entry/src/lib.rs +31 -0
- data/gems/server/ext/itsi_rb_helpers/Cargo.toml +2 -0
- data/gems/server/ext/itsi_rb_helpers/src/heap_value.rs +121 -0
- data/gems/server/ext/itsi_rb_helpers/src/lib.rs +90 -10
- data/gems/server/ext/itsi_scheduler/Cargo.toml +24 -0
- data/gems/server/ext/itsi_scheduler/extconf.rb +6 -0
- data/gems/server/ext/itsi_scheduler/src/itsi_scheduler/io_helpers.rs +56 -0
- data/gems/server/ext/itsi_scheduler/src/itsi_scheduler/io_waiter.rs +44 -0
- data/gems/server/ext/itsi_scheduler/src/itsi_scheduler/timer.rs +44 -0
- data/gems/server/ext/itsi_scheduler/src/itsi_scheduler.rs +308 -0
- data/gems/server/ext/itsi_scheduler/src/lib.rs +38 -0
- data/gems/server/ext/itsi_server/Cargo.toml +14 -2
- data/gems/server/ext/itsi_server/extconf.rb +1 -1
- data/gems/server/ext/itsi_server/src/body_proxy/big_bytes.rs +104 -0
- data/gems/server/ext/itsi_server/src/body_proxy/itsi_body_proxy.rs +122 -0
- data/gems/server/ext/itsi_server/src/body_proxy/mod.rs +2 -0
- data/gems/server/ext/itsi_server/src/lib.rs +58 -7
- data/gems/server/ext/itsi_server/src/request/itsi_request.rs +238 -104
- data/gems/server/ext/itsi_server/src/response/itsi_response.rs +347 -0
- data/gems/server/ext/itsi_server/src/response/mod.rs +1 -0
- data/gems/server/ext/itsi_server/src/server/bind.rs +50 -20
- data/gems/server/ext/itsi_server/src/server/bind_protocol.rs +37 -0
- data/gems/server/ext/itsi_server/src/server/io_stream.rs +104 -0
- data/gems/server/ext/itsi_server/src/server/itsi_ca/itsi_ca.crt +11 -30
- data/gems/server/ext/itsi_server/src/server/itsi_ca/itsi_ca.key +3 -50
- data/gems/server/ext/itsi_server/src/server/itsi_server.rs +196 -134
- data/gems/server/ext/itsi_server/src/server/lifecycle_event.rs +9 -0
- data/gems/server/ext/itsi_server/src/server/listener.rs +184 -127
- data/gems/server/ext/itsi_server/src/server/mod.rs +7 -1
- data/gems/server/ext/itsi_server/src/server/process_worker.rs +196 -0
- data/gems/server/ext/itsi_server/src/server/serve_strategy/cluster_mode.rs +254 -0
- data/gems/server/ext/itsi_server/src/server/serve_strategy/mod.rs +27 -0
- data/gems/server/ext/itsi_server/src/server/serve_strategy/single_mode.rs +241 -0
- data/gems/server/ext/itsi_server/src/server/signal.rs +70 -0
- data/gems/server/ext/itsi_server/src/server/thread_worker.rs +368 -0
- data/gems/server/ext/itsi_server/src/server/tls.rs +42 -28
- data/gems/server/ext/itsi_tracing/Cargo.toml +4 -0
- data/gems/server/ext/itsi_tracing/src/lib.rs +36 -6
- data/gems/server/itsi-server.gemspec +4 -5
- data/gems/server/lib/itsi/request.rb +30 -14
- data/gems/server/lib/itsi/server/rack/handler/itsi.rb +25 -0
- data/gems/server/lib/itsi/server/scheduler_mode.rb +6 -0
- data/gems/server/lib/itsi/server/version.rb +1 -1
- data/gems/server/lib/itsi/server.rb +82 -2
- data/gems/server/lib/itsi/signals.rb +23 -0
- data/gems/server/lib/itsi/stream_io.rb +38 -0
- data/gems/server/test/test_helper.rb +2 -0
- data/gems/server/test/test_itsi_server.rb +1 -1
- data/lib/itsi/version.rb +1 -1
- data/tasks.txt +18 -0
- metadata +102 -12
- data/crates/itsi_server/src/server/transfer_protocol.rs +0 -23
- data/crates/itsi_server/src/stream_writer/mod.rs +0 -21
- data/gems/scheduler/test/test_helper.rb +0 -6
- data/gems/server/ext/itsi_server/src/server/transfer_protocol.rs +0 -23
- data/gems/server/ext/itsi_server/src/stream_writer/mod.rs +0 -21
@@ -0,0 +1,244 @@
|
|
1
|
+
use super::{
|
2
|
+
bind::Bind,
|
3
|
+
listener::Listener,
|
4
|
+
serve_strategy::{cluster_mode::ClusterMode, single_mode::SingleMode},
|
5
|
+
signal::{clear_signal_handlers, reset_signal_handlers, SIGNAL_HANDLER_CHANNEL},
|
6
|
+
};
|
7
|
+
use crate::{request::itsi_request::ItsiRequest, server::serve_strategy::ServeStrategy};
|
8
|
+
use derive_more::Debug;
|
9
|
+
use itsi_rb_helpers::call_without_gvl;
|
10
|
+
use itsi_tracing::error;
|
11
|
+
use magnus::{
|
12
|
+
block::Proc,
|
13
|
+
error::Result,
|
14
|
+
scan_args::{get_kwargs, scan_args, Args, KwArgs},
|
15
|
+
value::{InnerValue, Opaque, ReprValue},
|
16
|
+
RHash, Ruby, Symbol, Value,
|
17
|
+
};
|
18
|
+
use parking_lot::Mutex;
|
19
|
+
use std::{cmp::max, ops::Deref, sync::Arc};
|
20
|
+
use tracing::{info, instrument};
|
21
|
+
|
22
|
+
static DEFAULT_BIND: &str = "localhost:3000";
|
23
|
+
|
24
|
+
#[magnus::wrap(class = "Itsi::Server", free_immediately, size)]
|
25
|
+
#[derive(Clone)]
|
26
|
+
pub struct Server {
|
27
|
+
pub config: Arc<ServerConfig>,
|
28
|
+
}
|
29
|
+
|
30
|
+
impl Deref for Server {
|
31
|
+
type Target = ServerConfig;
|
32
|
+
|
33
|
+
fn deref(&self) -> &Self::Target {
|
34
|
+
&self.config
|
35
|
+
}
|
36
|
+
}
|
37
|
+
type AfterFork = Mutex<Arc<Option<Box<dyn Fn() + Send + Sync>>>>;
|
38
|
+
|
39
|
+
#[derive(Debug)]
|
40
|
+
pub struct ServerConfig {
|
41
|
+
#[debug(skip)]
|
42
|
+
pub app: Opaque<Value>,
|
43
|
+
#[allow(unused)]
|
44
|
+
pub workers: u8,
|
45
|
+
#[allow(unused)]
|
46
|
+
pub threads: u8,
|
47
|
+
#[allow(unused)]
|
48
|
+
pub shutdown_timeout: f64,
|
49
|
+
pub script_name: String,
|
50
|
+
pub(crate) binds: Mutex<Vec<Bind>>,
|
51
|
+
#[debug(skip)]
|
52
|
+
pub before_fork: Mutex<Option<Box<dyn FnOnce() + Send + Sync>>>,
|
53
|
+
#[debug(skip)]
|
54
|
+
pub after_fork: AfterFork,
|
55
|
+
pub scheduler_class: Option<String>,
|
56
|
+
pub stream_body: Option<bool>,
|
57
|
+
pub worker_memory_limit: Option<u64>,
|
58
|
+
}
|
59
|
+
|
60
|
+
#[derive(Debug)]
|
61
|
+
pub enum RequestJob {
|
62
|
+
ProcessRequest(ItsiRequest),
|
63
|
+
Shutdown,
|
64
|
+
}
|
65
|
+
|
66
|
+
impl Server {
|
67
|
+
#[instrument(
|
68
|
+
name = "Itsi",
|
69
|
+
parent=None,
|
70
|
+
skip(args),
|
71
|
+
fields(workers = 1, threads = 1, shutdown_timeout = 5)
|
72
|
+
)]
|
73
|
+
pub fn new(args: &[Value]) -> Result<Self> {
|
74
|
+
let scan_args: Args<(), (), (), (), RHash, ()> = scan_args(args)?;
|
75
|
+
|
76
|
+
type ArgSet1 = (
|
77
|
+
Option<u8>,
|
78
|
+
Option<u8>,
|
79
|
+
Option<f64>,
|
80
|
+
Option<String>,
|
81
|
+
Option<Vec<String>>,
|
82
|
+
Option<Proc>,
|
83
|
+
Option<Proc>,
|
84
|
+
Option<String>,
|
85
|
+
Option<bool>,
|
86
|
+
);
|
87
|
+
|
88
|
+
type ArgSet2 = (Option<u64>,);
|
89
|
+
|
90
|
+
let args1: KwArgs<(Value,), ArgSet1, ()> = get_kwargs(
|
91
|
+
scan_args
|
92
|
+
.keywords
|
93
|
+
.funcall::<_, _, RHash>(
|
94
|
+
"slice",
|
95
|
+
(
|
96
|
+
Symbol::new("app"),
|
97
|
+
Symbol::new("workers"),
|
98
|
+
Symbol::new("threads"),
|
99
|
+
Symbol::new("shutdown_timeout"),
|
100
|
+
Symbol::new("script_name"),
|
101
|
+
Symbol::new("binds"),
|
102
|
+
Symbol::new("before_fork"),
|
103
|
+
Symbol::new("after_fork"),
|
104
|
+
Symbol::new("scheduler_class"),
|
105
|
+
Symbol::new("stream_body"),
|
106
|
+
),
|
107
|
+
)
|
108
|
+
.unwrap(),
|
109
|
+
&["app"],
|
110
|
+
&[
|
111
|
+
"workers",
|
112
|
+
"threads",
|
113
|
+
"shutdown_timeout",
|
114
|
+
"script_name",
|
115
|
+
"binds",
|
116
|
+
"before_fork",
|
117
|
+
"after_fork",
|
118
|
+
"scheduler_class",
|
119
|
+
"stream_body",
|
120
|
+
],
|
121
|
+
)?;
|
122
|
+
|
123
|
+
let args2: KwArgs<(), ArgSet2, ()> = get_kwargs(
|
124
|
+
scan_args
|
125
|
+
.keywords
|
126
|
+
.funcall::<_, _, RHash>("slice", (Symbol::new("worker_memory_limit"),))
|
127
|
+
.unwrap(),
|
128
|
+
&[],
|
129
|
+
&["worker_memory_limit"],
|
130
|
+
)?;
|
131
|
+
|
132
|
+
let config = ServerConfig {
|
133
|
+
app: Opaque::from(args1.required.0),
|
134
|
+
workers: max(args1.optional.0.unwrap_or(1), 1),
|
135
|
+
threads: max(args1.optional.1.unwrap_or(1), 1),
|
136
|
+
shutdown_timeout: args1.optional.2.unwrap_or(5.0),
|
137
|
+
script_name: args1.optional.3.unwrap_or("".to_string()),
|
138
|
+
binds: Mutex::new(
|
139
|
+
args1
|
140
|
+
.optional
|
141
|
+
.4
|
142
|
+
.unwrap_or_else(|| vec![DEFAULT_BIND.to_string()])
|
143
|
+
.into_iter()
|
144
|
+
.map(|s| s.parse())
|
145
|
+
.collect::<itsi_error::Result<Vec<Bind>>>()?,
|
146
|
+
),
|
147
|
+
before_fork: Mutex::new(args1.optional.5.map(|p| {
|
148
|
+
let opaque_proc = Opaque::from(p);
|
149
|
+
Box::new(move || {
|
150
|
+
opaque_proc
|
151
|
+
.get_inner_with(&Ruby::get().unwrap())
|
152
|
+
.call::<_, Value>(())
|
153
|
+
.unwrap();
|
154
|
+
}) as Box<dyn FnOnce() + Send + Sync>
|
155
|
+
})),
|
156
|
+
after_fork: Mutex::new(Arc::new(args1.optional.6.map(|p| {
|
157
|
+
let opaque_proc = Opaque::from(p);
|
158
|
+
Box::new(move || {
|
159
|
+
opaque_proc
|
160
|
+
.get_inner_with(&Ruby::get().unwrap())
|
161
|
+
.call::<_, Value>(())
|
162
|
+
.unwrap();
|
163
|
+
}) as Box<dyn Fn() + Send + Sync>
|
164
|
+
}))),
|
165
|
+
scheduler_class: args1.optional.7.clone(),
|
166
|
+
stream_body: args1.optional.8,
|
167
|
+
worker_memory_limit: args2.optional.0,
|
168
|
+
};
|
169
|
+
|
170
|
+
if let Some(scheduler_class) = args1.optional.7 {
|
171
|
+
info!(scheduler_class, fiber_scheduler = true);
|
172
|
+
} else {
|
173
|
+
info!(fiber_scheduler = false);
|
174
|
+
}
|
175
|
+
|
176
|
+
Ok(Server {
|
177
|
+
config: Arc::new(config),
|
178
|
+
})
|
179
|
+
}
|
180
|
+
|
181
|
+
#[instrument(name = "Bind", skip_all, fields(binds=format!("{:?}", self.config.binds.lock())))]
|
182
|
+
pub(crate) fn listeners(&self) -> Result<Arc<Vec<Arc<Listener>>>> {
|
183
|
+
let listeners = self
|
184
|
+
.config
|
185
|
+
.binds
|
186
|
+
.lock()
|
187
|
+
.iter()
|
188
|
+
.cloned()
|
189
|
+
.map(Listener::try_from)
|
190
|
+
.collect::<std::result::Result<Vec<Listener>, _>>()?
|
191
|
+
.into_iter()
|
192
|
+
.map(Arc::new)
|
193
|
+
.collect::<Vec<_>>();
|
194
|
+
info!("Bound {:?} listeners", listeners.len());
|
195
|
+
Ok(Arc::new(listeners))
|
196
|
+
}
|
197
|
+
|
198
|
+
pub(crate) fn build_strategy(
|
199
|
+
self,
|
200
|
+
listeners: Arc<Vec<Arc<Listener>>>,
|
201
|
+
) -> Result<ServeStrategy> {
|
202
|
+
let server = Arc::new(self);
|
203
|
+
|
204
|
+
let strategy = if server.config.workers == 1 {
|
205
|
+
ServeStrategy::Single(Arc::new(SingleMode::new(
|
206
|
+
server,
|
207
|
+
listeners,
|
208
|
+
SIGNAL_HANDLER_CHANNEL.0.clone(),
|
209
|
+
)?))
|
210
|
+
} else {
|
211
|
+
ServeStrategy::Cluster(Arc::new(ClusterMode::new(
|
212
|
+
server,
|
213
|
+
listeners,
|
214
|
+
SIGNAL_HANDLER_CHANNEL.0.clone(),
|
215
|
+
)))
|
216
|
+
};
|
217
|
+
Ok(strategy)
|
218
|
+
}
|
219
|
+
|
220
|
+
pub fn start(&self) -> Result<()> {
|
221
|
+
reset_signal_handlers();
|
222
|
+
let rself = self.clone();
|
223
|
+
let listeners = self.listeners()?;
|
224
|
+
let listeners_clone = listeners.clone();
|
225
|
+
call_without_gvl(move || -> Result<()> {
|
226
|
+
let strategy = rself.build_strategy(listeners_clone)?;
|
227
|
+
if let Err(e) = strategy.run() {
|
228
|
+
error!("Error running server: {}", e);
|
229
|
+
strategy.stop()?;
|
230
|
+
}
|
231
|
+
drop(strategy);
|
232
|
+
Ok(())
|
233
|
+
})?;
|
234
|
+
if let Ok(listeners) = Arc::try_unwrap(listeners) {
|
235
|
+
listeners.into_iter().for_each(|listener| {
|
236
|
+
if let Ok(listener) = Arc::try_unwrap(listener) {
|
237
|
+
listener.unbind()
|
238
|
+
};
|
239
|
+
});
|
240
|
+
}
|
241
|
+
clear_signal_handlers();
|
242
|
+
Ok(())
|
243
|
+
}
|
244
|
+
}
|
@@ -0,0 +1,275 @@
|
|
1
|
+
use super::bind::{Bind, BindAddress};
|
2
|
+
use super::bind_protocol::BindProtocol;
|
3
|
+
use super::io_stream::IoStream;
|
4
|
+
use itsi_error::Result;
|
5
|
+
use itsi_tracing::info;
|
6
|
+
use socket2::{Domain, Protocol, Socket, Type};
|
7
|
+
use std::net::{IpAddr, SocketAddr, TcpListener};
|
8
|
+
use std::sync::Arc;
|
9
|
+
use std::{os::unix::net::UnixListener, path::PathBuf};
|
10
|
+
use tokio::net::TcpListener as TokioTcpListener;
|
11
|
+
use tokio::net::UnixListener as TokioUnixListener;
|
12
|
+
use tokio::net::{unix, TcpStream, UnixStream};
|
13
|
+
use tokio_rustls::TlsAcceptor;
|
14
|
+
|
15
|
+
pub(crate) enum Listener {
|
16
|
+
Tcp(TcpListener),
|
17
|
+
TcpTls((TcpListener, TlsAcceptor)),
|
18
|
+
Unix(UnixListener),
|
19
|
+
UnixTls((UnixListener, TlsAcceptor)),
|
20
|
+
}
|
21
|
+
|
22
|
+
pub(crate) enum TokioListener {
|
23
|
+
Tcp {
|
24
|
+
listener: TokioTcpListener,
|
25
|
+
host: String,
|
26
|
+
port: u16,
|
27
|
+
},
|
28
|
+
TcpTls {
|
29
|
+
listener: TokioTcpListener,
|
30
|
+
acceptor: TlsAcceptor,
|
31
|
+
host: String,
|
32
|
+
port: u16,
|
33
|
+
},
|
34
|
+
Unix {
|
35
|
+
listener: TokioUnixListener,
|
36
|
+
},
|
37
|
+
UnixTls {
|
38
|
+
listener: TokioUnixListener,
|
39
|
+
acceptor: TlsAcceptor,
|
40
|
+
},
|
41
|
+
}
|
42
|
+
|
43
|
+
impl TokioListener {
|
44
|
+
pub fn unbind(self) {
|
45
|
+
match self {
|
46
|
+
TokioListener::Tcp { listener, .. } => drop(listener.into_std().unwrap()),
|
47
|
+
TokioListener::TcpTls { listener, .. } => drop(listener.into_std().unwrap()),
|
48
|
+
TokioListener::Unix { listener } => drop(listener.into_std().unwrap()),
|
49
|
+
TokioListener::UnixTls { listener, .. } => drop(listener.into_std().unwrap()),
|
50
|
+
};
|
51
|
+
}
|
52
|
+
pub(crate) async fn accept(&self) -> Result<IoStream> {
|
53
|
+
match self {
|
54
|
+
TokioListener::Tcp { listener, .. } => TokioListener::accept_tcp(listener).await,
|
55
|
+
TokioListener::TcpTls {
|
56
|
+
listener, acceptor, ..
|
57
|
+
} => TokioListener::accept_tls(listener, acceptor).await,
|
58
|
+
TokioListener::Unix { listener, .. } => TokioListener::accept_unix(listener).await,
|
59
|
+
TokioListener::UnixTls {
|
60
|
+
listener, acceptor, ..
|
61
|
+
} => TokioListener::accept_unix_tls(listener, acceptor).await,
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
async fn accept_tcp(listener: &TokioTcpListener) -> Result<IoStream> {
|
66
|
+
let tcp_stream = listener.accept().await?;
|
67
|
+
Self::to_tokio_io(Stream::TcpStream(tcp_stream), None).await
|
68
|
+
}
|
69
|
+
|
70
|
+
async fn accept_tls(listener: &TokioTcpListener, acceptor: &TlsAcceptor) -> Result<IoStream> {
|
71
|
+
let tcp_stream = listener.accept().await?;
|
72
|
+
Self::to_tokio_io(Stream::TcpStream(tcp_stream), Some(acceptor)).await
|
73
|
+
}
|
74
|
+
|
75
|
+
async fn accept_unix(listener: &TokioUnixListener) -> Result<IoStream> {
|
76
|
+
let unix_stream = listener.accept().await?;
|
77
|
+
Self::to_tokio_io(Stream::UnixStream(unix_stream), None).await
|
78
|
+
}
|
79
|
+
|
80
|
+
async fn accept_unix_tls(
|
81
|
+
listener: &TokioUnixListener,
|
82
|
+
acceptor: &TlsAcceptor,
|
83
|
+
) -> Result<IoStream> {
|
84
|
+
let unix_stream = listener.accept().await?;
|
85
|
+
Self::to_tokio_io(Stream::UnixStream(unix_stream), Some(acceptor)).await
|
86
|
+
}
|
87
|
+
|
88
|
+
async fn to_tokio_io(
|
89
|
+
input_stream: Stream,
|
90
|
+
tls_acceptor: Option<&TlsAcceptor>,
|
91
|
+
) -> Result<IoStream> {
|
92
|
+
match tls_acceptor {
|
93
|
+
Some(acceptor) => match input_stream {
|
94
|
+
Stream::TcpStream((tcp_stream, socket_address)) => {
|
95
|
+
match acceptor.accept(tcp_stream).await {
|
96
|
+
Ok(tls_stream) => Ok(IoStream::TcpTls {
|
97
|
+
stream: tls_stream,
|
98
|
+
addr: SockAddr::Tcp(Arc::new(socket_address)),
|
99
|
+
}),
|
100
|
+
Err(err) => Err(err.into()),
|
101
|
+
}
|
102
|
+
}
|
103
|
+
Stream::UnixStream((unix_stream, socket_address)) => {
|
104
|
+
match acceptor.accept(unix_stream).await {
|
105
|
+
Ok(tls_stream) => Ok(IoStream::UnixTls {
|
106
|
+
stream: tls_stream,
|
107
|
+
addr: SockAddr::Unix(Arc::new(socket_address)),
|
108
|
+
}),
|
109
|
+
Err(err) => Err(err.into()),
|
110
|
+
}
|
111
|
+
}
|
112
|
+
},
|
113
|
+
None => match input_stream {
|
114
|
+
Stream::TcpStream((tcp_stream, socket_address)) => Ok(IoStream::Tcp {
|
115
|
+
stream: tcp_stream,
|
116
|
+
addr: SockAddr::Tcp(Arc::new(socket_address)),
|
117
|
+
}),
|
118
|
+
Stream::UnixStream((unix_stream, socket_address)) => Ok(IoStream::Unix {
|
119
|
+
stream: unix_stream,
|
120
|
+
addr: SockAddr::Unix(Arc::new(socket_address)),
|
121
|
+
}),
|
122
|
+
},
|
123
|
+
}
|
124
|
+
}
|
125
|
+
|
126
|
+
pub(crate) fn scheme(&self) -> String {
|
127
|
+
match self {
|
128
|
+
TokioListener::Tcp { .. } => "http".to_string(),
|
129
|
+
TokioListener::TcpTls { .. } => "https".to_string(),
|
130
|
+
TokioListener::Unix { .. } => "http".to_string(),
|
131
|
+
TokioListener::UnixTls { .. } => "https".to_string(),
|
132
|
+
}
|
133
|
+
}
|
134
|
+
|
135
|
+
pub(crate) fn port(&self) -> u16 {
|
136
|
+
match self {
|
137
|
+
TokioListener::Tcp { port, .. } => *port,
|
138
|
+
TokioListener::TcpTls { port, .. } => *port,
|
139
|
+
TokioListener::Unix { .. } => 0,
|
140
|
+
TokioListener::UnixTls { .. } => 0,
|
141
|
+
}
|
142
|
+
}
|
143
|
+
|
144
|
+
pub(crate) fn host(&self) -> String {
|
145
|
+
match self {
|
146
|
+
TokioListener::Tcp { host, .. } => host.to_string(),
|
147
|
+
TokioListener::TcpTls { host, .. } => host.to_string(),
|
148
|
+
TokioListener::Unix { .. } => "unix".to_string(),
|
149
|
+
TokioListener::UnixTls { .. } => "unix".to_string(),
|
150
|
+
}
|
151
|
+
}
|
152
|
+
}
|
153
|
+
|
154
|
+
enum Stream {
|
155
|
+
TcpStream((TcpStream, SocketAddr)),
|
156
|
+
UnixStream((UnixStream, unix::SocketAddr)),
|
157
|
+
}
|
158
|
+
|
159
|
+
#[derive(Clone, Debug)]
|
160
|
+
pub enum SockAddr {
|
161
|
+
Tcp(Arc<SocketAddr>),
|
162
|
+
Unix(Arc<unix::SocketAddr>),
|
163
|
+
}
|
164
|
+
impl std::fmt::Display for SockAddr {
|
165
|
+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
166
|
+
match self {
|
167
|
+
SockAddr::Tcp(socket_addr) => write!(f, "{}", socket_addr.ip().to_canonical()),
|
168
|
+
SockAddr::Unix(socket_addr) => match socket_addr.as_pathname() {
|
169
|
+
Some(path) => write!(f, "{:?}", path),
|
170
|
+
None => write!(f, ""),
|
171
|
+
},
|
172
|
+
}
|
173
|
+
}
|
174
|
+
}
|
175
|
+
|
176
|
+
impl Listener {
|
177
|
+
pub fn unbind(self) {
|
178
|
+
match self {
|
179
|
+
Listener::Tcp(listener) => drop(listener),
|
180
|
+
Listener::TcpTls((listener, _)) => drop(listener),
|
181
|
+
Listener::Unix(listener) => drop(listener),
|
182
|
+
Listener::UnixTls((listener, _)) => drop(listener),
|
183
|
+
};
|
184
|
+
}
|
185
|
+
pub fn to_tokio_listener(&self) -> TokioListener {
|
186
|
+
match self {
|
187
|
+
Listener::Tcp(listener) => TokioListener::Tcp {
|
188
|
+
listener: TokioTcpListener::from_std(TcpListener::try_clone(listener).unwrap())
|
189
|
+
.unwrap(),
|
190
|
+
host: listener
|
191
|
+
.local_addr()
|
192
|
+
.unwrap()
|
193
|
+
.ip()
|
194
|
+
.to_canonical()
|
195
|
+
.to_string(),
|
196
|
+
port: listener.local_addr().unwrap().port(),
|
197
|
+
},
|
198
|
+
Listener::TcpTls((listener, acceptor)) => TokioListener::TcpTls {
|
199
|
+
listener: TokioTcpListener::from_std(TcpListener::try_clone(listener).unwrap())
|
200
|
+
.unwrap(),
|
201
|
+
acceptor: acceptor.clone(),
|
202
|
+
host: listener
|
203
|
+
.local_addr()
|
204
|
+
.unwrap()
|
205
|
+
.ip()
|
206
|
+
.to_canonical()
|
207
|
+
.to_string(),
|
208
|
+
port: listener.local_addr().unwrap().port(),
|
209
|
+
},
|
210
|
+
Listener::Unix(listener) => TokioListener::Unix {
|
211
|
+
listener: TokioUnixListener::from_std(UnixListener::try_clone(listener).unwrap())
|
212
|
+
.unwrap(),
|
213
|
+
},
|
214
|
+
Listener::UnixTls((listener, acceptor)) => TokioListener::UnixTls {
|
215
|
+
listener: TokioUnixListener::from_std(UnixListener::try_clone(listener).unwrap())
|
216
|
+
.unwrap(),
|
217
|
+
acceptor: acceptor.clone(),
|
218
|
+
},
|
219
|
+
}
|
220
|
+
}
|
221
|
+
}
|
222
|
+
|
223
|
+
impl TryFrom<Bind> for Listener {
|
224
|
+
type Error = itsi_error::ItsiError;
|
225
|
+
|
226
|
+
fn try_from(bind: Bind) -> std::result::Result<Self, Self::Error> {
|
227
|
+
let bound = match bind.address {
|
228
|
+
BindAddress::Ip(addr) => match bind.protocol {
|
229
|
+
BindProtocol::Http => Listener::Tcp(connect_tcp_socket(addr, bind.port.unwrap())?),
|
230
|
+
BindProtocol::Https => {
|
231
|
+
let tcp_listener = connect_tcp_socket(addr, bind.port.unwrap())?;
|
232
|
+
let tls_acceptor = TlsAcceptor::from(Arc::new(bind.tls_config.unwrap()));
|
233
|
+
Listener::TcpTls((tcp_listener, tls_acceptor))
|
234
|
+
}
|
235
|
+
_ => unreachable!(),
|
236
|
+
},
|
237
|
+
BindAddress::UnixSocket(path) => match bind.tls_config {
|
238
|
+
Some(tls_config) => {
|
239
|
+
let tls_acceptor = TlsAcceptor::from(Arc::new(tls_config));
|
240
|
+
Listener::UnixTls((connect_unix_socket(&path)?, tls_acceptor))
|
241
|
+
}
|
242
|
+
None => Listener::Unix(connect_unix_socket(&path)?),
|
243
|
+
},
|
244
|
+
};
|
245
|
+
Ok(bound)
|
246
|
+
}
|
247
|
+
}
|
248
|
+
|
249
|
+
fn connect_tcp_socket(addr: IpAddr, port: u16) -> Result<TcpListener> {
|
250
|
+
let domain = match addr {
|
251
|
+
IpAddr::V4(_) => Domain::IPV4,
|
252
|
+
IpAddr::V6(_) => Domain::IPV6,
|
253
|
+
};
|
254
|
+
let socket = Socket::new(domain, Type::STREAM, Some(Protocol::TCP))?;
|
255
|
+
let socket_address: SocketAddr = SocketAddr::new(addr, port);
|
256
|
+
socket.set_nonblocking(true).ok();
|
257
|
+
socket.set_nodelay(true).ok();
|
258
|
+
socket.set_recv_buffer_size(1_048_576).ok();
|
259
|
+
socket.bind(&socket_address.into())?;
|
260
|
+
socket.listen(1024)?;
|
261
|
+
Ok(socket.into())
|
262
|
+
}
|
263
|
+
|
264
|
+
fn connect_unix_socket(path: &PathBuf) -> Result<UnixListener> {
|
265
|
+
let _ = std::fs::remove_file(path);
|
266
|
+
let socket = Socket::new(Domain::UNIX, Type::STREAM, None)?;
|
267
|
+
socket.set_nonblocking(true).ok();
|
268
|
+
let socket_address = socket2::SockAddr::unix(path)?;
|
269
|
+
|
270
|
+
info!("Binding to {:?}", path);
|
271
|
+
socket.bind(&socket_address)?;
|
272
|
+
socket.listen(1024)?;
|
273
|
+
|
274
|
+
Ok(socket.into())
|
275
|
+
}
|