Encryption primitives; Continue work on handshake

This commit is contained in:
arkpar 2015-11-30 16:38:55 +01:00
parent 5c975d06cc
commit 4873c33fef
9 changed files with 571 additions and 140 deletions

View File

@ -18,5 +18,5 @@ tiny-keccak = "0.3"
rocksdb = "0.2.1" rocksdb = "0.2.1"
num = "0.1" num = "0.1"
lazy_static = "0.1.*" lazy_static = "0.1.*"
secp256k1 = "0.5.1" eth-secp256k1 = { git = "https://github.com/arkpar/rust-secp256k1.git" }
rust-crypto = "0.2.34" rust-crypto = "0.2.34"

View File

@ -5,7 +5,8 @@ use rand::os::OsRng;
pub type Secret=H256; pub type Secret=H256;
pub type Public=H512; pub type Public=H512;
pub type Signature=H520;
pub use ::sha3::Hashable;
#[derive(Debug)] #[derive(Debug)]
pub enum CryptoError { pub enum CryptoError {
@ -94,8 +95,13 @@ impl KeyPair {
} }
} }
/// Recovers Public key from signed message hash. pub mod ec {
pub fn recover(signature: &Signature, message: &H256) -> Result<Public, CryptoError> { use hash::*;
use crypto::*;
pub type Signature = H520;
/// Recovers Public key from signed message hash.
pub fn recover(signature: &Signature, message: &H256) -> Result<Public, CryptoError> {
use secp256k1::*; use secp256k1::*;
let context = Secp256k1::new(); let context = Secp256k1::new();
let rsig = try!(RecoverableSignature::from_compact(&context, &signature[0..64], try!(RecoveryId::from_i32(signature[64] as i32)))); let rsig = try!(RecoverableSignature::from_compact(&context, &signature[0..64], try!(RecoveryId::from_i32(signature[64] as i32))));
@ -103,21 +109,21 @@ pub fn recover(signature: &Signature, message: &H256) -> Result<Public, CryptoEr
let serialized = publ.serialize_vec(&context, false); let serialized = publ.serialize_vec(&context, false);
let p: Public = Public::from_slice(&serialized[1..65]); let p: Public = Public::from_slice(&serialized[1..65]);
Ok(p) Ok(p)
} }
/// Returns siganture of message hash. /// Returns siganture of message hash.
pub fn sign(secret: &Secret, message: &H256) -> Result<Signature, CryptoError> { pub fn sign(secret: &Secret, message: &H256) -> Result<Signature, CryptoError> {
use secp256k1::*; use secp256k1::*;
let context = Secp256k1::new(); let context = Secp256k1::new();
let sec: &key::SecretKey = unsafe { ::std::mem::transmute(secret) }; let sec: &key::SecretKey = unsafe { ::std::mem::transmute(secret) };
let s = try!(context.sign_recoverable(&try!(Message::from_slice(&message)), sec)); let s = try!(context.sign_recoverable(&try!(Message::from_slice(&message)), sec));
let (rec_id, data) = s.serialize_compact(&context); let (rec_id, data) = s.serialize_compact(&context);
let mut signature: ::crypto::Signature = unsafe { ::std::mem::uninitialized() }; let mut signature: ec::Signature = unsafe { ::std::mem::uninitialized() };
signature.clone_from_slice(&data); signature.clone_from_slice(&data);
signature[64] = rec_id.to_i32() as u8; signature[64] = rec_id.to_i32() as u8;
Ok(signature) Ok(signature)
} }
/// Verify signature. /// Verify signature.
pub fn verify(public: &Public, signature: &Signature, message: &H256) -> Result<bool, CryptoError> { pub fn verify(public: &Public, signature: &Signature, message: &H256) -> Result<bool, CryptoError> {
use secp256k1::*; use secp256k1::*;
let context = Secp256k1::new(); let context = Secp256k1::new();
let rsig = try!(RecoverableSignature::from_compact(&context, &signature[0..64], try!(RecoveryId::from_i32(signature[64] as i32)))); let rsig = try!(RecoverableSignature::from_compact(&context, &signature[0..64], try!(RecoveryId::from_i32(signature[64] as i32))));
@ -133,8 +139,108 @@ pub fn verify(public: &Public, signature: &Signature, message: &H256) -> Result<
Err(Error::IncorrectSignature) => Ok(false), Err(Error::IncorrectSignature) => Ok(false),
Err(x) => Err(<CryptoError as From<Error>>::from(x)) Err(x) => Err(<CryptoError as From<Error>>::from(x))
} }
}
} }
pub mod ecdh {
use crypto::*;
pub fn agree(secret: &Secret, public: &Public, ) -> Result<Secret, CryptoError> {
use secp256k1::*;
let context = Secp256k1::new();
let mut pdata: [u8; 65] = [4u8; 65];
let ptr = pdata[1..].as_mut_ptr();
let src = public.as_ptr();
unsafe { ::std::ptr::copy_nonoverlapping(src, ptr, 64) };
let publ = try!(key::PublicKey::from_slice(&context, &pdata));
let sec: &key::SecretKey = unsafe { ::std::mem::transmute(secret) };
let shared = ecdh::SharedSecret::new_raw(&context, &publ, &sec);
let s: Secret = unsafe { ::std::mem::transmute(shared) };
Ok(s)
}
}
pub mod ecies {
use hash::*;
use bytes::*;
use crypto::*;
pub fn encrypt(public: &Public, plain: &[u8]) -> Result<Bytes, CryptoError> {
use ::rcrypto::digest::Digest;
use ::rcrypto::sha2::Sha256;
use ::rcrypto::hmac::Hmac;
use ::rcrypto::mac::Mac;
let r = try!(KeyPair::create());
let z = try!(ecdh::agree(r.secret(), public));
let mut key = [0u8; 32];
let mut mkey = [0u8; 32];
kdf(&z, &[0u8; 0], &mut key);
let mut hasher = Sha256::new();
let mkey_material = &key[16..32];
hasher.input(mkey_material);
hasher.result(&mut mkey);
let ekey = &key[0..16];
let mut msg = vec![0u8; (1 + 64 + 16 + plain.len() + 32)];
msg[0] = 0x04u8;
{
let msgd = &mut msg[1..];
r.public().copy_to(&mut msgd[0..64]);
{
let cipher = &mut msgd[(64 + 16)..(64 + 16 + plain.len())];
aes::encrypt(ekey, &H128::new(), plain, cipher);
}
let mut hmac = Hmac::new(Sha256::new(), &mkey);
{
let cipher_iv = &msgd[64..(64 + 16 + plain.len())];
hmac.input(cipher_iv);
}
hmac.raw_result(&mut msgd[(64 + 16 + plain.len())..]);
}
Ok(msg)
}
fn kdf(secret: &Secret, s1: &[u8], dest: &mut [u8]) {
use ::rcrypto::digest::Digest;
use ::rcrypto::sha2::Sha256;
let mut hasher = Sha256::new();
// SEC/ISO/Shoup specify counter size SHOULD be equivalent
// to size of hash output, however, it also notes that
// the 4 bytes is okay. NIST specifies 4 bytes.
let mut ctr = 1u32;
let mut written = 0usize;
while written < dest.len() {
let ctrs = [(ctr >> 24) as u8, (ctr >> 16) as u8, (ctr >> 8) as u8, ctr as u8];
hasher.input(&ctrs);
hasher.input(secret);
hasher.input(s1);
hasher.result(&mut dest[written..(written + 32)]);
hasher.reset();
written += 32;
ctr += 1;
}
}
}
pub mod aes {
use hash::*;
use ::rcrypto::blockmodes::*;
use ::rcrypto::aessafe::*;
use ::rcrypto::symmetriccipher::*;
use ::rcrypto::buffer::*;
pub fn encrypt(k: &[u8], iv: &H128, plain: &[u8], dest: &mut [u8]) {
let mut encryptor = CtrMode::new(AesSafe128Encryptor::new(k), iv[..].to_vec());
encryptor.encrypt(&mut RefReadBuffer::new(plain), &mut RefWriteBuffer::new(dest), true).expect("Invalid length or padding");
}
pub fn decrypt(k: &[u8], iv: &H128, encrypted: &[u8], dest: &mut [u8]) {
let mut encryptor = CtrMode::new(AesSafe128Encryptor::new(k), iv[..].to_vec());
encryptor.decrypt(&mut RefReadBuffer::new(encrypted), &mut RefWriteBuffer::new(dest), true).expect("Invalid length or padding");
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {

View File

@ -2,7 +2,7 @@ use std::str::FromStr;
use std::fmt; use std::fmt;
use std::ops; use std::ops;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::ops::{Index, IndexMut, Deref, DerefMut, BitOr, BitAnd}; use std::ops::{Index, IndexMut, Deref, DerefMut, BitOr, BitAnd, BitXor};
use rustc_serialize::hex::*; use rustc_serialize::hex::*;
use error::EthcoreError; use error::EthcoreError;
use rand::Rng; use rand::Rng;
@ -19,6 +19,7 @@ pub trait FixedHash: Sized + BytesConvertable {
fn mut_bytes(&mut self) -> &mut [u8]; fn mut_bytes(&mut self) -> &mut [u8];
fn from_slice(src: &[u8]) -> Self; fn from_slice(src: &[u8]) -> Self;
fn clone_from_slice(&mut self, src: &[u8]) -> usize; fn clone_from_slice(&mut self, src: &[u8]) -> usize;
fn copy_to(&self, dest: &mut [u8]);
fn shift_bloom<'a, T>(&'a mut self, b: &T) -> &'a mut Self where T: FixedHash; fn shift_bloom<'a, T>(&'a mut self, b: &T) -> &'a mut Self where T: FixedHash;
fn bloom_part<T>(&self, m: usize) -> T where T: FixedHash; fn bloom_part<T>(&self, m: usize) -> T where T: FixedHash;
fn contains_bloom<T>(&self, b: &T) -> bool where T: FixedHash; fn contains_bloom<T>(&self, b: &T) -> bool where T: FixedHash;
@ -95,6 +96,13 @@ macro_rules! impl_hash {
r r
} }
fn copy_to(&self, dest: &mut[u8]) {
unsafe {
let min = ::std::cmp::min($size, dest.len());
::std::ptr::copy(self.0.as_ptr(), dest.as_mut_ptr(), min);
}
}
fn shift_bloom<'a, T>(&'a mut self, b: &T) -> &'a mut Self where T: FixedHash { fn shift_bloom<'a, T>(&'a mut self, b: &T) -> &'a mut Self where T: FixedHash {
let bp: Self = b.bloom_part($size); let bp: Self = b.bloom_part($size);
let new_self = &bp | self; let new_self = &bp | self;
@ -299,6 +307,30 @@ macro_rules! impl_hash {
} }
} }
/// BitXor on references
impl <'a> BitXor for &'a $from {
type Output = $from;
fn bitxor(self, rhs: Self) -> Self::Output {
unsafe {
use std::mem;
let mut ret: $from = mem::uninitialized();
for i in 0..$size {
ret.0[i] = self.0[i] ^ rhs.0[i];
}
ret
}
}
}
/// Moving BitXor
impl BitXor for $from {
type Output = $from;
fn bitxor(self, rhs: Self) -> Self::Output {
&self ^ &rhs
}
}
impl $from { impl $from {
pub fn hex(&self) -> String { pub fn hex(&self) -> String {
format!("{}", self) format!("{}", self)

View File

@ -34,7 +34,7 @@ pub mod math;
pub mod chainfilter; pub mod chainfilter;
pub mod crypto; pub mod crypto;
//pub mod network; pub mod network;
// reexports // reexports
pub use std::str::FromStr; pub use std::str::FromStr;

109
src/network/connection.rs Normal file
View File

@ -0,0 +1,109 @@
use std::io::{self, Cursor, Read};
use mio::*;
use mio::tcp::*;
use hash::*;
use bytes::*;
use network::host::Host;
pub struct Connection {
pub token: Token,
pub socket: TcpStream,
rec_buf: Bytes,
rec_size: usize,
send_buf: Cursor<Bytes>,
interest: EventSet,
}
pub enum WriteStatus {
Ongoing,
Complete
}
impl Connection {
pub fn new(token: Token, socket: TcpStream) -> Connection {
Connection {
token: token,
socket: socket,
send_buf: Cursor::new(Bytes::new()),
rec_buf: Bytes::new(),
rec_size: 0,
interest: EventSet::hup(),
}
}
pub fn expect(&mut self, size: usize) {
if self.rec_size != self.rec_buf.len() {
warn!(target:"net", "Unexpected connection read start");
}
unsafe { self.rec_buf.set_len(size) }
self.rec_size = size;
}
pub fn readable(&mut self) -> io::Result<Option<&[u8]>> {
if self.rec_size == 0 || self.rec_buf.len() >= self.rec_size {
warn!(target:"net", "Unexpected connection read");
}
let max = self.rec_size - self.rec_buf.len();
// resolve "multiple applicable items in scope [E0034]" error
let sock_ref = <TcpStream as Read>::by_ref(&mut self.socket);
match sock_ref.take(max as u64).try_read_buf(&mut self.rec_buf) {
Ok(Some(_)) if self.rec_buf.len() == self.rec_size => Ok(Some(&self.rec_buf[0..self.rec_size])),
Ok(_) => Ok(None),
Err(e) => Err(e),
}
}
pub fn send(&mut self, data: &[u8]) { //TODO: take ownership version
let send_size = self.send_buf.get_ref().len();
if send_size != 0 || self.send_buf.position() as usize >= send_size {
warn!(target:"net", "Unexpected connection send start");
}
if self.send_buf.get_ref().capacity() < data.len() {
let capacity = self.send_buf.get_ref().capacity();
self.send_buf.get_mut().reserve(data.len() - capacity);
}
unsafe { self.send_buf.get_mut().set_len(data.len()) }
unsafe { ::std::ptr::copy_nonoverlapping(data.as_ptr(), self.send_buf.get_mut()[..].as_mut_ptr(), data.len()) };
if !self.interest.is_writable() {
self.interest.insert(EventSet::writable());
}
}
pub fn writable(&mut self) -> io::Result<WriteStatus> {
let send_size = self.send_buf.get_ref().len();
if (self.send_buf.position() as usize) >= send_size {
warn!(target:"net", "Unexpected connection data");
return Ok(WriteStatus::Complete)
}
match self.socket.try_write_buf(&mut self.send_buf) {
Ok(_) if (self.send_buf.position() as usize) < send_size => {
self.interest.insert(EventSet::writable());
Ok(WriteStatus::Ongoing)
},
Ok(_) if (self.send_buf.position() as usize) == send_size => {
self.interest.remove(EventSet::writable());
Ok(WriteStatus::Complete)
},
Ok(_) => { panic!("Wrote past buffer");},
Err(e) => Err(e)
}
}
pub fn register(&mut self, event_loop: &mut EventLoop<Host>) -> io::Result<()> {
trace!(target: "net", "connection register; token={:?}", self.token);
self.interest.insert(EventSet::readable());
event_loop.register_opt(&self.socket, self.token, self.interest, PollOpt::edge() | PollOpt::oneshot()).or_else(|e| {
error!("Failed to reregister {:?}, {:?}", self.token, e);
Err(e)
})
}
pub fn reregister(&mut self, event_loop: &mut EventLoop<Host>) -> io::Result<()> {
trace!(target: "net", "connection reregister; token={:?}", self.token);
event_loop.reregister( &self.socket, self.token, self.interest, PollOpt::edge() | PollOpt::oneshot()).or_else(|e| {
error!("Failed to reregister {:?}, {:?}", self.token, e);
Err(e)
})
}
}

145
src/network/handshake.rs Normal file
View File

@ -0,0 +1,145 @@
use mio::*;
use mio::tcp::*;
use hash::*;
use crypto::*;
use crypto;
use network::connection::{Connection, WriteStatus};
use network::host::{NodeId, Host, HostInfo};
use network::Error;
#[derive(PartialEq, Eq)]
enum HandshakeState {
New,
ReadingAuth,
WritingAuth,
ReadingAck,
WritingAck,
WritingHello,
ReadingHello,
StartSession,
}
pub struct Handshake {
pub id: NodeId,
pub connection: Connection,
state: HandshakeState,
idle_timeout: Option<Timeout>,
ecdhe: KeyPair,
nonce: H256,
remote_public: Public,
remote_nonce: H256
}
impl Handshake {
pub fn new(token: Token, id: &NodeId, socket: TcpStream, nonce: &H256) -> Result<Handshake, Error> {
Ok(Handshake {
id: id.clone(),
connection: Connection::new(token, socket),
state: HandshakeState::New,
idle_timeout: None,
ecdhe: try!(KeyPair::create()),
nonce: nonce.clone(),
remote_public: Public::new(),
remote_nonce: H256::new()
})
}
pub fn start(&mut self, host: &HostInfo, originated: bool) {
if originated {
self.write_auth(host);
}
else {
self.read_auth();
};
}
pub fn done(&self) -> bool {
self.state == HandshakeState::StartSession
}
pub fn readable(&mut self, event_loop: &mut EventLoop<Host>, host: &HostInfo) -> Result<(), Error> {
self.idle_timeout.map(|t| event_loop.clear_timeout(t));
Ok(())
}
pub fn writable(&mut self, event_loop: &mut EventLoop<Host>, host: &HostInfo) -> Result<(), Error> {
self.idle_timeout.map(|t| event_loop.clear_timeout(t));
match self.state {
HandshakeState::WritingAuth => {
match (try!(self.connection.writable())) {
WriteStatus::Complete => { try!(self.read_ack()); },
_ => {}
};
try!(self.connection.reregister(event_loop));
},
HandshakeState::WritingAck => {
match (try!(self.connection.writable())) {
WriteStatus::Complete => { try!(self.read_hello()); },
_ => {}
};
try!(self.connection.reregister(event_loop));
},
HandshakeState::WritingHello => {
match (try!(self.connection.writable())) {
WriteStatus::Complete => { self.state = HandshakeState::StartSession; },
_ => { try!(self.connection.reregister(event_loop)); }
};
},
_ => { panic!("Unexpected state") }
}
Ok(())
}
pub fn register(&mut self, event_loop: &mut EventLoop<Host>) -> Result<(), Error> {
self.idle_timeout.map(|t| event_loop.clear_timeout(t));
self.idle_timeout = event_loop.timeout_ms(self.connection.token, 1800).ok();
self.connection.register(event_loop);
Ok(())
}
fn read_auth(&mut self) -> Result<(), Error> {
Ok(())
}
fn read_ack(&mut self) -> Result<(), Error> {
Ok(())
}
fn read_hello(&mut self) -> Result<(), Error> {
Ok(())
}
fn write_auth(&mut self, host: &HostInfo) -> Result<(), Error> {
trace!(target:"net", "Sending auth to {:?}", self.connection.socket.peer_addr());
let mut data = [0u8; /*Signature::SIZE*/ 65 + /*H256::SIZE*/ 32 + /*Public::SIZE*/ 64 + /*H256::SIZE*/ 32 + 1]; //TODO: use associated constants
let len = data.len();
{
data[len - 1] = 0x0;
let (sig, rest) = data.split_at_mut(65);
let (hepubk, rest) = rest.split_at_mut(32);
let (mut pubk, rest) = rest.split_at_mut(64);
let (nonce, rest) = rest.split_at_mut(32);
// E(remote-pubk, S(ecdhe-random, ecdh-shared-secret^nonce) || H(ecdhe-random-pubk) || pubk || nonce || 0x0)
let shared = try!(crypto::ecdh::agree(host.secret(), &self.id));
let signature = try!(crypto::ec::sign(self.ecdhe.secret(), &(&shared ^ &self.nonce))).copy_to(sig);
self.ecdhe.public().sha3_into(hepubk);
host.id().copy_to(&mut pubk);
self.nonce.copy_to(nonce);
}
let message = try!(crypto::ecies::encrypt(&self.id, &data));
self.connection.send(&message[..]);
self.state = HandshakeState::WritingAuth;
Ok(())
}
fn write_ack(&mut self) -> Result<(), Error> {
Ok(())
}
fn write_hello(&mut self) -> Result<(), Error> {
Ok(())
}
}

View File

@ -11,9 +11,11 @@ use mio::util::{Slab};
use mio::tcp::*; use mio::tcp::*;
use mio::udp::*; use mio::udp::*;
use hash::*; use hash::*;
use bytes::*; use crypto::*;
use time::Tm; use time::Tm;
use error::EthcoreError; use error::EthcoreError;
use network::connection::Connection;
use network::handshake::Handshake;
const DEFAULT_PORT: u16 = 30303; const DEFAULT_PORT: u16 = 30303;
@ -27,9 +29,7 @@ const IDEAL_PEERS:u32 = 10;
const BUCKET_SIZE: u32 = 16; ///< Denoted by k in [Kademlia]. Number of nodes stored in each bucket. const BUCKET_SIZE: u32 = 16; ///< Denoted by k in [Kademlia]. Number of nodes stored in each bucket.
const ALPHA: usize = 3; ///< Denoted by \alpha in [Kademlia]. Number of concurrent FindNode requests. const ALPHA: usize = 3; ///< Denoted by \alpha in [Kademlia]. Number of concurrent FindNode requests.
type NodeId = H512; pub type NodeId = H512;
type PublicKey = H512;
type SecretKey = H256;
#[derive(Debug)] #[derive(Debug)]
struct NetworkConfiguration { struct NetworkConfiguration {
@ -47,7 +47,7 @@ impl NetworkConfiguration {
public_address: SocketAddr::from_str("0.0.0.0:30303").unwrap(), public_address: SocketAddr::from_str("0.0.0.0:30303").unwrap(),
no_nat: false, no_nat: false,
no_discovery: false, no_discovery: false,
pin: false pin: false,
} }
} }
} }
@ -164,45 +164,6 @@ impl NodeBucket {
} }
} }
struct Connection {
socket: TcpStream,
send_queue: Vec<Bytes>,
}
impl Connection {
fn new(socket: TcpStream) -> Connection {
Connection {
socket: socket,
send_queue: Vec::new(),
}
}
}
#[derive(PartialEq, Eq)]
enum HandshakeState {
New,
AckAuth,
WriteHello,
ReadHello,
StartSession,
}
struct Handshake {
id: NodeId,
connection: Connection,
state: HandshakeState,
}
impl Handshake {
fn new(id: NodeId, socket: TcpStream) -> Handshake {
Handshake {
id: id,
connection: Connection::new(socket),
state: HandshakeState::New
}
}
}
struct Peer { struct Peer {
id: NodeId, id: NodeId,
connection: Connection, connection: Connection,
@ -214,7 +175,7 @@ impl FindNodePacket {
fn new(_endpoint: &NodeEndpoint, _id: &NodeId) -> FindNodePacket { fn new(_endpoint: &NodeEndpoint, _id: &NodeId) -> FindNodePacket {
FindNodePacket FindNodePacket
} }
fn sign(&mut self, _secret: &SecretKey) { fn sign(&mut self, _secret: &Secret) {
} }
fn send(& self, _socket: &mut UdpSocket) { fn send(& self, _socket: &mut UdpSocket) {
@ -236,11 +197,29 @@ pub enum HostMessage {
Shutdown Shutdown
} }
pub struct Host { pub struct HostInfo {
secret: SecretKey, keys: KeyPair,
node: Node,
sender: Sender<HostMessage>,
config: NetworkConfiguration, config: NetworkConfiguration,
nonce: H256
}
impl HostInfo {
pub fn id(&self) -> &NodeId {
self.keys.public()
}
pub fn secret(&self) -> &Secret {
self.keys.secret()
}
pub fn next_nonce(&mut self) -> H256 {
self.nonce = self.nonce.sha3();
return self.nonce.clone();
}
}
pub struct Host {
info: HostInfo,
sender: Sender<HostMessage>,
udp_socket: UdpSocket, udp_socket: UdpSocket,
listener: TcpListener, listener: TcpListener,
peers: Slab<Peer>, peers: Slab<Peer>,
@ -282,9 +261,11 @@ impl Host {
event_loop.timeout_ms(Token(NODETABLE_MAINTAIN), 7200).unwrap(); event_loop.timeout_ms(Token(NODETABLE_MAINTAIN), 7200).unwrap();
let mut host = Host { let mut host = Host {
secret: SecretKey::new(), info: HostInfo {
node: Node::new(NodeId::new(), config.public_address.clone(), PeerType::Required), keys: KeyPair::create().unwrap(),
config: config, config: config,
nonce: H256::random()
},
sender: sender, sender: sender,
udp_socket: udp_socket, udp_socket: udp_socket,
listener: listener, listener: listener,
@ -338,7 +319,7 @@ impl Host {
} }
let mut tried_count = 0; let mut tried_count = 0;
{ {
let nearest = Host::nearest_node_entries(&self.node.id, &self.discovery_id, &self.node_buckets).into_iter(); let nearest = Host::nearest_node_entries(&self.info.id(), &self.discovery_id, &self.node_buckets).into_iter();
let nodes = RefCell::new(&mut self.discovery_nodes); let nodes = RefCell::new(&mut self.discovery_nodes);
let nearest = nearest.filter(|x| nodes.borrow().contains(&x)).take(ALPHA); let nearest = nearest.filter(|x| nodes.borrow().contains(&x)).take(ALPHA);
for r in nearest { for r in nearest {
@ -380,14 +361,14 @@ impl Host {
ret ret
} }
fn nearest_node_entries<'a>(source: &NodeId, target: &NodeId, buckets: &'a Vec<NodeBucket>) -> Vec<&'a NodeId> fn nearest_node_entries<'b>(source: &NodeId, target: &NodeId, buckets: &'b Vec<NodeBucket>) -> Vec<&'b NodeId>
{ {
// send ALPHA FindNode packets to nodes we know, closest to target // send ALPHA FindNode packets to nodes we know, closest to target
const LAST_BIN: u32 = NODE_BINS - 1; const LAST_BIN: u32 = NODE_BINS - 1;
let mut head = Host::distance(source, target); let mut head = Host::distance(source, target);
let mut tail = if head == 0 { LAST_BIN } else { (head - 1) % NODE_BINS }; let mut tail = if head == 0 { LAST_BIN } else { (head - 1) % NODE_BINS };
let mut found: BTreeMap<u32, Vec<&'a NodeId>> = BTreeMap::new(); let mut found: BTreeMap<u32, Vec<&'b NodeId>> = BTreeMap::new();
let mut count = 0; let mut count = 0;
// if d is 0, then we roll look forward, if last, we reverse, else, spread from d // if d is 0, then we roll look forward, if last, we reverse, else, spread from d
@ -463,7 +444,6 @@ impl Host {
} }
fn maintain_network(&mut self, event_loop: &mut EventLoop<Host>) { fn maintain_network(&mut self, event_loop: &mut EventLoop<Host>) {
self.keep_alive();
self.connect_peers(event_loop); self.connect_peers(event_loop);
} }
@ -491,7 +471,7 @@ impl Host {
if connected && required { if connected && required {
req_conn += 1; req_conn += 1;
} }
else if !connected && (!self.config.pin || required) { else if !connected && (!self.info.config.pin || required) {
to_connect.push(n); to_connect.push(n);
} }
} }
@ -505,7 +485,7 @@ impl Host {
} }
} }
if !self.config.pin if !self.info.config.pin
{ {
let pending_count = 0; //TODO: let pending_count = 0; //TODO:
let peer_count = 0; let peer_count = 0;
@ -532,56 +512,88 @@ impl Host {
warn!("Aborted connect. Node already connecting."); warn!("Aborted connect. Node already connecting.");
return; return;
} }
let socket = {
let node = self.nodes.get_mut(id).unwrap(); let node = self.nodes.get_mut(id).unwrap();
node.last_attempted = Some(::time::now()); node.last_attempted = Some(::time::now());
//blog(NetConnect) << "Attempting connection to node" << _p->id << "@" << ep << "from" << id(); //blog(NetConnect) << "Attempting connection to node" << _p->id << "@" << ep << "from" << id();
let socket = match TcpStream::connect(&node.endpoint.address) { match TcpStream::connect(&node.endpoint.address) {
Ok(socket) => socket, Ok(socket) => socket,
Err(_) => { Err(_) => {
warn!("Cannot connect to node"); warn!("Cannot connect to node");
return; return;
} }
};
let handshake = Handshake::new(id.clone(), socket);
match self.connecting.insert(handshake) {
Ok(token) => event_loop.register_opt(&self.connecting[token].connection.socket, token, EventSet::all(), PollOpt::edge()).unwrap(),
Err(_) => warn!("Max connections reached")
};
} }
};
fn keep_alive(&mut self) { let nonce = self.info.next_nonce();
match self.connecting.insert_with(|token| Handshake::new(token, id, socket, &nonce).expect("Can't create handshake")) {
Some(token) => {
self.connecting[token].register(event_loop).expect("Handshake token regisration failed");
self.connecting[token].start(&self.info, true);
},
None => { warn!("Max connections reached") }
}
} }
fn accept(&mut self, _event_loop: &mut EventLoop<Host>) { fn accept(&mut self, _event_loop: &mut EventLoop<Host>) {
warn!(target "net", "accept"); warn!(target: "net", "accept");
} }
fn start_handshake(&mut self, token: Token, _event_loop: &mut EventLoop<Host>) { fn handshake_writable(&mut self, token: Token, event_loop: &mut EventLoop<Host>) {
let handshake = match self.handshakes.get(&token) { if !{
let handshake = match self.connecting.get_mut(token) {
Some(h) => h, Some(h) => h,
None => { None => {
warn!(target "net", "Received event for unknown handshake"); warn!(target: "net", "Received event for unknown handshake");
return; return;
} }
}; };
match handshake.writable(event_loop, &self.info) {
Err(e) => {
debug!(target: "net", "Handshake read error: {:?}", e);
false
},
Ok(_) => true
}
} {
self.kill_handshake(token, event_loop);
}
}
fn handshake_readable(&mut self, token: Token, event_loop: &mut EventLoop<Host>) {
if !{
let handshake = match self.connecting.get_mut(token) {
Some(h) => h,
None => {
warn!(target: "net", "Received event for unknown handshake");
return;
}
};
match handshake.writable(event_loop, &self.info) {
Err(e) => {
debug!(target: "net", "Handshake read error: {:?}", e);
false
},
Ok(_) => true
}
} {
self.kill_handshake(token, event_loop);
}
}
fn handshake_timeout(&mut self, token: Token, event_loop: &mut EventLoop<Host>) {
self.kill_handshake(token, event_loop)
}
fn kill_handshake(&mut self, token: Token, _event_loop: &mut EventLoop<Host>) {
self.connecting.remove(token);
} }
fn read_handshake(&mut self, _event_loop: &mut EventLoop<Host>) { fn read_connection(&mut self, _token: Token, _event_loop: &mut EventLoop<Host>) {
warn!(target "net", "accept");
} }
fn read_connection(&mut self, _event_loop: &mut EventLoop<Host>) { fn write_connection(&mut self, _token: Token, _event_loop: &mut EventLoop<Host>) {
}
fn write_connection(&mut self, _event_loop: &mut EventLoop<Host>) {
} }
} }
@ -594,16 +606,16 @@ impl Handler for Host {
match token.as_usize() { match token.as_usize() {
TCP_ACCEPT => self.accept(event_loop), TCP_ACCEPT => self.accept(event_loop),
IDLE => self.maintain_network(event_loop), IDLE => self.maintain_network(event_loop),
FIRST_CONNECTION ... LAST_CONNECTION => self.read_connection(event_loop), FIRST_CONNECTION ... LAST_CONNECTION => self.read_connection(token, event_loop),
FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.read_handshake(event_loop), FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.handshake_readable(token, event_loop),
NODETABLE_RECEIVE => {}, NODETABLE_RECEIVE => {},
_ => panic!("Received unknown readable token"), _ => panic!("Received unknown readable token"),
} }
} }
else if events.is_writable() { else if events.is_writable() {
match token.as_usize() { match token.as_usize() {
FIRST_CONNECTION ... LAST_CONNECTION => self.write_connection(event_loop), FIRST_CONNECTION ... LAST_CONNECTION => self.write_connection(token, event_loop),
FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.start_handshake(event_loop), FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.handshake_writable(token, event_loop),
_ => panic!("Received unknown writable token"), _ => panic!("Received unknown writable token"),
} }
} }
@ -612,6 +624,7 @@ impl Handler for Host {
fn timeout(&mut self, event_loop: &mut EventLoop<Host>, token: Token) { fn timeout(&mut self, event_loop: &mut EventLoop<Host>, token: Token) {
match token.as_usize() { match token.as_usize() {
IDLE => self.maintain_network(event_loop), IDLE => self.maintain_network(event_loop),
FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.handshake_timeout(token, event_loop),
NODETABLE_DISCOVERY => {}, NODETABLE_DISCOVERY => {},
NODETABLE_MAINTAIN => {}, NODETABLE_MAINTAIN => {},
_ => panic!("Received unknown timer token"), _ => panic!("Received unknown timer token"),

View File

@ -1,2 +1,24 @@
extern crate mio; extern crate mio;
pub mod host; pub mod host;
pub mod connection;
pub mod handshake;
#[derive(Debug)]
pub enum Error {
Crypto(::crypto::CryptoError),
Io(::std::io::Error),
}
impl From<::std::io::Error> for Error {
fn from(err: ::std::io::Error) -> Error {
Error::Io(err)
}
}
impl From<::crypto::CryptoError> for Error {
fn from(err: ::crypto::CryptoError) -> Error {
Error::Crypto(err)
}
}

View File

@ -5,6 +5,7 @@ use hash::{FixedHash, H256};
pub trait Hashable { pub trait Hashable {
fn sha3(&self) -> H256; fn sha3(&self) -> H256;
fn sha3_into(&self, dest: &mut [u8]);
} }
impl<T> Hashable for T where T: BytesConvertable { impl<T> Hashable for T where T: BytesConvertable {
@ -15,6 +16,9 @@ impl<T> Hashable for T where T: BytesConvertable {
ret ret
} }
} }
fn sha3_into(&self, dest: &mut [u8]) {
keccak_256(self.bytes(), dest);
}
} }
#[test] #[test]