     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 std::time::Duration;
    use bytes::Bytes;
    use message::{Error, Command, deserialize_payload, Payload};
    use message::types::{GetAddr, Addr};
    use protocol::Protocol;
    use net::PeerContext;
    use util::Direction;

    pub struct AddrProtocol {
    	/// Context
    	context: Arc<PeerContext>,
    	/// True if this is a connection to the seednode && we should disconnect after receiving addr message
    	is_seed_node_connection: bool,
    }

    impl AddrProtocol {
    	pub fn new(context: Arc<PeerContext>, is_seed_node_connection: bool) -> Self {
    		AddrProtocol {
    			context: context,
    			is_seed_node_connection: is_seed_node_connection,
    		}
    	}
    }

    impl Protocol for AddrProtocol {
    	fn initialize(&mut self) {
    		if let Direction::Outbound = self.context.info().direction {
    			self.context.send_request(&GetAddr);
    		}
    	}

    	fn on_message(&mut self, command: &Command, payload: &Bytes) -> Result<(), Error> {
    		// normal nodes send addr message only after they receive getaddr message
    		// meanwhile seednodes, surprisingly, send addr message even before they are asked for it
    		if command == &GetAddr::command() {
    			let _: GetAddr = try!(deserialize_payload(payload, self.context.info().version));
    			let entries = self.context.global().node_table_entries().into_iter().map(Into::into).collect();
    			let addr = Addr::new(entries);
    			self.context.send_response_inline(&addr);
    		} else if command == &Addr::command() {
    			let addr: Addr = try!(deserialize_payload(payload, self.context.info().version));
    			match addr {
    				Addr::V0(_) => {
    					unreachable!("This version of protocol is not supported!");
    				},
    				Addr::V31402(addr) => {
    					let nodes_len = addr.addresses.len();
    					self.context.global().update_node_table(addr.addresses);
    					// seednodes are currently responding with two addr messages:
    					// 1) addr message with single address - seednode itself
    					// 2) addr message with 1000 addresses (seednode node_table contents)
    					if self.is_seed_node_connection && nodes_len > 1 {
    						self.context.close();
    					}
    				},
    			}
    		}
    		Ok(())
    	}
    }

    pub struct SeednodeProtocol {
    	/// Context
    	context: Arc<PeerContext>,
    	/// Indicates if disconnecting has been scheduled.
    	disconnecting: bool,
    }

    impl SeednodeProtocol {
    	pub fn new(context: Arc<PeerContext>) -> Self {
    		SeednodeProtocol {
    			context: context,
    			disconnecting: false,
    		}
    	}
    }

    impl Protocol for SeednodeProtocol {
    	fn on_message(&mut self, command: &Command, _payload: &Bytes) -> Result<(), Error> {
    		// Seednodes send addr message more than once with different addresses.
    		// We can't disconenct after first read. Let's delay it by 60 seconds.
    		if !self.disconnecting && command == &Addr::command() {
    			self.disconnecting = true;
    			let context = self.context.global().clone();
    			let peer = self.context.info().id;
    			self.context.global().execute_after(Duration::new(60, 0), move || {
    				context.close_channel(peer);
    			});
    		}
    		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`)