mirror of
https://github.com/openai/codex.git
synced 2026-10-20 00:18:49 +00:00
Fix Unix socket connections through long symlink paths (#48772)
## Why An advertised control socket path can exceed the Unix socket path limit even when its symlink target is short enough to connect to. ## What changed On Unix, resolve the socket path and retry the connection when the initial attempt returns `InvalidInput`. ## Testing Add a regression test that creates control sockets under two long home paths, checks that their symlink targets are distinct, and verifies that clients can connect through both advertised paths. GitOrigin-RevId: 2541f0a9b02d85035fa89fe26bbcd36d5cd0cc1e
This commit is contained in:
@@ -55,6 +55,48 @@ fn listen_unix_socket_accepts_relative_custom_path() {
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[tokio::test]
|
||||
async fn long_control_socket_paths_connect_to_distinct_daemons() {
|
||||
let temp_dir = tempfile::TempDir::new().expect("temp dir");
|
||||
let long_parent = temp_dir.path().join("x".repeat(120));
|
||||
let mut sockets = Vec::new();
|
||||
let mut acceptors = Vec::new();
|
||||
|
||||
for name in ["first", "second"] {
|
||||
let codex_home = long_parent.join(name);
|
||||
std::fs::create_dir_all(&codex_home).expect("codex home");
|
||||
let socket_path = app_server_control_socket_path(&codex_home).expect("socket path");
|
||||
let (transport_event_tx, _transport_event_rx) =
|
||||
mpsc::channel::<TransportEvent>(CHANNEL_CAPACITY);
|
||||
let shutdown_token = CancellationToken::new();
|
||||
let acceptor = start_control_socket_acceptor(
|
||||
socket_path.clone(),
|
||||
transport_event_tx,
|
||||
shutdown_token.clone(),
|
||||
DaemonShutdownAccess::Disabled,
|
||||
)
|
||||
.await
|
||||
.expect("control socket acceptor should start");
|
||||
sockets.push(socket_path);
|
||||
acceptors.push((shutdown_token, acceptor));
|
||||
}
|
||||
|
||||
assert_ne!(
|
||||
std::fs::read_link(sockets[0].as_path()).expect("first socket target"),
|
||||
std::fs::read_link(sockets[1].as_path()).expect("second socket target")
|
||||
);
|
||||
for socket in &sockets {
|
||||
connect_to_socket(socket.as_path())
|
||||
.await
|
||||
.expect("client should connect through long path");
|
||||
}
|
||||
for (shutdown_token, acceptor) in acceptors {
|
||||
shutdown_token.cancel();
|
||||
acceptor.await.expect("acceptor should stop");
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn control_socket_acceptor_upgrades_and_forwards_websocket_text_messages_and_pings() {
|
||||
let temp_dir = tempfile::TempDir::new().expect("temp dir");
|
||||
|
||||
@@ -164,7 +164,14 @@ mod platform {
|
||||
}
|
||||
|
||||
pub(super) async fn connect_stream(socket_path: &Path) -> IoResult<Stream> {
|
||||
UnixStream::connect(socket_path).await
|
||||
match UnixStream::connect(socket_path).await {
|
||||
Err(err) if err.kind() == ErrorKind::InvalidInput => {
|
||||
// The advertised path may exceed sun_path even when its symlink
|
||||
// target is a short socket path. Resolve it before retrying.
|
||||
UnixStream::connect(fs::canonicalize(socket_path).await?).await
|
||||
}
|
||||
result => result,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) async fn is_stale_socket_path(socket_path: &Path) -> IoResult<bool> {
|
||||
|
||||
Reference in New Issue
Block a user