1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
// Copyright (c) 2022, Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0
use std::net::{TcpListener, TcpStream};
/// Return an ephemeral, available port. On unix systems, the port returned will be in the
/// TIME_WAIT state ensuring that the OS won't hand out this port for some grace period.
/// Callers should be able to bind to this port given they use SO_REUSEADDR.
pub fn get_available_port(host: &str) -> u16 {
const MAX_PORT_RETRIES: u32 = 1000;
for _ in 0..MAX_PORT_RETRIES {
if let Ok(port) = get_ephemeral_port(host) {
return port;
}
}
panic!("Error: could not find an available port");
}
fn get_ephemeral_port(host: &str) -> ::std::io::Result<u16> {
// Request a random available port from the OS
let listener = TcpListener::bind((host, 0))?;
let addr = listener.local_addr()?;
// Create and accept a connection (which we'll promptly drop) in order to force the port
// into the TIME_WAIT state, ensuring that the port will be reserved from some limited
// amount of time (roughly 60s on some Linux systems)
let _sender = TcpStream::connect(addr)?;
let _incoming = listener.accept()?;
Ok(addr.port())
}