diff --git a/src/bin/client-demo.rs b/src/bin/client-demo.rs old mode 100644 new mode 100755 index a366f268c9..4013b825a2 --- a/src/bin/client-demo.rs +++ b/src/bin/client-demo.rs @@ -11,7 +11,7 @@ use rayon::prelude::*; use solana::crdt::{Crdt, ReplicatedData}; use solana::hash::Hash; use solana::mint::Mint; -use solana::nat::udp_public_bind; +use solana::nat::{udp_public_bind, udp_random_bind}; use solana::ncp::Ncp; use solana::service::Service; use solana::signature::{GenKeys, KeyPair, KeyPairUtil}; @@ -302,8 +302,8 @@ fn main() { } fn mk_client(r: &ReplicatedData) -> ThinClient { - let requests_socket = UdpSocket::bind("0.0.0.0:0").unwrap(); - let transactions_socket = UdpSocket::bind("0.0.0.0:0").unwrap(); + let requests_socket = udp_random_bind(8000, 10000, 5).unwrap(); + let transactions_socket = udp_random_bind(8000, 10000, 5).unwrap(); requests_socket .set_read_timeout(Some(Duration::new(1, 0))) @@ -318,7 +318,7 @@ fn mk_client(r: &ReplicatedData) -> ThinClient { } fn spy_node() -> (ReplicatedData, UdpSocket) { - let gossip_socket_pair = udp_public_bind("gossip"); + let gossip_socket_pair = udp_public_bind("gossip", 8000, 10000); let pubkey = KeyPair::new().pubkey(); let daddr = "0.0.0.0:0".parse().unwrap(); let node = ReplicatedData::new( @@ -347,7 +347,7 @@ fn converge( spy_crdt.set_leader(leader.id); let spy_ref = Arc::new(RwLock::new(spy_crdt)); let window = default_window(); - let gossip_send_socket = UdpSocket::bind("0.0.0.0:0").expect("bind 0"); + let gossip_send_socket = udp_random_bind(8000, 10000, 5).unwrap(); let ncp = Ncp::new( spy_ref.clone(), window.clone(), diff --git a/src/nat.rs b/src/nat.rs old mode 100644 new mode 100755 index 19da9716a6..3ca30a7efc --- a/src/nat.rs +++ b/src/nat.rs @@ -2,6 +2,7 @@ extern crate futures; extern crate p2p; +extern crate rand; extern crate reqwest; extern crate tokio_core; @@ -9,7 +10,9 @@ use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket}; use self::futures::Future; use self::p2p::UdpSocketExt; +use rand::{thread_rng, Rng}; use std::env; +use std::io; use std::str; /// A data type representing a public Udp socket @@ -32,8 +35,25 @@ pub fn get_public_ip_addr() -> Result { } } +pub fn udp_random_bind(start: u16, end: u16, tries: u32) -> io::Result { + let mut count = 0; + loop { + count += 1; + + let rand_port = thread_rng().gen_range(start, end); + let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), rand_port); + + match UdpSocket::bind(addr) { + Result::Ok(val) => break Result::Ok(val), + Result::Err(err) => if err.kind() != io::ErrorKind::AddrInUse || count >= tries { + return Err(err); + }, + } + } +} + /// Binds a private Udp address to a public address using UPnP if possible -pub fn udp_public_bind(label: &str) -> UdpSocketPair { +pub fn udp_public_bind(label: &str, startport: u16, endport: u16) -> UdpSocketPair { let private_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0); let mut core = tokio_core::reactor::Core::new().unwrap(); @@ -84,7 +104,7 @@ pub fn udp_public_bind(label: &str) -> UdpSocketPair { } } Err(_) => { - let sender = UdpSocket::bind(private_addr).unwrap(); + let sender = udp_random_bind(startport, endport, 5).unwrap(); let local_addr = sender.local_addr().unwrap(); info!("Using local address {} for {}", local_addr, label); UdpSocketPair {