Fix IPC errors with DDG caused by big messages being split (#11987)
This commit is contained in:
parent
5e6c5c8779
commit
079f84e7d9
|
@ -53,7 +53,7 @@ ssh-key = { version = "=0.6.6", default-features = false, features = [
|
||||||
bitwarden-russh = { git = "https://github.com/bitwarden/bitwarden-russh.git", branch = "km/pm-10098/clean-russh-implementation" }
|
bitwarden-russh = { git = "https://github.com/bitwarden/bitwarden-russh.git", branch = "km/pm-10098/clean-russh-implementation" }
|
||||||
tokio = { version = "=1.40.0", features = ["io-util", "sync", "macros", "net"] }
|
tokio = { version = "=1.40.0", features = ["io-util", "sync", "macros", "net"] }
|
||||||
tokio-stream = { version = "=0.1.15", features = ["net"] }
|
tokio-stream = { version = "=0.1.15", features = ["net"] }
|
||||||
tokio-util = "=0.7.12"
|
tokio-util = { version = "0.7.11", features = ["codec"] }
|
||||||
thiserror = "=1.0.69"
|
thiserror = "=1.0.69"
|
||||||
typenum = "=1.17.0"
|
typenum = "=1.17.0"
|
||||||
rand_chacha = "=0.3.1"
|
rand_chacha = "=0.3.1"
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use futures::{SinkExt, StreamExt};
|
||||||
use interprocess::local_socket::{
|
use interprocess::local_socket::{
|
||||||
tokio::{prelude::*, Stream},
|
tokio::{prelude::*, Stream},
|
||||||
GenericFilePath, ToFsName,
|
GenericFilePath, ToFsName,
|
||||||
};
|
};
|
||||||
use log::{error, info};
|
use log::{error, info};
|
||||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
|
||||||
|
|
||||||
use crate::ipc::NATIVE_MESSAGING_BUFFER_SIZE;
|
|
||||||
|
|
||||||
pub async fn connect(
|
pub async fn connect(
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
|
@ -17,7 +15,9 @@ pub async fn connect(
|
||||||
info!("Attempting to connect to {}", path.display());
|
info!("Attempting to connect to {}", path.display());
|
||||||
|
|
||||||
let name = path.as_os_str().to_fs_name::<GenericFilePath>()?;
|
let name = path.as_os_str().to_fs_name::<GenericFilePath>()?;
|
||||||
let mut conn = Stream::connect(name).await?;
|
let conn = Stream::connect(name).await?;
|
||||||
|
|
||||||
|
let mut conn = crate::ipc::internal_ipc_codec(conn);
|
||||||
|
|
||||||
info!("Connected to {}", path.display());
|
info!("Connected to {}", path.display());
|
||||||
|
|
||||||
|
@ -26,8 +26,6 @@ pub async fn connect(
|
||||||
// As it's only two, we hardcode the JSON values to avoid pulling in a JSON library.
|
// As it's only two, we hardcode the JSON values to avoid pulling in a JSON library.
|
||||||
send.send("{\"command\":\"connected\"}".to_owned()).await?;
|
send.send("{\"command\":\"connected\"}".to_owned()).await?;
|
||||||
|
|
||||||
let mut buffer = vec![0; NATIVE_MESSAGING_BUFFER_SIZE];
|
|
||||||
|
|
||||||
// Listen to IPC messages
|
// Listen to IPC messages
|
||||||
loop {
|
loop {
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
|
@ -35,7 +33,7 @@ pub async fn connect(
|
||||||
msg = recv.recv() => {
|
msg = recv.recv() => {
|
||||||
match msg {
|
match msg {
|
||||||
Some(msg) => {
|
Some(msg) => {
|
||||||
conn.write_all(msg.as_bytes()).await?;
|
conn.send(msg.into()).await?;
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
info!("Client channel closed");
|
info!("Client channel closed");
|
||||||
|
@ -45,18 +43,18 @@ pub async fn connect(
|
||||||
},
|
},
|
||||||
|
|
||||||
// Forward messages from the IPC server
|
// Forward messages from the IPC server
|
||||||
res = conn.read(&mut buffer[..]) => {
|
res = conn.next() => {
|
||||||
match res {
|
match res {
|
||||||
Err(e) => {
|
Some(Err(e)) => {
|
||||||
error!("Error reading from IPC server: {e}");
|
error!("Error reading from IPC server: {e}");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Ok(0) => {
|
None => {
|
||||||
info!("Connection closed");
|
info!("Connection closed");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Ok(n) => {
|
Some(Ok(bytes)) => {
|
||||||
let message = String::from_utf8_lossy(&buffer[..n]).to_string();
|
let message = String::from_utf8_lossy(&bytes).to_string();
|
||||||
send.send(message).await?;
|
send.send(message).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
use tokio::io::{AsyncRead, AsyncWrite};
|
||||||
|
use tokio_util::codec::{Framed, LengthDelimitedCodec};
|
||||||
|
|
||||||
pub mod client;
|
pub mod client;
|
||||||
pub mod server;
|
pub mod server;
|
||||||
|
|
||||||
|
@ -16,6 +19,16 @@ pub const NATIVE_MESSAGING_BUFFER_SIZE: usize = 1024 * 1024;
|
||||||
/// but ideally the messages should be processed as quickly as possible.
|
/// but ideally the messages should be processed as quickly as possible.
|
||||||
pub const MESSAGE_CHANNEL_BUFFER: usize = 32;
|
pub const MESSAGE_CHANNEL_BUFFER: usize = 32;
|
||||||
|
|
||||||
|
/// This is the codec used for communication through the UNIX socket / Windows named pipe.
|
||||||
|
/// It's an internal implementation detail, but we want to make sure that both the client
|
||||||
|
/// and the server use the same one.
|
||||||
|
fn internal_ipc_codec<T: AsyncRead + AsyncWrite>(inner: T) -> Framed<T, LengthDelimitedCodec> {
|
||||||
|
LengthDelimitedCodec::builder()
|
||||||
|
.max_frame_length(NATIVE_MESSAGING_BUFFER_SIZE)
|
||||||
|
.native_endian()
|
||||||
|
.new_framed(inner)
|
||||||
|
}
|
||||||
|
|
||||||
/// Resolve the path to the IPC socket.
|
/// Resolve the path to the IPC socket.
|
||||||
pub fn path(name: &str) -> std::path::PathBuf {
|
pub fn path(name: &str) -> std::path::PathBuf {
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
|
|
|
@ -1,21 +1,20 @@
|
||||||
use std::{
|
use std::{
|
||||||
error::Error,
|
error::Error,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
vec,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use futures::TryFutureExt;
|
use futures::{SinkExt, StreamExt, TryFutureExt};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use interprocess::local_socket::{tokio::prelude::*, GenericFilePath, ListenerOptions};
|
use interprocess::local_socket::{tokio::prelude::*, GenericFilePath, ListenerOptions};
|
||||||
use log::{error, info};
|
use log::{error, info};
|
||||||
use tokio::{
|
use tokio::{
|
||||||
io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt},
|
io::{AsyncRead, AsyncWrite},
|
||||||
sync::{broadcast, mpsc},
|
sync::{broadcast, mpsc},
|
||||||
};
|
};
|
||||||
use tokio_util::sync::CancellationToken;
|
use tokio_util::sync::CancellationToken;
|
||||||
|
|
||||||
use super::{MESSAGE_CHANNEL_BUFFER, NATIVE_MESSAGING_BUFFER_SIZE};
|
use super::MESSAGE_CHANNEL_BUFFER;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Message {
|
pub struct Message {
|
||||||
|
@ -158,7 +157,7 @@ async fn listen_incoming(
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_connection(
|
async fn handle_connection(
|
||||||
mut client_stream: impl AsyncRead + AsyncWrite + Unpin,
|
client_stream: impl AsyncRead + AsyncWrite + Unpin,
|
||||||
client_to_server_send: mpsc::Sender<Message>,
|
client_to_server_send: mpsc::Sender<Message>,
|
||||||
mut server_to_clients_recv: broadcast::Receiver<String>,
|
mut server_to_clients_recv: broadcast::Receiver<String>,
|
||||||
cancel_token: CancellationToken,
|
cancel_token: CancellationToken,
|
||||||
|
@ -172,7 +171,7 @@ async fn handle_connection(
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let mut buf = vec![0u8; NATIVE_MESSAGING_BUFFER_SIZE];
|
let mut client_stream = crate::ipc::internal_ipc_codec(client_stream);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
|
@ -185,7 +184,7 @@ async fn handle_connection(
|
||||||
msg = server_to_clients_recv.recv() => {
|
msg = server_to_clients_recv.recv() => {
|
||||||
match msg {
|
match msg {
|
||||||
Ok(msg) => {
|
Ok(msg) => {
|
||||||
client_stream.write_all(msg.as_bytes()).await?;
|
client_stream.send(msg.into()).await?;
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
info!("Error reading message: {}", e);
|
info!("Error reading message: {}", e);
|
||||||
|
@ -197,9 +196,9 @@ async fn handle_connection(
|
||||||
// Forwards messages from the IPC clients to the server
|
// Forwards messages from the IPC clients to the server
|
||||||
// Note that we also send connect and disconnect events so that
|
// Note that we also send connect and disconnect events so that
|
||||||
// the server can keep track of multiple clients
|
// the server can keep track of multiple clients
|
||||||
result = client_stream.read(&mut buf) => {
|
result = client_stream.next() => {
|
||||||
match result {
|
match result {
|
||||||
Err(e) => {
|
Some(Err(e)) => {
|
||||||
info!("Error reading from client {client_id}: {e}");
|
info!("Error reading from client {client_id}: {e}");
|
||||||
|
|
||||||
client_to_server_send.send(Message {
|
client_to_server_send.send(Message {
|
||||||
|
@ -209,7 +208,7 @@ async fn handle_connection(
|
||||||
}).await?;
|
}).await?;
|
||||||
break;
|
break;
|
||||||
},
|
},
|
||||||
Ok(0) => {
|
None => {
|
||||||
info!("Client {client_id} disconnected.");
|
info!("Client {client_id} disconnected.");
|
||||||
|
|
||||||
client_to_server_send.send(Message {
|
client_to_server_send.send(Message {
|
||||||
|
@ -219,8 +218,8 @@ async fn handle_connection(
|
||||||
}).await?;
|
}).await?;
|
||||||
break;
|
break;
|
||||||
},
|
},
|
||||||
Ok(size) => {
|
Some(Ok(bytes)) => {
|
||||||
let msg = std::str::from_utf8(&buf[..size])?;
|
let msg = std::str::from_utf8(&bytes)?;
|
||||||
|
|
||||||
client_to_server_send.send(Message {
|
client_to_server_send.send(Message {
|
||||||
client_id,
|
client_id,
|
||||||
|
|
Loading…
Reference in New Issue