diff --git a/src/bin/fullnode.rs b/src/bin/fullnode.rs index 434baab116302b..e88e42e998ec1c 100644 --- a/src/bin/fullnode.rs +++ b/src/bin/fullnode.rs @@ -73,11 +73,19 @@ fn main() -> () { } let leader_pubkey = keypair.pubkey(); - let repl_clone = repl_data.clone(); let ledger_path = matches.value_of("ledger").unwrap(); - let mut node = TestNode::new_with_bind_addr(repl_data, bind_addr); + let mut 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 fullnode = if let Some(t) = matches.value_of("testnet") { let testnet_address_string = t.to_string(); diff --git a/src/crdt.rs b/src/crdt.rs index fd3345081a427e..ea201c2e1b96d9 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}; @@ -1353,6 +1354,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.clone(), gossip_port), + SocketAddr::new(ip.clone(), replicate_port), + SocketAddr::new(ip.clone(), requests_port), + SocketAddr::new(ip.clone(), transaction_port), + SocketAddr::new(ip.clone(), 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) {