From 7e9d393d03a2233eca7dfbdf0551464c66aca7dc Mon Sep 17 00:00:00 2001 From: Carl Dong Date: Sun, 2 Sep 2018 22:04:05 -0700 Subject: [PATCH] Remove low-level networking support - Modify VersionMessage constructor to take in parameters directly that would have otherwise been extracted from a Socket (now removed) --- src/network/listener.rs | 90 --------------- src/network/message_network.rs | 34 +++--- src/network/mod.rs | 2 - src/network/socket.rs | 195 --------------------------------- 4 files changed, 17 insertions(+), 304 deletions(-) delete mode 100644 src/network/listener.rs delete mode 100644 src/network/socket.rs diff --git a/src/network/listener.rs b/src/network/listener.rs deleted file mode 100644 index 9d48de9..0000000 --- a/src/network/listener.rs +++ /dev/null @@ -1,90 +0,0 @@ -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! Abstract Bitcoin listener -//! -//! This module defines a listener on the Bitcoin network which is able -//! to connect to a peer, send network messages, and receive Bitcoin data. -//! - -use std::thread; -use std::sync::mpsc::{channel, Receiver}; - -use network::constants::Network; -use network::message; -use network::message::NetworkMessage::Verack; -use network::socket::Socket; -use util; - -/// A message which can be sent on the Bitcoin network -pub trait Listener { - /// Return a string encoding of the peer's network address - fn peer(&self) -> &str; - /// Return the port we have connected to the peer on - fn port(&self) -> u16; - /// Return the network this `Listener` is operating on - fn network(&self) -> Network; - /// Main listen loop - fn start(&self) -> Result<(Receiver, Socket), util::Error> { - // Open socket - let mut ret_sock = Socket::new(self.network()); - ret_sock.connect(self.peer(), self.port())?; - let mut sock = ret_sock.clone(); - - let (recv_tx, recv_rx) = channel(); - - // Send version message to peer - let version_message = sock.version_message(0)?; - sock.send_message(version_message)?; - - // Message loop - thread::spawn(move || { - let mut handshake_complete = false; - loop { - // Receive new message - match sock.receive_message() { - Ok(payload) => { - // React to any network messages that affect our state. - if let Verack = payload { - // Make an exception for verack since there is no response required - // TODO: when the timeout stuff in std::io::net::tcp is sorted out we should - // actually time out if the verack doesn't come in in time - if handshake_complete { - println!("Received second verack (peer is misbehaving)"); - } else { - handshake_complete = true; - } - }; - // We have to pass the message to the main thread for processing, - // unfortunately, because sipa says we have to handle everything - // in order. - recv_tx.send(message::SocketResponse::MessageReceived(payload)).unwrap(); - } - Err(e) => { - // On failure we send an error message to the main thread, along with - // a channel to receive an acknowledgement that we may tear down this - // thread. (If we simply exited immediately, the channel would be torn - // down and the main thread would never see the error message.) - let (tx, rx) = channel(); - recv_tx.send(message::SocketResponse::ConnectionFailed(e, tx)).unwrap(); - rx.recv().unwrap(); - break; - } - } - } - }); - Ok((recv_rx, ret_sock)) - } -} - diff --git a/src/network/message_network.rs b/src/network/message_network.rs index 93c4dfa..ff34989 100644 --- a/src/network/message_network.rs +++ b/src/network/message_network.rs @@ -18,10 +18,8 @@ //! capabilities //! -use network::constants; use network::address::Address; -use network::socket::Socket; -use util; +use network::constants; /// Some simple messages @@ -53,21 +51,26 @@ pub struct VersionMessage { impl VersionMessage { // TODO: we have fixed services and relay to 0 /// Constructs a new `version` message - pub fn new(timestamp: i64, mut socket: Socket, nonce: u64, start_height: i32) -> Result { - let recv_addr = socket.receiver_address()?; - let send_addr = socket.sender_address()?; - - Ok(VersionMessage { + pub fn new( + services: u64, + timestamp: i64, + receiver: Address, + sender: Address, + nonce: u64, + user_agent: String, + start_height: i32, + ) -> VersionMessage { + VersionMessage { version: constants::PROTOCOL_VERSION, - services: socket.services, + services: services, timestamp: timestamp, - receiver: recv_addr, - sender: send_addr, + receiver: receiver, + sender: sender, nonce: nonce, - user_agent: socket.user_agent, + user_agent: user_agent, start_height: start_height, - relay: false - }) + relay: false, + } } } @@ -103,6 +106,3 @@ mod tests { assert_eq!(serialize(&real_decode).ok(), Some(from_sat)); } } - - - diff --git a/src/network/mod.rs b/src/network/mod.rs index e93876a..b19077a 100644 --- a/src/network/mod.rs +++ b/src/network/mod.rs @@ -25,11 +25,9 @@ use std::error; pub mod constants; pub mod consensus_params; pub mod encodable; -pub mod socket; pub mod serialize; pub mod address; -pub mod listener; pub mod message; pub mod message_blockdata; pub mod message_network; diff --git a/src/network/socket.rs b/src/network/socket.rs deleted file mode 100644 index ee682a4..0000000 --- a/src/network/socket.rs +++ /dev/null @@ -1,195 +0,0 @@ -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! Sockets -//! -//! This module provides support for low-level network communication. -//! - -use std::time::{UNIX_EPOCH, SystemTime}; -use rand::{thread_rng, Rng}; -use std::io::Write; -use std::net; -use std::sync::{Arc, Mutex}; - -use network; -use network::constants; -use network::address::Address; -use network::encodable::{ConsensusEncodable, ConsensusDecodable}; -use network::message::{RawNetworkMessage, NetworkMessage}; -use network::message::NetworkMessage::Version; -use network::message_network::VersionMessage; -use network::serialize::{self, RawEncoder, RawDecoder}; -use util; - -/// Format an IP address in the 16-byte bitcoin protocol serialization -fn ipaddr_to_bitcoin_addr(addr: &net::SocketAddr) -> [u16; 8] { - match *addr { - net::SocketAddr::V4(ref addr) => addr.ip().to_ipv6_mapped().segments(), - net::SocketAddr::V6(ref addr) => addr.ip().segments() - } -} - -/// A network socket along with information about the peer -#[derive(Clone)] -pub struct Socket { - /// The underlying TCP socket - socket: Arc>>, - /// Services supported by us - pub services: u64, - /// Our user agent - pub user_agent: String, - /// Nonce to identify our `version` messages - pub version_nonce: u64, - /// Network magic - pub magic: u32 -} - -macro_rules! with_socket(($s:ident, $sock:ident, $body:block) => ({ - use ::std::ops::DerefMut; - let sock_lock = $s.socket.lock(); - match sock_lock { - Err(_) => { - Err(network::Error::SocketMutexPoisoned.into()) - } - Ok(mut guard) => { - match *guard.deref_mut() { - Some(ref mut $sock) => { - $body - } - None => { - Err(network::Error::SocketNotConnectedToPeer.into()) - } - } - } - } -})); - -impl Socket { - // TODO: we fix services to 0 - /// Construct a new socket - pub fn new(network: constants::Network) -> Socket { - let mut rng = thread_rng(); - Socket { - socket: Arc::new(Mutex::new(None)), - services: 0, - version_nonce: rng.gen(), - user_agent: constants::USER_AGENT.to_owned(), - magic: network.magic(), - } - } - - /// (Re)connect to the peer - pub fn connect(&mut self, host: &str, port: u16) -> Result<(), network::Error> { - // Entirely replace the Mutex, in case it was poisoned; - // this will also drop any preexisting socket that might be open - match net::TcpStream::connect((host, port)) { - Ok(s) => { - self.socket = Arc::new(Mutex::new(Some(s))); - Ok(()) - } - Err(e) => { - self.socket = Arc::new(Mutex::new(None)); - Err(network::Error::Io(e)) - } - } - } - - /// Peer address - pub fn receiver_address(&mut self) -> Result { - with_socket!(self, sock, { - match sock.peer_addr() { - Ok(addr) => { - Ok(Address { - services: self.services, - address: ipaddr_to_bitcoin_addr(&addr), - port: addr.port() - }) - }, - Err(e) => Err(network::Error::Io(e)) - } - }) - } - - /// Our own address - pub fn sender_address(&mut self) -> Result { - with_socket!(self, sock, { - match sock.local_addr() { - Ok(addr) => { - Ok(Address { - services: self.services, - address: ipaddr_to_bitcoin_addr(&addr), - port: addr.port() - }) - }, - Err(e) => Err(network::Error::Io(e)) - } - }) - } - - /// Produce a version message appropriate for this socket - pub fn version_message(&mut self, start_height: i32) -> Result { - let recv_addr = self.receiver_address()?; - let send_addr = self.sender_address()?; - let timestamp = match SystemTime::now().duration_since(UNIX_EPOCH) { - Ok(dur) => dur, - Err(err) => err.duration(), - }.as_secs() as i64; - - Ok(Version(VersionMessage { - version: constants::PROTOCOL_VERSION, - services: constants::SERVICES, - timestamp: timestamp, - receiver: recv_addr, - sender: send_addr, - nonce: self.version_nonce, - user_agent: self.user_agent.clone(), - start_height: start_height, - relay: false - })) - } - - /// Send a general message across the line - pub fn send_message(&mut self, payload: NetworkMessage) -> Result<(), util::Error> { - with_socket!(self, sock, { - let message = RawNetworkMessage { magic: self.magic, payload: payload }; - message.consensus_encode(&mut RawEncoder::new(&mut *sock))?; - sock.flush().map_err(network::Error::Io).map_err(util::Error::Network) - }) - } - - /// Receive the next message from the peer, decoding the network header - /// and verifying its correctness. Returns the undecoded payload. - pub fn receive_message(&mut self) -> Result { - with_socket!(self, sock, { - // We need a new scope since the closure in here borrows read_err, - // and we try to read it afterward. Letting `iter` go out fixes it. - let mut decoder = RawDecoder::new(sock); - - let decoded: RawNetworkMessage = ConsensusDecodable::consensus_decode(&mut decoder)?; - - // Then for magic (this should come before parse error, but we can't - // get to it if the deserialization failed). TODO restructure this - if decoded.magic != self.magic { - Err(serialize::Error::UnexpectedNetworkMagic { - expected: self.magic, - actual: decoded.magic, - }.into()) - } else { - Ok(decoded.payload) - } - }) - } -} -