Small refactoring
This commit is contained in:
parent
62b9f4b91d
commit
76ea030b78
@ -82,7 +82,7 @@ const RECEIPTS_PACKET: u8 = 0x10;
|
|||||||
|
|
||||||
const NETWORK_ID: U256 = ONE_U256; //TODO: get this from parent
|
const NETWORK_ID: U256 = ONE_U256; //TODO: get this from parent
|
||||||
|
|
||||||
const CONNECTION_TIMEOUT_SEC: f64 = 30f64;
|
const CONNECTION_TIMEOUT_SEC: f64 = 10f64;
|
||||||
|
|
||||||
struct Header {
|
struct Header {
|
||||||
/// Header data
|
/// Header data
|
||||||
@ -309,7 +309,7 @@ impl ChainSync {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.peers.insert(peer_id.clone(), peer);
|
self.peers.insert(peer_id.clone(), peer);
|
||||||
info!(target: "sync", "Connected {}:{}", peer_id, io.peer_info(peer_id));
|
debug!(target: "sync", "Connected {}:{}", peer_id, io.peer_info(peer_id));
|
||||||
self.sync_peer(io, peer_id, false);
|
self.sync_peer(io, peer_id, false);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -537,7 +537,7 @@ impl ChainSync {
|
|||||||
pub fn on_peer_aborting(&mut self, io: &mut SyncIo, peer: PeerId) {
|
pub fn on_peer_aborting(&mut self, io: &mut SyncIo, peer: PeerId) {
|
||||||
trace!(target: "sync", "== Disconnecting {}", peer);
|
trace!(target: "sync", "== Disconnecting {}", peer);
|
||||||
if self.peers.contains_key(&peer) {
|
if self.peers.contains_key(&peer) {
|
||||||
info!(target: "sync", "Disconnected {}", peer);
|
debug!(target: "sync", "Disconnected {}", peer);
|
||||||
self.clear_peer_download(peer);
|
self.clear_peer_download(peer);
|
||||||
self.peers.remove(&peer);
|
self.peers.remove(&peer);
|
||||||
self.continue_sync(io);
|
self.continue_sync(io);
|
||||||
|
@ -26,7 +26,7 @@ use time;
|
|||||||
use hash::*;
|
use hash::*;
|
||||||
use crypto::*;
|
use crypto::*;
|
||||||
use rlp::*;
|
use rlp::*;
|
||||||
use network::node::*;
|
use network::node_table::*;
|
||||||
use network::error::NetworkError;
|
use network::error::NetworkError;
|
||||||
use io::StreamToken;
|
use io::StreamToken;
|
||||||
|
|
||||||
@ -227,8 +227,7 @@ impl Discovery {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(map_clone)]
|
#[allow(map_clone)]
|
||||||
fn nearest_node_entries(target: &NodeId, buckets: &[NodeBucket]) -> Vec<NodeEntry>
|
fn nearest_node_entries(target: &NodeId, buckets: &[NodeBucket]) -> Vec<NodeEntry> {
|
||||||
{
|
|
||||||
let mut found: BTreeMap<u32, Vec<&NodeEntry>> = BTreeMap::new();
|
let mut found: BTreeMap<u32, Vec<&NodeEntry>> = BTreeMap::new();
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
|
|
||||||
@ -425,6 +424,7 @@ impl Discovery {
|
|||||||
let node_id: NodeId = try!(r.val_at(3));
|
let node_id: NodeId = try!(r.val_at(3));
|
||||||
let entry = NodeEntry { id: node_id.clone(), endpoint: endpoint };
|
let entry = NodeEntry { id: node_id.clone(), endpoint: endpoint };
|
||||||
added.insert(node_id, entry.clone());
|
added.insert(node_id, entry.clone());
|
||||||
|
self.ping(&entry.endpoint);
|
||||||
self.update_node(entry);
|
self.update_node(entry);
|
||||||
}
|
}
|
||||||
Ok(Some(TableUpdates { added: added, removed: HashSet::new() }))
|
Ok(Some(TableUpdates { added: added, removed: HashSet::new() }))
|
||||||
|
@ -24,7 +24,7 @@ use crypto::*;
|
|||||||
use crypto;
|
use crypto;
|
||||||
use network::connection::{Connection};
|
use network::connection::{Connection};
|
||||||
use network::host::{HostInfo};
|
use network::host::{HostInfo};
|
||||||
use network::node::NodeId;
|
use network::node_table::NodeId;
|
||||||
use error::*;
|
use error::*;
|
||||||
use network::error::NetworkError;
|
use network::error::NetworkError;
|
||||||
use network::stats::NetworkStats;
|
use network::stats::NetworkStats;
|
||||||
|
@ -32,18 +32,18 @@ use network::session::{Session, SessionData};
|
|||||||
use error::*;
|
use error::*;
|
||||||
use io::*;
|
use io::*;
|
||||||
use network::{NetworkProtocolHandler, PROTOCOL_VERSION};
|
use network::{NetworkProtocolHandler, PROTOCOL_VERSION};
|
||||||
use network::node::*;
|
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 igd::{PortMappingProtocol,search_gateway};
|
||||||
use network::discovery::{Discovery, TableUpdates, NodeEntry};
|
use network::discovery::{Discovery, TableUpdates, NodeEntry};
|
||||||
use network::node_table::NodeTable;
|
|
||||||
|
|
||||||
type Slab<T> = ::slab::Slab<T, usize>;
|
type Slab<T> = ::slab::Slab<T, usize>;
|
||||||
|
|
||||||
const _DEFAULT_PORT: u16 = 30304;
|
const _DEFAULT_PORT: u16 = 30304;
|
||||||
const MAX_CONNECTIONS: usize = 1024;
|
const MAX_CONNECTIONS: usize = 1024;
|
||||||
const MAINTENANCE_TIMEOUT: u64 = 1000;
|
const MAINTENANCE_TIMEOUT: u64 = 1000;
|
||||||
|
const MAX_HANDSHAKES: usize = 100;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
/// Network service configuration
|
/// Network service configuration
|
||||||
@ -226,7 +226,7 @@ impl<'s, Message> NetworkContext<'s, Message> where Message: Send + Sync + Clone
|
|||||||
_ => warn!(target: "net", "Send: Peer is not connected yet")
|
_ => warn!(target: "net", "Send: Peer is not connected yet")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
warn!(target: "net", "Send: Peer does not exist")
|
trace!(target: "net", "Send: Peer no longer exist")
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -405,11 +405,23 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn have_session(&self, id: &NodeId) -> bool {
|
fn have_session(&self, id: &NodeId) -> bool {
|
||||||
self.connections.read().unwrap().iter().any(|e| match *e.lock().unwrap().deref() { ConnectionEntry::Session(ref s) => s.info.id.eq(&id), _ => false })
|
self.connections.read().unwrap().iter().any(|e|
|
||||||
|
match *e.lock().unwrap().deref() { ConnectionEntry::Session(ref s) => s.info.id.eq(&id), _ => false })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn session_count(&self) -> usize {
|
||||||
|
self.connections.read().unwrap().iter().filter(|e|
|
||||||
|
match *e.lock().unwrap().deref() { ConnectionEntry::Session(_) => true, _ => false }).count()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn connecting_to(&self, id: &NodeId) -> bool {
|
fn connecting_to(&self, id: &NodeId) -> bool {
|
||||||
self.connections.read().unwrap().iter().any(|e| match *e.lock().unwrap().deref() { ConnectionEntry::Handshake(ref h) => h.id.eq(&id), _ => false })
|
self.connections.read().unwrap().iter().any(|e|
|
||||||
|
match *e.lock().unwrap().deref() { ConnectionEntry::Handshake(ref h) => h.id.eq(&id), _ => false })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handshake_count(&self) -> usize {
|
||||||
|
self.connections.read().unwrap().iter().filter(|e|
|
||||||
|
match *e.lock().unwrap().deref() { ConnectionEntry::Handshake(_) => true, _ => false }).count()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn keep_alive(&self, io: &IoContext<NetworkIoMessage<Message>>) {
|
fn keep_alive(&self, io: &IoContext<NetworkIoMessage<Message>>) {
|
||||||
@ -423,64 +435,40 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for p in to_kill {
|
for p in to_kill {
|
||||||
self.kill_connection(p, io);
|
self.kill_connection(p, io, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn connect_peers(&self, io: &IoContext<NetworkIoMessage<Message>>) {
|
fn connect_peers(&self, io: &IoContext<NetworkIoMessage<Message>>) {
|
||||||
struct NodeInfo {
|
let ideal_peers = { self.info.read().unwrap().deref().config.ideal_peers };
|
||||||
id: NodeId,
|
let connections = self.session_count();
|
||||||
peer_type: PeerType
|
if connections >= ideal_peers as usize {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut to_connect: Vec<NodeInfo> = Vec::new();
|
let handshake_count = self.handshake_count();
|
||||||
let mut req_conn = 0;
|
if handshake_count >= MAX_HANDSHAKES {
|
||||||
let pin = self.info.read().unwrap().deref().config.pin;
|
return;
|
||||||
let ideal_peers = self.info.read().unwrap().deref().config.ideal_peers;
|
|
||||||
for n in self.nodes.read().unwrap().nodes().map(|n| NodeInfo { id: n.id.clone(), peer_type: n.peer_type }) {
|
|
||||||
let connected = self.have_session(&n.id) || self.connecting_to(&n.id);
|
|
||||||
let required = n.peer_type == PeerType::Required;
|
|
||||||
if connected && required {
|
|
||||||
req_conn += 1;
|
|
||||||
}
|
|
||||||
else if !connected && (!pin || required) {
|
|
||||||
to_connect.push(n);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for n in &to_connect {
|
|
||||||
if n.peer_type == PeerType::Required {
|
|
||||||
if req_conn < ideal_peers {
|
|
||||||
self.connect_peer(&n.id, io);
|
|
||||||
}
|
|
||||||
req_conn += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !pin {
|
let nodes = { self.nodes.read().unwrap().nodes() };
|
||||||
let pending_count = 0; //TODO:
|
|
||||||
let peer_count = 0;
|
for id in nodes.iter().filter(|ref id| !self.have_session(id) && !self.connecting_to(id)).take(MAX_HANDSHAKES - handshake_count) {
|
||||||
let mut open_slots = ideal_peers - peer_count - pending_count + req_conn;
|
self.connect_peer(&id, io);
|
||||||
if open_slots > 0 {
|
|
||||||
for n in &to_connect {
|
|
||||||
if n.peer_type == PeerType::Optional && open_slots > 0 {
|
|
||||||
open_slots -= 1;
|
|
||||||
self.connect_peer(&n.id, io);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
debug!(target: "net", "Connecting peers: {} sessions, {} pending", self.session_count(), self.handshake_count());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(single_match)]
|
#[allow(single_match)]
|
||||||
fn connect_peer(&self, id: &NodeId, io: &IoContext<NetworkIoMessage<Message>>) {
|
fn connect_peer(&self, id: &NodeId, io: &IoContext<NetworkIoMessage<Message>>) {
|
||||||
if self.have_session(id)
|
if self.have_session(id)
|
||||||
{
|
{
|
||||||
debug!("Aborted connect. Node already connected.");
|
trace!("Aborted connect. Node already connected.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if self.connecting_to(id) {
|
if self.connecting_to(id) {
|
||||||
debug!("Aborted connect. Node already connecting.");
|
trace!("Aborted connect. Node already connecting.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -542,7 +530,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
|
|||||||
ConnectionEntry::Handshake(ref mut h) => {
|
ConnectionEntry::Handshake(ref mut h) => {
|
||||||
match h.writable(io, &self.info.read().unwrap()) {
|
match h.writable(io, &self.info.read().unwrap()) {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
debug!(target: "net", "Handshake write error: {:?}", e);
|
debug!(target: "net", "Handshake write error: {}:{:?}", token, e);
|
||||||
kill = true;
|
kill = true;
|
||||||
},
|
},
|
||||||
Ok(_) => ()
|
Ok(_) => ()
|
||||||
@ -554,7 +542,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
|
|||||||
ConnectionEntry::Session(ref mut s) => {
|
ConnectionEntry::Session(ref mut s) => {
|
||||||
match s.writable(io, &self.info.read().unwrap()) {
|
match s.writable(io, &self.info.read().unwrap()) {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
debug!(target: "net", "Session write error: {:?}", e);
|
debug!(target: "net", "Session write error: {}:{:?}", token, e);
|
||||||
kill = true;
|
kill = true;
|
||||||
},
|
},
|
||||||
Ok(_) => ()
|
Ok(_) => ()
|
||||||
@ -564,7 +552,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if kill {
|
if kill {
|
||||||
self.kill_connection(token, io); //TODO: mark connection as dead an check in kill_connection
|
self.kill_connection(token, io, true); //TODO: mark connection as dead an check in kill_connection
|
||||||
return;
|
return;
|
||||||
} else if create_session {
|
} else if create_session {
|
||||||
self.start_session(token, io);
|
self.start_session(token, io);
|
||||||
@ -573,7 +561,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn connection_closed(&self, token: TimerToken, io: &IoContext<NetworkIoMessage<Message>>) {
|
fn connection_closed(&self, token: TimerToken, io: &IoContext<NetworkIoMessage<Message>>) {
|
||||||
self.kill_connection(token, io);
|
self.kill_connection(token, io, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn connection_readable(&self, token: StreamToken, io: &IoContext<NetworkIoMessage<Message>>) {
|
fn connection_readable(&self, token: StreamToken, io: &IoContext<NetworkIoMessage<Message>>) {
|
||||||
@ -585,7 +573,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
|
|||||||
match *connection.lock().unwrap().deref_mut() {
|
match *connection.lock().unwrap().deref_mut() {
|
||||||
ConnectionEntry::Handshake(ref mut h) => {
|
ConnectionEntry::Handshake(ref mut h) => {
|
||||||
if let Err(e) = h.readable(io, &self.info.read().unwrap()) {
|
if let Err(e) = h.readable(io, &self.info.read().unwrap()) {
|
||||||
debug!(target: "net", "Handshake read error: {:?}", e);
|
debug!(target: "net", "Handshake read error: {}:{:?}", token, e);
|
||||||
kill = true;
|
kill = true;
|
||||||
}
|
}
|
||||||
if h.done() {
|
if h.done() {
|
||||||
@ -595,7 +583,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
|
|||||||
ConnectionEntry::Session(ref mut s) => {
|
ConnectionEntry::Session(ref mut s) => {
|
||||||
match s.readable(io, &self.info.read().unwrap()) {
|
match s.readable(io, &self.info.read().unwrap()) {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
debug!(target: "net", "Handshake read error: {:?}", e);
|
debug!(target: "net", "Handshake read error: {}:{:?}", token, e);
|
||||||
kill = true;
|
kill = true;
|
||||||
},
|
},
|
||||||
Ok(SessionData::Ready) => {
|
Ok(SessionData::Ready) => {
|
||||||
@ -621,7 +609,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if kill {
|
if kill {
|
||||||
self.kill_connection(token, io); //TODO: mark connection as dead an check in kill_connection
|
self.kill_connection(token, io, true); //TODO: mark connection as dead an check in kill_connection
|
||||||
return;
|
return;
|
||||||
} else if create_session {
|
} else if create_session {
|
||||||
self.start_session(token, io);
|
self.start_session(token, io);
|
||||||
@ -657,17 +645,20 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn connection_timeout(&self, token: StreamToken, io: &IoContext<NetworkIoMessage<Message>>) {
|
fn connection_timeout(&self, token: StreamToken, io: &IoContext<NetworkIoMessage<Message>>) {
|
||||||
self.kill_connection(token, io)
|
self.kill_connection(token, io, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn kill_connection(&self, token: StreamToken, io: &IoContext<NetworkIoMessage<Message>>) {
|
fn kill_connection(&self, token: StreamToken, io: &IoContext<NetworkIoMessage<Message>>, remote: bool) {
|
||||||
let mut to_disconnect: Vec<ProtocolId> = Vec::new();
|
let mut to_disconnect: Vec<ProtocolId> = Vec::new();
|
||||||
{
|
{
|
||||||
let mut connections = self.connections.write().unwrap();
|
let mut connections = self.connections.write().unwrap();
|
||||||
if let Some(connection) = connections.get(token).cloned() {
|
if let Some(connection) = connections.get(token).cloned() {
|
||||||
match *connection.lock().unwrap().deref_mut() {
|
match *connection.lock().unwrap().deref_mut() {
|
||||||
ConnectionEntry::Handshake(_) => {
|
ConnectionEntry::Handshake(ref h) => {
|
||||||
connections.remove(token);
|
connections.remove(token);
|
||||||
|
if remote {
|
||||||
|
self.nodes.write().unwrap().note_failure(h.id());
|
||||||
|
}
|
||||||
},
|
},
|
||||||
ConnectionEntry::Session(ref mut s) if s.is_ready() => {
|
ConnectionEntry::Session(ref mut s) if s.is_ready() => {
|
||||||
for (p, _) in self.handlers.read().unwrap().iter() {
|
for (p, _) in self.handlers.read().unwrap().iter() {
|
||||||
@ -676,6 +667,9 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
connections.remove(token);
|
connections.remove(token);
|
||||||
|
if remote {
|
||||||
|
self.nodes.write().unwrap().note_failure(s.id());
|
||||||
|
}
|
||||||
},
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
@ -706,7 +700,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i in to_remove {
|
for i in to_remove {
|
||||||
self.kill_connection(i, io);
|
self.kill_connection(i, io, false);
|
||||||
}
|
}
|
||||||
self.nodes.write().unwrap().update(node_changes);
|
self.nodes.write().unwrap().update(node_changes);
|
||||||
}
|
}
|
||||||
@ -816,7 +810,7 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
|
|||||||
ConnectionEntry::Session(ref mut s) => { s.disconnect(DisconnectReason::DisconnectRequested); }
|
ConnectionEntry::Session(ref mut s) => { s.disconnect(DisconnectReason::DisconnectRequested); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.kill_connection(*peer, io);
|
self.kill_connection(*peer, io, false);
|
||||||
},
|
},
|
||||||
NetworkIoMessage::User(ref message) => {
|
NetworkIoMessage::User(ref message) => {
|
||||||
for (p, h) in self.handlers.read().unwrap().iter() {
|
for (p, h) in self.handlers.read().unwrap().iter() {
|
||||||
|
@ -71,7 +71,6 @@ mod session;
|
|||||||
mod discovery;
|
mod discovery;
|
||||||
mod service;
|
mod service;
|
||||||
mod error;
|
mod error;
|
||||||
mod node;
|
|
||||||
mod node_table;
|
mod node_table;
|
||||||
mod stats;
|
mod stats;
|
||||||
|
|
||||||
|
@ -1,198 +0,0 @@
|
|||||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
use std::mem;
|
|
||||||
use std::slice::from_raw_parts;
|
|
||||||
use std::net::{SocketAddr, ToSocketAddrs, SocketAddrV4, SocketAddrV6, Ipv4Addr, Ipv6Addr};
|
|
||||||
use std::hash::{Hash, Hasher};
|
|
||||||
use std::str::{FromStr};
|
|
||||||
use hash::*;
|
|
||||||
use rlp::*;
|
|
||||||
use time::Tm;
|
|
||||||
use error::*;
|
|
||||||
|
|
||||||
/// Node public key
|
|
||||||
pub type NodeId = H512;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
/// Node address info
|
|
||||||
pub struct NodeEndpoint {
|
|
||||||
/// IP(V4 or V6) address
|
|
||||||
pub address: SocketAddr,
|
|
||||||
/// Conneciton port.
|
|
||||||
pub udp_port: u16
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NodeEndpoint {
|
|
||||||
pub fn udp_address(&self) -> SocketAddr {
|
|
||||||
match self.address {
|
|
||||||
SocketAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a.ip().clone(), self.udp_port)),
|
|
||||||
SocketAddr::V6(a) => SocketAddr::V6(SocketAddrV6::new(a.ip().clone(), self.udp_port, a.flowinfo(), a.scope_id())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NodeEndpoint {
|
|
||||||
pub fn from_rlp(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
|
|
||||||
let tcp_port = try!(rlp.val_at::<u16>(2));
|
|
||||||
let udp_port = try!(rlp.val_at::<u16>(1));
|
|
||||||
let addr_bytes = try!(try!(rlp.at(0)).data());
|
|
||||||
let address = try!(match addr_bytes.len() {
|
|
||||||
4 => Ok(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(addr_bytes[0], addr_bytes[1], addr_bytes[2], addr_bytes[3]), tcp_port))),
|
|
||||||
16 => unsafe {
|
|
||||||
let o: *const u16 = mem::transmute(addr_bytes.as_ptr());
|
|
||||||
let o = from_raw_parts(o, 8);
|
|
||||||
Ok(SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::new(o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7]), tcp_port, 0, 0)))
|
|
||||||
},
|
|
||||||
_ => Err(DecoderError::RlpInconsistentLengthAndData)
|
|
||||||
});
|
|
||||||
Ok(NodeEndpoint { address: address, udp_port: udp_port })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_rlp(&self, rlp: &mut RlpStream) {
|
|
||||||
match self.address {
|
|
||||||
SocketAddr::V4(a) => {
|
|
||||||
rlp.append(&(&a.ip().octets()[..]));
|
|
||||||
}
|
|
||||||
SocketAddr::V6(a) => unsafe {
|
|
||||||
let o: *const u8 = mem::transmute(a.ip().segments().as_ptr());
|
|
||||||
rlp.append(&from_raw_parts(o, 16));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
rlp.append(&self.udp_port);
|
|
||||||
rlp.append(&self.address.port());
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_rlp_list(&self, rlp: &mut RlpStream) {
|
|
||||||
rlp.begin_list(3);
|
|
||||||
self.to_rlp(rlp);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_valid(&self) -> bool {
|
|
||||||
self.udp_port != 0 && self.address.port() != 0 &&
|
|
||||||
match self.address {
|
|
||||||
SocketAddr::V4(a) => !a.ip().is_unspecified(),
|
|
||||||
SocketAddr::V6(a) => !a.ip().is_unspecified()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromStr for NodeEndpoint {
|
|
||||||
type Err = UtilError;
|
|
||||||
|
|
||||||
/// Create endpoint from string. Performs name resolution if given a host name.
|
|
||||||
fn from_str(s: &str) -> Result<NodeEndpoint, UtilError> {
|
|
||||||
let address = s.to_socket_addrs().map(|mut i| i.next());
|
|
||||||
match address {
|
|
||||||
Ok(Some(a)) => Ok(NodeEndpoint {
|
|
||||||
address: a,
|
|
||||||
udp_port: a.port()
|
|
||||||
}),
|
|
||||||
Ok(_) => Err(UtilError::AddressResolve(None)),
|
|
||||||
Err(e) => Err(UtilError::AddressResolve(Some(e)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Copy, Clone)]
|
|
||||||
pub enum PeerType {
|
|
||||||
Required,
|
|
||||||
Optional
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Node {
|
|
||||||
pub id: NodeId,
|
|
||||||
pub endpoint: NodeEndpoint,
|
|
||||||
pub peer_type: PeerType,
|
|
||||||
pub last_attempted: Option<Tm>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Node {
|
|
||||||
pub fn new(id: NodeId, endpoint: NodeEndpoint) -> Node {
|
|
||||||
Node {
|
|
||||||
id: id,
|
|
||||||
endpoint: endpoint,
|
|
||||||
peer_type: PeerType::Optional,
|
|
||||||
last_attempted: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromStr for Node {
|
|
||||||
type Err = UtilError;
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
||||||
let (id, endpoint) = if &s[0..8] == "enode://" && s.len() > 136 && &s[136..137] == "@" {
|
|
||||||
(try!(NodeId::from_str(&s[8..136])), try!(NodeEndpoint::from_str(&s[137..])))
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
(NodeId::new(), try!(NodeEndpoint::from_str(s)))
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Node {
|
|
||||||
id: id,
|
|
||||||
endpoint: endpoint,
|
|
||||||
peer_type: PeerType::Optional,
|
|
||||||
last_attempted: None,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for Node {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.id == other.id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Eq for Node {}
|
|
||||||
|
|
||||||
impl Hash for Node {
|
|
||||||
fn hash<H>(&self, state: &mut H) where H: Hasher {
|
|
||||||
self.id.hash(state)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
use std::str::FromStr;
|
|
||||||
use std::net::*;
|
|
||||||
use hash::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn endpoint_parse() {
|
|
||||||
let endpoint = NodeEndpoint::from_str("123.99.55.44:7770");
|
|
||||||
assert!(endpoint.is_ok());
|
|
||||||
let v4 = match endpoint.unwrap().address {
|
|
||||||
SocketAddr::V4(v4address) => v4address,
|
|
||||||
_ => panic!("should ve v4 address")
|
|
||||||
};
|
|
||||||
assert_eq!(SocketAddrV4::new(Ipv4Addr::new(123, 99, 55, 44), 7770), v4);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn node_parse() {
|
|
||||||
let node = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770");
|
|
||||||
assert!(node.is_ok());
|
|
||||||
let node = node.unwrap();
|
|
||||||
let v4 = match node.endpoint.address {
|
|
||||||
SocketAddr::V4(v4address) => v4address,
|
|
||||||
_ => panic!("should ve v4 address")
|
|
||||||
};
|
|
||||||
assert_eq!(SocketAddrV4::new(Ipv4Addr::new(22, 99, 55, 44), 7770), v4);
|
|
||||||
assert_eq!(
|
|
||||||
H512::from_str("a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(),
|
|
||||||
node.id);
|
|
||||||
}
|
|
||||||
}
|
|
@ -14,11 +14,161 @@
|
|||||||
// 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::mem;
|
||||||
|
use std::slice::from_raw_parts;
|
||||||
|
use std::net::{SocketAddr, ToSocketAddrs, SocketAddrV4, SocketAddrV6, Ipv4Addr, Ipv6Addr};
|
||||||
|
use std::hash::{Hash, Hasher};
|
||||||
|
use std::str::{FromStr};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::collections::hash_map::Values;
|
use hash::*;
|
||||||
use network::node::*;
|
use rlp::*;
|
||||||
|
use time::Tm;
|
||||||
|
use error::*;
|
||||||
use network::discovery::TableUpdates;
|
use network::discovery::TableUpdates;
|
||||||
|
|
||||||
|
/// Node public key
|
||||||
|
pub type NodeId = H512;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
/// Node address info
|
||||||
|
pub struct NodeEndpoint {
|
||||||
|
/// IP(V4 or V6) address
|
||||||
|
pub address: SocketAddr,
|
||||||
|
/// Conneciton port.
|
||||||
|
pub udp_port: u16
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NodeEndpoint {
|
||||||
|
pub fn udp_address(&self) -> SocketAddr {
|
||||||
|
match self.address {
|
||||||
|
SocketAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a.ip().clone(), self.udp_port)),
|
||||||
|
SocketAddr::V6(a) => SocketAddr::V6(SocketAddrV6::new(a.ip().clone(), self.udp_port, a.flowinfo(), a.scope_id())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NodeEndpoint {
|
||||||
|
pub fn from_rlp(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
|
||||||
|
let tcp_port = try!(rlp.val_at::<u16>(2));
|
||||||
|
let udp_port = try!(rlp.val_at::<u16>(1));
|
||||||
|
let addr_bytes = try!(try!(rlp.at(0)).data());
|
||||||
|
let address = try!(match addr_bytes.len() {
|
||||||
|
4 => Ok(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(addr_bytes[0], addr_bytes[1], addr_bytes[2], addr_bytes[3]), tcp_port))),
|
||||||
|
16 => unsafe {
|
||||||
|
let o: *const u16 = mem::transmute(addr_bytes.as_ptr());
|
||||||
|
let o = from_raw_parts(o, 8);
|
||||||
|
Ok(SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::new(o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7]), tcp_port, 0, 0)))
|
||||||
|
},
|
||||||
|
_ => Err(DecoderError::RlpInconsistentLengthAndData)
|
||||||
|
});
|
||||||
|
Ok(NodeEndpoint { address: address, udp_port: udp_port })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_rlp(&self, rlp: &mut RlpStream) {
|
||||||
|
match self.address {
|
||||||
|
SocketAddr::V4(a) => {
|
||||||
|
rlp.append(&(&a.ip().octets()[..]));
|
||||||
|
}
|
||||||
|
SocketAddr::V6(a) => unsafe {
|
||||||
|
let o: *const u8 = mem::transmute(a.ip().segments().as_ptr());
|
||||||
|
rlp.append(&from_raw_parts(o, 16));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
rlp.append(&self.udp_port);
|
||||||
|
rlp.append(&self.address.port());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_rlp_list(&self, rlp: &mut RlpStream) {
|
||||||
|
rlp.begin_list(3);
|
||||||
|
self.to_rlp(rlp);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_valid(&self) -> bool {
|
||||||
|
self.udp_port != 0 && self.address.port() != 0 &&
|
||||||
|
match self.address {
|
||||||
|
SocketAddr::V4(a) => !a.ip().is_unspecified(),
|
||||||
|
SocketAddr::V6(a) => !a.ip().is_unspecified()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for NodeEndpoint {
|
||||||
|
type Err = UtilError;
|
||||||
|
|
||||||
|
/// Create endpoint from string. Performs name resolution if given a host name.
|
||||||
|
fn from_str(s: &str) -> Result<NodeEndpoint, UtilError> {
|
||||||
|
let address = s.to_socket_addrs().map(|mut i| i.next());
|
||||||
|
match address {
|
||||||
|
Ok(Some(a)) => Ok(NodeEndpoint {
|
||||||
|
address: a,
|
||||||
|
udp_port: a.port()
|
||||||
|
}),
|
||||||
|
Ok(_) => Err(UtilError::AddressResolve(None)),
|
||||||
|
Err(e) => Err(UtilError::AddressResolve(Some(e)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Copy, Clone)]
|
||||||
|
pub enum PeerType {
|
||||||
|
_Required,
|
||||||
|
Optional
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Node {
|
||||||
|
pub id: NodeId,
|
||||||
|
pub endpoint: NodeEndpoint,
|
||||||
|
pub peer_type: PeerType,
|
||||||
|
pub failures: u32,
|
||||||
|
pub last_attempted: Option<Tm>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Node {
|
||||||
|
pub fn new(id: NodeId, endpoint: NodeEndpoint) -> Node {
|
||||||
|
Node {
|
||||||
|
id: id,
|
||||||
|
endpoint: endpoint,
|
||||||
|
peer_type: PeerType::Optional,
|
||||||
|
failures: 0,
|
||||||
|
last_attempted: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Node {
|
||||||
|
type Err = UtilError;
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let (id, endpoint) = if &s[0..8] == "enode://" && s.len() > 136 && &s[136..137] == "@" {
|
||||||
|
(try!(NodeId::from_str(&s[8..136])), try!(NodeEndpoint::from_str(&s[137..])))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
(NodeId::new(), try!(NodeEndpoint::from_str(s)))
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Node {
|
||||||
|
id: id,
|
||||||
|
endpoint: endpoint,
|
||||||
|
peer_type: PeerType::Optional,
|
||||||
|
last_attempted: None,
|
||||||
|
failures: 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Node {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.id == other.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Eq for Node {}
|
||||||
|
|
||||||
|
impl Hash for Node {
|
||||||
|
fn hash<H>(&self, state: &mut H) where H: Hasher {
|
||||||
|
self.id.hash(state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Node table backed by disk file.
|
||||||
pub struct NodeTable {
|
pub struct NodeTable {
|
||||||
nodes: HashMap<NodeId, Node>
|
nodes: HashMap<NodeId, Node>
|
||||||
}
|
}
|
||||||
@ -30,18 +180,24 @@ impl NodeTable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add a node to table
|
||||||
pub fn add_node(&mut self, node: Node) {
|
pub fn add_node(&mut self, node: Node) {
|
||||||
self.nodes.insert(node.id.clone(), node);
|
self.nodes.insert(node.id.clone(), node);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn nodes(&self) -> Values<NodeId, Node> {
|
/// Returns node ids sorted by number of failures
|
||||||
self.nodes.values()
|
pub fn nodes(&self) -> Vec<NodeId> {
|
||||||
|
let mut refs: Vec<&Node> = self.nodes.values().collect();
|
||||||
|
refs.sort_by(|a, b| a.failures.cmp(&b.failures));
|
||||||
|
refs.iter().map(|n| n.id.clone()).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get particular node
|
||||||
pub fn get_mut(&mut self, id: &NodeId) -> Option<&mut Node> {
|
pub fn get_mut(&mut self, id: &NodeId) -> Option<&mut Node> {
|
||||||
self.nodes.get_mut(id)
|
self.nodes.get_mut(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Apply table changes coming from discovery
|
||||||
pub fn update(&mut self, mut update: TableUpdates) {
|
pub fn update(&mut self, mut update: TableUpdates) {
|
||||||
for (_, node) in update.added.drain() {
|
for (_, node) in update.added.drain() {
|
||||||
let mut entry = self.nodes.entry(node.id.clone()).or_insert_with(|| Node::new(node.id.clone(), node.endpoint.clone()));
|
let mut entry = self.nodes.entry(node.id.clone()).or_insert_with(|| Node::new(node.id.clone(), node.endpoint.clone()));
|
||||||
@ -52,4 +208,43 @@ impl NodeTable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn note_failure(&mut self, id: &NodeId) {
|
||||||
|
if let Some(node) = self.nodes.get_mut(id) {
|
||||||
|
node.failures += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use std::str::FromStr;
|
||||||
|
use std::net::*;
|
||||||
|
use hash::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn endpoint_parse() {
|
||||||
|
let endpoint = NodeEndpoint::from_str("123.99.55.44:7770");
|
||||||
|
assert!(endpoint.is_ok());
|
||||||
|
let v4 = match endpoint.unwrap().address {
|
||||||
|
SocketAddr::V4(v4address) => v4address,
|
||||||
|
_ => panic!("should ve v4 address")
|
||||||
|
};
|
||||||
|
assert_eq!(SocketAddrV4::new(Ipv4Addr::new(123, 99, 55, 44), 7770), v4);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn node_parse() {
|
||||||
|
let node = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770");
|
||||||
|
assert!(node.is_ok());
|
||||||
|
let node = node.unwrap();
|
||||||
|
let v4 = match node.endpoint.address {
|
||||||
|
SocketAddr::V4(v4address) => v4address,
|
||||||
|
_ => panic!("should ve v4 address")
|
||||||
|
};
|
||||||
|
assert_eq!(SocketAddrV4::new(Ipv4Addr::new(22, 99, 55, 44), 7770), v4);
|
||||||
|
assert_eq!(
|
||||||
|
H512::from_str("a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(),
|
||||||
|
node.id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ use error::*;
|
|||||||
use io::{IoContext, StreamToken};
|
use io::{IoContext, StreamToken};
|
||||||
use network::error::{NetworkError, DisconnectReason};
|
use network::error::{NetworkError, DisconnectReason};
|
||||||
use network::host::*;
|
use network::host::*;
|
||||||
use network::node::NodeId;
|
use network::node_table::NodeId;
|
||||||
use time;
|
use time;
|
||||||
|
|
||||||
const PING_TIMEOUT_SEC: u64 = 30;
|
const PING_TIMEOUT_SEC: u64 = 30;
|
||||||
|
Loading…
Reference in New Issue
Block a user