// 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 . use std::net::{SocketAddr, ToSocketAddrs}; 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)] /// Noe address info pub struct NodeEndpoint { /// IP(V4 or V6) address pub address: SocketAddr, /// Address as string (can be host name). pub address_str: String, /// Conneciton port. pub udp_port: u16 } 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 { let address = s.to_socket_addrs().map(|mut i| i.next()); match address { Ok(Some(a)) => Ok(NodeEndpoint { address: a, address_str: s.to_owned(), 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, } impl FromStr for Node { type Err = UtilError; fn from_str(s: &str) -> Result { 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(&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); } }