From c7e201df0fee6a10a26fffc0566da7f648ccfdeb Mon Sep 17 00:00:00 2001 From: Surya Prakash Kahar Date: Wed, 3 Sep 2025 20:54:56 +0530 Subject: [PATCH] feat: implement getsockname() --- src/demikernel/bindings.rs | 60 +++++++++++++++++++++++++-- src/demikernel/libos/mod.rs | 6 +++ src/demikernel/libos/network/libos.rs | 5 +++ src/demikernel/libos/network/queue.rs | 14 +++++++ 4 files changed, 81 insertions(+), 4 deletions(-) diff --git a/src/demikernel/bindings.rs b/src/demikernel/bindings.rs index 33cc41902..41b6099f8 100644 --- a/src/demikernel/bindings.rs +++ b/src/demikernel/bindings.rs @@ -646,11 +646,63 @@ pub unsafe extern "C" fn demi_sgafree(sga: *mut demi_sgarray_t) -> c_int { } } -#[allow(unused)] +/// # Safety +/// +/// The `addr` argument must be a valid pointer to a `sockaddr` structure, and `addrlen` must be a valid pointer to a +/// `Socklen` value that specifies the size of the `sockaddr` structure. #[no_mangle] -pub extern "C" fn demi_getsockname(qd: c_int, saddr: *mut sockaddr, size: *mut Socklen) -> c_int { - // TODO: Implement this system call. - libc::ENOSYS +pub unsafe extern "C" fn demi_getsockname(qd: c_int, addr: *mut SockAddr, addrlen: *mut Socklen) -> c_int { + trace!("demi_getsockname()"); + + if addr.is_null() { + warn!("demi_getsockname() addr value is a null pointer"); + return libc::EINVAL; + } + + if addrlen.is_null() { + warn!("demi_getsockname(): addrlen value is a null pointer"); + return libc::EINVAL; + } + + let expected_len = mem::size_of::() as Socklen; + + if unsafe { *addrlen < expected_len } { + warn!("demi_getsockname(): addrlen does not match size of SockAddrIn"); + return libc::EINVAL; + } + + let ret = match do_syscall(|libos| libos.getsockname(qd.into())) { + Ok(result) => result, + Err(e) => { + trace!("demi_getsockname() failed: {:?}", e); + return e.errno; + }, + }; + + match ret { + Ok(sockaddr) => { + let result = socketaddrv4_to_sockaddr(&sockaddr); + let result_length = mem::size_of::(); + unsafe { + if (result_length as Socklen) < *addrlen { + *addrlen = result_length as Socklen; + } + + // Need to pass dst as c_void pointer or else we get a stack-smashing error + ptr::copy_nonoverlapping( + &result as *const sockaddr as *const c_void, + addr as *mut c_void, + *addrlen as usize, + ); + } + + 0 + }, + Err(e) => { + trace!("demi_getsockname() failed: {:?}", e); + e.errno + }, + } } /// # Safety diff --git a/src/demikernel/libos/mod.rs b/src/demikernel/libos/mod.rs index 34df84aa6..039fba5fc 100644 --- a/src/demikernel/libos/mod.rs +++ b/src/demikernel/libos/mod.rs @@ -145,6 +145,12 @@ impl LibOS { } } + pub fn getsockname(&mut self, sockqd: QDesc) -> Result { + match self { + LibOS::NetworkLibOS(libos) => libos.getsockname(sockqd), + } + } + #[allow(unused_variables)] pub fn bind(&mut self, sockqd: QDesc, local: SocketAddr) -> Result<(), Fail> { match self { diff --git a/src/demikernel/libos/network/libos.rs b/src/demikernel/libos/network/libos.rs index 2bea33dca..c5a495ff0 100644 --- a/src/demikernel/libos/network/libos.rs +++ b/src/demikernel/libos/network/libos.rs @@ -98,6 +98,11 @@ impl SharedNetworkLibOS { self.get_shared_queue(&qd)?.getpeername() } + pub fn getsockname(&mut self, qd: QDesc) -> Result { + trace!("getsockname() qd={:?}", qd); + self.get_shared_queue(&qd)?.getsockname() + } + /// This function contains the LibOS-level functionality needed to bind a SharedNetworkQueue to a local address. pub fn bind(&mut self, qd: QDesc, socket_addr: SocketAddr) -> Result<(), Fail> { trace!("bind() qd={:?}, local={:?}", qd, socket_addr); diff --git a/src/demikernel/libos/network/queue.rs b/src/demikernel/libos/network/queue.rs index f22c05464..73019c23d 100644 --- a/src/demikernel/libos/network/queue.rs +++ b/src/demikernel/libos/network/queue.rs @@ -91,6 +91,20 @@ impl SharedNetworkQueue { self.transport.clone().getpeername(&mut self.socket) } + /// Gets the local address bound to the socket. + pub fn getsockname(&mut self) -> Result { + match self.local() { + Some(addr) => { + // We only support IPv4 addresses in demikernel + match addr { + SocketAddr::V4(addr_v4) => Ok(addr_v4), + SocketAddr::V6(_) => Err(Fail::new(libc::ENOTSUP, "IPv6 not supported")), + } + }, + None => Err(Fail::new(libc::ENOTCONN, "socket is not bound to any address")), + } + } + /// Binds the target queue to `local` address. pub fn bind(&mut self, local: SocketAddr) -> Result<(), Fail> { self.state_machine.may_bind()?;