Get public address/UPNP refactoring

This commit is contained in:
arkpar 2016-02-16 02:05:36 +01:00
parent 64913d5009
commit 203947388b
8 changed files with 84 additions and 81 deletions

1
Cargo.lock generated
View File

@ -214,6 +214,7 @@ dependencies = [
"itertools 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"json-tests 0.1.0", "json-tests 0.1.0",
"lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@ -64,8 +64,8 @@ Options:
-d --db-path PATH Specify the database & configuration directory path [default: $HOME/.parity] -d --db-path PATH Specify the database & configuration directory path [default: $HOME/.parity]
--no-bootstrap Don't bother trying to connect to any nodes initially. --no-bootstrap Don't bother trying to connect to any nodes initially.
--listen-address URL Specify the IP/port on which to listen for peers [default: 0.0.0.0:30304]. --listen-address URL Specify the IP/port on which to listen for peers.
--public-address URL Specify the IP/port on which peers may connect [default: 0.0.0.0:30304]. --public-address URL Specify the IP/port on which peers may connect.
--address URL Equivalent to --listen-address URL --public-address URL. --address URL Equivalent to --listen-address URL --public-address URL.
--upnp Use UPnP to try to figure out the correct network settings. --upnp Use UPnP to try to figure out the correct network settings.
--node-key KEY Specify node secret key as hex string. --node-key KEY Specify node secret key as hex string.
@ -79,7 +79,12 @@ Options:
-l --logging LOGGING Specify the logging level. -l --logging LOGGING Specify the logging level.
-v --version Show information about version. -v --version Show information about version.
-h --help Show this screen. -h --help Show this screen.
", flag_cache_pref_size: usize, flag_cache_max_size: usize, flag_address: Option<String>, flag_node_key: Option<String>); ", flag_cache_pref_size: usize,
flag_cache_max_size: usize,
flag_address: Option<String>,
flag_listen_address: Option<String>,
flag_public_address: Option<String>,
flag_node_key: Option<String>);
fn setup_log(init: &str) { fn setup_log(init: &str) {
let mut builder = LogBuilder::new(); let mut builder = LogBuilder::new();
@ -155,21 +160,26 @@ impl Configuration {
} }
} }
fn net_addresses(&self) -> (SocketAddr, SocketAddr) { fn net_addresses(&self) -> (Option<SocketAddr>, Option<SocketAddr>) {
let listen_address; let mut listen_address = None;
let public_address; let mut public_address = None;
match self.args.flag_address { if let Some(ref a) = self.args.flag_address {
None => { public_address = Some(SocketAddr::from_str(a.as_ref()).expect("Invalid listen/public address given with --address"));
listen_address = SocketAddr::from_str(self.args.flag_listen_address.as_ref()).expect("Invalid listen address given with --listen-address"); listen_address = public_address;
public_address = SocketAddr::from_str(self.args.flag_public_address.as_ref()).expect("Invalid public address given with --public-address"); }
if let Some(ref a) = self.args.flag_listen_address {
if listen_address.is_some() {
panic!("Conflicting flags: --address and --listen-address");
} }
Some(ref a) => { listen_address = Some(SocketAddr::from_str(a.as_ref()).expect("Invalid listen address given with --listen-address"));
public_address = SocketAddr::from_str(a.as_ref()).expect("Invalid listen/public address given with --address"); }
listen_address = public_address; if let Some(ref a) = self.args.flag_public_address {
if public_address.is_some() {
panic!("Conflicting flags: --address and --public-address");
} }
}; public_address = Some(SocketAddr::from_str(a.as_ref()).expect("Invalid listen address given with --public-address"));
}
(listen_address, public_address) (listen_address, public_address)
} }
} }

View File

@ -30,3 +30,4 @@ clippy = "0.0.41"
json-tests = { path = "json-tests" } json-tests = { path = "json-tests" }
target_info = "0.1.0" target_info = "0.1.0"
igd = "0.4.2" igd = "0.4.2"
libc = "0.2.7"

View File

@ -110,6 +110,7 @@ extern crate serde;
#[macro_use] #[macro_use]
extern crate log as rlog; extern crate log as rlog;
extern crate igd; extern crate igd;
extern crate libc;
pub mod standard; pub mod standard;
#[macro_use] #[macro_use]

View File

@ -78,7 +78,7 @@ struct Datagramm {
pub struct Discovery { pub struct Discovery {
id: NodeId, id: NodeId,
secret: Secret, secret: Secret,
address: NodeEndpoint, public_endpoint: NodeEndpoint,
udp_socket: UdpSocket, udp_socket: UdpSocket,
token: StreamToken, token: StreamToken,
discovery_round: u16, discovery_round: u16,
@ -94,12 +94,12 @@ pub struct TableUpdates {
} }
impl Discovery { impl Discovery {
pub fn new(key: &KeyPair, address: NodeEndpoint, token: StreamToken) -> Discovery { pub fn new(key: &KeyPair, listen: SocketAddr, public: NodeEndpoint, token: StreamToken) -> Discovery {
let socket = UdpSocket::bound(&address.udp_address()).expect("Error binding UDP socket"); let socket = UdpSocket::bound(&listen).expect("Error binding UDP socket");
Discovery { Discovery {
id: key.public().clone(), id: key.public().clone(),
secret: key.secret().clone(), secret: key.secret().clone(),
address: address, public_endpoint: public,
token: token, token: token,
discovery_round: 0, discovery_round: 0,
discovery_id: NodeId::new(), discovery_id: NodeId::new(),
@ -199,7 +199,7 @@ impl Discovery {
fn ping(&mut self, node: &NodeEndpoint) { fn ping(&mut self, node: &NodeEndpoint) {
let mut rlp = RlpStream::new_list(3); let mut rlp = RlpStream::new_list(3);
rlp.append(&PROTOCOL_VERSION); rlp.append(&PROTOCOL_VERSION);
self.address.to_rlp_list(&mut rlp); self.public_endpoint.to_rlp_list(&mut rlp);
node.to_rlp_list(&mut rlp); node.to_rlp_list(&mut rlp);
trace!(target: "discovery", "Sent Ping to {:?}", &node); trace!(target: "discovery", "Sent Ping to {:?}", &node);
self.send_packet(PACKET_PING, &node.udp_address(), &rlp.drain()); self.send_packet(PACKET_PING, &node.udp_address(), &rlp.drain());
@ -507,8 +507,8 @@ mod tests {
let key2 = KeyPair::create().unwrap(); let key2 = KeyPair::create().unwrap();
let ep1 = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40444").unwrap(), udp_port: 40444 }; let ep1 = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40444").unwrap(), udp_port: 40444 };
let ep2 = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40445").unwrap(), udp_port: 40445 }; let ep2 = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40445").unwrap(), udp_port: 40445 };
let mut discovery1 = Discovery::new(&key1, ep1.clone(), 0); let mut discovery1 = Discovery::new(&key1, ep1.address.clone(), ep1.clone(), 0);
let mut discovery2 = Discovery::new(&key2, ep2.clone(), 0); let mut discovery2 = Discovery::new(&key2, ep2.address.clone(), ep2.clone(), 0);
let node1 = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@127.0.0.1:7770").unwrap(); let node1 = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@127.0.0.1:7770").unwrap();
let node2 = Node::from_str("enode://b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@127.0.0.1:7771").unwrap(); let node2 = Node::from_str("enode://b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@127.0.0.1:7771").unwrap();

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::net::{SocketAddr, SocketAddrV4}; use std::net::{SocketAddr};
use std::collections::{HashMap}; use std::collections::{HashMap};
use std::hash::{Hasher}; use std::hash::{Hasher};
use std::str::{FromStr}; use std::str::{FromStr};
@ -39,8 +39,8 @@ use network::{NetworkProtocolHandler, PROTOCOL_VERSION};
use network::node_table::*; use network::node_table::*;
use network::stats::NetworkStats; use network::stats::NetworkStats;
use network::error::DisconnectReason; use network::error::DisconnectReason;
use igd::{PortMappingProtocol, search_gateway};
use network::discovery::{Discovery, TableUpdates, NodeEntry}; use network::discovery::{Discovery, TableUpdates, NodeEntry};
use network::ip_utils::{map_external_address, select_public_address};
type Slab<T> = ::slab::Slab<T, usize>; type Slab<T> = ::slab::Slab<T, usize>;
@ -55,10 +55,12 @@ const MAINTENANCE_TIMEOUT: u64 = 1000;
pub struct NetworkConfiguration { pub struct NetworkConfiguration {
/// Directory path to store network configuration. None means nothing will be saved /// Directory path to store network configuration. None means nothing will be saved
pub config_path: Option<String>, pub config_path: Option<String>,
/// IP address to listen for incoming connections /// IP address to listen for incoming connections. Listen to all connections by default
pub listen_address: SocketAddr, pub listen_address: Option<SocketAddr>,
/// IP address to advertise /// IP address to advertise. Detected automatically if none.
pub public_address: SocketAddr, pub public_address: Option<SocketAddr>,
/// Port for UDP connections, same as TCP by default
pub udp_port: Option<u16>,
/// Enable NAT configuration /// Enable NAT configuration
pub nat_enabled: bool, pub nat_enabled: bool,
/// Enable discovery /// Enable discovery
@ -78,8 +80,9 @@ impl NetworkConfiguration {
pub fn new() -> NetworkConfiguration { pub fn new() -> NetworkConfiguration {
NetworkConfiguration { NetworkConfiguration {
config_path: None, config_path: None,
listen_address: SocketAddr::from_str("0.0.0.0:30304").unwrap(), listen_address: None,
public_address: SocketAddr::from_str("0.0.0.0:30304").unwrap(), public_address: None,
udp_port: None,
nat_enabled: true, nat_enabled: true,
discovery_enabled: true, discovery_enabled: true,
pin: false, pin: false,
@ -92,48 +95,9 @@ impl NetworkConfiguration {
/// Create new default configuration with sepcified listen port. /// Create new default configuration with sepcified listen port.
pub fn new_with_port(port: u16) -> NetworkConfiguration { pub fn new_with_port(port: u16) -> NetworkConfiguration {
let mut config = NetworkConfiguration::new(); let mut config = NetworkConfiguration::new();
config.listen_address = SocketAddr::from_str(&format!("0.0.0.0:{}", port)).unwrap(); config.listen_address = Some(SocketAddr::from_str(&format!("0.0.0.0:{}", port)).unwrap());
config.public_address = SocketAddr::from_str(&format!("0.0.0.0:{}", port)).unwrap();
config config
} }
/// Conduct NAT if needed.
pub fn prepared(self) -> Self {
let mut listen = self.listen_address;
let mut public = self.public_address;
if self.nat_enabled {
info!("Enabling NAT...");
match search_gateway() {
Err(ref err) => warn!("Port mapping error: {}", err),
Ok(gateway) => {
let int_addr = SocketAddrV4::from_str("127.0.0.1:30304").unwrap();
match gateway.get_any_address(PortMappingProtocol::TCP, int_addr, 0, "Parity Node/TCP") {
Err(ref err) => {
warn!("Port mapping error: {}", err);
},
Ok(ext_addr) => {
info!("Local gateway: {}, External ip address: {}", gateway, ext_addr);
public = SocketAddr::V4(ext_addr);
listen = SocketAddr::V4(int_addr);
},
}
},
}
}
NetworkConfiguration {
config_path: self.config_path,
listen_address: listen,
public_address: public,
nat_enabled: false,
discovery_enabled: self.discovery_enabled,
pin: self.pin,
boot_nodes: self.boot_nodes,
use_secret: self.use_secret,
ideal_peers: self.ideal_peers,
}
}
} }
// Tokens // Tokens
@ -333,16 +297,39 @@ pub struct Host<Message> where Message: Send + Sync + Clone {
timers: RwLock<HashMap<TimerToken, ProtocolTimer>>, timers: RwLock<HashMap<TimerToken, ProtocolTimer>>,
timer_counter: RwLock<usize>, timer_counter: RwLock<usize>,
stats: Arc<NetworkStats>, stats: Arc<NetworkStats>,
public_endpoint: NodeEndpoint,
} }
impl<Message> Host<Message> where Message: Send + Sync + Clone { impl<Message> Host<Message> where Message: Send + Sync + Clone {
/// Create a new instance /// Create a new instance
pub fn new(config: NetworkConfiguration) -> Host<Message> { pub fn new(config: NetworkConfiguration) -> Host<Message> {
let config = config.prepared(); let listen_address = match config.listen_address {
None => SocketAddr::from_str("0.0.0.0:30304").unwrap(),
Some(addr) => addr,
};
let udp_port = config.udp_port.unwrap_or(listen_address.port());
let public_endpoint = match config.public_address {
None => {
let public_address = select_public_address(listen_address.port());
let local_endpoint = NodeEndpoint { address: public_address, udp_port: udp_port };
if config.nat_enabled {
match map_external_address(&local_endpoint) {
Some(endpoint) => {
info!("NAT Mappped to external address {}", endpoint.address);
endpoint
},
None => local_endpoint
}
} else {
local_endpoint
}
}
Some(addr) => NodeEndpoint { address: addr, udp_port: udp_port }
};
let addr = config.listen_address;
// Setup the server socket // Setup the server socket
let tcp_listener = TcpListener::bind(&addr).unwrap(); let tcp_listener = TcpListener::bind(&listen_address).unwrap();
let keys = if let Some(ref secret) = config.use_secret { let keys = if let Some(ref secret) = config.use_secret {
KeyPair::from_secret(secret.clone()).unwrap() KeyPair::from_secret(secret.clone()).unwrap()
} else { } else {
@ -356,8 +343,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
}, },
|s| KeyPair::from_secret(s).expect("Error creating node secret key")) |s| KeyPair::from_secret(s).expect("Error creating node secret key"))
}; };
let endpoint = NodeEndpoint { address: config.public_address.clone(), udp_port: addr.port() }; let discovery = Discovery::new(&keys, listen_address.clone(), public_endpoint.clone(), DISCOVERY);
let discovery = Discovery::new(&keys, endpoint, DISCOVERY);
let path = config.config_path.clone(); let path = config.config_path.clone();
let mut host = Host::<Message> { let mut host = Host::<Message> {
info: RwLock::new(HostInfo { info: RwLock::new(HostInfo {
@ -378,8 +364,9 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
timers: RwLock::new(HashMap::new()), timers: RwLock::new(HashMap::new()),
timer_counter: RwLock::new(USER_TIMER), timer_counter: RwLock::new(USER_TIMER),
stats: Arc::new(NetworkStats::default()), stats: Arc::new(NetworkStats::default()),
public_endpoint: public_endpoint,
}; };
let port = host.info.read().unwrap().config.listen_address.port(); let port = listen_address.port();
host.info.write().unwrap().deref_mut().listen_port = port; host.info.write().unwrap().deref_mut().listen_port = port;
let boot_nodes = host.info.read().unwrap().config.boot_nodes.clone(); let boot_nodes = host.info.read().unwrap().config.boot_nodes.clone();
@ -409,8 +396,8 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
self.info.read().unwrap().client_version.clone() self.info.read().unwrap().client_version.clone()
} }
pub fn client_id(&self) -> NodeId { pub fn client_url(&self) -> String {
self.info.read().unwrap().id().clone() format!("{}", Node::new(self.info.read().unwrap().id().clone(), self.public_endpoint.clone()))
} }
fn maintain_network(&self, io: &IoContext<NetworkIoMessage<Message>>) { fn maintain_network(&self, io: &IoContext<NetworkIoMessage<Message>>) {
@ -456,13 +443,15 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
} }
let handshake_count = self.handshake_count(); let handshake_count = self.handshake_count();
if handshake_count >= MAX_HANDSHAKES { // allow 16 slots for incoming connections
let handshake_limit = MAX_HANDSHAKES - 16;
if handshake_count >= handshake_limit {
return; return;
} }
let nodes = { self.nodes.read().unwrap().nodes() }; let nodes = { self.nodes.read().unwrap().nodes() };
for id in nodes.iter().filter(|ref id| !self.have_session(id) && !self.connecting_to(id)) for id in nodes.iter().filter(|ref id| !self.have_session(id) && !self.connecting_to(id))
.take(min(MAX_HANDSHAKES_PER_ROUND, MAX_HANDSHAKES - handshake_count)) { .take(min(MAX_HANDSHAKES_PER_ROUND, handshake_limit - handshake_count)) {
self.connect_peer(&id, io); self.connect_peer(&id, io);
} }
debug!(target: "net", "Connecting peers: {} sessions, {} pending", self.session_count(), self.handshake_count()); debug!(target: "net", "Connecting peers: {} sessions, {} pending", self.session_count(), self.handshake_count());

View File

@ -73,6 +73,7 @@ mod service;
mod error; mod error;
mod node_table; mod node_table;
mod stats; mod stats;
mod ip_utils;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;

View File

@ -42,7 +42,7 @@ impl<Message> NetworkService<Message> where Message: Send + Sync + Clone + 'stat
let host = Arc::new(Host::new(config)); let host = Arc::new(Host::new(config));
let stats = host.stats().clone(); let stats = host.stats().clone();
let host_info = host.client_version(); let host_info = host.client_version();
info!("Host ID={:?}", host.client_id()); info!("Node URL: {}", host.client_url());
try!(io_service.register_handler(host)); try!(io_service.register_handler(host));
Ok(NetworkService { Ok(NetworkService {
io_service: io_service, io_service: io_service,