Skip to content

Commit f13bb77

Browse files
committed
request: Shutdown socket when server sends disconnected
This allows the reading thread to cleanly exit without waiting for the client.
1 parent 532a271 commit f13bb77

File tree

3 files changed

+34
-1
lines changed

3 files changed

+34
-1
lines changed

src/calloop.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,17 @@ impl ConnectedContextState {
8686
where
8787
F: FnMut(Result<EisRequestSourceEvent, Error>, &mut Connection) -> io::Result<PostAction>,
8888
{
89+
// If server has sent `disconected`, return `Disconnect` event and stop polling.
90+
if self.handle.has_send_disconnected() {
91+
// TODO express if server or client requested disconnect?
92+
handle_result(
93+
Ok(request::EisRequest::Disconnect),
94+
&mut self.handle,
95+
&mut cb,
96+
)?;
97+
return Ok(calloop::PostAction::Remove);
98+
}
99+
89100
if let Err(err) = self.context.read() {
90101
handle_result(Err(Error::Io(err)), &mut self.handle, &mut cb)?;
91102
return Ok(calloop::PostAction::Remove);

src/request.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ use crate::{
1313
use std::{
1414
collections::{HashMap, HashSet, VecDeque},
1515
fmt,
16-
sync::{Arc, Mutex, Weak},
16+
sync::{
17+
atomic::{AtomicBool, Ordering},
18+
Arc, Mutex, Weak,
19+
},
1720
};
1821

1922
pub use crate::event::DeviceCapability;
@@ -49,6 +52,7 @@ struct ConnectionInner {
4952
devices: Mutex<HashMap<eis::Device, Device>>,
5053
device_for_interface: Mutex<HashMap<Object, Device>>,
5154
last_serial: Mutex<u32>,
55+
disconnected: AtomicBool,
5256
}
5357

5458
/// High-level server-side wrapper for `ei_connection`.
@@ -89,6 +93,18 @@ impl Connection {
8993
}
9094
self.connection()
9195
.disconnected(self.last_serial(), reason, explanation);
96+
// If flush fails because buffer is full, client can just get an EOF without
97+
// a message.
98+
let _ = self.flush();
99+
self.0.disconnected.store(true, Ordering::SeqCst);
100+
// Shutdown read end of socket, so anything reading/polling it will get EOF,
101+
// without waiting for client to disconnect first.
102+
self.0.context.0.shutdown_read();
103+
}
104+
105+
#[cfg(feature = "calloop")]
106+
pub(crate) fn has_sent_disconnected(&self) -> bool {
107+
self.0.disconnected.load(Ordering::SeqCst)
92108
}
93109

94110
/// Sends buffered messages. Call after you're finished with sending events.
@@ -247,6 +263,7 @@ impl EisRequestConverter {
247263
devices: Mutex::default(),
248264
device_for_interface: Mutex::default(),
249265
last_serial: Mutex::new(initial_serial),
266+
disconnected: AtomicBool::new(false),
250267
})),
251268
}
252269
}

src/wire/backend.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,11 @@ impl Backend {
326326
pub fn flush(&self) -> rustix::io::Result<()> {
327327
self.0.write.lock().unwrap().flush_write(&self.0.socket)
328328
}
329+
330+
/// Shutdown read end of socket, so all future reads will return EOF
331+
pub(crate) fn shutdown_read(&self) {
332+
let _ = self.0.socket.shutdown(std::net::Shutdown::Read);
333+
}
329334
}
330335

331336
fn is_reis_debug() -> bool {

0 commit comments

Comments
 (0)