diff --git a/ext/net/01_net.js b/ext/net/01_net.js index 3afbd031e6eede..e322e63cb593c9 100644 --- a/ext/net/01_net.js +++ b/ext/net/01_net.js @@ -99,8 +99,9 @@ class Conn { #readable; #writable; + #fd = -1; - constructor(rid, remoteAddr, localAddr) { + constructor(rid, remoteAddr, localAddr, fd) { ObjectDefineProperty(this, internalRidSymbol, { __proto__: null, enumerable: false, @@ -109,12 +110,17 @@ class Conn { this.#rid = rid; this.#remoteAddr = remoteAddr; this.#localAddr = localAddr; + this.#fd = fd; } get remoteAddr() { return this.#remoteAddr; } + get fd() { + return this.#fd; + } + get localAddr() { return this.#localAddr; } @@ -211,8 +217,8 @@ class UpgradedConn extends Conn { class TcpConn extends Conn { #rid = 0; - constructor(rid, remoteAddr, localAddr) { - super(rid, remoteAddr, localAddr); + constructor(rid, remoteAddr, localAddr, fd) { + super(rid, remoteAddr, localAddr, fd); ObjectDefineProperty(this, internalRidSymbol, { __proto__: null, enumerable: false, @@ -278,12 +284,12 @@ class Listener { } this.#promise = promise; if (this.#unref) core.unrefOpPromise(promise); - const { 0: rid, 1: localAddr, 2: remoteAddr } = await promise; + const { 0: rid, 1: localAddr, 2: remoteAddr, 3: fd } = await promise; this.#promise = null; if (this.addr.transport == "tcp") { localAddr.transport = "tcp"; remoteAddr.transport = "tcp"; - return new TcpConn(rid, remoteAddr, localAddr); + return new TcpConn(rid, remoteAddr, localAddr, fd); } else if (this.addr.transport == "unix") { return new UnixConn( rid, diff --git a/ext/net/lib.deno_net.d.ts b/ext/net/lib.deno_net.d.ts index 30d3357395f24b..ea720f51dad46c 100644 --- a/ext/net/lib.deno_net.d.ts +++ b/ext/net/lib.deno_net.d.ts @@ -138,6 +138,8 @@ declare namespace Deno { readonly readable: ReadableStream; readonly writable: WritableStream; + + readonly fd: number; } /** @category Network */ diff --git a/ext/net/ops.rs b/ext/net/ops.rs index 768dd33135e311..d1415d36362302 100644 --- a/ext/net/ops.rs +++ b/ext/net/ops.rs @@ -5,6 +5,8 @@ use std::cell::RefCell; use std::net::Ipv4Addr; use std::net::Ipv6Addr; use std::net::SocketAddr; +use std::os::fd::AsFd; +use std::os::fd::AsRawFd; use std::rc::Rc; use std::str::FromStr; @@ -46,6 +48,8 @@ use crate::resolve_addr::resolve_addr_sync; use crate::tcp::TcpListener; use crate::NetPermissions; +pub type Fd = u32; + #[derive(Serialize, Clone, Debug)] #[serde(rename_all = "camelCase")] pub struct TlsHandshakeInfo { @@ -165,7 +169,7 @@ pub(crate) fn accept_err(e: std::io::Error) -> NetError { pub async fn op_net_accept_tcp( state: Rc>, #[smi] rid: ResourceId, -) -> Result<(ResourceId, IpAddr, IpAddr), NetError> { +) -> Result<(ResourceId, IpAddr, IpAddr, Fd), NetError> { let resource = state .borrow() .resource_table @@ -180,6 +184,8 @@ pub async fn op_net_accept_tcp( .try_or_cancel(cancel) .await .map_err(accept_err)?; + let fd = tcp_stream.as_fd(); + let fd_raw = fd.as_raw_fd() as u32; let local_addr = tcp_stream.local_addr()?; let remote_addr = tcp_stream.peer_addr()?; @@ -187,7 +193,12 @@ pub async fn op_net_accept_tcp( let rid = state .resource_table .add(TcpStreamResource::new(tcp_stream.into_split())); - Ok((rid, IpAddr::from(local_addr), IpAddr::from(remote_addr))) + Ok(( + rid, + IpAddr::from(local_addr), + IpAddr::from(remote_addr), + fd_raw, + )) } #[op2(async)] diff --git a/ext/node/polyfills/internal_binding/tcp_wrap.ts b/ext/node/polyfills/internal_binding/tcp_wrap.ts index 6c19e2dd29837e..61eb4a586645d0 100644 --- a/ext/node/polyfills/internal_binding/tcp_wrap.ts +++ b/ext/node/polyfills/internal_binding/tcp_wrap.ts @@ -100,6 +100,7 @@ export class TCP extends ConnectionWrap { #closed = false; #acceptBackoffDelay?: number; + fd = -1; /** * Creates a new TCP class instance. @@ -127,6 +128,10 @@ export class TCP extends ConnectionWrap { super(provider, conn); + if (conn?.fd) { + this.fd = conn.fd; + } + // TODO(cmorten): the handling of new connections and construction feels // a little off. Suspect duplicating in some fashion. if (conn && provider === providerType.TCPWRAP) {