author | alfadur |
Sat, 25 Mar 2023 03:29:22 +0300 | |
changeset 15967 | e514ceb5e7d6 |
parent 15966 | c5c53ebb2d91 |
child 15968 | ce47259d5c86 |
permissions | -rw-r--r-- |
15853 | 1 |
use bytes::{Buf, Bytes}; |
2 |
use log::*; |
|
3 |
use slab::Slab; |
|
15966 | 4 |
use std::io::Error; |
5 |
use std::pin::Pin; |
|
6 |
use std::task::{Context, Poll}; |
|
13414 | 7 |
use std::{ |
15853 | 8 |
iter::Iterator, |
15854 | 9 |
net::{IpAddr, SocketAddr}, |
15822 | 10 |
time::Duration, |
13414 | 11 |
}; |
15853 | 12 |
use tokio::{ |
15966 | 13 |
io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt, ReadBuf}, |
14478 | 14 |
net::{TcpListener, TcpStream}, |
15853 | 15 |
sync::mpsc::{channel, Receiver, Sender}, |
13414 | 16 |
}; |
15966 | 17 |
#[cfg(feature = "tls-connections")] |
18 |
use tokio_native_tls::{TlsAcceptor, TlsStream}; |
|
13119 | 19 |
|
13666 | 20 |
use crate::{ |
15822 | 21 |
core::{ |
22 |
events::{TimedEvents, Timeout}, |
|
23 |
types::ClientId, |
|
24 |
}, |
|
15095 | 25 |
handlers, |
15542 | 26 |
handlers::{IoResult, IoTask, ServerState}, |
15854 | 27 |
protocol::{self, ProtocolDecoder, ProtocolError}, |
13666 | 28 |
utils, |
13414 | 29 |
}; |
15853 | 30 |
use hedgewars_network_protocol::{ |
31 |
messages::HwServerMessage::Redirect, messages::*, parser::server_message, |
|
32 |
}; |
|
14800
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14718
diff
changeset
|
33 |
|
15854 | 34 |
const PING_TIMEOUT: Duration = Duration::from_secs(15); |
35 |
||
15853 | 36 |
enum ClientUpdateData { |
37 |
Message(HwProtocolMessage), |
|
38 |
Error(String), |
|
39 |
} |
|
40 |
||
41 |
struct ClientUpdate { |
|
42 |
client_id: ClientId, |
|
43 |
data: ClientUpdateData, |
|
44 |
} |
|
13414 | 45 |
|
15853 | 46 |
struct ClientUpdateSender { |
47 |
client_id: ClientId, |
|
48 |
sender: Sender<ClientUpdate>, |
|
49 |
} |
|
13119 | 50 |
|
15853 | 51 |
impl ClientUpdateSender { |
52 |
async fn send(&mut self, data: ClientUpdateData) -> bool { |
|
53 |
self.sender |
|
54 |
.send(ClientUpdate { |
|
55 |
client_id: self.client_id, |
|
56 |
data, |
|
57 |
}) |
|
58 |
.await |
|
59 |
.is_ok() |
|
60 |
} |
|
61 |
} |
|
62 |
||
15966 | 63 |
enum ClientStream { |
64 |
Tcp(TcpStream), |
|
65 |
#[cfg(feature = "tls-connections")] |
|
66 |
Tls(TlsStream<TcpStream>), |
|
67 |
} |
|
68 |
||
69 |
impl Unpin for ClientStream {} |
|
70 |
||
71 |
impl AsyncRead for ClientStream { |
|
72 |
fn poll_read( |
|
73 |
self: Pin<&mut Self>, |
|
74 |
cx: &mut Context<'_>, |
|
75 |
buf: &mut ReadBuf<'_>, |
|
76 |
) -> Poll<std::io::Result<()>> { |
|
77 |
use ClientStream::*; |
|
78 |
match Pin::into_inner(self) { |
|
79 |
Tcp(stream) => Pin::new(stream).poll_read(cx, buf), |
|
80 |
#[cfg(feature = "tls-connections")] |
|
81 |
Tls(stream) => Pin::new(stream).poll_read(cx, buf), |
|
82 |
} |
|
83 |
} |
|
84 |
} |
|
85 |
||
86 |
impl AsyncWrite for ClientStream { |
|
87 |
fn poll_write( |
|
88 |
self: Pin<&mut Self>, |
|
89 |
cx: &mut Context<'_>, |
|
90 |
buf: &[u8], |
|
91 |
) -> Poll<Result<usize, Error>> { |
|
92 |
use ClientStream::*; |
|
93 |
match Pin::into_inner(self) { |
|
94 |
Tcp(stream) => Pin::new(stream).poll_write(cx, buf), |
|
95 |
#[cfg(feature = "tls-connections")] |
|
96 |
Tls(stream) => Pin::new(stream).poll_write(cx, buf), |
|
97 |
} |
|
98 |
} |
|
99 |
||
100 |
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Error>> { |
|
101 |
use ClientStream::*; |
|
102 |
match Pin::into_inner(self) { |
|
103 |
Tcp(stream) => Pin::new(stream).poll_flush(cx), |
|
104 |
#[cfg(feature = "tls-connections")] |
|
105 |
Tls(stream) => Pin::new(stream).poll_flush(cx), |
|
106 |
} |
|
107 |
} |
|
108 |
||
109 |
fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Error>> { |
|
110 |
use ClientStream::*; |
|
111 |
match Pin::into_inner(self) { |
|
112 |
Tcp(stream) => Pin::new(stream).poll_shutdown(cx), |
|
113 |
#[cfg(feature = "tls-connections")] |
|
114 |
Tls(stream) => Pin::new(stream).poll_shutdown(cx), |
|
115 |
} |
|
116 |
} |
|
117 |
} |
|
118 |
||
15853 | 119 |
struct NetworkClient { |
120 |
id: ClientId, |
|
15966 | 121 |
stream: ClientStream, |
15853 | 122 |
receiver: Receiver<Bytes>, |
123 |
peer_addr: SocketAddr, |
|
124 |
decoder: ProtocolDecoder, |
|
13414 | 125 |
} |
126 |
||
15853 | 127 |
impl NetworkClient { |
128 |
fn new( |
|
129 |
id: ClientId, |
|
15966 | 130 |
stream: ClientStream, |
15853 | 131 |
peer_addr: SocketAddr, |
132 |
receiver: Receiver<Bytes>, |
|
133 |
) -> Self { |
|
134 |
Self { |
|
135 |
id, |
|
15966 | 136 |
stream, |
15853 | 137 |
peer_addr, |
138 |
receiver, |
|
15854 | 139 |
decoder: ProtocolDecoder::new(PING_TIMEOUT), |
15853 | 140 |
} |
141 |
} |
|
13119 | 142 |
|
15966 | 143 |
async fn read<T: AsyncRead + AsyncWrite + Unpin>( |
144 |
stream: &mut T, |
|
15854 | 145 |
decoder: &mut ProtocolDecoder, |
146 |
) -> protocol::Result<HwProtocolMessage> { |
|
15966 | 147 |
let result = decoder.read_from(stream).await; |
15854 | 148 |
if matches!(result, Err(ProtocolError::Timeout)) { |
15966 | 149 |
if Self::write(stream, Bytes::from(HwServerMessage::Ping.to_raw_protocol())).await { |
150 |
decoder.read_from(stream).await |
|
15854 | 151 |
} else { |
152 |
Err(ProtocolError::Eof) |
|
153 |
} |
|
154 |
} else { |
|
155 |
result |
|
156 |
} |
|
15853 | 157 |
} |
158 |
||
15966 | 159 |
async fn write<T: AsyncWrite + Unpin>(stream: &mut T, mut data: Bytes) -> bool { |
160 |
!data.has_remaining() || matches!(stream.write_buf(&mut data).await, Ok(n) if n > 0) |
|
15853 | 161 |
} |
13773 | 162 |
|
15853 | 163 |
async fn run(mut self, sender: Sender<ClientUpdate>) { |
164 |
use ClientUpdateData::*; |
|
165 |
let mut sender = ClientUpdateSender { |
|
166 |
client_id: self.id, |
|
167 |
sender, |
|
168 |
}; |
|
169 |
||
170 |
loop { |
|
171 |
tokio::select! { |
|
172 |
server_message = self.receiver.recv() => { |
|
173 |
match server_message { |
|
15966 | 174 |
Some(message) => if !Self::write(&mut self.stream, message).await { |
15853 | 175 |
sender.send(Error("Connection reset by peer".to_string())).await; |
176 |
break; |
|
177 |
} |
|
178 |
None => { |
|
179 |
break; |
|
180 |
} |
|
181 |
} |
|
182 |
} |
|
15966 | 183 |
client_message = Self::read(&mut self.stream, &mut self.decoder) => { |
15853 | 184 |
match client_message { |
15854 | 185 |
Ok(message) => { |
15853 | 186 |
if !sender.send(Message(message)).await { |
187 |
break; |
|
188 |
} |
|
189 |
} |
|
15854 | 190 |
Err(e) => { |
191 |
sender.send(Error(format!("{}", e))).await; |
|
192 |
if matches!(e, ProtocolError::Timeout) { |
|
15966 | 193 |
Self::write(&mut self.stream, Bytes::from(HwServerMessage::Bye("Ping timeout".to_string()).to_raw_protocol())).await; |
15854 | 194 |
} |
15853 | 195 |
break; |
196 |
} |
|
197 |
} |
|
198 |
} |
|
199 |
} |
|
13773 | 200 |
} |
201 |
} |
|
202 |
} |
|
203 |
||
15966 | 204 |
#[cfg(feature = "tls-connections")] |
205 |
struct TlsListener { |
|
206 |
listener: TcpListener, |
|
207 |
acceptor: TlsAcceptor, |
|
208 |
} |
|
209 |
||
15853 | 210 |
pub struct NetworkLayer { |
211 |
listener: TcpListener, |
|
15966 | 212 |
#[cfg(feature = "tls-connections")] |
213 |
tls: TlsListener, |
|
15853 | 214 |
server_state: ServerState, |
215 |
clients: Slab<Sender<Bytes>>, |
|
13119 | 216 |
} |
217 |
||
15853 | 218 |
impl NetworkLayer { |
219 |
pub async fn run(&mut self) { |
|
220 |
let (update_tx, mut update_rx) = channel(128); |
|
13119 | 221 |
|
15966 | 222 |
async fn accept_plain_branch( |
223 |
layer: &mut NetworkLayer, |
|
224 |
value: (TcpStream, SocketAddr), |
|
225 |
update_tx: Sender<ClientUpdate>, |
|
226 |
) { |
|
227 |
let (stream, addr) = value; |
|
228 |
if let Some(client) = layer.create_client(ClientStream::Tcp(stream), addr).await { |
|
229 |
tokio::spawn(client.run(update_tx)); |
|
230 |
} |
|
231 |
} |
|
232 |
||
233 |
#[cfg(feature = "tls-connections")] |
|
234 |
async fn accept_tls_branch( |
|
235 |
layer: &mut NetworkLayer, |
|
236 |
value: (TcpStream, SocketAddr), |
|
237 |
update_tx: Sender<ClientUpdate>, |
|
238 |
) { |
|
239 |
let (stream, addr) = value; |
|
240 |
match layer.tls.acceptor.accept(stream).await { |
|
241 |
Ok(stream) => { |
|
242 |
if let Some(client) = layer.create_client(ClientStream::Tls(stream), addr).await |
|
243 |
{ |
|
15967 | 244 |
tokio::spawn(client.run(update_tx)); |
15853 | 245 |
} |
246 |
} |
|
15966 | 247 |
Err(e) => { |
248 |
warn!("Unable to establish TLS connection: {}", e); |
|
249 |
} |
|
250 |
} |
|
251 |
} |
|
252 |
||
253 |
async fn client_message_branch( |
|
254 |
layer: &mut NetworkLayer, |
|
255 |
client_message: Option<ClientUpdate>, |
|
256 |
) { |
|
257 |
use ClientUpdateData::*; |
|
258 |
match client_message { |
|
259 |
Some(ClientUpdate { |
|
260 |
client_id, |
|
261 |
data: Message(message), |
|
262 |
}) => { |
|
263 |
layer.handle_message(client_id, message).await; |
|
15853 | 264 |
} |
15966 | 265 |
Some(ClientUpdate { |
266 |
client_id, |
|
267 |
data: Error(e), |
|
268 |
}) => { |
|
269 |
let mut response = handlers::Response::new(client_id); |
|
270 |
info!("Client {} error: {:?}", client_id, e); |
|
271 |
response.remove_client(client_id); |
|
272 |
handlers::handle_client_loss(&mut layer.server_state, client_id, &mut response); |
|
273 |
layer.handle_response(response).await; |
|
274 |
} |
|
275 |
None => unreachable!(), |
|
276 |
} |
|
277 |
} |
|
278 |
||
279 |
loop { |
|
280 |
#[cfg(not(feature = "tls-connections"))] |
|
281 |
tokio::select! { |
|
282 |
Ok(value) = self.listener.accept() => accept_plain_branch(self, value, update_tx.clone()).await, |
|
283 |
client_message = update_rx.recv(), if !self.clients.is_empty() => client_message_branch(self, client_message).await |
|
284 |
} |
|
285 |
||
286 |
#[cfg(feature = "tls-connections")] |
|
287 |
tokio::select! { |
|
288 |
Ok(value) = self.listener.accept() => accept_plain_branch(self, value, update_tx.clone()).await, |
|
289 |
Ok(value) = self.tls.listener.accept() => accept_tls_branch(self, value, update_tx.clone()).await, |
|
290 |
client_message = update_rx.recv(), if !self.clients.is_empty() => client_message_branch(self, client_message).await |
|
13776 | 291 |
} |
292 |
} |
|
293 |
} |
|
294 |
||
15853 | 295 |
async fn create_client( |
296 |
&mut self, |
|
15966 | 297 |
stream: ClientStream, |
15853 | 298 |
addr: SocketAddr, |
299 |
) -> Option<NetworkClient> { |
|
300 |
let entry = self.clients.vacant_entry(); |
|
301 |
let client_id = entry.key(); |
|
302 |
let (tx, rx) = channel(16); |
|
303 |
entry.insert(tx); |
|
304 |
||
305 |
let client = NetworkClient::new(client_id, stream, addr, rx); |
|
13414 | 306 |
|
15853 | 307 |
info!("client {} ({}) added", client.id, client.peer_addr); |
308 |
||
309 |
let mut response = handlers::Response::new(client_id); |
|
310 |
||
311 |
let added = if let IpAddr::V4(addr) = client.peer_addr.ip() { |
|
312 |
handlers::handle_client_accept( |
|
313 |
&mut self.server_state, |
|
314 |
client_id, |
|
315 |
&mut response, |
|
316 |
addr.octets(), |
|
317 |
addr.is_loopback(), |
|
318 |
) |
|
319 |
} else { |
|
320 |
todo!("implement something") |
|
15822 | 321 |
}; |
322 |
||
15853 | 323 |
self.handle_response(response).await; |
13414 | 324 |
|
15853 | 325 |
if added { |
326 |
Some(client) |
|
14800
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14718
diff
changeset
|
327 |
} else { |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14718
diff
changeset
|
328 |
None |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14718
diff
changeset
|
329 |
} |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14718
diff
changeset
|
330 |
} |
f43ab2bd76ae
add a thread for internal server IO and implement account checking with it
alfadur
parents:
14718
diff
changeset
|
331 |
|
15853 | 332 |
async fn handle_message(&mut self, client_id: ClientId, message: HwProtocolMessage) { |
333 |
debug!("Handling message {:?} for client {}", message, client_id); |
|
334 |
let mut response = handlers::Response::new(client_id); |
|
335 |
handlers::handle(&mut self.server_state, client_id, &mut response, message); |
|
336 |
self.handle_response(response).await; |
|
13119 | 337 |
} |
338 |
||
15853 | 339 |
async fn handle_response(&mut self, mut response: handlers::Response) { |
14851
8ddb5842fe0b
allow running plaintext and tls servers in parallel
alfadur
parents:
14828
diff
changeset
|
340 |
if response.is_empty() { |
8ddb5842fe0b
allow running plaintext and tls servers in parallel
alfadur
parents:
14828
diff
changeset
|
341 |
return; |
8ddb5842fe0b
allow running plaintext and tls servers in parallel
alfadur
parents:
14828
diff
changeset
|
342 |
} |
8ddb5842fe0b
allow running plaintext and tls servers in parallel
alfadur
parents:
14828
diff
changeset
|
343 |
|
14693
6e6632068a33
Server action refactoring part 3 of N
alfadur <mail@none>
parents:
14692
diff
changeset
|
344 |
debug!("{} pending server messages", response.len()); |
15542 | 345 |
let output = response.extract_messages(&mut self.server_state.server); |
14693
6e6632068a33
Server action refactoring part 3 of N
alfadur <mail@none>
parents:
14692
diff
changeset
|
346 |
for (clients, message) in output { |
13419 | 347 |
debug!("Message {:?} to {:?}", message, clients); |
15853 | 348 |
Self::send_message(&mut self.clients, message, clients.iter().cloned()).await; |
13414 | 349 |
} |
14717 | 350 |
|
351 |
for client_id in response.extract_removed_clients() { |
|
15853 | 352 |
if self.clients.contains(client_id) { |
353 |
self.clients.remove(client_id); |
|
14824 | 354 |
} |
15853 | 355 |
info!("Client {} removed", client_id); |
15539 | 356 |
} |
14856 | 357 |
} |
358 |
||
15853 | 359 |
async fn send_message<I>( |
360 |
clients: &mut Slab<Sender<Bytes>>, |
|
361 |
message: HwServerMessage, |
|
362 |
to_clients: I, |
|
363 |
) where |
|
364 |
I: Iterator<Item = ClientId>, |
|
365 |
{ |
|
366 |
let msg_string = message.to_raw_protocol(); |
|
367 |
let bytes = Bytes::copy_from_slice(msg_string.as_bytes()); |
|
368 |
for client_id in to_clients { |
|
369 |
if let Some(client) = clients.get_mut(client_id) { |
|
370 |
if !client.send(bytes.clone()).await.is_ok() { |
|
371 |
clients.remove(client_id); |
|
13414 | 372 |
} |
14478 | 373 |
} |
13119 | 374 |
} |
13414 | 375 |
} |
13119 | 376 |
} |
14851
8ddb5842fe0b
allow running plaintext and tls servers in parallel
alfadur
parents:
14828
diff
changeset
|
377 |
|
8ddb5842fe0b
allow running plaintext and tls servers in parallel
alfadur
parents:
14828
diff
changeset
|
378 |
pub struct NetworkLayerBuilder { |
8ddb5842fe0b
allow running plaintext and tls servers in parallel
alfadur
parents:
14828
diff
changeset
|
379 |
listener: Option<TcpListener>, |
15966 | 380 |
#[cfg(feature = "tls-connections")] |
381 |
tls_listener: Option<TcpListener>, |
|
382 |
#[cfg(feature = "tls-connections")] |
|
383 |
tls_acceptor: Option<TlsAcceptor>, |
|
14851
8ddb5842fe0b
allow running plaintext and tls servers in parallel
alfadur
parents:
14828
diff
changeset
|
384 |
clients_capacity: usize, |
8ddb5842fe0b
allow running plaintext and tls servers in parallel
alfadur
parents:
14828
diff
changeset
|
385 |
rooms_capacity: usize, |
8ddb5842fe0b
allow running plaintext and tls servers in parallel
alfadur
parents:
14828
diff
changeset
|
386 |
} |
8ddb5842fe0b
allow running plaintext and tls servers in parallel
alfadur
parents:
14828
diff
changeset
|
387 |
|
8ddb5842fe0b
allow running plaintext and tls servers in parallel
alfadur
parents:
14828
diff
changeset
|
388 |
impl Default for NetworkLayerBuilder { |
8ddb5842fe0b
allow running plaintext and tls servers in parallel
alfadur
parents:
14828
diff
changeset
|
389 |
fn default() -> Self { |
8ddb5842fe0b
allow running plaintext and tls servers in parallel
alfadur
parents:
14828
diff
changeset
|
390 |
Self { |
8ddb5842fe0b
allow running plaintext and tls servers in parallel
alfadur
parents:
14828
diff
changeset
|
391 |
clients_capacity: 1024, |
8ddb5842fe0b
allow running plaintext and tls servers in parallel
alfadur
parents:
14828
diff
changeset
|
392 |
rooms_capacity: 512, |
8ddb5842fe0b
allow running plaintext and tls servers in parallel
alfadur
parents:
14828
diff
changeset
|
393 |
listener: None, |
15966 | 394 |
#[cfg(feature = "tls-connections")] |
395 |
tls_listener: None, |
|
396 |
#[cfg(feature = "tls-connections")] |
|
397 |
tls_acceptor: None, |
|
14851
8ddb5842fe0b
allow running plaintext and tls servers in parallel
alfadur
parents:
14828
diff
changeset
|
398 |
} |
8ddb5842fe0b
allow running plaintext and tls servers in parallel
alfadur
parents:
14828
diff
changeset
|
399 |
} |
8ddb5842fe0b
allow running plaintext and tls servers in parallel
alfadur
parents:
14828
diff
changeset
|
400 |
} |
8ddb5842fe0b
allow running plaintext and tls servers in parallel
alfadur
parents:
14828
diff
changeset
|
401 |
|
8ddb5842fe0b
allow running plaintext and tls servers in parallel
alfadur
parents:
14828
diff
changeset
|
402 |
impl NetworkLayerBuilder { |
8ddb5842fe0b
allow running plaintext and tls servers in parallel
alfadur
parents:
14828
diff
changeset
|
403 |
pub fn with_listener(self, listener: TcpListener) -> Self { |
8ddb5842fe0b
allow running plaintext and tls servers in parallel
alfadur
parents:
14828
diff
changeset
|
404 |
Self { |
8ddb5842fe0b
allow running plaintext and tls servers in parallel
alfadur
parents:
14828
diff
changeset
|
405 |
listener: Some(listener), |
8ddb5842fe0b
allow running plaintext and tls servers in parallel
alfadur
parents:
14828
diff
changeset
|
406 |
..self |
8ddb5842fe0b
allow running plaintext and tls servers in parallel
alfadur
parents:
14828
diff
changeset
|
407 |
} |
8ddb5842fe0b
allow running plaintext and tls servers in parallel
alfadur
parents:
14828
diff
changeset
|
408 |
} |
8ddb5842fe0b
allow running plaintext and tls servers in parallel
alfadur
parents:
14828
diff
changeset
|
409 |
|
15966 | 410 |
#[cfg(feature = "tls-connections")] |
411 |
pub fn with_tls_acceptor(self, listener: TlsAcceptor) -> Self { |
|
412 |
Self { |
|
413 |
tls_acceptor: Option::from(listener), |
|
414 |
..self |
|
415 |
} |
|
416 |
} |
|
417 |
||
418 |
#[cfg(feature = "tls-connections")] |
|
419 |
pub fn with_tls_listener(self, listener: TlsAcceptor) -> Self { |
|
420 |
Self { |
|
421 |
tls_acceptor: Option::from(listener), |
|
422 |
..self |
|
423 |
} |
|
424 |
} |
|
425 |
||
15853 | 426 |
pub fn build(self) -> NetworkLayer { |
15542 | 427 |
let server_state = ServerState::new(self.clients_capacity, self.rooms_capacity); |
428 |
||
14851
8ddb5842fe0b
allow running plaintext and tls servers in parallel
alfadur
parents:
14828
diff
changeset
|
429 |
let clients = Slab::with_capacity(self.clients_capacity); |
8ddb5842fe0b
allow running plaintext and tls servers in parallel
alfadur
parents:
14828
diff
changeset
|
430 |
|
8ddb5842fe0b
allow running plaintext and tls servers in parallel
alfadur
parents:
14828
diff
changeset
|
431 |
NetworkLayer { |
8ddb5842fe0b
allow running plaintext and tls servers in parallel
alfadur
parents:
14828
diff
changeset
|
432 |
listener: self.listener.expect("No listener provided"), |
15966 | 433 |
#[cfg(feature = "tls-connections")] |
434 |
tls: TlsListener { |
|
435 |
listener: self.tls_listener.expect("No TLS listener provided"), |
|
436 |
acceptor: self.tls_acceptor.expect("No TLS acceptor provided"), |
|
437 |
}, |
|
15542 | 438 |
server_state, |
14851
8ddb5842fe0b
allow running plaintext and tls servers in parallel
alfadur
parents:
14828
diff
changeset
|
439 |
clients, |
8ddb5842fe0b
allow running plaintext and tls servers in parallel
alfadur
parents:
14828
diff
changeset
|
440 |
} |
8ddb5842fe0b
allow running plaintext and tls servers in parallel
alfadur
parents:
14828
diff
changeset
|
441 |
} |
8ddb5842fe0b
allow running plaintext and tls servers in parallel
alfadur
parents:
14828
diff
changeset
|
442 |
} |