diff --git a/src/blockdata/block.rs b/src/blockdata/block.rs index bcde959..2687c5a 100644 --- a/src/blockdata/block.rs +++ b/src/blockdata/block.rs @@ -31,7 +31,7 @@ use blockdata::transaction::Transaction; /// A block header, which contains all the block's information except /// the actual transactions -#[deriving(PartialEq, Show)] +#[deriving(PartialEq, Eq, Clone, Show)] pub struct BlockHeader { /// The protocol version. Should always be 1. pub version: u32, @@ -50,7 +50,7 @@ pub struct BlockHeader { /// A Bitcoin block, which is a collection of transactions with an attached /// proof of work. -#[deriving(PartialEq, Show)] +#[deriving(PartialEq, Eq, Clone, Show)] pub struct Block { /// The block header pub header: BlockHeader, @@ -60,7 +60,7 @@ pub struct Block { /// A block header with txcount attached, which is given in the `headers` /// network message. -#[deriving(PartialEq, Show)] +#[deriving(PartialEq, Eq, Clone, Show)] pub struct LoneBlockHeader { /// The actual block header pub header: BlockHeader, diff --git a/src/network/address.rs b/src/network/address.rs index 8736254..7a10269 100644 --- a/src/network/address.rs +++ b/src/network/address.rs @@ -69,6 +69,30 @@ impl fmt::Show for Address { } } +impl Clone for Address { + fn clone(&self) -> Address { + unsafe { + use std::intrinsics::copy_nonoverlapping_memory; + use std::mem; + let mut ret = mem::uninitialized(); + copy_nonoverlapping_memory(&mut ret, + self, + mem::size_of::
()); + ret + } + } +} + +impl PartialEq for Address { + fn eq(&self, other: &Address) -> bool { + self.services == other.services && + self.address.as_slice() == other.address.as_slice() && + self.port == other.port + } +} + +impl Eq for Address {} + #[cfg(test)] mod test { use super::Address; diff --git a/src/network/encodable.rs b/src/network/encodable.rs index 1491b86..9f02581 100644 --- a/src/network/encodable.rs +++ b/src/network/encodable.rs @@ -51,11 +51,11 @@ pub trait ConsensusDecodable, E> { } /// A variable-length unsigned integer -#[deriving(PartialEq, Show)] +#[deriving(PartialEq, Eq, PartialOrd, Ord, Clone, Show)] pub struct VarInt(pub u64); /// Data which must be preceded by a 4-byte checksum -#[deriving(PartialEq, Clone, Show)] +#[deriving(PartialEq, Eq, Clone, Show)] pub struct CheckedData(pub Vec); // Primitive types diff --git a/src/network/listener.rs b/src/network/listener.rs index 6e4b594..3152df3 100644 --- a/src/network/listener.rs +++ b/src/network/listener.rs @@ -19,11 +19,9 @@ //! use std::io::{IoResult, standard_error, ConnectionFailed}; -use std::io::timer; -use std::time::Duration; use network::constants::Network; -use network::message::{NetworkMessage, Verack}; +use network::message::{mod, SocketResponse, MessageReceived, Verack}; use network::socket::Socket; /// A message which can be sent on the Bitcoin network @@ -35,7 +33,7 @@ pub trait Listener { /// Return the network this `Listener` is operating on fn network(&self) -> Network; /// Main listen loop - fn start(&self) -> IoResult<(Receiver, Socket)> { + fn start(&self) -> IoResult<(Receiver, Socket)> { // Open socket let mut ret_sock = Socket::new(self.network()); match ret_sock.connect(self.peer(), self.port()) { @@ -75,20 +73,17 @@ pub trait Listener { // 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(payload); + recv_tx.send(MessageReceived(payload)); } Err(e) => { - println!("Received error {:} when decoding message. Pausing for 5 seconds then reconnecting.", e); - timer::sleep(Duration::seconds(5)); - // Reconnect - sock.reconnect() - // Create version message - .and_then(|_| sock.version_message(0)) - // Send it out - .and_then(|msg| sock.send_message(msg)) - // For now, not much we can do on error - .unwrap_or_else(|e| println!("Error {} when reconnecting.", e)); - handshake_complete = false; + // 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::ConnectionFailed(e, tx)); + rx.recv(); + break; } } } diff --git a/src/network/message.rs b/src/network/message.rs index 5418dca..c0ebd7a 100644 --- a/src/network/message.rs +++ b/src/network/message.rs @@ -34,7 +34,7 @@ use network::serialize::{serialize, RawDecoder, SimpleEncoder, SimpleDecoder}; use util::misc::prepend_err; /// Serializer for command string -#[deriving(PartialEq, Clone, Show)] +#[deriving(PartialEq, Eq, Clone, Show)] pub struct CommandString(pub String); impl, E> ConsensusEncodable for CommandString { @@ -64,10 +64,18 @@ pub struct RawNetworkMessage { pub payload: NetworkMessage } -#[deriving(Show)] +/// A response from the peer-connected socket +pub enum SocketResponse { + /// A message was received + MessageReceived(NetworkMessage), + /// An error occured and the socket needs to close + ConnectionFailed(IoError, Sender<()>) +} + +#[deriving(Clone, PartialEq, Eq, Show)] /// A Network message payload. Proper documentation is available on the Bitcoin /// wiki https://en.bitcoin.it/wiki/Protocol_specification -pub enum NetworkMessage{ +pub enum NetworkMessage { /// `version` Version(message_network::VersionMessage), /// `verack` @@ -98,7 +106,7 @@ pub enum NetworkMessage{ /// `ping` Ping(u64), /// `pong` - Pong(u64), + Pong(u64) // TODO: reject, // TODO: bloom filtering // TODO: alert @@ -119,7 +127,7 @@ impl RawNetworkMessage { Block(_) => "block", Headers(_) => "headers", Ping(_) => "ping", - Pong(_) => "pong" + Pong(_) => "pong", }.to_string() } } diff --git a/src/network/message_blockdata.rs b/src/network/message_blockdata.rs index 7021d07..70a73ad 100644 --- a/src/network/message_blockdata.rs +++ b/src/network/message_blockdata.rs @@ -23,7 +23,7 @@ use network::encodable::{ConsensusDecodable, ConsensusEncodable}; use network::serialize::{SimpleDecoder, SimpleEncoder}; use util::hash::Sha256dHash; -#[deriving(Clone, PartialEq, Show)] +#[deriving(PartialEq, Eq, Clone, Show)] /// The type of an inventory object pub enum InvType { /// Error --- these inventories can be ignored @@ -37,7 +37,7 @@ pub enum InvType { // Some simple messages /// The `getblocks` message -#[deriving(Show)] +#[deriving(PartialEq, Eq, Clone, Show)] pub struct GetBlocksMessage { /// The protocol version pub version: u32, @@ -50,7 +50,7 @@ pub struct GetBlocksMessage { } /// The `getheaders` message -#[deriving(Show)] +#[deriving(PartialEq, Eq, Clone, Show)] pub struct GetHeadersMessage { /// The protocol version pub version: u32, @@ -63,7 +63,7 @@ pub struct GetHeadersMessage { } /// An inventory object --- a reference to a Bitcoin object -#[deriving(Clone, Show)] +#[deriving(PartialEq, Eq, Clone, Show)] pub struct Inventory { /// The type of object that is referenced pub inv_type: InvType, diff --git a/src/network/message_network.rs b/src/network/message_network.rs index 11de60a..996de6a 100644 --- a/src/network/message_network.rs +++ b/src/network/message_network.rs @@ -27,7 +27,7 @@ use network::socket::Socket; /// Some simple messages /// The `version` message -#[deriving(Show)] +#[deriving(PartialEq, Eq, Clone, Show)] pub struct VersionMessage { /// The P2P network protocol version pub version: u32, diff --git a/src/network/socket.rs b/src/network/socket.rs index 74ec9a6..7481590 100644 --- a/src/network/socket.rs +++ b/src/network/socket.rs @@ -105,18 +105,6 @@ impl Socket { } } - /// Reset the connection to the peer - pub fn reconnect(&mut self) -> IoResult<()> { - let (host, port) = match self.socket { - Some(ref mut s) => match s.peer_name() { - Ok(addr) => (format!("{}", addr.ip), addr.port), - Err(e) => { return Err(e); } - }, - None => { return Err(standard_error(NotConnected)); } - }; - self.connect(host.as_slice(), port) - } - /// Peer address pub fn receiver_address(&mut self) -> IoResult
{ match self.socket {