fix(gui-client): keep the IPC service running even if the GUI quits during sign-in (#5451)

Closes #5450

Now the entire `Handler::run` function is allowed to fail, similar to a
web request handler failing in a web server.
Previously we only allowed the Handler to fail if it was idle, waiting
on incoming IPC requests. Now it can fail even if it's working with
connlib and about to send over IPC.

I replicated this on my Windows 11 VM in Parallels and the fix works
fine there. Should be the same bug and same fix in Linux.
This commit is contained in:
Reactor Scram
2024-06-24 23:00:45 +00:00
committed by GitHub
parent 82e244ef49
commit 058b04178a

View File

@@ -447,10 +447,7 @@ async fn ipc_listen() -> Result<std::convert::Infallible> {
.next_client_split()
.await
.context("Failed to wait for incoming IPC connection from a GUI")?;
Handler::new(rx, tx)?
.run()
.await
.context("Error while handling IPC client")?;
Handler::new(rx, tx)?.run().await;
}
}
@@ -488,14 +485,18 @@ impl Handler {
})
}
async fn run(&mut self) -> Result<()> {
// Infallible so that we only give up on an IPC client explicitly
async fn run(&mut self) {
loop {
let event = {
// This borrows `self` so we must drop it before handling the `Event`.
let cb = pin!(self.cb_rx.recv());
match future::select(self.ipc_rx.next(), cb).await {
future::Either::Left((Some(Ok(x)), _)) => Event::Ipc(x),
future::Either::Left((Some(Err(error)), _)) => Err(error)?,
future::Either::Left((Some(Err(error)), _)) => {
tracing::error!(?error, "Error while deserializing IPC message");
continue;
}
future::Either::Left((None, _)) => {
tracing::info!("IPC client disconnected");
break;
@@ -508,13 +509,20 @@ impl Handler {
}
};
match event {
Event::Callback(x) => self.handle_connlib_cb(x).await?,
Event::Ipc(msg) => self
.handle_ipc_msg(msg)
.context("Error while handling IPC message from client")?,
Event::Callback(x) => {
if let Err(error) = self.handle_connlib_cb(x).await {
tracing::error!(?error, "Error while handling connlib callback");
continue;
}
}
Event::Ipc(msg) => {
if let Err(error) = self.handle_ipc_msg(msg) {
tracing::error!(?error, "Error while handling IPC message from client");
continue;
}
}
}
}
Ok(())
}
async fn handle_connlib_cb(&mut self, msg: InternalServerMsg) -> Result<()> {
@@ -527,12 +535,18 @@ impl Handler {
tracing::info!(?dur, "Connlib started");
}
}
self.ipc_tx.send(&msg).await?
self.ipc_tx
.send(&msg)
.await
.context("Error while sending IPC message")?
}
InternalServerMsg::OnSetInterfaceConfig { ipv4, ipv6, dns } => {
self.tun_device.set_ips(ipv4, ipv6).await?;
self.dns_controller.set_dns(&dns).await?;
self.ipc_tx.send(&IpcServerMsg::OnTunnelReady).await?;
self.ipc_tx
.send(&IpcServerMsg::OnTunnelReady)
.await
.context("Error while sending `OnTunnelReady`")?
}
InternalServerMsg::OnUpdateRoutes { ipv4, ipv6 } => {
self.tun_device.set_routes(ipv4, ipv6).await?