Skip to content

Commit

Permalink
net: add TcpListener.local_addr method (#107)
Browse files Browse the repository at this point in the history
Closes #106.
  • Loading branch information
FrankReh authored Sep 6, 2022
1 parent f80207b commit 587c9c3
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 3 deletions.
2 changes: 2 additions & 0 deletions examples/tcp_listener.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ fn main() {
tokio_uring::start(async {
let listener = TcpListener::bind(socket_addr).unwrap();

println!("Listening on {}", listener.local_addr().unwrap());

loop {
let (stream, socket_addr) = listener.accept().await.unwrap();
tokio_uring::spawn(async move {
Expand Down
32 changes: 29 additions & 3 deletions src/net/tcp/listener.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,41 @@ impl TcpListener {
///
/// Binding with a port number of 0 will request that the OS assigns a port
/// to this listener.
///
/// In the future, the port allocated can be queried via a (blocking) `local_addr`
/// method.
pub fn bind(addr: SocketAddr) -> io::Result<Self> {
let socket = Socket::bind(addr, libc::SOCK_STREAM)?;
socket.listen(1024)?;
Ok(TcpListener { inner: socket })
}

/// Returns the local address that this listener is bound to.
///
/// This can be useful, for example, when binding to port 0 to
/// figure out which port was actually bound.
///
/// # Examples
///
/// ```
/// use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
/// use tokio_uring::net::TcpListener;
///
/// let listener = TcpListener::bind("127.0.0.1:8080".parse().unwrap()).unwrap();
///
/// let addr = listener.local_addr().expect("Couldn't get local address");
/// assert_eq!(addr, SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080)));
/// ```
pub fn local_addr(&self) -> io::Result<SocketAddr> {
use std::os::unix::io::{AsRawFd, FromRawFd};

let fd = self.inner.as_raw_fd();
// SAFETY: Our fd is the handle the kernel has given us for a TcpListener.
// Create a std::net::TcpListener long enough to call its local_addr method
// and then forget it so the socket is not closed here.
let l = unsafe { std::net::TcpListener::from_raw_fd(fd) };
let local_addr = l.local_addr();
std::mem::forget(l);
local_addr
}

/// Accepts a new incoming connection from this listener.
///
/// This function will yield once a new TCP connection is established. When
Expand Down
29 changes: 29 additions & 0 deletions src/net/unix/listener.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,35 @@ impl UnixListener {
Ok(UnixListener { inner: socket })
}

/// Returns the local address that this listener is bound to.
///
/// # Examples
///
/// ```
/// use tokio_uring::net::UnixListener;
/// use std::path::Path;
///
/// let sock_file = "/tmp/tokio-uring-unix-test.sock";
/// let listener = UnixListener::bind(&sock_file).unwrap();
///
/// let addr = listener.local_addr().expect("Couldn't get local address");
/// assert_eq!(addr.as_pathname(), Some(Path::new(sock_file)));
///
/// std::fs::remove_file(&sock_file).unwrap();
/// ```
pub fn local_addr(&self) -> io::Result<std::os::unix::net::SocketAddr> {
use std::os::unix::io::{AsRawFd, FromRawFd};

let fd = self.inner.as_raw_fd();
// SAFETY: Our fd is the handle the kernel has given us for a UnixListener.
// Create a std::net::UnixListener long enough to call its local_addr method
// and then forget it so the socket is not closed here.
let l = unsafe { std::os::unix::net::UnixListener::from_raw_fd(fd) };
let local_addr = l.local_addr();
std::mem::forget(l);
local_addr
}

/// Accepts a new incoming connection from this listener.
///
/// This function will yield once a new Unix domain socket connection
Expand Down

0 comments on commit 587c9c3

Please sign in to comment.