From 006ac8feef9a476e1e4595118410e8faa78716c3 Mon Sep 17 00:00:00 2001 From: Pankaj Garg Date: Thu, 9 Aug 2018 21:35:38 +0000 Subject: [PATCH] Dynamically bind to available UDP ports in Fullnode --- src/bin/fullnode.rs | 13 +++++++-- src/crdt.rs | 66 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 76 insertions(+), 3 deletions(-) diff --git a/src/bin/fullnode.rs b/src/bin/fullnode.rs index 72ac52ccae0bfb..9ac23431724df6 100644 --- a/src/bin/fullnode.rs +++ b/src/bin/fullnode.rs @@ -72,11 +72,20 @@ fn main() -> () { } let leader_pubkey = keypair.pubkey(); - let repl_clone = repl_data.clone(); let ledger_path = matches.value_of("ledger").unwrap(); - let node = TestNode::new_with_bind_addr(repl_data, bind_addr); + let node = if let Some(_t) = matches.value_of("testnet") { + TestNode::new_with_external_ip(leader_pubkey, repl_data.contact_info.ncp.ip(), 0) + } else { + TestNode::new_with_external_ip( + leader_pubkey, + repl_data.contact_info.ncp.ip(), + repl_data.contact_info.ncp.port(), + ) + }; + let repl_clone = node.data.clone(); + let mut drone_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), DRONE_PORT); let testnet_addr = matches.value_of("testnet").map(|addr_str| { let addr: SocketAddr = addr_str.parse().unwrap(); diff --git a/src/crdt.rs b/src/crdt.rs index ad0e7a3744bb7c..8276ebf7c57c9b 100644 --- a/src/crdt.rs +++ b/src/crdt.rs @@ -20,6 +20,7 @@ use counter::Counter; use hash::Hash; use ledger::LedgerWindow; use log::Level; +use nat::udp_random_bind; use packet::{to_blob, Blob, BlobRecycler, SharedBlob, BLOB_SIZE}; use pnet_datalink as datalink; use rand::{thread_rng, RngCore}; @@ -30,7 +31,7 @@ use std; use std::collections::HashMap; use std::collections::VecDeque; use std::io::Cursor; -use std::net::{IpAddr, SocketAddr, UdpSocket}; +use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket}; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use std::sync::{Arc, RwLock}; use std::thread::{sleep, Builder, JoinHandle}; @@ -1354,6 +1355,69 @@ impl TestNode { }, } } + pub fn new_with_external_ip(pubkey: Pubkey, ip: IpAddr, ncp_port: u16) -> TestNode { + fn bind() -> (u16, UdpSocket) { + match udp_random_bind(8100, 10000, 5) { + Ok(socket) => (socket.local_addr().unwrap().port(), socket), + Err(err) => { + panic!("Failed to bind to {:?}", err); + } + } + }; + + fn bind_to(port: u16) -> UdpSocket { + let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), port); + match UdpSocket::bind(addr) { + Ok(socket) => socket, + Err(err) => { + panic!("Failed to bind to {:?}: {:?}", addr, err); + } + } + }; + + let (gossip_port, gossip) = if ncp_port != 0 { + (ncp_port, bind_to(ncp_port)) + } else { + bind() + }; + let (replicate_port, replicate) = bind(); + let (requests_port, requests) = bind(); + let (transaction_port, transaction) = bind(); + let (repair_port, repair) = bind(); + + // Responses are sent from the same Udp port as requests are received + // from, in hopes that a NAT sitting in the middle will route the + // response Udp packet correctly back to the requester. + let respond = requests.try_clone().unwrap(); + + let gossip_send = UdpSocket::bind("0.0.0.0:0").unwrap(); + let broadcast = UdpSocket::bind("0.0.0.0:0").unwrap(); + let retransmit = UdpSocket::bind("0.0.0.0:0").unwrap(); + + let node_info = NodeInfo::new( + pubkey, + SocketAddr::new(ip, gossip_port), + SocketAddr::new(ip, replicate_port), + SocketAddr::new(ip, requests_port), + SocketAddr::new(ip, transaction_port), + SocketAddr::new(ip, repair_port), + ); + + TestNode { + data: node_info, + sockets: Sockets { + gossip, + gossip_send, + requests, + replicate, + transaction, + respond, + broadcast, + repair, + retransmit, + }, + } + } } fn report_time_spent(label: &str, time: &Duration, extra: &str) {