     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93

    use std::sync::Arc;
    use time;
    use bytes::Bytes;
    use message::{Error, Payload, deserialize_payload};
    use message::types::{Ping, Pong};
    use message::common::Command;
    use protocol::Protocol;
    use net::PeerContext;
    use util::nonce::{NonceGenerator, RandomNonce};

    /// Time that must pass since last message from this peer, before we send ping request
    const PING_INTERVAL_S: f64 = 60f64;
    /// If peer has not responded to our ping request with pong during this interval => close connection
    const MAX_PING_RESPONSE_TIME_S: f64 = 60f64;

    /// Ping state
    #[derive(Debug, Copy, Clone, PartialEq)]
    enum State {
    	/// Peer is sending us messages && we wait for `PING_INTERVAL_S` to pass before sending ping request
    	WaitingTimeout(f64),
    	/// Ping message is sent to the peer && we are waiting for pong response for `MAX_PING_RESPONSE_TIME_S`
    	WaitingPong(f64),
    }

    pub struct PingProtocol<T = RandomNonce, C = PeerContext> {
    	/// Context
    	context: Arc<C>,
    	/// Nonce generator.
    	nonce_generator: T,
    	/// Ping state
    	state: State,
    	/// Last nonce sent in the ping message.
    	last_ping_nonce: Option<u64>,
    }

    impl PingProtocol {
    	pub fn new(context: Arc<PeerContext>) -> Self {
    		PingProtocol {
    			context: context,
    			nonce_generator: RandomNonce::default(),
    			state: State::WaitingTimeout(time::precise_time_s()),
    			last_ping_nonce: None,
    		}
    	}
    }

    impl Protocol for PingProtocol {
    	fn initialize(&mut self) {
    		// bitcoind always sends ping, let's do the same
    		self.maintain();
    	}

    	fn maintain(&mut self) {
    		let now = time::precise_time_s();
    		match self.state {
    			State::WaitingTimeout(time) => {
    				// send ping request if enough time has passed since last message
    				if now - time > PING_INTERVAL_S {
    					let nonce = self.nonce_generator.get();
    					self.state = State::WaitingPong(now);
    					self.last_ping_nonce = Some(nonce);
    					let ping = Ping::new(nonce);
    					self.context.send_request(&ping);
    				}
    			},
    			State::WaitingPong(time) => {
    				// if no new messages from peer for last MAX_PING_RESPONSE_TIME_S => disconnect
    				if now - time > MAX_PING_RESPONSE_TIME_S {
    					trace!("closing connection to peer {}: no messages for last {} seconds", self.context.info().id, now - time);
    					self.context.close();
    				}
    			},
    		}
    	}

    	fn on_message(&mut self, command: &Command, payload: &Bytes) -> Result<(), Error> {
    		// we have received new message => do not close connection because of timeout
    		self.state = State::WaitingTimeout(time::precise_time_s());

    		if command == &Ping::command() {
    			let ping: Ping = try!(deserialize_payload(payload, self.context.info().version));
    			let pong = Pong::new(ping.nonce);
    			self.context.send_response_inline(&pong);
    		} else if command == &Pong::command() {
    			let pong: Pong = try!(deserialize_payload(payload, self.context.info().version));
    			if Some(pong.nonce) != self.last_ping_nonce.take() {
    				return Err(Error::InvalidCommand)
    			}
    		}

    		Ok(())
    	}
    }

# Help

## Keyboard Shortcuts

`?`
  Show this help dialog
`S`
  Focus the search field
`↑`
  Move up in search results
`↓`
  Move down in search results
`↹`
  Switch tab
`⏎`
  Go to active search result
`+`
  Expand all sections
`-`
  Collapse all sections

## Search Tricks

Prefix searches with a type followed by a colon (e.g. `fn:`) to restrict the search to a given type.

Accepted types are: `fn`, `mod`, `struct`, `enum`, `trait`, `type`, `macro`, and `const`.

Search functions by type signature (e.g. `vec -> usize` or `* -> vec`)

Search multiple things at once by splitting your query with comma (e.g. `str,u8` or `String,struct:Vec,test`)