Skip to content

Commit b41a022

Browse files
authored
Add getter for local_addr on TcpSocket (#1379)
1 parent 183bbe4 commit b41a022

File tree

5 files changed

+73
-2
lines changed

5 files changed

+73
-2
lines changed

src/net/tcp/socket.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,13 @@ impl TcpSocket {
105105
pub fn set_linger(&self, dur: Option<Duration>) -> io::Result<()> {
106106
sys::tcp::set_linger(self.sys, dur)
107107
}
108+
109+
/// Returns the local address of this socket
110+
///
111+
/// Will return `Err` result in windows if called before calling `bind`
112+
pub fn get_localaddr(&self) -> io::Result<SocketAddr> {
113+
sys::tcp::get_localaddr(self.sys)
114+
}
108115
}
109116

110117
impl Drop for TcpSocket {

src/sys/shell/tcp.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,7 @@ pub(crate) fn set_linger(_: TcpSocket, _: Option<Duration>) -> io::Result<()> {
5353
pub fn accept(_: &net::TcpListener) -> io::Result<(net::TcpStream, SocketAddr)> {
5454
os_required!();
5555
}
56+
57+
pub(crate) fn get_localaddr(_: TcpSocket) -> io::Result<SocketAddr> {
58+
os_required!();
59+
}

src/sys/unix/tcp.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,19 @@ pub(crate) fn get_reuseport(socket: TcpSocket) -> io::Result<bool> {
103103
Ok(optval != 0)
104104
}
105105

106+
pub(crate) fn get_localaddr(socket: TcpSocket) -> io::Result<SocketAddr> {
107+
let mut addr: libc::sockaddr_storage = unsafe { std::mem::zeroed() };
108+
let mut length = size_of::<libc::sockaddr_storage>() as libc::socklen_t;
109+
110+
syscall!(getsockname(
111+
socket,
112+
&mut addr as *mut _ as *mut _,
113+
&mut length
114+
))?;
115+
116+
unsafe { to_socket_addr(&addr) }
117+
}
118+
106119
pub(crate) fn set_linger(socket: TcpSocket, dur: Option<Duration>) -> io::Result<()> {
107120
let val: libc::linger = libc::linger {
108121
l_onoff: if dur.is_some() { 1 } else { 0 },

src/sys/windows/tcp.rs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
use std::io;
22
use std::mem::size_of;
3-
use std::net::{self, SocketAddr};
3+
use std::net::{self, SocketAddr, SocketAddrV4, SocketAddrV6};
44
use std::time::Duration;
55
use std::os::windows::io::FromRawSocket;
66
use std::os::windows::raw::SOCKET as StdSocket; // winapi uses usize, stdlib uses u32/u64.
77

88
use winapi::ctypes::{c_char, c_int, c_ushort};
9+
use winapi::shared::ws2def::{SOCKADDR_STORAGE, AF_INET, SOCKADDR_IN};
10+
use winapi::shared::ws2ipdef::SOCKADDR_IN6_LH;
11+
912
use winapi::shared::minwindef::{BOOL, TRUE, FALSE};
1013
use winapi::um::winsock2::{
11-
self, closesocket, linger, setsockopt, getsockopt, PF_INET, PF_INET6, SOCKET, SOCKET_ERROR,
14+
self, closesocket, linger, setsockopt, getsockopt, getsockname, PF_INET, PF_INET6, SOCKET, SOCKET_ERROR,
1215
SOCK_STREAM, SOL_SOCKET, SO_LINGER, SO_REUSEADDR,
1316
};
1417

@@ -103,6 +106,31 @@ pub(crate) fn get_reuseaddr(socket: TcpSocket) -> io::Result<bool> {
103106
}
104107
}
105108

109+
pub(crate) fn get_localaddr(socket: TcpSocket) -> io::Result<SocketAddr> {
110+
let mut addr: SOCKADDR_STORAGE = unsafe { std::mem::zeroed() };
111+
let mut length = std::mem::size_of_val(&addr) as c_int;
112+
113+
match unsafe { getsockname(
114+
socket,
115+
&mut addr as *mut _ as *mut _,
116+
&mut length
117+
) } {
118+
SOCKET_ERROR => Err(io::Error::last_os_error()),
119+
_ => {
120+
let storage: *const SOCKADDR_STORAGE = (&addr) as *const _;
121+
if addr.ss_family as c_int == AF_INET {
122+
let sock_addr : SocketAddrV4 = unsafe { *(storage as *const SOCKADDR_IN as *const _) };
123+
Ok(sock_addr.into())
124+
} else {
125+
let sock_addr : SocketAddrV6 = unsafe { *(storage as *const SOCKADDR_IN6_LH as *const _) };
126+
Ok(sock_addr.into())
127+
}
128+
},
129+
}
130+
131+
132+
}
133+
106134
pub(crate) fn set_linger(socket: TcpSocket, dur: Option<Duration>) -> io::Result<()> {
107135
let val: linger = linger {
108136
l_onoff: if dur.is_some() { 1 } else { 0 },

tests/tcp_socket.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,22 @@ fn set_reuseport() {
3737

3838
let _ = socket.listen(128).unwrap();
3939
}
40+
41+
#[test]
42+
fn get_localaddr() {
43+
let expected_addr = "127.0.0.1:0".parse().unwrap();
44+
let socket = TcpSocket::new_v4().unwrap();
45+
46+
//Windows doesn't support calling getsockname before calling `bind`
47+
#[cfg(not(windows))]
48+
assert_eq!("0.0.0.0:0", socket.get_localaddr().unwrap().to_string());
49+
50+
socket.bind(expected_addr).unwrap();
51+
52+
let actual_addr = socket.get_localaddr().unwrap();
53+
54+
assert_eq!(expected_addr.ip(), actual_addr.ip());
55+
assert!(actual_addr.port() > 0);
56+
57+
let _ = socket.listen(128).unwrap();
58+
}

0 commit comments

Comments
 (0)