Small refactoring

This commit is contained in:
arkpar 2016-02-14 01:03:48 +01:00
parent 62b9f4b91d
commit 76ea030b78
8 changed files with 257 additions and 267 deletions

View File

@ -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);

View File

@ -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() }))

View File

@ -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;

View File

@ -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() {

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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);
}
} }

View File

@ -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;