Reformat the source code
This commit is contained in:
@@ -28,168 +28,169 @@ const PARITY_CLIENT_ID_PREFIX: &str = "Parity-Ethereum";
|
||||
lazy_static! {
|
||||
/// Parity versions starting from this will accept block bodies requests
|
||||
/// of 256 bodies
|
||||
static ref PARITY_CLIENT_LARGE_REQUESTS_VERSION: Version = Version::parse("2.4.0").unwrap();
|
||||
static ref PARITY_CLIENT_LARGE_REQUESTS_VERSION: Version = Version::parse("2.4.0").unwrap();
|
||||
}
|
||||
|
||||
/// Description of the software version running in a peer
|
||||
/// according to https://github.com/ethereum/wiki/wiki/Client-Version-Strings
|
||||
/// This structure as it is represents the format used by Parity clients. Other
|
||||
/// vendors may provide additional fields.
|
||||
#[derive(Clone,Debug,PartialEq,Eq,Serialize)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
|
||||
pub struct ParityClientData {
|
||||
name: String,
|
||||
identity: Option<String>,
|
||||
semver: Version,
|
||||
os: String,
|
||||
compiler: String,
|
||||
name: String,
|
||||
identity: Option<String>,
|
||||
semver: Version,
|
||||
os: String,
|
||||
compiler: String,
|
||||
|
||||
// Capability flags, should be calculated in constructor
|
||||
can_handle_large_requests: bool,
|
||||
// Capability flags, should be calculated in constructor
|
||||
can_handle_large_requests: bool,
|
||||
}
|
||||
|
||||
/// Accessor methods for ParityClientData. This will probably
|
||||
/// need to be abstracted away into a trait.
|
||||
impl ParityClientData {
|
||||
fn new(
|
||||
name: String,
|
||||
identity: Option<String>,
|
||||
semver: Version,
|
||||
os: String,
|
||||
compiler: String,
|
||||
) -> Self {
|
||||
// Flags logic
|
||||
let can_handle_large_requests = &semver >= &PARITY_CLIENT_LARGE_REQUESTS_VERSION;
|
||||
fn new(
|
||||
name: String,
|
||||
identity: Option<String>,
|
||||
semver: Version,
|
||||
os: String,
|
||||
compiler: String,
|
||||
) -> Self {
|
||||
// Flags logic
|
||||
let can_handle_large_requests = &semver >= &PARITY_CLIENT_LARGE_REQUESTS_VERSION;
|
||||
|
||||
// Instantiate and return
|
||||
ParityClientData {
|
||||
name: name,
|
||||
identity: identity,
|
||||
semver: semver,
|
||||
os: os,
|
||||
compiler: compiler,
|
||||
// Instantiate and return
|
||||
ParityClientData {
|
||||
name: name,
|
||||
identity: identity,
|
||||
semver: semver,
|
||||
os: os,
|
||||
compiler: compiler,
|
||||
|
||||
can_handle_large_requests: can_handle_large_requests,
|
||||
}
|
||||
}
|
||||
can_handle_large_requests: can_handle_large_requests,
|
||||
}
|
||||
}
|
||||
|
||||
fn name(&self) -> &str {
|
||||
self.name.as_str()
|
||||
}
|
||||
fn name(&self) -> &str {
|
||||
self.name.as_str()
|
||||
}
|
||||
|
||||
fn identity(&self) -> Option<&str> {
|
||||
self.identity.as_ref().map(String::as_str)
|
||||
}
|
||||
fn identity(&self) -> Option<&str> {
|
||||
self.identity.as_ref().map(String::as_str)
|
||||
}
|
||||
|
||||
fn semver(&self) -> &Version {
|
||||
&self.semver
|
||||
}
|
||||
fn semver(&self) -> &Version {
|
||||
&self.semver
|
||||
}
|
||||
|
||||
fn os(&self) -> &str {
|
||||
self.os.as_str()
|
||||
}
|
||||
fn os(&self) -> &str {
|
||||
self.os.as_str()
|
||||
}
|
||||
|
||||
fn compiler(&self) -> &str {
|
||||
self.compiler.as_str()
|
||||
}
|
||||
fn compiler(&self) -> &str {
|
||||
self.compiler.as_str()
|
||||
}
|
||||
|
||||
fn can_handle_large_requests(&self) -> bool {
|
||||
self.can_handle_large_requests
|
||||
}
|
||||
fn can_handle_large_requests(&self) -> bool {
|
||||
self.can_handle_large_requests
|
||||
}
|
||||
}
|
||||
|
||||
/// Enum describing the version of the software running on a peer.
|
||||
#[derive(Clone,Debug,Eq,PartialEq,Serialize)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
||||
pub enum ClientVersion {
|
||||
/// The peer runs software from parity and the string format is known
|
||||
ParityClient(
|
||||
/// The actual information fields: name, version, os, ...
|
||||
ParityClientData
|
||||
),
|
||||
/// The string ID is recognized as Parity but the overall format
|
||||
/// could not be parsed
|
||||
ParityUnknownFormat(String),
|
||||
/// Other software vendors than Parity
|
||||
Other(String),
|
||||
/// The peer runs software from parity and the string format is known
|
||||
ParityClient(
|
||||
/// The actual information fields: name, version, os, ...
|
||||
ParityClientData,
|
||||
),
|
||||
/// The string ID is recognized as Parity but the overall format
|
||||
/// could not be parsed
|
||||
ParityUnknownFormat(String),
|
||||
/// Other software vendors than Parity
|
||||
Other(String),
|
||||
}
|
||||
|
||||
impl Default for ClientVersion {
|
||||
fn default() -> Self {
|
||||
ClientVersion::Other("".to_owned())
|
||||
}
|
||||
fn default() -> Self {
|
||||
ClientVersion::Other("".to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
/// Provide information about what a particular version of a
|
||||
/// peer software can do
|
||||
pub trait ClientCapabilities {
|
||||
/// Parity versions before PARITY_CLIENT_LARGE_REQUESTS_VERSION would not
|
||||
/// check the accumulated size of a packet when building a response to a
|
||||
/// GET_BLOCK_BODIES request. If the packet was larger than a given limit,
|
||||
/// instead of sending fewer blocks no packet would get sent at all. Query
|
||||
/// if this version can handle requests for a large number of block bodies.
|
||||
fn can_handle_large_requests(&self) -> bool;
|
||||
/// Parity versions before PARITY_CLIENT_LARGE_REQUESTS_VERSION would not
|
||||
/// check the accumulated size of a packet when building a response to a
|
||||
/// GET_BLOCK_BODIES request. If the packet was larger than a given limit,
|
||||
/// instead of sending fewer blocks no packet would get sent at all. Query
|
||||
/// if this version can handle requests for a large number of block bodies.
|
||||
fn can_handle_large_requests(&self) -> bool;
|
||||
|
||||
/// Service transactions are specific to parity. Query if this version
|
||||
/// accepts them.
|
||||
fn accepts_service_transaction(&self) -> bool;
|
||||
/// Service transactions are specific to parity. Query if this version
|
||||
/// accepts them.
|
||||
fn accepts_service_transaction(&self) -> bool;
|
||||
}
|
||||
|
||||
impl ClientCapabilities for ClientVersion {
|
||||
fn can_handle_large_requests(&self) -> bool {
|
||||
match self {
|
||||
ClientVersion::ParityClient(data) => data.can_handle_large_requests(),
|
||||
ClientVersion::ParityUnknownFormat(_) => false, // Play it safe
|
||||
ClientVersion::Other(_) => true // As far as we know
|
||||
}
|
||||
}
|
||||
|
||||
fn accepts_service_transaction(&self) -> bool {
|
||||
match self {
|
||||
ClientVersion::ParityClient(_) => true,
|
||||
ClientVersion::ParityUnknownFormat(_) => true,
|
||||
ClientVersion::Other(_) => false
|
||||
}
|
||||
}
|
||||
fn can_handle_large_requests(&self) -> bool {
|
||||
match self {
|
||||
ClientVersion::ParityClient(data) => data.can_handle_large_requests(),
|
||||
ClientVersion::ParityUnknownFormat(_) => false, // Play it safe
|
||||
ClientVersion::Other(_) => true, // As far as we know
|
||||
}
|
||||
}
|
||||
|
||||
fn accepts_service_transaction(&self) -> bool {
|
||||
match self {
|
||||
ClientVersion::ParityClient(_) => true,
|
||||
ClientVersion::ParityUnknownFormat(_) => true,
|
||||
ClientVersion::Other(_) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_parity(client_id: &str) -> bool {
|
||||
client_id.starts_with(LEGACY_CLIENT_ID_PREFIX) || client_id.starts_with(PARITY_CLIENT_ID_PREFIX)
|
||||
client_id.starts_with(LEGACY_CLIENT_ID_PREFIX) || client_id.starts_with(PARITY_CLIENT_ID_PREFIX)
|
||||
}
|
||||
|
||||
/// Parse known parity formats. Recognizes either a short format with four fields
|
||||
/// or a long format which includes the same fields and an identity one.
|
||||
fn parse_parity_format(client_version: &str) -> Result<ParityClientData, ()> {
|
||||
const PARITY_ID_STRING_MINIMUM_TOKENS: usize = 4;
|
||||
const PARITY_ID_STRING_MINIMUM_TOKENS: usize = 4;
|
||||
|
||||
let tokens: Vec<&str> = client_version.split("/").collect();
|
||||
let tokens: Vec<&str> = client_version.split("/").collect();
|
||||
|
||||
if tokens.len() < PARITY_ID_STRING_MINIMUM_TOKENS {
|
||||
return Err(())
|
||||
}
|
||||
if tokens.len() < PARITY_ID_STRING_MINIMUM_TOKENS {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
let name = tokens[0];
|
||||
let name = tokens[0];
|
||||
|
||||
let identity = if tokens.len() - 3 > 1 {
|
||||
Some(tokens[1..(tokens.len() - 3)].join("/"))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let identity = if tokens.len() - 3 > 1 {
|
||||
Some(tokens[1..(tokens.len() - 3)].join("/"))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let compiler = tokens[tokens.len() - 1];
|
||||
let os = tokens[tokens.len() - 2];
|
||||
let compiler = tokens[tokens.len() - 1];
|
||||
let os = tokens[tokens.len() - 2];
|
||||
|
||||
// If version is in the right position and valid format return a valid
|
||||
// result. Otherwise return an error.
|
||||
get_number_from_version(tokens[tokens.len() - 3])
|
||||
.and_then(|v| Version::parse(v).ok())
|
||||
.map(|semver| ParityClientData::new(
|
||||
name.to_owned(),
|
||||
identity,
|
||||
semver,
|
||||
os.to_owned(),
|
||||
compiler.to_owned(),
|
||||
))
|
||||
.ok_or(())
|
||||
// If version is in the right position and valid format return a valid
|
||||
// result. Otherwise return an error.
|
||||
get_number_from_version(tokens[tokens.len() - 3])
|
||||
.and_then(|v| Version::parse(v).ok())
|
||||
.map(|semver| {
|
||||
ParityClientData::new(
|
||||
name.to_owned(),
|
||||
identity,
|
||||
semver,
|
||||
os.to_owned(),
|
||||
compiler.to_owned(),
|
||||
)
|
||||
})
|
||||
.ok_or(())
|
||||
}
|
||||
|
||||
/// Parse a version string and return the corresponding
|
||||
@@ -199,317 +200,347 @@ fn parse_parity_format(client_version: &str) -> Result<ParityClientData, ()> {
|
||||
/// The parsing for parity may still fail, in which case return a ParityUnknownFormat with
|
||||
/// the original version string. TryFrom would be a better trait to implement.
|
||||
impl<T> From<T> for ClientVersion
|
||||
where T: AsRef<str> {
|
||||
fn from(client_version: T) -> Self {
|
||||
let client_version_str: &str = client_version.as_ref();
|
||||
where
|
||||
T: AsRef<str>,
|
||||
{
|
||||
fn from(client_version: T) -> Self {
|
||||
let client_version_str: &str = client_version.as_ref();
|
||||
|
||||
if !is_parity(client_version_str) {
|
||||
return ClientVersion::Other(client_version_str.to_owned());
|
||||
}
|
||||
if !is_parity(client_version_str) {
|
||||
return ClientVersion::Other(client_version_str.to_owned());
|
||||
}
|
||||
|
||||
if let Ok(data) = parse_parity_format(client_version_str) {
|
||||
ClientVersion::ParityClient(data)
|
||||
} else {
|
||||
ClientVersion::ParityUnknownFormat(client_version_str.to_owned())
|
||||
}
|
||||
}
|
||||
if let Ok(data) = parse_parity_format(client_version_str) {
|
||||
ClientVersion::ParityClient(data)
|
||||
} else {
|
||||
ClientVersion::ParityUnknownFormat(client_version_str.to_owned())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn format_parity_version_string(client_version: &ParityClientData, f: &mut fmt::Formatter) -> std::fmt::Result {
|
||||
let name = client_version.name();
|
||||
let semver = client_version.semver();
|
||||
let os = client_version.os();
|
||||
let compiler = client_version.compiler();
|
||||
fn format_parity_version_string(
|
||||
client_version: &ParityClientData,
|
||||
f: &mut fmt::Formatter,
|
||||
) -> std::fmt::Result {
|
||||
let name = client_version.name();
|
||||
let semver = client_version.semver();
|
||||
let os = client_version.os();
|
||||
let compiler = client_version.compiler();
|
||||
|
||||
match client_version.identity() {
|
||||
None => write!(f, "{}/v{}/{}/{}", name, semver, os, compiler),
|
||||
Some(identity) => write!(f, "{}/{}/v{}/{}/{}", name, identity, semver, os, compiler),
|
||||
}
|
||||
match client_version.identity() {
|
||||
None => write!(f, "{}/v{}/{}/{}", name, semver, os, compiler),
|
||||
Some(identity) => write!(f, "{}/{}/v{}/{}/{}", name, identity, semver, os, compiler),
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ClientVersion {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
ClientVersion::ParityClient(data) => format_parity_version_string(data, f),
|
||||
ClientVersion::ParityUnknownFormat(id) => write!(f, "{}", id),
|
||||
ClientVersion::Other(id) => write!(f, "{}", id)
|
||||
}
|
||||
}
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
ClientVersion::ParityClient(data) => format_parity_version_string(data, f),
|
||||
ClientVersion::ParityUnknownFormat(id) => write!(f, "{}", id),
|
||||
ClientVersion::Other(id) => write!(f, "{}", id),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_number_from_version(version: &str) -> Option<&str> {
|
||||
if version.starts_with("v") {
|
||||
return version.get(1..);
|
||||
}
|
||||
if version.starts_with("v") {
|
||||
return version.get(1..);
|
||||
}
|
||||
|
||||
None
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use super::*;
|
||||
use super::*;
|
||||
|
||||
const PARITY_CLIENT_SEMVER: &str = "2.4.0";
|
||||
const PARITY_CLIENT_OLD_SEMVER: &str = "2.2.0";
|
||||
const PARITY_CLIENT_OS: &str = "linux";
|
||||
const PARITY_CLIENT_COMPILER: &str = "rustc";
|
||||
const PARITY_CLIENT_IDENTITY: &str = "ExpanseSOLO";
|
||||
const PARITY_CLIENT_MULTITOKEN_IDENTITY: &str = "ExpanseSOLO/abc/v1.2.3";
|
||||
const PARITY_CLIENT_SEMVER: &str = "2.4.0";
|
||||
const PARITY_CLIENT_OLD_SEMVER: &str = "2.2.0";
|
||||
const PARITY_CLIENT_OS: &str = "linux";
|
||||
const PARITY_CLIENT_COMPILER: &str = "rustc";
|
||||
const PARITY_CLIENT_IDENTITY: &str = "ExpanseSOLO";
|
||||
const PARITY_CLIENT_MULTITOKEN_IDENTITY: &str = "ExpanseSOLO/abc/v1.2.3";
|
||||
|
||||
fn make_default_version_string() -> String {
|
||||
format!(
|
||||
"{}/v{}/{}/{}",
|
||||
PARITY_CLIENT_ID_PREFIX, PARITY_CLIENT_SEMVER, PARITY_CLIENT_OS, PARITY_CLIENT_COMPILER
|
||||
)
|
||||
}
|
||||
|
||||
fn make_default_version_string() -> String {
|
||||
format!(
|
||||
"{}/v{}/{}/{}",
|
||||
PARITY_CLIENT_ID_PREFIX,
|
||||
PARITY_CLIENT_SEMVER,
|
||||
PARITY_CLIENT_OS,
|
||||
PARITY_CLIENT_COMPILER
|
||||
)
|
||||
}
|
||||
fn make_default_long_version_string() -> String {
|
||||
format!(
|
||||
"{}/{}/v{}/{}/{}",
|
||||
PARITY_CLIENT_ID_PREFIX,
|
||||
PARITY_CLIENT_IDENTITY,
|
||||
PARITY_CLIENT_SEMVER,
|
||||
PARITY_CLIENT_OS,
|
||||
PARITY_CLIENT_COMPILER
|
||||
)
|
||||
}
|
||||
|
||||
fn make_default_long_version_string() -> String {
|
||||
format!(
|
||||
"{}/{}/v{}/{}/{}",
|
||||
PARITY_CLIENT_ID_PREFIX,
|
||||
PARITY_CLIENT_IDENTITY,
|
||||
PARITY_CLIENT_SEMVER,
|
||||
PARITY_CLIENT_OS,
|
||||
PARITY_CLIENT_COMPILER
|
||||
)
|
||||
}
|
||||
fn make_multitoken_identity_long_version_string() -> String {
|
||||
format!(
|
||||
"{}/{}/v{}/{}/{}",
|
||||
PARITY_CLIENT_ID_PREFIX,
|
||||
PARITY_CLIENT_MULTITOKEN_IDENTITY,
|
||||
PARITY_CLIENT_SEMVER,
|
||||
PARITY_CLIENT_OS,
|
||||
PARITY_CLIENT_COMPILER
|
||||
)
|
||||
}
|
||||
|
||||
fn make_multitoken_identity_long_version_string() -> String {
|
||||
format!(
|
||||
"{}/{}/v{}/{}/{}",
|
||||
PARITY_CLIENT_ID_PREFIX,
|
||||
PARITY_CLIENT_MULTITOKEN_IDENTITY,
|
||||
PARITY_CLIENT_SEMVER,
|
||||
PARITY_CLIENT_OS,
|
||||
PARITY_CLIENT_COMPILER
|
||||
)
|
||||
}
|
||||
fn make_old_semver_version_string() -> String {
|
||||
format!(
|
||||
"{}/v{}/{}/{}",
|
||||
PARITY_CLIENT_ID_PREFIX,
|
||||
PARITY_CLIENT_OLD_SEMVER,
|
||||
PARITY_CLIENT_OS,
|
||||
PARITY_CLIENT_COMPILER
|
||||
)
|
||||
}
|
||||
|
||||
fn make_old_semver_version_string() -> String {
|
||||
format!(
|
||||
"{}/v{}/{}/{}",
|
||||
PARITY_CLIENT_ID_PREFIX,
|
||||
PARITY_CLIENT_OLD_SEMVER,
|
||||
PARITY_CLIENT_OS,
|
||||
PARITY_CLIENT_COMPILER
|
||||
)
|
||||
}
|
||||
#[test]
|
||||
pub fn client_version_when_from_empty_string_then_default() {
|
||||
let default = ClientVersion::default();
|
||||
|
||||
#[test]
|
||||
pub fn client_version_when_from_empty_string_then_default() {
|
||||
let default = ClientVersion::default();
|
||||
assert_eq!(ClientVersion::from(""), default);
|
||||
}
|
||||
|
||||
assert_eq!(ClientVersion::from(""), default);
|
||||
}
|
||||
#[test]
|
||||
pub fn get_number_from_version_when_valid_then_number() {
|
||||
let version_string = format!("v{}", PARITY_CLIENT_SEMVER);
|
||||
|
||||
#[test]
|
||||
pub fn get_number_from_version_when_valid_then_number() {
|
||||
let version_string = format!("v{}", PARITY_CLIENT_SEMVER);
|
||||
assert_eq!(
|
||||
get_number_from_version(&version_string).unwrap(),
|
||||
PARITY_CLIENT_SEMVER
|
||||
);
|
||||
}
|
||||
|
||||
assert_eq!(get_number_from_version(&version_string).unwrap(), PARITY_CLIENT_SEMVER);
|
||||
}
|
||||
#[test]
|
||||
pub fn client_version_when_str_parity_format_and_valid_then_all_fields_match() {
|
||||
let client_version_string = make_default_version_string();
|
||||
|
||||
#[test]
|
||||
pub fn client_version_when_str_parity_format_and_valid_then_all_fields_match() {
|
||||
let client_version_string = make_default_version_string();
|
||||
if let ClientVersion::ParityClient(client_version) =
|
||||
ClientVersion::from(client_version_string.as_str())
|
||||
{
|
||||
assert_eq!(client_version.name(), PARITY_CLIENT_ID_PREFIX);
|
||||
assert_eq!(
|
||||
*client_version.semver(),
|
||||
Version::parse(PARITY_CLIENT_SEMVER).unwrap()
|
||||
);
|
||||
assert_eq!(client_version.os(), PARITY_CLIENT_OS);
|
||||
assert_eq!(client_version.compiler(), PARITY_CLIENT_COMPILER);
|
||||
} else {
|
||||
panic!("shouldn't be here");
|
||||
}
|
||||
}
|
||||
|
||||
if let ClientVersion::ParityClient(client_version) = ClientVersion::from(client_version_string.as_str()) {
|
||||
assert_eq!(client_version.name(), PARITY_CLIENT_ID_PREFIX);
|
||||
assert_eq!(*client_version.semver(), Version::parse(PARITY_CLIENT_SEMVER).unwrap());
|
||||
assert_eq!(client_version.os(), PARITY_CLIENT_OS);
|
||||
assert_eq!(client_version.compiler(), PARITY_CLIENT_COMPILER);
|
||||
} else {
|
||||
panic!("shouldn't be here");
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
pub fn client_version_when_str_parity_long_format_and_valid_then_all_fields_match() {
|
||||
let client_version_string = make_default_long_version_string();
|
||||
|
||||
#[test]
|
||||
pub fn client_version_when_str_parity_long_format_and_valid_then_all_fields_match() {
|
||||
let client_version_string = make_default_long_version_string();
|
||||
if let ClientVersion::ParityClient(client_version) =
|
||||
ClientVersion::from(client_version_string.as_str())
|
||||
{
|
||||
assert_eq!(client_version.name(), PARITY_CLIENT_ID_PREFIX);
|
||||
assert_eq!(client_version.identity().unwrap(), PARITY_CLIENT_IDENTITY);
|
||||
assert_eq!(
|
||||
*client_version.semver(),
|
||||
Version::parse(PARITY_CLIENT_SEMVER).unwrap()
|
||||
);
|
||||
assert_eq!(client_version.os(), PARITY_CLIENT_OS);
|
||||
assert_eq!(client_version.compiler(), PARITY_CLIENT_COMPILER);
|
||||
} else {
|
||||
panic!("shouldnt be here");
|
||||
}
|
||||
}
|
||||
|
||||
if let ClientVersion::ParityClient(client_version) = ClientVersion::from(client_version_string.as_str()) {
|
||||
assert_eq!(client_version.name(), PARITY_CLIENT_ID_PREFIX);
|
||||
assert_eq!(client_version.identity().unwrap(), PARITY_CLIENT_IDENTITY);
|
||||
assert_eq!(*client_version.semver(), Version::parse(PARITY_CLIENT_SEMVER).unwrap());
|
||||
assert_eq!(client_version.os(), PARITY_CLIENT_OS);
|
||||
assert_eq!(client_version.compiler(), PARITY_CLIENT_COMPILER);
|
||||
} else {
|
||||
panic!("shouldnt be here");
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
pub fn client_version_when_str_parity_long_format_and_valid_and_identity_multiple_tokens_then_all_fields_match(
|
||||
) {
|
||||
let client_version_string = make_multitoken_identity_long_version_string();
|
||||
|
||||
#[test]
|
||||
pub fn client_version_when_str_parity_long_format_and_valid_and_identity_multiple_tokens_then_all_fields_match() {
|
||||
let client_version_string = make_multitoken_identity_long_version_string();
|
||||
if let ClientVersion::ParityClient(client_version) =
|
||||
ClientVersion::from(client_version_string.as_str())
|
||||
{
|
||||
assert_eq!(client_version.name(), PARITY_CLIENT_ID_PREFIX);
|
||||
assert_eq!(
|
||||
client_version.identity().unwrap(),
|
||||
PARITY_CLIENT_MULTITOKEN_IDENTITY
|
||||
);
|
||||
assert_eq!(
|
||||
*client_version.semver(),
|
||||
Version::parse(PARITY_CLIENT_SEMVER).unwrap()
|
||||
);
|
||||
assert_eq!(client_version.os(), PARITY_CLIENT_OS);
|
||||
assert_eq!(client_version.compiler(), PARITY_CLIENT_COMPILER);
|
||||
} else {
|
||||
panic!("shouldnt be here");
|
||||
}
|
||||
}
|
||||
|
||||
if let ClientVersion::ParityClient(client_version) = ClientVersion::from(client_version_string.as_str()) {
|
||||
assert_eq!(client_version.name(), PARITY_CLIENT_ID_PREFIX);
|
||||
assert_eq!(client_version.identity().unwrap(), PARITY_CLIENT_MULTITOKEN_IDENTITY);
|
||||
assert_eq!(*client_version.semver(), Version::parse(PARITY_CLIENT_SEMVER).unwrap());
|
||||
assert_eq!(client_version.os(), PARITY_CLIENT_OS);
|
||||
assert_eq!(client_version.compiler(), PARITY_CLIENT_COMPILER);
|
||||
} else {
|
||||
panic!("shouldnt be here");
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
pub fn client_version_when_string_parity_format_and_valid_then_all_fields_match() {
|
||||
let client_version_string: String = make_default_version_string();
|
||||
|
||||
#[test]
|
||||
pub fn client_version_when_string_parity_format_and_valid_then_all_fields_match() {
|
||||
let client_version_string: String = make_default_version_string();
|
||||
if let ClientVersion::ParityClient(client_version) =
|
||||
ClientVersion::from(client_version_string.as_str())
|
||||
{
|
||||
assert_eq!(client_version.name(), PARITY_CLIENT_ID_PREFIX);
|
||||
assert_eq!(
|
||||
*client_version.semver(),
|
||||
Version::parse(PARITY_CLIENT_SEMVER).unwrap()
|
||||
);
|
||||
assert_eq!(client_version.os(), PARITY_CLIENT_OS);
|
||||
assert_eq!(client_version.compiler(), PARITY_CLIENT_COMPILER);
|
||||
} else {
|
||||
panic!("shouldn't be here");
|
||||
}
|
||||
}
|
||||
|
||||
if let ClientVersion::ParityClient(client_version) = ClientVersion::from(client_version_string.as_str()) {
|
||||
assert_eq!(client_version.name(), PARITY_CLIENT_ID_PREFIX);
|
||||
assert_eq!(*client_version.semver(), Version::parse(PARITY_CLIENT_SEMVER).unwrap());
|
||||
assert_eq!(client_version.os(), PARITY_CLIENT_OS);
|
||||
assert_eq!(client_version.compiler(), PARITY_CLIENT_COMPILER);
|
||||
} else {
|
||||
panic!("shouldn't be here");
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
pub fn client_version_when_parity_format_and_invalid_then_equals_parity_unknown_client_version_string(
|
||||
) {
|
||||
// This is invalid because version has no leading 'v'
|
||||
let client_version_string = format!(
|
||||
"{}/{}/{}/{}",
|
||||
PARITY_CLIENT_ID_PREFIX, PARITY_CLIENT_SEMVER, PARITY_CLIENT_OS, PARITY_CLIENT_COMPILER
|
||||
);
|
||||
|
||||
#[test]
|
||||
pub fn client_version_when_parity_format_and_invalid_then_equals_parity_unknown_client_version_string() {
|
||||
// This is invalid because version has no leading 'v'
|
||||
let client_version_string = format!(
|
||||
"{}/{}/{}/{}",
|
||||
PARITY_CLIENT_ID_PREFIX,
|
||||
PARITY_CLIENT_SEMVER,
|
||||
PARITY_CLIENT_OS,
|
||||
PARITY_CLIENT_COMPILER);
|
||||
let client_version = ClientVersion::from(client_version_string.as_str());
|
||||
|
||||
let client_version = ClientVersion::from(client_version_string.as_str());
|
||||
let parity_unknown = ClientVersion::ParityUnknownFormat(client_version_string.to_string());
|
||||
|
||||
let parity_unknown = ClientVersion::ParityUnknownFormat(client_version_string.to_string());
|
||||
assert_eq!(client_version, parity_unknown);
|
||||
}
|
||||
|
||||
assert_eq!(client_version, parity_unknown);
|
||||
}
|
||||
#[test]
|
||||
pub fn client_version_when_parity_format_without_identity_and_missing_compiler_field_then_equals_parity_unknown_client_version_string(
|
||||
) {
|
||||
let client_version_string = format!(
|
||||
"{}/v{}/{}",
|
||||
PARITY_CLIENT_ID_PREFIX, PARITY_CLIENT_SEMVER, PARITY_CLIENT_OS,
|
||||
);
|
||||
|
||||
#[test]
|
||||
pub fn client_version_when_parity_format_without_identity_and_missing_compiler_field_then_equals_parity_unknown_client_version_string() {
|
||||
let client_version_string = format!(
|
||||
"{}/v{}/{}",
|
||||
PARITY_CLIENT_ID_PREFIX,
|
||||
PARITY_CLIENT_SEMVER,
|
||||
PARITY_CLIENT_OS,
|
||||
);
|
||||
let client_version = ClientVersion::from(client_version_string.as_str());
|
||||
|
||||
let client_version = ClientVersion::from(client_version_string.as_str());
|
||||
let parity_unknown = ClientVersion::ParityUnknownFormat(client_version_string.to_string());
|
||||
|
||||
let parity_unknown = ClientVersion::ParityUnknownFormat(client_version_string.to_string());
|
||||
assert_eq!(client_version, parity_unknown);
|
||||
}
|
||||
|
||||
assert_eq!(client_version, parity_unknown);
|
||||
}
|
||||
#[test]
|
||||
pub fn client_version_when_parity_format_with_identity_and_missing_compiler_field_then_equals_parity_unknown_client_version_string(
|
||||
) {
|
||||
let client_version_string = format!(
|
||||
"{}/{}/v{}/{}",
|
||||
PARITY_CLIENT_ID_PREFIX, PARITY_CLIENT_IDENTITY, PARITY_CLIENT_SEMVER, PARITY_CLIENT_OS,
|
||||
);
|
||||
|
||||
#[test]
|
||||
pub fn client_version_when_parity_format_with_identity_and_missing_compiler_field_then_equals_parity_unknown_client_version_string() {
|
||||
let client_version_string = format!(
|
||||
"{}/{}/v{}/{}",
|
||||
PARITY_CLIENT_ID_PREFIX,
|
||||
PARITY_CLIENT_IDENTITY,
|
||||
PARITY_CLIENT_SEMVER,
|
||||
PARITY_CLIENT_OS,
|
||||
);
|
||||
let client_version = ClientVersion::from(client_version_string.as_str());
|
||||
|
||||
let client_version = ClientVersion::from(client_version_string.as_str());
|
||||
let parity_unknown = ClientVersion::ParityUnknownFormat(client_version_string.to_string());
|
||||
|
||||
let parity_unknown = ClientVersion::ParityUnknownFormat(client_version_string.to_string());
|
||||
assert_eq!(client_version, parity_unknown);
|
||||
}
|
||||
|
||||
assert_eq!(client_version, parity_unknown);
|
||||
}
|
||||
#[test]
|
||||
pub fn client_version_when_not_parity_format_and_valid_then_other_with_client_version_string() {
|
||||
let client_version_string = "Geth/main.jnode.network/v1.8.21-stable-9dc5d1a9/linux";
|
||||
|
||||
#[test]
|
||||
pub fn client_version_when_not_parity_format_and_valid_then_other_with_client_version_string() {
|
||||
let client_version_string = "Geth/main.jnode.network/v1.8.21-stable-9dc5d1a9/linux";
|
||||
let client_version = ClientVersion::from(client_version_string);
|
||||
|
||||
let client_version = ClientVersion::from(client_version_string);
|
||||
assert_eq!(
|
||||
client_version,
|
||||
ClientVersion::Other(client_version_string.to_string())
|
||||
);
|
||||
}
|
||||
|
||||
assert_eq!(client_version, ClientVersion::Other(client_version_string.to_string()));
|
||||
}
|
||||
#[test]
|
||||
pub fn client_version_when_parity_format_and_valid_then_to_string_equal() {
|
||||
let client_version_string: String = make_default_version_string();
|
||||
|
||||
#[test]
|
||||
pub fn client_version_when_parity_format_and_valid_then_to_string_equal() {
|
||||
let client_version_string: String = make_default_version_string();
|
||||
let client_version = ClientVersion::from(client_version_string.as_str());
|
||||
|
||||
let client_version = ClientVersion::from(client_version_string.as_str());
|
||||
assert_eq!(client_version.to_string(), client_version_string);
|
||||
}
|
||||
|
||||
assert_eq!(client_version.to_string(), client_version_string);
|
||||
}
|
||||
#[test]
|
||||
pub fn client_version_when_other_then_to_string_equal_input_string() {
|
||||
let client_version_string: String = "Other".to_string();
|
||||
|
||||
#[test]
|
||||
pub fn client_version_when_other_then_to_string_equal_input_string() {
|
||||
let client_version_string: String = "Other".to_string();
|
||||
let client_version = ClientVersion::from("Other");
|
||||
|
||||
let client_version = ClientVersion::from("Other");
|
||||
assert_eq!(client_version.to_string(), client_version_string);
|
||||
}
|
||||
|
||||
assert_eq!(client_version.to_string(), client_version_string);
|
||||
}
|
||||
#[test]
|
||||
pub fn client_capabilities_when_parity_old_version_then_handles_large_requests_false() {
|
||||
let client_version_string: String = make_old_semver_version_string();
|
||||
|
||||
#[test]
|
||||
pub fn client_capabilities_when_parity_old_version_then_handles_large_requests_false() {
|
||||
let client_version_string: String = make_old_semver_version_string();
|
||||
let client_version = ClientVersion::from(client_version_string.as_str());
|
||||
|
||||
let client_version = ClientVersion::from(client_version_string.as_str());
|
||||
assert!(!client_version.can_handle_large_requests());
|
||||
}
|
||||
|
||||
assert!(!client_version.can_handle_large_requests());
|
||||
}
|
||||
#[test]
|
||||
pub fn client_capabilities_when_parity_beta_version_then_not_handles_large_requests_true() {
|
||||
let client_version_string: String = format!(
|
||||
"{}/v{}/{}/{}",
|
||||
"Parity-Ethereum", "2.4.0-beta", "x86_64-linux-gnu", "rustc1.31.1"
|
||||
)
|
||||
.to_string();
|
||||
|
||||
#[test]
|
||||
pub fn client_capabilities_when_parity_beta_version_then_not_handles_large_requests_true() {
|
||||
let client_version_string: String = format!(
|
||||
"{}/v{}/{}/{}",
|
||||
"Parity-Ethereum",
|
||||
"2.4.0-beta",
|
||||
"x86_64-linux-gnu",
|
||||
"rustc1.31.1")
|
||||
.to_string();
|
||||
let client_version = ClientVersion::from(client_version_string.as_str());
|
||||
|
||||
let client_version = ClientVersion::from(client_version_string.as_str());
|
||||
assert!(!client_version.can_handle_large_requests());
|
||||
}
|
||||
|
||||
assert!(!client_version.can_handle_large_requests());
|
||||
}
|
||||
#[test]
|
||||
pub fn client_version_when_to_owned_then_both_objects_equal() {
|
||||
let client_version_string: String = make_old_semver_version_string();
|
||||
|
||||
#[test]
|
||||
pub fn client_version_when_to_owned_then_both_objects_equal() {
|
||||
let client_version_string: String = make_old_semver_version_string();
|
||||
let origin = ClientVersion::from(client_version_string.as_str());
|
||||
|
||||
let origin = ClientVersion::from(client_version_string.as_str());
|
||||
let borrowed = &origin;
|
||||
|
||||
let borrowed = &origin;
|
||||
let owned = origin.to_owned();
|
||||
|
||||
let owned = origin.to_owned();
|
||||
assert_eq!(*borrowed, owned);
|
||||
}
|
||||
|
||||
assert_eq!(*borrowed, owned);
|
||||
}
|
||||
#[test]
|
||||
fn client_version_accepts_service_transaction_for_different_versions() {
|
||||
assert!(!ClientVersion::from("Geth").accepts_service_transaction());
|
||||
assert!(
|
||||
ClientVersion::from("Parity-Ethereum/v2.6.0/linux/rustc").accepts_service_transaction()
|
||||
);
|
||||
assert!(
|
||||
ClientVersion::from("Parity-Ethereum/ABCDEFGH/v2.7.3/linux/rustc")
|
||||
.accepts_service_transaction()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn client_version_accepts_service_transaction_for_different_versions() {
|
||||
assert!(!ClientVersion::from("Geth").accepts_service_transaction());
|
||||
assert!(ClientVersion::from("Parity-Ethereum/v2.6.0/linux/rustc").accepts_service_transaction());
|
||||
assert!(ClientVersion::from("Parity-Ethereum/ABCDEFGH/v2.7.3/linux/rustc").accepts_service_transaction());
|
||||
}
|
||||
#[test]
|
||||
fn is_parity_when_parity_then_true() {
|
||||
let client_id = format!("{}/", PARITY_CLIENT_ID_PREFIX);
|
||||
|
||||
#[test]
|
||||
fn is_parity_when_parity_then_true() {
|
||||
let client_id = format!("{}/", PARITY_CLIENT_ID_PREFIX);
|
||||
assert!(is_parity(&client_id));
|
||||
}
|
||||
|
||||
assert!(is_parity(&client_id));
|
||||
}
|
||||
#[test]
|
||||
fn is_parity_when_empty_then_false() {
|
||||
let client_id = "";
|
||||
|
||||
#[test]
|
||||
fn is_parity_when_empty_then_false() {
|
||||
let client_id = "";
|
||||
assert!(!is_parity(&client_id));
|
||||
}
|
||||
|
||||
assert!(!is_parity(&client_id));
|
||||
}
|
||||
#[test]
|
||||
fn is_parity_when_other_then_false() {
|
||||
let client_id = "other";
|
||||
|
||||
#[test]
|
||||
fn is_parity_when_other_then_false() {
|
||||
let client_id = "other";
|
||||
|
||||
assert!(!is_parity(&client_id));
|
||||
}
|
||||
assert!(!is_parity(&client_id));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,12 +20,17 @@ use super::NodeId;
|
||||
|
||||
/// Filtered connection direction.
|
||||
pub enum ConnectionDirection {
|
||||
Inbound,
|
||||
Outbound,
|
||||
Inbound,
|
||||
Outbound,
|
||||
}
|
||||
|
||||
/// Connection filter. Each connection is checked against `connection_allowed`.
|
||||
pub trait ConnectionFilter : Send + Sync {
|
||||
/// Filter a connection. Returns `true` if connection should be allowed. `false` if rejected.
|
||||
fn connection_allowed(&self, own_id: &NodeId, connecting_id: &NodeId, direction: ConnectionDirection) -> bool;
|
||||
pub trait ConnectionFilter: Send + Sync {
|
||||
/// Filter a connection. Returns `true` if connection should be allowed. `false` if rejected.
|
||||
fn connection_allowed(
|
||||
&self,
|
||||
own_id: &NodeId,
|
||||
connecting_id: &NodeId,
|
||||
direction: ConnectionDirection,
|
||||
) -> bool;
|
||||
}
|
||||
|
||||
@@ -18,226 +18,229 @@
|
||||
// https://github.com/paritytech/parity-ethereum/issues/10302
|
||||
#![allow(deprecated)]
|
||||
|
||||
use std::{io, net, fmt};
|
||||
use libc::{ENFILE, EMFILE};
|
||||
use crypto;
|
||||
use ethkey;
|
||||
use io::IoError;
|
||||
use {rlp, ethkey, crypto, snappy};
|
||||
use libc::{EMFILE, ENFILE};
|
||||
use rlp;
|
||||
use snappy;
|
||||
use std::{fmt, io, net};
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum DisconnectReason
|
||||
{
|
||||
DisconnectRequested,
|
||||
TCPError,
|
||||
BadProtocol,
|
||||
UselessPeer,
|
||||
TooManyPeers,
|
||||
DuplicatePeer,
|
||||
IncompatibleProtocol,
|
||||
NullIdentity,
|
||||
ClientQuit,
|
||||
UnexpectedIdentity,
|
||||
LocalIdentity,
|
||||
PingTimeout,
|
||||
Unknown,
|
||||
pub enum DisconnectReason {
|
||||
DisconnectRequested,
|
||||
TCPError,
|
||||
BadProtocol,
|
||||
UselessPeer,
|
||||
TooManyPeers,
|
||||
DuplicatePeer,
|
||||
IncompatibleProtocol,
|
||||
NullIdentity,
|
||||
ClientQuit,
|
||||
UnexpectedIdentity,
|
||||
LocalIdentity,
|
||||
PingTimeout,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl DisconnectReason {
|
||||
pub fn from_u8(n: u8) -> DisconnectReason {
|
||||
match n {
|
||||
0 => DisconnectReason::DisconnectRequested,
|
||||
1 => DisconnectReason::TCPError,
|
||||
2 => DisconnectReason::BadProtocol,
|
||||
3 => DisconnectReason::UselessPeer,
|
||||
4 => DisconnectReason::TooManyPeers,
|
||||
5 => DisconnectReason::DuplicatePeer,
|
||||
6 => DisconnectReason::IncompatibleProtocol,
|
||||
7 => DisconnectReason::NullIdentity,
|
||||
8 => DisconnectReason::ClientQuit,
|
||||
9 => DisconnectReason::UnexpectedIdentity,
|
||||
10 => DisconnectReason::LocalIdentity,
|
||||
11 => DisconnectReason::PingTimeout,
|
||||
_ => DisconnectReason::Unknown,
|
||||
}
|
||||
}
|
||||
pub fn from_u8(n: u8) -> DisconnectReason {
|
||||
match n {
|
||||
0 => DisconnectReason::DisconnectRequested,
|
||||
1 => DisconnectReason::TCPError,
|
||||
2 => DisconnectReason::BadProtocol,
|
||||
3 => DisconnectReason::UselessPeer,
|
||||
4 => DisconnectReason::TooManyPeers,
|
||||
5 => DisconnectReason::DuplicatePeer,
|
||||
6 => DisconnectReason::IncompatibleProtocol,
|
||||
7 => DisconnectReason::NullIdentity,
|
||||
8 => DisconnectReason::ClientQuit,
|
||||
9 => DisconnectReason::UnexpectedIdentity,
|
||||
10 => DisconnectReason::LocalIdentity,
|
||||
11 => DisconnectReason::PingTimeout,
|
||||
_ => DisconnectReason::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for DisconnectReason {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use self::DisconnectReason::*;
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use self::DisconnectReason::*;
|
||||
|
||||
let msg = match *self {
|
||||
DisconnectRequested => "disconnect requested",
|
||||
TCPError => "TCP error",
|
||||
BadProtocol => "bad protocol",
|
||||
UselessPeer => "useless peer",
|
||||
TooManyPeers => "too many peers",
|
||||
DuplicatePeer => "duplicate peer",
|
||||
IncompatibleProtocol => "incompatible protocol",
|
||||
NullIdentity => "null identity",
|
||||
ClientQuit => "client quit",
|
||||
UnexpectedIdentity => "unexpected identity",
|
||||
LocalIdentity => "local identity",
|
||||
PingTimeout => "ping timeout",
|
||||
Unknown => "unknown",
|
||||
};
|
||||
let msg = match *self {
|
||||
DisconnectRequested => "disconnect requested",
|
||||
TCPError => "TCP error",
|
||||
BadProtocol => "bad protocol",
|
||||
UselessPeer => "useless peer",
|
||||
TooManyPeers => "too many peers",
|
||||
DuplicatePeer => "duplicate peer",
|
||||
IncompatibleProtocol => "incompatible protocol",
|
||||
NullIdentity => "null identity",
|
||||
ClientQuit => "client quit",
|
||||
UnexpectedIdentity => "unexpected identity",
|
||||
LocalIdentity => "local identity",
|
||||
PingTimeout => "ping timeout",
|
||||
Unknown => "unknown",
|
||||
};
|
||||
|
||||
f.write_str(msg)
|
||||
}
|
||||
f.write_str(msg)
|
||||
}
|
||||
}
|
||||
|
||||
error_chain! {
|
||||
foreign_links {
|
||||
SocketIo(IoError) #[doc = "Socket IO error."];
|
||||
Decompression(snappy::InvalidInput) #[doc = "Decompression error."];
|
||||
Rlp(rlp::DecoderError) #[doc = "Rlp decoder error."];
|
||||
}
|
||||
foreign_links {
|
||||
SocketIo(IoError) #[doc = "Socket IO error."];
|
||||
Decompression(snappy::InvalidInput) #[doc = "Decompression error."];
|
||||
Rlp(rlp::DecoderError) #[doc = "Rlp decoder error."];
|
||||
}
|
||||
|
||||
errors {
|
||||
#[doc = "Error concerning the network address parsing subsystem."]
|
||||
AddressParse {
|
||||
description("Failed to parse network address"),
|
||||
display("Failed to parse network address"),
|
||||
}
|
||||
errors {
|
||||
#[doc = "Error concerning the network address parsing subsystem."]
|
||||
AddressParse {
|
||||
description("Failed to parse network address"),
|
||||
display("Failed to parse network address"),
|
||||
}
|
||||
|
||||
#[doc = "Error concerning the network address resolution subsystem."]
|
||||
AddressResolve(err: Option<io::Error>) {
|
||||
description("Failed to resolve network address"),
|
||||
display("Failed to resolve network address {}", err.as_ref().map_or("".to_string(), |e| e.to_string())),
|
||||
}
|
||||
#[doc = "Error concerning the network address resolution subsystem."]
|
||||
AddressResolve(err: Option<io::Error>) {
|
||||
description("Failed to resolve network address"),
|
||||
display("Failed to resolve network address {}", err.as_ref().map_or("".to_string(), |e| e.to_string())),
|
||||
}
|
||||
|
||||
#[doc = "Authentication failure"]
|
||||
Auth {
|
||||
description("Authentication failure"),
|
||||
display("Authentication failure"),
|
||||
}
|
||||
#[doc = "Authentication failure"]
|
||||
Auth {
|
||||
description("Authentication failure"),
|
||||
display("Authentication failure"),
|
||||
}
|
||||
|
||||
#[doc = "Unrecognised protocol"]
|
||||
BadProtocol {
|
||||
description("Bad protocol"),
|
||||
display("Bad protocol"),
|
||||
}
|
||||
#[doc = "Unrecognised protocol"]
|
||||
BadProtocol {
|
||||
description("Bad protocol"),
|
||||
display("Bad protocol"),
|
||||
}
|
||||
|
||||
#[doc = "Expired message"]
|
||||
Expired {
|
||||
description("Expired message"),
|
||||
display("Expired message"),
|
||||
}
|
||||
#[doc = "Expired message"]
|
||||
Expired {
|
||||
description("Expired message"),
|
||||
display("Expired message"),
|
||||
}
|
||||
|
||||
#[doc = "Peer not found"]
|
||||
PeerNotFound {
|
||||
description("Peer not found"),
|
||||
display("Peer not found"),
|
||||
}
|
||||
#[doc = "Peer not found"]
|
||||
PeerNotFound {
|
||||
description("Peer not found"),
|
||||
display("Peer not found"),
|
||||
}
|
||||
|
||||
#[doc = "Peer is disconnected"]
|
||||
Disconnect(reason: DisconnectReason) {
|
||||
description("Peer disconnected"),
|
||||
display("Peer disconnected: {}", reason),
|
||||
}
|
||||
#[doc = "Peer is disconnected"]
|
||||
Disconnect(reason: DisconnectReason) {
|
||||
description("Peer disconnected"),
|
||||
display("Peer disconnected: {}", reason),
|
||||
}
|
||||
|
||||
#[doc = "Invalid node id"]
|
||||
InvalidNodeId {
|
||||
description("Invalid node id"),
|
||||
display("Invalid node id"),
|
||||
}
|
||||
#[doc = "Invalid node id"]
|
||||
InvalidNodeId {
|
||||
description("Invalid node id"),
|
||||
display("Invalid node id"),
|
||||
}
|
||||
|
||||
#[doc = "Packet size is over the protocol limit"]
|
||||
OversizedPacket {
|
||||
description("Packet is too large"),
|
||||
display("Packet is too large"),
|
||||
}
|
||||
#[doc = "Packet size is over the protocol limit"]
|
||||
OversizedPacket {
|
||||
description("Packet is too large"),
|
||||
display("Packet is too large"),
|
||||
}
|
||||
|
||||
#[doc = "Reached system resource limits for this process"]
|
||||
ProcessTooManyFiles {
|
||||
description("Too many open files in process."),
|
||||
display("Too many open files in this process. Check your resource limits and restart parity"),
|
||||
}
|
||||
#[doc = "Reached system resource limits for this process"]
|
||||
ProcessTooManyFiles {
|
||||
description("Too many open files in process."),
|
||||
display("Too many open files in this process. Check your resource limits and restart parity"),
|
||||
}
|
||||
|
||||
#[doc = "Reached system wide resource limits"]
|
||||
SystemTooManyFiles {
|
||||
description("Too many open files on system."),
|
||||
display("Too many open files on system. Consider closing some processes/release some file handlers or increas the system-wide resource limits and restart parity."),
|
||||
}
|
||||
#[doc = "Reached system wide resource limits"]
|
||||
SystemTooManyFiles {
|
||||
description("Too many open files on system."),
|
||||
display("Too many open files on system. Consider closing some processes/release some file handlers or increas the system-wide resource limits and restart parity."),
|
||||
}
|
||||
|
||||
#[doc = "An unknown IO error occurred."]
|
||||
Io(err: io::Error) {
|
||||
description("IO Error"),
|
||||
display("Unexpected IO error: {}", err),
|
||||
}
|
||||
}
|
||||
#[doc = "An unknown IO error occurred."]
|
||||
Io(err: io::Error) {
|
||||
description("IO Error"),
|
||||
display("Unexpected IO error: {}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<io::Error> for Error {
|
||||
fn from(err: io::Error) -> Self {
|
||||
match err.raw_os_error() {
|
||||
Some(ENFILE) => ErrorKind::ProcessTooManyFiles.into(),
|
||||
Some(EMFILE) => ErrorKind::SystemTooManyFiles.into(),
|
||||
_ => Error::from_kind(ErrorKind::Io(err))
|
||||
}
|
||||
}
|
||||
fn from(err: io::Error) -> Self {
|
||||
match err.raw_os_error() {
|
||||
Some(ENFILE) => ErrorKind::ProcessTooManyFiles.into(),
|
||||
Some(EMFILE) => ErrorKind::SystemTooManyFiles.into(),
|
||||
_ => Error::from_kind(ErrorKind::Io(err)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ethkey::Error> for Error {
|
||||
fn from(_err: ethkey::Error) -> Self {
|
||||
ErrorKind::Auth.into()
|
||||
}
|
||||
fn from(_err: ethkey::Error) -> Self {
|
||||
ErrorKind::Auth.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ethkey::crypto::Error> for Error {
|
||||
fn from(_err: ethkey::crypto::Error) -> Self {
|
||||
ErrorKind::Auth.into()
|
||||
}
|
||||
fn from(_err: ethkey::crypto::Error) -> Self {
|
||||
ErrorKind::Auth.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crypto::error::SymmError> for Error {
|
||||
fn from(_err: crypto::error::SymmError) -> Self {
|
||||
ErrorKind::Auth.into()
|
||||
}
|
||||
fn from(_err: crypto::error::SymmError) -> Self {
|
||||
ErrorKind::Auth.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<net::AddrParseError> for Error {
|
||||
fn from(_err: net::AddrParseError) -> Self { ErrorKind::AddressParse.into() }
|
||||
fn from(_err: net::AddrParseError) -> Self {
|
||||
ErrorKind::AddressParse.into()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_errors() {
|
||||
assert_eq!(DisconnectReason::ClientQuit, DisconnectReason::from_u8(8));
|
||||
let mut r = DisconnectReason::DisconnectRequested;
|
||||
for i in 0 .. 20 {
|
||||
r = DisconnectReason::from_u8(i);
|
||||
}
|
||||
assert_eq!(DisconnectReason::Unknown, r);
|
||||
assert_eq!(DisconnectReason::ClientQuit, DisconnectReason::from_u8(8));
|
||||
let mut r = DisconnectReason::DisconnectRequested;
|
||||
for i in 0..20 {
|
||||
r = DisconnectReason::from_u8(i);
|
||||
}
|
||||
assert_eq!(DisconnectReason::Unknown, r);
|
||||
|
||||
match *<Error as From<rlp::DecoderError>>::from(rlp::DecoderError::RlpIsTooBig).kind() {
|
||||
ErrorKind::Rlp(_) => {},
|
||||
_ => panic!("Unexpected error"),
|
||||
}
|
||||
match *<Error as From<rlp::DecoderError>>::from(rlp::DecoderError::RlpIsTooBig).kind() {
|
||||
ErrorKind::Rlp(_) => {}
|
||||
_ => panic!("Unexpected error"),
|
||||
}
|
||||
|
||||
match *<Error as From<ethkey::crypto::Error>>::from(ethkey::crypto::Error::InvalidMessage).kind() {
|
||||
ErrorKind::Auth => {},
|
||||
_ => panic!("Unexpected error"),
|
||||
}
|
||||
match *<Error as From<ethkey::crypto::Error>>::from(ethkey::crypto::Error::InvalidMessage)
|
||||
.kind()
|
||||
{
|
||||
ErrorKind::Auth => {}
|
||||
_ => panic!("Unexpected error"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_io_errors() {
|
||||
use libc::{EMFILE, ENFILE};
|
||||
use libc::{EMFILE, ENFILE};
|
||||
|
||||
assert_matches!(
|
||||
<Error as From<io::Error>>::from(
|
||||
io::Error::from_raw_os_error(ENFILE)
|
||||
).kind(),
|
||||
ErrorKind::ProcessTooManyFiles);
|
||||
assert_matches!(
|
||||
<Error as From<io::Error>>::from(io::Error::from_raw_os_error(ENFILE)).kind(),
|
||||
ErrorKind::ProcessTooManyFiles
|
||||
);
|
||||
|
||||
assert_matches!(
|
||||
<Error as From<io::Error>>::from(
|
||||
io::Error::from_raw_os_error(EMFILE)
|
||||
).kind(),
|
||||
ErrorKind::SystemTooManyFiles);
|
||||
assert_matches!(
|
||||
<Error as From<io::Error>>::from(io::Error::from_raw_os_error(EMFILE)).kind(),
|
||||
ErrorKind::SystemTooManyFiles
|
||||
);
|
||||
|
||||
assert_matches!(
|
||||
<Error as From<io::Error>>::from(
|
||||
io::Error::from_raw_os_error(0)
|
||||
).kind(),
|
||||
ErrorKind::Io(_));
|
||||
assert_matches!(
|
||||
<Error as From<io::Error>>::from(io::Error::from_raw_os_error(0)).kind(),
|
||||
ErrorKind::Io(_)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -14,23 +14,24 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#![recursion_limit="128"]
|
||||
#![recursion_limit = "128"]
|
||||
|
||||
extern crate parity_crypto as crypto;
|
||||
extern crate ethcore_io as io;
|
||||
extern crate ethereum_types;
|
||||
extern crate ethkey;
|
||||
extern crate rlp;
|
||||
extern crate ipnetwork;
|
||||
extern crate parity_snappy as snappy;
|
||||
extern crate libc;
|
||||
extern crate parity_crypto as crypto;
|
||||
extern crate parity_snappy as snappy;
|
||||
extern crate rlp;
|
||||
extern crate semver;
|
||||
extern crate serde;
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
#[cfg(test)] #[macro_use]
|
||||
#[cfg(test)]
|
||||
#[macro_use]
|
||||
extern crate assert_matches;
|
||||
|
||||
#[macro_use]
|
||||
@@ -44,21 +45,23 @@ pub mod client_version;
|
||||
mod connection_filter;
|
||||
mod error;
|
||||
|
||||
pub use connection_filter::{ConnectionFilter, ConnectionDirection};
|
||||
pub use connection_filter::{ConnectionDirection, ConnectionFilter};
|
||||
pub use error::{DisconnectReason, Error, ErrorKind};
|
||||
pub use io::TimerToken;
|
||||
pub use error::{Error, ErrorKind, DisconnectReason};
|
||||
|
||||
use client_version::ClientVersion;
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::HashMap;
|
||||
use std::net::{SocketAddr, SocketAddrV4, Ipv4Addr};
|
||||
use std::str::{self, FromStr};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use ipnetwork::{IpNetwork, IpNetworkError};
|
||||
use ethkey::Secret;
|
||||
use ethereum_types::H512;
|
||||
use ethkey::Secret;
|
||||
use ipnetwork::{IpNetwork, IpNetworkError};
|
||||
use rlp::{Decodable, DecoderError, Rlp};
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
collections::HashMap,
|
||||
net::{Ipv4Addr, SocketAddr, SocketAddrV4},
|
||||
str::{self, FromStr},
|
||||
sync::Arc,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
/// Protocol handler level packet id
|
||||
pub type PacketId = u8;
|
||||
@@ -74,324 +77,351 @@ pub type PeerId = usize;
|
||||
/// Messages used to communitate with the event loop from other threads.
|
||||
#[derive(Clone)]
|
||||
pub enum NetworkIoMessage {
|
||||
/// Register a new protocol handler.
|
||||
AddHandler {
|
||||
/// Handler shared instance.
|
||||
handler: Arc<NetworkProtocolHandler + Sync>,
|
||||
/// Protocol Id.
|
||||
protocol: ProtocolId,
|
||||
/// Supported protocol versions and number of packet IDs reserved by the protocol (packet count).
|
||||
versions: Vec<(u8, u8)>,
|
||||
},
|
||||
/// Register a new protocol timer
|
||||
AddTimer {
|
||||
/// Protocol Id.
|
||||
protocol: ProtocolId,
|
||||
/// Timer token.
|
||||
token: TimerToken,
|
||||
/// Timer delay.
|
||||
delay: Duration,
|
||||
},
|
||||
/// Initliaze public interface.
|
||||
InitPublicInterface,
|
||||
/// Disconnect a peer.
|
||||
Disconnect(PeerId),
|
||||
/// Disconnect and temporary disable peer.
|
||||
DisablePeer(PeerId),
|
||||
/// Network has been started with the host as the given enode.
|
||||
NetworkStarted(String),
|
||||
/// Register a new protocol handler.
|
||||
AddHandler {
|
||||
/// Handler shared instance.
|
||||
handler: Arc<NetworkProtocolHandler + Sync>,
|
||||
/// Protocol Id.
|
||||
protocol: ProtocolId,
|
||||
/// Supported protocol versions and number of packet IDs reserved by the protocol (packet count).
|
||||
versions: Vec<(u8, u8)>,
|
||||
},
|
||||
/// Register a new protocol timer
|
||||
AddTimer {
|
||||
/// Protocol Id.
|
||||
protocol: ProtocolId,
|
||||
/// Timer token.
|
||||
token: TimerToken,
|
||||
/// Timer delay.
|
||||
delay: Duration,
|
||||
},
|
||||
/// Initliaze public interface.
|
||||
InitPublicInterface,
|
||||
/// Disconnect a peer.
|
||||
Disconnect(PeerId),
|
||||
/// Disconnect and temporary disable peer.
|
||||
DisablePeer(PeerId),
|
||||
/// Network has been started with the host as the given enode.
|
||||
NetworkStarted(String),
|
||||
}
|
||||
|
||||
/// Shared session information
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SessionInfo {
|
||||
/// Peer public key
|
||||
pub id: Option<NodeId>,
|
||||
/// Peer client ID
|
||||
pub client_version: ClientVersion,
|
||||
/// Peer RLPx protocol version
|
||||
pub protocol_version: u32,
|
||||
/// Session protocol capabilities
|
||||
pub capabilities: Vec<SessionCapabilityInfo>,
|
||||
/// Peer protocol capabilities
|
||||
pub peer_capabilities: Vec<PeerCapabilityInfo>,
|
||||
/// Peer ping delay
|
||||
pub ping: Option<Duration>,
|
||||
/// True if this session was originated by us.
|
||||
pub originated: bool,
|
||||
/// Remote endpoint address of the session
|
||||
pub remote_address: String,
|
||||
/// Local endpoint address of the session
|
||||
pub local_address: String,
|
||||
/// Peer public key
|
||||
pub id: Option<NodeId>,
|
||||
/// Peer client ID
|
||||
pub client_version: ClientVersion,
|
||||
/// Peer RLPx protocol version
|
||||
pub protocol_version: u32,
|
||||
/// Session protocol capabilities
|
||||
pub capabilities: Vec<SessionCapabilityInfo>,
|
||||
/// Peer protocol capabilities
|
||||
pub peer_capabilities: Vec<PeerCapabilityInfo>,
|
||||
/// Peer ping delay
|
||||
pub ping: Option<Duration>,
|
||||
/// True if this session was originated by us.
|
||||
pub originated: bool,
|
||||
/// Remote endpoint address of the session
|
||||
pub remote_address: String,
|
||||
/// Local endpoint address of the session
|
||||
pub local_address: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct PeerCapabilityInfo {
|
||||
pub protocol: ProtocolId,
|
||||
pub version: u8,
|
||||
pub protocol: ProtocolId,
|
||||
pub version: u8,
|
||||
}
|
||||
|
||||
impl Decodable for PeerCapabilityInfo {
|
||||
fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
|
||||
let p: Vec<u8> = rlp.val_at(0)?;
|
||||
if p.len() != 3 {
|
||||
return Err(DecoderError::Custom("Invalid subprotocol string length. Should be 3"));
|
||||
}
|
||||
let mut p2: ProtocolId = [0u8; 3];
|
||||
p2.clone_from_slice(&p);
|
||||
Ok(PeerCapabilityInfo {
|
||||
protocol: p2,
|
||||
version: rlp.val_at(1)?
|
||||
})
|
||||
}
|
||||
fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
|
||||
let p: Vec<u8> = rlp.val_at(0)?;
|
||||
if p.len() != 3 {
|
||||
return Err(DecoderError::Custom(
|
||||
"Invalid subprotocol string length. Should be 3",
|
||||
));
|
||||
}
|
||||
let mut p2: ProtocolId = [0u8; 3];
|
||||
p2.clone_from_slice(&p);
|
||||
Ok(PeerCapabilityInfo {
|
||||
protocol: p2,
|
||||
version: rlp.val_at(1)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for PeerCapabilityInfo {
|
||||
fn to_string(&self) -> String {
|
||||
format!("{}/{}", str::from_utf8(&self.protocol[..]).unwrap_or("???"), self.version)
|
||||
}
|
||||
fn to_string(&self) -> String {
|
||||
format!(
|
||||
"{}/{}",
|
||||
str::from_utf8(&self.protocol[..]).unwrap_or("???"),
|
||||
self.version
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct SessionCapabilityInfo {
|
||||
pub protocol: [u8; 3],
|
||||
pub version: u8,
|
||||
pub packet_count: u8,
|
||||
pub id_offset: u8,
|
||||
pub protocol: [u8; 3],
|
||||
pub version: u8,
|
||||
pub packet_count: u8,
|
||||
pub id_offset: u8,
|
||||
}
|
||||
|
||||
impl PartialOrd for SessionCapabilityInfo {
|
||||
fn partial_cmp(&self, other: &SessionCapabilityInfo) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
fn partial_cmp(&self, other: &SessionCapabilityInfo) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for SessionCapabilityInfo {
|
||||
fn cmp(&self, b: &SessionCapabilityInfo) -> Ordering {
|
||||
// By protocol id first
|
||||
if self.protocol != b.protocol {
|
||||
return self.protocol.cmp(&b.protocol);
|
||||
}
|
||||
// By version
|
||||
self.version.cmp(&b.version)
|
||||
}
|
||||
fn cmp(&self, b: &SessionCapabilityInfo) -> Ordering {
|
||||
// By protocol id first
|
||||
if self.protocol != b.protocol {
|
||||
return self.protocol.cmp(&b.protocol);
|
||||
}
|
||||
// By version
|
||||
self.version.cmp(&b.version)
|
||||
}
|
||||
}
|
||||
|
||||
/// Network service configuration
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct NetworkConfiguration {
|
||||
/// Directory path to store general network configuration. None means nothing will be saved
|
||||
pub config_path: Option<String>,
|
||||
/// Directory path to store network-specific configuration. None means nothing will be saved
|
||||
pub net_config_path: Option<String>,
|
||||
/// IP address to listen for incoming connections. Listen to all connections by default
|
||||
pub listen_address: Option<SocketAddr>,
|
||||
/// IP address to advertise. Detected automatically if none.
|
||||
pub public_address: Option<SocketAddr>,
|
||||
/// Port for UDP connections, same as TCP by default
|
||||
pub udp_port: Option<u16>,
|
||||
/// Enable NAT configuration
|
||||
pub nat_enabled: bool,
|
||||
/// Enable discovery
|
||||
pub discovery_enabled: bool,
|
||||
/// List of initial node addresses
|
||||
pub boot_nodes: Vec<String>,
|
||||
/// Use provided node key instead of default
|
||||
pub use_secret: Option<Secret>,
|
||||
/// Minimum number of connected peers to maintain
|
||||
pub min_peers: u32,
|
||||
/// Maximum allowed number of peers
|
||||
pub max_peers: u32,
|
||||
/// Maximum handshakes
|
||||
pub max_handshakes: u32,
|
||||
/// Reserved protocols. Peers with <key> protocol get additional <value> connection slots.
|
||||
pub reserved_protocols: HashMap<ProtocolId, u32>,
|
||||
/// List of reserved node addresses.
|
||||
pub reserved_nodes: Vec<String>,
|
||||
/// The non-reserved peer mode.
|
||||
pub non_reserved_mode: NonReservedPeerMode,
|
||||
/// IP filter
|
||||
pub ip_filter: IpFilter,
|
||||
/// Client identifier
|
||||
pub client_version: String,
|
||||
/// Directory path to store general network configuration. None means nothing will be saved
|
||||
pub config_path: Option<String>,
|
||||
/// Directory path to store network-specific configuration. None means nothing will be saved
|
||||
pub net_config_path: Option<String>,
|
||||
/// IP address to listen for incoming connections. Listen to all connections by default
|
||||
pub listen_address: Option<SocketAddr>,
|
||||
/// IP address to advertise. Detected automatically if none.
|
||||
pub public_address: Option<SocketAddr>,
|
||||
/// Port for UDP connections, same as TCP by default
|
||||
pub udp_port: Option<u16>,
|
||||
/// Enable NAT configuration
|
||||
pub nat_enabled: bool,
|
||||
/// Enable discovery
|
||||
pub discovery_enabled: bool,
|
||||
/// List of initial node addresses
|
||||
pub boot_nodes: Vec<String>,
|
||||
/// Use provided node key instead of default
|
||||
pub use_secret: Option<Secret>,
|
||||
/// Minimum number of connected peers to maintain
|
||||
pub min_peers: u32,
|
||||
/// Maximum allowed number of peers
|
||||
pub max_peers: u32,
|
||||
/// Maximum handshakes
|
||||
pub max_handshakes: u32,
|
||||
/// Reserved protocols. Peers with <key> protocol get additional <value> connection slots.
|
||||
pub reserved_protocols: HashMap<ProtocolId, u32>,
|
||||
/// List of reserved node addresses.
|
||||
pub reserved_nodes: Vec<String>,
|
||||
/// The non-reserved peer mode.
|
||||
pub non_reserved_mode: NonReservedPeerMode,
|
||||
/// IP filter
|
||||
pub ip_filter: IpFilter,
|
||||
/// Client identifier
|
||||
pub client_version: String,
|
||||
}
|
||||
|
||||
impl Default for NetworkConfiguration {
|
||||
fn default() -> Self {
|
||||
NetworkConfiguration::new()
|
||||
}
|
||||
fn default() -> Self {
|
||||
NetworkConfiguration::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl NetworkConfiguration {
|
||||
/// Create a new instance of default settings.
|
||||
pub fn new() -> Self {
|
||||
NetworkConfiguration {
|
||||
config_path: None,
|
||||
net_config_path: None,
|
||||
listen_address: None,
|
||||
public_address: None,
|
||||
udp_port: None,
|
||||
nat_enabled: true,
|
||||
discovery_enabled: true,
|
||||
boot_nodes: Vec::new(),
|
||||
use_secret: None,
|
||||
min_peers: 25,
|
||||
max_peers: 50,
|
||||
max_handshakes: 64,
|
||||
reserved_protocols: HashMap::new(),
|
||||
ip_filter: IpFilter::default(),
|
||||
reserved_nodes: Vec::new(),
|
||||
non_reserved_mode: NonReservedPeerMode::Accept,
|
||||
client_version: "Parity-network".into(),
|
||||
}
|
||||
}
|
||||
/// Create a new instance of default settings.
|
||||
pub fn new() -> Self {
|
||||
NetworkConfiguration {
|
||||
config_path: None,
|
||||
net_config_path: None,
|
||||
listen_address: None,
|
||||
public_address: None,
|
||||
udp_port: None,
|
||||
nat_enabled: true,
|
||||
discovery_enabled: true,
|
||||
boot_nodes: Vec::new(),
|
||||
use_secret: None,
|
||||
min_peers: 25,
|
||||
max_peers: 50,
|
||||
max_handshakes: 64,
|
||||
reserved_protocols: HashMap::new(),
|
||||
ip_filter: IpFilter::default(),
|
||||
reserved_nodes: Vec::new(),
|
||||
non_reserved_mode: NonReservedPeerMode::Accept,
|
||||
client_version: "Parity-network".into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create new default configuration with specified listen port.
|
||||
pub fn new_with_port(port: u16) -> NetworkConfiguration {
|
||||
let mut config = NetworkConfiguration::new();
|
||||
config.listen_address = Some(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), port)));
|
||||
config
|
||||
}
|
||||
/// Create new default configuration with specified listen port.
|
||||
pub fn new_with_port(port: u16) -> NetworkConfiguration {
|
||||
let mut config = NetworkConfiguration::new();
|
||||
config.listen_address = Some(SocketAddr::V4(SocketAddrV4::new(
|
||||
Ipv4Addr::new(0, 0, 0, 0),
|
||||
port,
|
||||
)));
|
||||
config
|
||||
}
|
||||
|
||||
/// Create new default configuration for localhost-only connection with random port (usefull for testing)
|
||||
pub fn new_local() -> NetworkConfiguration {
|
||||
let mut config = NetworkConfiguration::new();
|
||||
config.listen_address = Some(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 0)));
|
||||
config.nat_enabled = false;
|
||||
config
|
||||
}
|
||||
/// Create new default configuration for localhost-only connection with random port (usefull for testing)
|
||||
pub fn new_local() -> NetworkConfiguration {
|
||||
let mut config = NetworkConfiguration::new();
|
||||
config.listen_address = Some(SocketAddr::V4(SocketAddrV4::new(
|
||||
Ipv4Addr::new(127, 0, 0, 1),
|
||||
0,
|
||||
)));
|
||||
config.nat_enabled = false;
|
||||
config
|
||||
}
|
||||
}
|
||||
|
||||
/// IO access point. This is passed to all IO handlers and provides an interface to the IO subsystem.
|
||||
pub trait NetworkContext {
|
||||
/// Send a packet over the network to another peer.
|
||||
fn send(&self, peer: PeerId, packet_id: PacketId, data: Vec<u8>) -> Result<(), Error>;
|
||||
/// Send a packet over the network to another peer.
|
||||
fn send(&self, peer: PeerId, packet_id: PacketId, data: Vec<u8>) -> Result<(), Error>;
|
||||
|
||||
/// Send a packet over the network to another peer using specified protocol.
|
||||
fn send_protocol(&self, protocol: ProtocolId, peer: PeerId, packet_id: PacketId, data: Vec<u8>) -> Result<(), Error>;
|
||||
/// Send a packet over the network to another peer using specified protocol.
|
||||
fn send_protocol(
|
||||
&self,
|
||||
protocol: ProtocolId,
|
||||
peer: PeerId,
|
||||
packet_id: PacketId,
|
||||
data: Vec<u8>,
|
||||
) -> Result<(), Error>;
|
||||
|
||||
/// Respond to a current network message. Panics if no there is no packet in the context. If the session is expired returns nothing.
|
||||
fn respond(&self, packet_id: PacketId, data: Vec<u8>) -> Result<(), Error>;
|
||||
/// Respond to a current network message. Panics if no there is no packet in the context. If the session is expired returns nothing.
|
||||
fn respond(&self, packet_id: PacketId, data: Vec<u8>) -> Result<(), Error>;
|
||||
|
||||
/// Disconnect a peer and prevent it from connecting again.
|
||||
fn disable_peer(&self, peer: PeerId);
|
||||
/// Disconnect a peer and prevent it from connecting again.
|
||||
fn disable_peer(&self, peer: PeerId);
|
||||
|
||||
/// Disconnect peer. Reconnect can be attempted later.
|
||||
fn disconnect_peer(&self, peer: PeerId);
|
||||
/// Disconnect peer. Reconnect can be attempted later.
|
||||
fn disconnect_peer(&self, peer: PeerId);
|
||||
|
||||
/// Check if the session is still active.
|
||||
fn is_expired(&self) -> bool;
|
||||
/// Check if the session is still active.
|
||||
fn is_expired(&self) -> bool;
|
||||
|
||||
/// Register a new IO timer. 'IoHandler::timeout' will be called with the token.
|
||||
fn register_timer(&self, token: TimerToken, delay: Duration) -> Result<(), Error>;
|
||||
/// Register a new IO timer. 'IoHandler::timeout' will be called with the token.
|
||||
fn register_timer(&self, token: TimerToken, delay: Duration) -> Result<(), Error>;
|
||||
|
||||
/// Returns peer identification string
|
||||
fn peer_client_version(&self, peer: PeerId) -> ClientVersion;
|
||||
/// Returns peer identification string
|
||||
fn peer_client_version(&self, peer: PeerId) -> ClientVersion;
|
||||
|
||||
/// Returns information on p2p session
|
||||
fn session_info(&self, peer: PeerId) -> Option<SessionInfo>;
|
||||
/// Returns information on p2p session
|
||||
fn session_info(&self, peer: PeerId) -> Option<SessionInfo>;
|
||||
|
||||
/// Returns max version for a given protocol.
|
||||
fn protocol_version(&self, protocol: ProtocolId, peer: PeerId) -> Option<u8>;
|
||||
/// Returns max version for a given protocol.
|
||||
fn protocol_version(&self, protocol: ProtocolId, peer: PeerId) -> Option<u8>;
|
||||
|
||||
/// Returns this object's subprotocol name.
|
||||
fn subprotocol_name(&self) -> ProtocolId;
|
||||
/// Returns this object's subprotocol name.
|
||||
fn subprotocol_name(&self) -> ProtocolId;
|
||||
|
||||
/// Returns whether the given peer ID is a reserved peer.
|
||||
fn is_reserved_peer(&self, peer: PeerId) -> bool;
|
||||
/// Returns whether the given peer ID is a reserved peer.
|
||||
fn is_reserved_peer(&self, peer: PeerId) -> bool;
|
||||
|
||||
/// Returns the size the payload shouldn't exceed
|
||||
fn payload_soft_limit(&self) -> usize;
|
||||
/// Returns the size the payload shouldn't exceed
|
||||
fn payload_soft_limit(&self) -> usize;
|
||||
}
|
||||
|
||||
impl<'a, T> NetworkContext for &'a T where T: ?Sized + NetworkContext {
|
||||
fn send(&self, peer: PeerId, packet_id: PacketId, data: Vec<u8>) -> Result<(), Error> {
|
||||
(**self).send(peer, packet_id, data)
|
||||
}
|
||||
impl<'a, T> NetworkContext for &'a T
|
||||
where
|
||||
T: ?Sized + NetworkContext,
|
||||
{
|
||||
fn send(&self, peer: PeerId, packet_id: PacketId, data: Vec<u8>) -> Result<(), Error> {
|
||||
(**self).send(peer, packet_id, data)
|
||||
}
|
||||
|
||||
fn send_protocol(&self, protocol: ProtocolId, peer: PeerId, packet_id: PacketId, data: Vec<u8>) -> Result<(), Error> {
|
||||
(**self).send_protocol(protocol, peer, packet_id, data)
|
||||
}
|
||||
fn send_protocol(
|
||||
&self,
|
||||
protocol: ProtocolId,
|
||||
peer: PeerId,
|
||||
packet_id: PacketId,
|
||||
data: Vec<u8>,
|
||||
) -> Result<(), Error> {
|
||||
(**self).send_protocol(protocol, peer, packet_id, data)
|
||||
}
|
||||
|
||||
fn respond(&self, packet_id: PacketId, data: Vec<u8>) -> Result<(), Error> {
|
||||
(**self).respond(packet_id, data)
|
||||
}
|
||||
fn respond(&self, packet_id: PacketId, data: Vec<u8>) -> Result<(), Error> {
|
||||
(**self).respond(packet_id, data)
|
||||
}
|
||||
|
||||
fn disable_peer(&self, peer: PeerId) {
|
||||
(**self).disable_peer(peer)
|
||||
}
|
||||
fn disable_peer(&self, peer: PeerId) {
|
||||
(**self).disable_peer(peer)
|
||||
}
|
||||
|
||||
fn disconnect_peer(&self, peer: PeerId) {
|
||||
(**self).disconnect_peer(peer)
|
||||
}
|
||||
fn disconnect_peer(&self, peer: PeerId) {
|
||||
(**self).disconnect_peer(peer)
|
||||
}
|
||||
|
||||
fn is_expired(&self) -> bool {
|
||||
(**self).is_expired()
|
||||
}
|
||||
fn is_expired(&self) -> bool {
|
||||
(**self).is_expired()
|
||||
}
|
||||
|
||||
fn register_timer(&self, token: TimerToken, delay: Duration) -> Result<(), Error> {
|
||||
(**self).register_timer(token, delay)
|
||||
}
|
||||
fn register_timer(&self, token: TimerToken, delay: Duration) -> Result<(), Error> {
|
||||
(**self).register_timer(token, delay)
|
||||
}
|
||||
|
||||
fn peer_client_version(&self, peer: PeerId) -> ClientVersion {
|
||||
(**self).peer_client_version(peer)
|
||||
}
|
||||
fn peer_client_version(&self, peer: PeerId) -> ClientVersion {
|
||||
(**self).peer_client_version(peer)
|
||||
}
|
||||
|
||||
fn session_info(&self, peer: PeerId) -> Option<SessionInfo> {
|
||||
(**self).session_info(peer)
|
||||
}
|
||||
fn session_info(&self, peer: PeerId) -> Option<SessionInfo> {
|
||||
(**self).session_info(peer)
|
||||
}
|
||||
|
||||
fn protocol_version(&self, protocol: ProtocolId, peer: PeerId) -> Option<u8> {
|
||||
(**self).protocol_version(protocol, peer)
|
||||
}
|
||||
fn protocol_version(&self, protocol: ProtocolId, peer: PeerId) -> Option<u8> {
|
||||
(**self).protocol_version(protocol, peer)
|
||||
}
|
||||
|
||||
fn subprotocol_name(&self) -> ProtocolId {
|
||||
(**self).subprotocol_name()
|
||||
}
|
||||
fn subprotocol_name(&self) -> ProtocolId {
|
||||
(**self).subprotocol_name()
|
||||
}
|
||||
|
||||
fn is_reserved_peer(&self, peer: PeerId) -> bool {
|
||||
(**self).is_reserved_peer(peer)
|
||||
}
|
||||
fn is_reserved_peer(&self, peer: PeerId) -> bool {
|
||||
(**self).is_reserved_peer(peer)
|
||||
}
|
||||
|
||||
fn payload_soft_limit(&self) -> usize {
|
||||
(**self).payload_soft_limit()
|
||||
}
|
||||
fn payload_soft_limit(&self) -> usize {
|
||||
(**self).payload_soft_limit()
|
||||
}
|
||||
}
|
||||
|
||||
/// Network IO protocol handler. This needs to be implemented for each new subprotocol.
|
||||
/// All the handler function are called from within IO event loop.
|
||||
/// `Message` is the type for message data.
|
||||
pub trait NetworkProtocolHandler: Sync + Send {
|
||||
/// Initialize the handler
|
||||
fn initialize(&self, _io: &NetworkContext) {}
|
||||
/// Called when new network packet received.
|
||||
fn read(&self, io: &NetworkContext, peer: &PeerId, packet_id: u8, data: &[u8]);
|
||||
/// Called when new peer is connected. Only called when peer supports the same protocol.
|
||||
fn connected(&self, io: &NetworkContext, peer: &PeerId);
|
||||
/// Called when a previously connected peer disconnects.
|
||||
fn disconnected(&self, io: &NetworkContext, peer: &PeerId);
|
||||
/// Timer function called after a timeout created with `NetworkContext::timeout`.
|
||||
fn timeout(&self, _io: &NetworkContext, _timer: TimerToken) {}
|
||||
/// Initialize the handler
|
||||
fn initialize(&self, _io: &NetworkContext) {}
|
||||
/// Called when new network packet received.
|
||||
fn read(&self, io: &NetworkContext, peer: &PeerId, packet_id: u8, data: &[u8]);
|
||||
/// Called when new peer is connected. Only called when peer supports the same protocol.
|
||||
fn connected(&self, io: &NetworkContext, peer: &PeerId);
|
||||
/// Called when a previously connected peer disconnects.
|
||||
fn disconnected(&self, io: &NetworkContext, peer: &PeerId);
|
||||
/// Timer function called after a timeout created with `NetworkContext::timeout`.
|
||||
fn timeout(&self, _io: &NetworkContext, _timer: TimerToken) {}
|
||||
}
|
||||
|
||||
/// Non-reserved peer modes.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum NonReservedPeerMode {
|
||||
/// Accept them. This is the default.
|
||||
Accept,
|
||||
/// Deny them.
|
||||
Deny,
|
||||
/// Accept them. This is the default.
|
||||
Accept,
|
||||
/// Deny them.
|
||||
Deny,
|
||||
}
|
||||
|
||||
impl NonReservedPeerMode {
|
||||
/// Attempt to parse the peer mode from a string.
|
||||
pub fn parse(s: &str) -> Option<Self> {
|
||||
match s {
|
||||
"accept" => Some(NonReservedPeerMode::Accept),
|
||||
"deny" => Some(NonReservedPeerMode::Deny),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
/// Attempt to parse the peer mode from a string.
|
||||
pub fn parse(s: &str) -> Option<Self> {
|
||||
match s {
|
||||
"accept" => Some(NonReservedPeerMode::Accept),
|
||||
"deny" => Some(NonReservedPeerMode::Deny),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
@@ -423,7 +453,9 @@ impl IpFilter {
|
||||
"none" => filter.predefined = AllowIP::None,
|
||||
custom => {
|
||||
if custom.starts_with("-") {
|
||||
filter.custom_block.push(IpNetwork::from_str(&custom.to_owned().split_off(1))?)
|
||||
filter
|
||||
.custom_block
|
||||
.push(IpNetwork::from_str(&custom.to_owned().split_off(1))?)
|
||||
} else {
|
||||
filter.custom_allow.push(IpNetwork::from_str(custom)?)
|
||||
}
|
||||
@@ -437,12 +469,12 @@ impl IpFilter {
|
||||
/// IP fiter
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum AllowIP {
|
||||
/// Connect to any address
|
||||
All,
|
||||
/// Connect to private network only
|
||||
Private,
|
||||
/// Connect to public network only
|
||||
Public,
|
||||
/// Connect to any address
|
||||
All,
|
||||
/// Connect to private network only
|
||||
Private,
|
||||
/// Connect to public network only
|
||||
Public,
|
||||
/// Block all addresses
|
||||
None,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user