mirror of
https://github.com/openai/codex.git
synced 2026-10-26 18:38:47 +00:00
## What changed - Add helper protocol requests to create a WebRTC offer, apply an answer, and report readiness once the ordered `oai-events` data channel opens. - Support UDP and TCP candidates while bounding signaling size, remote candidates, inbound TCP streams, and WebRTC buffers. Redact session descriptions and peer errors from diagnostics. - Close unexpected remote data channels and tear down the peer during helper shutdown, including when the parent pipe is lost during startup. ## Testing - Exercise offer/answer negotiation and clean shutdown over real UDP and TCP sockets. - Cover signaling validation, candidate and connection limits, early packet loss, slow TCP connection setup, and blocked-startup parent loss. GitOrigin-RevId: 5f5e60a3a4d1d8eaca2e4724e66284f54061b6af
120 lines
3.4 KiB
Rust
120 lines
3.4 KiB
Rust
//! Bounds retained inbound TCP streams across one peer's listeners before authentication.
|
|
//! Weak references reuse slots after stream ownership ends; other Tokio I/O stays unchanged.
|
|
|
|
use std::future::Future;
|
|
use std::io;
|
|
use std::net::SocketAddr;
|
|
use std::pin::Pin;
|
|
use std::sync::Arc;
|
|
use std::sync::Mutex;
|
|
use std::sync::Weak;
|
|
use std::time::Duration;
|
|
|
|
use futures::future::BoxFuture;
|
|
use webrtc::runtime::AsyncInterval;
|
|
use webrtc::runtime::AsyncTcpListener;
|
|
use webrtc::runtime::AsyncTcpStream;
|
|
use webrtc::runtime::AsyncUdpSocket;
|
|
use webrtc::runtime::JoinHandle;
|
|
use webrtc::runtime::Runtime;
|
|
use webrtc::runtime::TokioRuntime;
|
|
|
|
const MAX_INBOUND_STREAMS: usize = 32;
|
|
type AcceptedStreams = Arc<Mutex<Vec<Weak<dyn AsyncTcpStream>>>>;
|
|
|
|
#[derive(Debug, Default)]
|
|
pub(crate) struct VoiceRuntime {
|
|
accepted: AcceptedStreams,
|
|
}
|
|
|
|
impl Runtime for VoiceRuntime {
|
|
fn spawn(&self, future: BoxFuture<'static, ()>) -> Box<dyn JoinHandle> {
|
|
TokioRuntime.spawn(future)
|
|
}
|
|
|
|
fn spawn_reactor(
|
|
&self,
|
|
reactor_pool_size: usize,
|
|
future: BoxFuture<'static, ()>,
|
|
) -> Box<dyn JoinHandle> {
|
|
TokioRuntime.spawn_reactor(reactor_pool_size, future)
|
|
}
|
|
|
|
fn wrap_udp_socket(&self, socket: std::net::UdpSocket) -> io::Result<Arc<dyn AsyncUdpSocket>> {
|
|
TokioRuntime.wrap_udp_socket(socket)
|
|
}
|
|
|
|
fn wrap_tcp_listener(
|
|
&self,
|
|
listener: std::net::TcpListener,
|
|
) -> io::Result<Arc<dyn AsyncTcpListener>> {
|
|
Ok(Arc::new(LimitedListener {
|
|
inner: TokioRuntime.wrap_tcp_listener(listener)?,
|
|
accepted: self.accepted.clone(),
|
|
}))
|
|
}
|
|
|
|
fn connect_tcp(
|
|
&self,
|
|
remote_addr: SocketAddr,
|
|
) -> BoxFuture<'_, io::Result<Arc<dyn AsyncTcpStream>>> {
|
|
TokioRuntime.connect_tcp(remote_addr)
|
|
}
|
|
|
|
fn resolve_host<'a>(&'a self, host: &'a str) -> BoxFuture<'a, io::Result<Vec<SocketAddr>>> {
|
|
TokioRuntime.resolve_host(host)
|
|
}
|
|
|
|
fn sleep(&self, duration: Duration) -> BoxFuture<'static, ()> {
|
|
TokioRuntime.sleep(duration)
|
|
}
|
|
|
|
fn interval(&self, period: Duration) -> Box<dyn AsyncInterval> {
|
|
TokioRuntime.interval(period)
|
|
}
|
|
|
|
fn block_on(&self, future: Pin<Box<dyn Future<Output = ()> + '_>>) {
|
|
TokioRuntime.block_on(future);
|
|
}
|
|
|
|
fn yield_now(&self) -> BoxFuture<'static, ()> {
|
|
TokioRuntime.yield_now()
|
|
}
|
|
|
|
fn name(&self) -> &'static str {
|
|
TokioRuntime.name()
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
struct LimitedListener {
|
|
inner: Arc<dyn AsyncTcpListener>,
|
|
accepted: AcceptedStreams,
|
|
}
|
|
|
|
impl AsyncTcpListener for LimitedListener {
|
|
fn accept(&self) -> BoxFuture<'_, io::Result<(Arc<dyn AsyncTcpStream>, SocketAddr)>> {
|
|
Box::pin(async move {
|
|
let (stream, address) = self.inner.accept().await?;
|
|
let mut accepted = self
|
|
.accepted
|
|
.lock()
|
|
.map_err(|_| io::Error::other("voice TCP admission unavailable"))?;
|
|
accepted.retain(|stream| stream.strong_count() > 0);
|
|
if accepted.len() >= MAX_INBOUND_STREAMS {
|
|
return Err(io::Error::other("voice TCP connection limit reached"));
|
|
}
|
|
accepted.push(Arc::downgrade(&stream));
|
|
Ok((stream, address))
|
|
})
|
|
}
|
|
|
|
fn local_addr(&self) -> io::Result<SocketAddr> {
|
|
self.inner.local_addr()
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
#[path = "transport_runtime_tests.rs"]
|
|
mod tests;
|