diff --git a/.travis.yml b/.travis.yml index 166cab99..326350fd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,7 @@ before_install: - if [ "${TRAVIS_OS_NAME}" == "linux" ]; then sudo sh -c 'echo 0 > /proc/sys/net/ipv6/conf/all/disable_ipv6'; fi + - rustup component add rustfmt-preview cache: cargo @@ -19,6 +20,6 @@ matrix: - rust: stable script: + - cargo fmt -- --write-mode=checkstyle - cargo check --all - cargo test --all - diff --git a/circular-buffer/src/lib.rs b/circular-buffer/src/lib.rs index e8bb855c..fe171460 100644 --- a/circular-buffer/src/lib.rs +++ b/circular-buffer/src/lib.rs @@ -221,9 +221,8 @@ impl CircularBuffer { /// when the slice goes out of scope), if you're using non-`Drop` types you can use /// `pop_slice_leaky`. pub fn pop_slice(&mut self) -> Option> { - self.pop_slice_leaky().map( - |x| unsafe { OwnedSlice::new(x) }, - ) + self.pop_slice_leaky() + .map(|x| unsafe { OwnedSlice::new(x) }) } /// Pop a slice containing the maximum possible contiguous number of elements. Since this buffer @@ -435,9 +434,9 @@ impl CircularBuffer { /// Get a borrow to an element at an index unsafely (behaviour is undefined if the index is out /// of bounds). pub unsafe fn get_unchecked(&self, index: usize) -> &B::Item { - &*self.buffer.ptr().offset( - ((index + self.start) % B::size()) as isize, - ) + &*self.buffer + .ptr() + .offset(((index + self.start) % B::size()) as isize) } /// Get a mutable borrow to an element at an index safely (if the index is out of bounds, return @@ -453,16 +452,15 @@ impl CircularBuffer { /// Get a mutable borrow to an element at an index unsafely (behaviour is undefined if the index /// is out of bounds). pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> &mut B::Item { - &mut *self.buffer.ptr_mut().offset( - ((index + self.start) % B::size()) as - isize, - ) + &mut *self.buffer + .ptr_mut() + .offset(((index + self.start) % B::size()) as isize) } /// Removes the first `by` elements of the start of the buffer. - /// + /// /// # Panic - /// + /// /// Panics if `by` is superior to the number of elements in the buffer. // This is not unsafe because it can only leak data, not cause uninit to be read. pub fn advance(&mut self, by: usize) { @@ -482,8 +480,7 @@ impl std::ops::Index for CircularBuffer { } else { panic!( "index out of bounds: the len is {} but the index is {}", - self.len, - index + self.len, index ); } } @@ -499,8 +496,7 @@ impl std::ops::IndexMut for CircularBuffer { } else { panic!( "index out of bounds: the len is {} but the index is {}", - len, - index + len, index ); } } @@ -624,7 +620,9 @@ where /// ```rust /// use circular_buffer::CircularBuffer; /// - /// let result = CircularBuffer::<[usize; 5]>::from_slice_prefix(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 20]); + /// let result = CircularBuffer::<[usize; 5]>::from_slice_prefix( + /// &[1, 2, 3, 4, 5, 6, 7, 8, 9, 20] + /// ); /// assert_eq!(result, (CircularBuffer::from_array([1, 2, 3, 4, 5]), 5)); /// ``` pub fn from_slice_prefix(slice: &[B::Item]) -> (Self, usize) { diff --git a/datastore/src/json_file.rs b/datastore/src/json_file.rs index 34231d05..ce7c44d8 100644 --- a/datastore/src/json_file.rs +++ b/datastore/src/json_file.rs @@ -23,11 +23,11 @@ use Datastore; use chashmap::{CHashMap, WriteGuard}; use futures::Future; -use futures::stream::{Stream, iter_ok}; -use query::{Query, naive_apply_query}; +use futures::stream::{iter_ok, Stream}; +use query::{naive_apply_query, Query}; use serde::Serialize; use serde::de::DeserializeOwned; -use serde_json::{Map, from_value, to_value, from_reader, to_writer}; +use serde_json::{from_reader, from_value, to_value, to_writer, Map}; use serde_json::value::Value; use std::borrow::Cow; use std::fs; @@ -41,268 +41,291 @@ use tempfile::NamedTempFile; /// Implementation of `Datastore` that uses a single plain JSON file. pub struct JsonFileDatastore - where T: Serialize + DeserializeOwned + Clone +where + T: Serialize + DeserializeOwned + Clone, { - path: PathBuf, - content: CHashMap, + path: PathBuf, + content: CHashMap, } impl JsonFileDatastore - where T: Serialize + DeserializeOwned + Clone +where + T: Serialize + DeserializeOwned + Clone, { - /// Opens or creates the datastore. If the path refers to an existing path, then this function - /// will attempt to load an existing set of values from it (which can result in an error). - /// Otherwise if the path doesn't exist, a new empty datastore will be created. - pub fn new

(path: P) -> Result, IoError> - where P: Into - { - let path = path.into(); + /// Opens or creates the datastore. If the path refers to an existing path, then this function + /// will attempt to load an existing set of values from it (which can result in an error). + /// Otherwise if the path doesn't exist, a new empty datastore will be created. + pub fn new

(path: P) -> Result, IoError> + where + P: Into, + { + let path = path.into(); - if !path.exists() { - return Ok(JsonFileDatastore { - path: path, - content: CHashMap::new(), - }); - } + if !path.exists() { + return Ok(JsonFileDatastore { + path: path, + content: CHashMap::new(), + }); + } - let content = { - let mut file = fs::File::open(&path)?; + let content = { + let mut file = fs::File::open(&path)?; - // We want to support empty files (and treat them as an empty recordset). Unfortunately - // `serde_json` will always produce an error if we do this ("unexpected EOF at line 0 - // column 0"). Therefore we start by reading one byte from the file in order to check - // for EOF. + // We want to support empty files (and treat them as an empty recordset). Unfortunately + // `serde_json` will always produce an error if we do this ("unexpected EOF at line 0 + // column 0"). Therefore we start by reading one byte from the file in order to check + // for EOF. - let mut first_byte = [0]; - if file.read(&mut first_byte)? == 0 { - // File is empty. - CHashMap::new() - } else { - match from_reader::<_, Value>(Cursor::new(first_byte).chain(file)) { - Ok(Value::Null) => CHashMap::new(), - Ok(Value::Object(map)) => { - let mut out = CHashMap::with_capacity(map.len()); - for (key, value) in map.into_iter() { - let value = match from_value(value) { - Ok(v) => v, - Err(err) => return Err(IoError::new(IoErrorKind::InvalidData, err)), - }; - out.insert(key, value); - } - out - } - Ok(_) => { - return Err(IoError::new(IoErrorKind::InvalidData, "expected JSON object")); - } - Err(err) => { - return Err(IoError::new(IoErrorKind::InvalidData, err)); - } - } - } - }; + let mut first_byte = [0]; + if file.read(&mut first_byte)? == 0 { + // File is empty. + CHashMap::new() + } else { + match from_reader::<_, Value>(Cursor::new(first_byte).chain(file)) { + Ok(Value::Null) => CHashMap::new(), + Ok(Value::Object(map)) => { + let mut out = CHashMap::with_capacity(map.len()); + for (key, value) in map.into_iter() { + let value = match from_value(value) { + Ok(v) => v, + Err(err) => return Err(IoError::new(IoErrorKind::InvalidData, err)), + }; + out.insert(key, value); + } + out + } + Ok(_) => { + return Err(IoError::new( + IoErrorKind::InvalidData, + "expected JSON object", + )); + } + Err(err) => { + return Err(IoError::new(IoErrorKind::InvalidData, err)); + } + } + } + }; - Ok(JsonFileDatastore { path: path, content: content }) - } + Ok(JsonFileDatastore { + path: path, + content: content, + }) + } - /// Flushes the content of the datastore to the disk. - /// - /// This function can only fail in case of a disk access error. If an error occurs, any change - /// to the datastore that was performed since the last successful flush will be lost. No data - /// will be corrupted. - pub fn flush(&self) -> Result<(), IoError> - where T: Clone - { - // Create a temporary file in the same directory as the destination, which avoids the - // problem of having a file cleaner delete our file while we use it. - let self_path_parent = self.path - .parent() - .ok_or(IoError::new( - IoErrorKind::Other, - "couldn't get parent directory of destination", - ))?; - let mut temporary_file = NamedTempFile::new_in(self_path_parent)?; + /// Flushes the content of the datastore to the disk. + /// + /// This function can only fail in case of a disk access error. If an error occurs, any change + /// to the datastore that was performed since the last successful flush will be lost. No data + /// will be corrupted. + pub fn flush(&self) -> Result<(), IoError> + where + T: Clone, + { + // Create a temporary file in the same directory as the destination, which avoids the + // problem of having a file cleaner delete our file while we use it. + let self_path_parent = self.path.parent().ok_or(IoError::new( + IoErrorKind::Other, + "couldn't get parent directory of destination", + ))?; + let mut temporary_file = NamedTempFile::new_in(self_path_parent)?; - let content = self.content.clone().into_iter(); - to_writer( - &mut temporary_file, - &content.map(|(k, v)| (k, to_value(v).unwrap())).collect::>(), - )?; - temporary_file.sync_data()?; + let content = self.content.clone().into_iter(); + to_writer( + &mut temporary_file, + &content + .map(|(k, v)| (k, to_value(v).unwrap())) + .collect::>(), + )?; + temporary_file.sync_data()?; - // Note that `persist` will fail if we try to persist across filesystems. However that - // shouldn't happen since we created the temporary file in the same directory as the final - // path. - temporary_file.persist(&self.path)?; - Ok(()) - } + // Note that `persist` will fail if we try to persist across filesystems. However that + // shouldn't happen since we created the temporary file in the same directory as the final + // path. + temporary_file.persist(&self.path)?; + Ok(()) + } } impl<'a, T> Datastore for &'a JsonFileDatastore - where T: Clone + Serialize + DeserializeOwned + Default + PartialOrd + 'static +where + T: Clone + Serialize + DeserializeOwned + Default + PartialOrd + 'static, { - type Entry = JsonFileDatastoreEntry<'a, T>; - type QueryResult = Box + 'a>; + type Entry = JsonFileDatastoreEntry<'a, T>; + type QueryResult = Box + 'a>; - #[inline] - fn lock(self, key: Cow) -> Option { - self.content.get_mut(&key.into_owned()).map(JsonFileDatastoreEntry) - } + #[inline] + fn lock(self, key: Cow) -> Option { + self.content + .get_mut(&key.into_owned()) + .map(JsonFileDatastoreEntry) + } - #[inline] - fn lock_or_create(self, key: Cow) -> Self::Entry { - loop { - self.content.upsert(key.clone().into_owned(), || Default::default(), |_| {}); + #[inline] + fn lock_or_create(self, key: Cow) -> Self::Entry { + loop { + self.content + .upsert(key.clone().into_owned(), || Default::default(), |_| {}); - // There is a slight possibility that another thread will delete our value in this - // small interval. If this happens, we just loop and reinsert the value again until - // we can acquire a lock. - if let Some(v) = self.content.get_mut(&key.clone().into_owned()) { - return JsonFileDatastoreEntry(v); - } - } - } + // There is a slight possibility that another thread will delete our value in this + // small interval. If this happens, we just loop and reinsert the value again until + // we can acquire a lock. + if let Some(v) = self.content.get_mut(&key.clone().into_owned()) { + return JsonFileDatastoreEntry(v); + } + } + } - #[inline] - fn put(self, key: Cow, value: T) { - self.content.insert(key.into_owned(), value); - } + #[inline] + fn put(self, key: Cow, value: T) { + self.content.insert(key.into_owned(), value); + } - #[inline] - fn get(self, key: &str) -> Option { - self.content.get(&key.to_owned()).map(|v| v.clone()) - } + #[inline] + fn get(self, key: &str) -> Option { + self.content.get(&key.to_owned()).map(|v| v.clone()) + } - #[inline] - fn has(self, key: &str) -> bool { - self.content.contains_key(&key.to_owned()) - } + #[inline] + fn has(self, key: &str) -> bool { + self.content.contains_key(&key.to_owned()) + } - #[inline] - fn delete(self, key: &str) -> Option { - self.content.remove(&key.to_owned()) - } + #[inline] + fn delete(self, key: &str) -> Option { + self.content.remove(&key.to_owned()) + } - fn query(self, query: Query) -> Self::QueryResult { - let content = self.content.clone(); + fn query(self, query: Query) -> Self::QueryResult { + let content = self.content.clone(); - let keys_only = query.keys_only; + let keys_only = query.keys_only; - let content_stream = iter_ok(content.into_iter().filter_map(|(key, value)| { - // Skip values that are malformed. - let value = if keys_only { Default::default() } else { value }; - Some((key, value)) - })); + let content_stream = iter_ok(content.into_iter().filter_map(|(key, value)| { + // Skip values that are malformed. + let value = if keys_only { Default::default() } else { value }; + Some((key, value)) + })); - // `content_stream` reads from the content of the `Mutex`, so we need to clone the data - // into a `Vec` before returning. - let collected = naive_apply_query(content_stream, query).collect().wait().expect( - "can only fail if either `naive_apply_query` or `content_stream` produce \ - an error, which cann't happen", - ); - let output_stream = iter_ok(collected.into_iter()); - Box::new(output_stream) as Box<_> - } + // `content_stream` reads from the content of the `Mutex`, so we need to clone the data + // into a `Vec` before returning. + let collected = naive_apply_query(content_stream, query) + .collect() + .wait() + .expect( + "can only fail if either `naive_apply_query` or `content_stream` produce \ + an error, which cann't happen", + ); + let output_stream = iter_ok(collected.into_iter()); + Box::new(output_stream) as Box<_> + } } impl Drop for JsonFileDatastore - where T: Serialize + DeserializeOwned + Clone +where + T: Serialize + DeserializeOwned + Clone, { - #[inline] - fn drop(&mut self) { - // Unfortunately there's not much we can do here in case of an error, as panicking would be - // very bad. Similar to `File`, the user should take care to call `flush()` before dropping - // the datastore. - // - // If an error happens here, any change since the last successful flush will be lost, but - // the data will not be corrupted. - let _ = self.flush(); - } + #[inline] + fn drop(&mut self) { + // Unfortunately there's not much we can do here in case of an error, as panicking would be + // very bad. Similar to `File`, the user should take care to call `flush()` before dropping + // the datastore. + // + // If an error happens here, any change since the last successful flush will be lost, but + // the data will not be corrupted. + let _ = self.flush(); + } } /// Implementation of `Datastore` that uses a single plain JSON file. -pub struct JsonFileDatastoreEntry<'a, T>(WriteGuard<'a, String, T>) where T: 'a; +pub struct JsonFileDatastoreEntry<'a, T>(WriteGuard<'a, String, T>) +where + T: 'a; impl<'a, T> Deref for JsonFileDatastoreEntry<'a, T> - where T: 'a +where + T: 'a, { - type Target = T; + type Target = T; - fn deref(&self) -> &T { - &*self.0 - } + fn deref(&self) -> &T { + &*self.0 + } } impl<'a, T> DerefMut for JsonFileDatastoreEntry<'a, T> - where T: 'a +where + T: 'a, { - fn deref_mut(&mut self) -> &mut T { - &mut *self.0 - } + fn deref_mut(&mut self) -> &mut T { + &mut *self.0 + } } #[cfg(test)] mod tests { - use {Query, Order, Filter, FilterTy, FilterOp}; - use Datastore; - use JsonFileDatastore; - use futures::{Future, Stream}; - use tempfile::NamedTempFile; + use {Filter, FilterOp, FilterTy, Order, Query}; + use Datastore; + use JsonFileDatastore; + use futures::{Future, Stream}; + use tempfile::NamedTempFile; - #[test] - fn open_and_flush() { - let temp_file = NamedTempFile::new().unwrap(); - let datastore = JsonFileDatastore::>::new(temp_file.path()).unwrap(); - datastore.flush().unwrap(); - } + #[test] + fn open_and_flush() { + let temp_file = NamedTempFile::new().unwrap(); + let datastore = JsonFileDatastore::>::new(temp_file.path()).unwrap(); + datastore.flush().unwrap(); + } - #[test] - fn values_store_and_reload() { - let temp_file = NamedTempFile::new().unwrap(); + #[test] + fn values_store_and_reload() { + let temp_file = NamedTempFile::new().unwrap(); - let datastore = JsonFileDatastore::>::new(temp_file.path()).unwrap(); - datastore.put("foo".into(), vec![1, 2, 3]); - datastore.put("bar".into(), vec![0, 255, 127]); - datastore.flush().unwrap(); - drop(datastore); + let datastore = JsonFileDatastore::>::new(temp_file.path()).unwrap(); + datastore.put("foo".into(), vec![1, 2, 3]); + datastore.put("bar".into(), vec![0, 255, 127]); + datastore.flush().unwrap(); + drop(datastore); - let reload = JsonFileDatastore::>::new(temp_file.path()).unwrap(); - assert_eq!(reload.get("bar").unwrap(), &[0, 255, 127]); - assert_eq!(reload.get("foo").unwrap(), &[1, 2, 3]); - } + let reload = JsonFileDatastore::>::new(temp_file.path()).unwrap(); + assert_eq!(reload.get("bar").unwrap(), &[0, 255, 127]); + assert_eq!(reload.get("foo").unwrap(), &[1, 2, 3]); + } - #[test] - fn query_basic() { - let temp_file = NamedTempFile::new().unwrap(); + #[test] + fn query_basic() { + let temp_file = NamedTempFile::new().unwrap(); - let datastore = JsonFileDatastore::>::new(temp_file.path()).unwrap(); - datastore.put("foo1".into(), vec![6, 7, 8]); - datastore.put("foo2".into(), vec![6, 7, 8]); - datastore.put("foo3".into(), vec![7, 8, 9]); - datastore.put("foo4".into(), vec![10, 11, 12]); - datastore.put("foo5".into(), vec![13, 14, 15]); - datastore.put("bar1".into(), vec![0, 255, 127]); - datastore.flush().unwrap(); + let datastore = JsonFileDatastore::>::new(temp_file.path()).unwrap(); + datastore.put("foo1".into(), vec![6, 7, 8]); + datastore.put("foo2".into(), vec![6, 7, 8]); + datastore.put("foo3".into(), vec![7, 8, 9]); + datastore.put("foo4".into(), vec![10, 11, 12]); + datastore.put("foo5".into(), vec![13, 14, 15]); + datastore.put("bar1".into(), vec![0, 255, 127]); + datastore.flush().unwrap(); - let query = datastore.query(Query { - prefix: "fo".into(), - filters: vec![ - Filter { - ty: FilterTy::ValueCompare(&vec![6, 7, 8].into()), - operation: FilterOp::NotEqual, - }, - ], - orders: vec![Order::ByKeyDesc], - skip: 1, - limit: u64::max_value(), - keys_only: false, - }) - .collect() - .wait() - .unwrap(); + let query = datastore + .query(Query { + prefix: "fo".into(), + filters: vec![ + Filter { + ty: FilterTy::ValueCompare(&vec![6, 7, 8].into()), + operation: FilterOp::NotEqual, + }, + ], + orders: vec![Order::ByKeyDesc], + skip: 1, + limit: u64::max_value(), + keys_only: false, + }) + .collect() + .wait() + .unwrap(); - assert_eq!(query[0].0, "foo4"); - assert_eq!(query[0].1, &[10, 11, 12]); - assert_eq!(query[1].0, "foo3"); - assert_eq!(query[1].1, &[7, 8, 9]); - } + assert_eq!(query[0].0, "foo4"); + assert_eq!(query[0].1, &[10, 11, 12]); + assert_eq!(query[1].0, "foo3"); + assert_eq!(query[1].1, &[7, 8, 9]); + } } diff --git a/datastore/src/lib.rs b/datastore/src/lib.rs index f7bbe00e..56b61a2d 100644 --- a/datastore/src/lib.rs +++ b/datastore/src/lib.rs @@ -23,78 +23,78 @@ //! General-purpose key-value storage. //! The keys are strings, and the values are of any type you want. -//! +//! //! > **Note**: This crate is meant to be a utility for the implementation of other crates ; it -//! > does not directly participate in the stack of libp2p. -//! +//! > does not directly participate in the stack of libp2p. +//! //! This crate provides the `Datastore` trait, whose template parameter is the type of the value. //! It is implemented on types that represent a key-value storage. //! The only available implementation for now is `JsonFileDatastore`. -//! +//! //! # JSON file datastore -//! +//! //! The `JsonFileDatastore` can provide a key-value storage that loads and stores data in a single //! JSON file. It is only available if the value implements the `Serialize`, `DeserializeOwned` //! and `Clone` traits. -//! +//! //! The `JsonFileDatastore::new` method will attempt to load existing data from the path you pass //! as parameter. This path is also where the data will be stored. The content of the store is //! flushed on drop or if you call `flush()`. -//! +//! //! ```no_run //! use datastore::Datastore; //! use datastore::JsonFileDatastore; -//! +//! //! let datastore = JsonFileDatastore::>::new("/tmp/test.json").unwrap(); //! datastore.put("foo".into(), vec![1, 2, 3]); //! datastore.put("bar".into(), vec![0, 255, 127]); //! assert_eq!(datastore.get("foo").unwrap(), &[1, 2, 3]); -//! datastore.flush().unwrap(); // optional +//! datastore.flush().unwrap(); // optional //! ``` -//! +//! //! # Query -//! +//! //! In addition to simple operations such as `get` or `put`, the `Datastore` trait also provides //! a way to perform queries on the key-value storage, using the `query` method. -//! +//! //! The struct returned by the `query` method implements the `Stream` trait from `futures`, //! meaning that the result is asynchronous. -//! +//! //! > **Note**: For now the API of the `get` and `has` methods makes them potentially blocking //! > operations, though the only available implementation doesn't block. The API of these //! > methods may become asynchronous in the future if deemed necessary. -//! +//! //! ```no_run //! extern crate datastore; //! extern crate futures; -//! +//! //! # fn main() { //! use datastore::{Query, Order, Filter, FilterTy, FilterOp}; //! use datastore::Datastore; //! use datastore::JsonFileDatastore; //! use futures::{Future, Stream}; -//! +//! //! let datastore = JsonFileDatastore::>::new("/tmp/test.json").unwrap(); //! let query = datastore.query(Query { -//! // Only return the keys that start with this prefix. -//! prefix: "fo".into(), -//! // List of filters for the keys and/or values. -//! filters: vec![ -//! Filter { -//! ty: FilterTy::ValueCompare(&vec![6, 7, 8].into()), -//! operation: FilterOp::NotEqual, -//! }, -//! ], -//! // Order in which to sort the results. -//! orders: vec![Order::ByKeyDesc], -//! // Number of entries to skip at the beginning of the results (after sorting). -//! skip: 1, -//! // Limit to the number of entries to return (use `u64::max_value()` for no limit). -//! limit: 12, -//! // If true, don't load the values. For optimization purposes. -//! keys_only: false, +//! // Only return the keys that start with this prefix. +//! prefix: "fo".into(), +//! // List of filters for the keys and/or values. +//! filters: vec![ +//! Filter { +//! ty: FilterTy::ValueCompare(&vec![6, 7, 8].into()), +//! operation: FilterOp::NotEqual, +//! }, +//! ], +//! // Order in which to sort the results. +//! orders: vec![Order::ByKeyDesc], +//! // Number of entries to skip at the beginning of the results (after sorting). +//! skip: 1, +//! // Limit to the number of entries to return (use `u64::max_value()` for no limit). +//! limit: 12, +//! // If true, don't load the values. For optimization purposes. +//! keys_only: false, //! }); -//! +//! //! let results = query.collect().wait().unwrap(); //! println!("{:?}", results); //! # } @@ -117,61 +117,64 @@ mod query; mod json_file; pub use self::json_file::{JsonFileDatastore, JsonFileDatastoreEntry}; -pub use self::query::{Query, Order, Filter, FilterTy, FilterOp}; +pub use self::query::{Filter, FilterOp, FilterTy, Order, Query}; /// Abstraction over any struct that can store `(key, value)` pairs. pub trait Datastore { - /// Locked entry. - type Entry: DerefMut; - /// Output of a query. - type QueryResult: Stream; + /// Locked entry. + type Entry: DerefMut; + /// Output of a query. + type QueryResult: Stream; - /// Sets the value of a key. - #[inline] - fn put(self, key: Cow, value: T) - where Self: Sized - { - *self.lock_or_create(key) = value; - } + /// Sets the value of a key. + #[inline] + fn put(self, key: Cow, value: T) + where + Self: Sized, + { + *self.lock_or_create(key) = value; + } - /// Checks if an entry exists, and if so locks it. - /// - /// Trying to lock a value that is already locked will block, therefore you should keep locks - /// for a duration that is as short as possible. - fn lock(self, key: Cow) -> Option; + /// Checks if an entry exists, and if so locks it. + /// + /// Trying to lock a value that is already locked will block, therefore you should keep locks + /// for a duration that is as short as possible. + fn lock(self, key: Cow) -> Option; - /// Locks an entry if it exists, or creates it otherwise. - /// - /// Same as `put` followed with `lock`, except that it is atomic. - fn lock_or_create(self, key: Cow) -> Self::Entry; + /// Locks an entry if it exists, or creates it otherwise. + /// + /// Same as `put` followed with `lock`, except that it is atomic. + fn lock_or_create(self, key: Cow) -> Self::Entry; - /// Returns the value corresponding to this key by cloning it. - #[inline] - fn get(self, key: &str) -> Option - where Self: Sized, - T: Clone - { - self.lock(key.into()).map(|v| v.clone()) - } + /// Returns the value corresponding to this key by cloning it. + #[inline] + fn get(self, key: &str) -> Option + where + Self: Sized, + T: Clone, + { + self.lock(key.into()).map(|v| v.clone()) + } - /// Returns true if the datastore contains the given key. - /// - /// > **Note**: Keep in mind that using this operation is probably racy. A secondary thread - /// > can delete a key right after you called `has()`. In other words, this function - /// > returns whether an entry with that key existed in the short past. - #[inline] - fn has(self, key: &str) -> bool - where Self: Sized - { - self.lock(key.into()).is_some() - } + /// Returns true if the datastore contains the given key. + /// + /// > **Note**: Keep in mind that using this operation is probably racy. A secondary thread + /// > can delete a key right after you called `has()`. In other words, this function + /// > returns whether an entry with that key existed in the short past. + #[inline] + fn has(self, key: &str) -> bool + where + Self: Sized, + { + self.lock(key.into()).is_some() + } - /// Removes the given key from the datastore. Returns the old value if the key existed. - fn delete(self, key: &str) -> Option; + /// Removes the given key from the datastore. Returns the old value if the key existed. + fn delete(self, key: &str) -> Option; - /// Executes a query on the key-value store. - /// - /// This operation is expensive on some implementations and cheap on others. It is your - /// responsibility to pick the right implementation for the right job. - fn query(self, query: Query) -> Self::QueryResult; + /// Executes a query on the key-value store. + /// + /// This operation is expensive on some implementations and cheap on others. It is your + /// responsibility to pick the right implementation for the right job. + fn query(self, query: Query) -> Self::QueryResult; } diff --git a/datastore/src/query.rs b/datastore/src/query.rs index 68423752..36828bec 100644 --- a/datastore/src/query.rs +++ b/datastore/src/query.rs @@ -18,8 +18,8 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -use futures::{Stream, Future, Async, Poll}; -use futures::stream::{iter_ok, Take as StreamTake, Skip as StreamSkip}; +use futures::{Async, Future, Poll, Stream}; +use futures::stream::{iter_ok, Skip as StreamSkip, Take as StreamTake}; use std::borrow::Cow; use std::cmp::Ordering; use std::io::Error as IoError; @@ -32,289 +32,319 @@ use std::vec::IntoIter as VecIntoIter; /// filters, orders, skip, limit). #[derive(Debug, Clone)] pub struct Query<'a, T: 'a> { - /// Only the keys that start with `prefix` will be returned. - pub prefix: Cow<'a, str>, - /// Filters to apply on the results. - pub filters: Vec>, - /// How to order the keys. Applied sequentially. - pub orders: Vec, - /// Number of elements to skip from at the start of the results. - pub skip: u64, - /// Maximum number of elements in the results. - pub limit: u64, - /// Only return keys. If true, then all the `Vec`s of the data will be empty. - pub keys_only: bool, + /// Only the keys that start with `prefix` will be returned. + pub prefix: Cow<'a, str>, + /// Filters to apply on the results. + pub filters: Vec>, + /// How to order the keys. Applied sequentially. + pub orders: Vec, + /// Number of elements to skip from at the start of the results. + pub skip: u64, + /// Maximum number of elements in the results. + pub limit: u64, + /// Only return keys. If true, then all the `Vec`s of the data will be empty. + pub keys_only: bool, } /// A filter to apply to the results set. #[derive(Debug, Clone)] pub struct Filter<'a, T: 'a> { - /// Type of filter and value to compare with. - pub ty: FilterTy<'a, T>, - /// Comparison operation. - pub operation: FilterOp, + /// Type of filter and value to compare with. + pub ty: FilterTy<'a, T>, + /// Comparison operation. + pub operation: FilterOp, } /// Type of filter and value to compare with. #[derive(Debug, Clone)] pub enum FilterTy<'a, T: 'a> { - /// Compare the key with a reference value. - KeyCompare(Cow<'a, str>), - /// Compare the value with a reference value. - ValueCompare(&'a T), + /// Compare the key with a reference value. + KeyCompare(Cow<'a, str>), + /// Compare the value with a reference value. + ValueCompare(&'a T), } /// Filtering operation. #[derive(Debug, Copy, Clone)] pub enum FilterOp { - Equal, - NotEqual, - Less, - LessOrEqual, - Greater, - GreaterOrEqual, + Equal, + NotEqual, + Less, + LessOrEqual, + Greater, + GreaterOrEqual, } /// Order in which to sort the results of a query. #[derive(Debug, Copy, Clone)] pub enum Order { - /// Put the values in ascending order. - ByValueAsc, - /// Put the values in descending order. - ByValueDesc, - /// Put the keys in ascending order. - ByKeyAsc, - /// Put the keys in descending order. - ByKeyDesc, + /// Put the values in ascending order. + ByValueAsc, + /// Put the values in descending order. + ByValueDesc, + /// Put the keys in ascending order. + ByKeyAsc, + /// Put the keys in descending order. + ByKeyDesc, } /// Naively applies a query on a set of results. -pub fn naive_apply_query<'a, S, V>(stream: S, query: Query<'a, V>) - -> StreamTake, VecIntoIter>>, V>>>> - where S: Stream + 'a, - V: Clone + PartialOrd + Default + 'static +pub fn naive_apply_query<'a, S, V>( + stream: S, + query: Query<'a, V>, +) -> StreamTake< + StreamSkip< + NaiveKeysOnlyApply< + NaiveApplyOrdered< + NaiveFiltersApply<'a, NaivePrefixApply<'a, S>, VecIntoIter>>, + V, + >, + >, + >, +> +where + S: Stream + 'a, + V: Clone + PartialOrd + Default + 'static, { - let prefixed = naive_apply_prefix(stream, query.prefix); - let filtered = naive_apply_filters(prefixed, query.filters.into_iter()); - let ordered = naive_apply_ordered(filtered, query.orders); - let keys_only = naive_apply_keys_only(ordered, query.keys_only); - naive_apply_skip_limit(keys_only, query.skip, query.limit) + let prefixed = naive_apply_prefix(stream, query.prefix); + let filtered = naive_apply_filters(prefixed, query.filters.into_iter()); + let ordered = naive_apply_ordered(filtered, query.orders); + let keys_only = naive_apply_keys_only(ordered, query.keys_only); + naive_apply_skip_limit(keys_only, query.skip, query.limit) } /// Skips the `skip` first element of a stream and only returns `limit` elements. #[inline] pub fn naive_apply_skip_limit(stream: S, skip: u64, limit: u64) -> StreamTake> - where S: Stream +where + S: Stream, { - stream.skip(skip).take(limit) + stream.skip(skip).take(limit) } /// Filters the result of a stream to empty values if `keys_only` is true. #[inline] pub fn naive_apply_keys_only(stream: S, keys_only: bool) -> NaiveKeysOnlyApply - where S: Stream +where + S: Stream, { - NaiveKeysOnlyApply { - keys_only: keys_only, - stream: stream, - } + NaiveKeysOnlyApply { + keys_only: keys_only, + stream: stream, + } } /// Returned by `naive_apply_keys_only`. #[derive(Debug, Clone)] pub struct NaiveKeysOnlyApply { - keys_only: bool, - stream: S, + keys_only: bool, + stream: S, } impl Stream for NaiveKeysOnlyApply - where S: Stream, - T: Default +where + S: Stream, + T: Default, { - type Item = (String, T); - type Error = IoError; + type Item = (String, T); + type Error = IoError; - #[inline] - fn poll(&mut self) -> Poll, Self::Error> { - if self.keys_only { - Ok(Async::Ready(try_ready!(self.stream.poll()).map(|mut v| { - v.1 = Default::default(); - v - }))) - } else { - self.stream.poll() - } - } + #[inline] + fn poll(&mut self) -> Poll, Self::Error> { + if self.keys_only { + Ok(Async::Ready(try_ready!(self.stream.poll()).map(|mut v| { + v.1 = Default::default(); + v + }))) + } else { + self.stream.poll() + } + } } /// Filters the result of a stream to only keep the results with a prefix. #[inline] pub fn naive_apply_prefix<'a, S, T>(stream: S, prefix: Cow<'a, str>) -> NaivePrefixApply<'a, S> - where S: Stream +where + S: Stream, { - NaivePrefixApply { prefix: prefix, stream: stream } + NaivePrefixApply { + prefix: prefix, + stream: stream, + } } /// Returned by `naive_apply_prefix`. #[derive(Debug, Clone)] pub struct NaivePrefixApply<'a, S> { - prefix: Cow<'a, str>, - stream: S, + prefix: Cow<'a, str>, + stream: S, } impl<'a, S, T> Stream for NaivePrefixApply<'a, S> - where S: Stream +where + S: Stream, { - type Item = (String, T); - type Error = IoError; + type Item = (String, T); + type Error = IoError; - #[inline] - fn poll(&mut self) -> Poll, Self::Error> { - loop { - let item = try_ready!(self.stream.poll()); - match item { - Some(i) => { - if i.0.starts_with(&*self.prefix) { - return Ok(Async::Ready(Some(i))); - } - } - None => return Ok(Async::Ready(None)), - } - } - } + #[inline] + fn poll(&mut self) -> Poll, Self::Error> { + loop { + let item = try_ready!(self.stream.poll()); + match item { + Some(i) => { + if i.0.starts_with(&*self.prefix) { + return Ok(Async::Ready(Some(i))); + } + } + None => return Ok(Async::Ready(None)), + } + } + } } /// Applies orderings on the stream data. Will simply pass data through if the list of orderings /// is empty. Otherwise will need to collect. pub fn naive_apply_ordered<'a, S, I, V>(stream: S, orders_iter: I) -> NaiveApplyOrdered<'a, S, V> - where S: Stream + 'a, - I: IntoIterator, - I::IntoIter: 'a, - V: PartialOrd + 'static +where + S: Stream + 'a, + I: IntoIterator, + I::IntoIter: 'a, + V: PartialOrd + 'static, { - let orders_iter = orders_iter.into_iter(); - if orders_iter.size_hint().1 == Some(0) { - return NaiveApplyOrdered { inner: NaiveApplyOrderedInner::PassThrough(stream) }; - } + let orders_iter = orders_iter.into_iter(); + if orders_iter.size_hint().1 == Some(0) { + return NaiveApplyOrdered { + inner: NaiveApplyOrderedInner::PassThrough(stream), + }; + } - let collected = stream.collect() - .and_then(move |mut collected| { - for order in orders_iter { - match order { - Order::ByValueAsc => { - collected.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap_or(Ordering::Equal)); - } - Order::ByValueDesc => { - collected.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(Ordering::Equal)); - } - Order::ByKeyAsc => { - collected.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or(Ordering::Equal)); - } - Order::ByKeyDesc => { - collected.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap_or(Ordering::Equal)); - } - } - } - Ok(iter_ok(collected.into_iter())) - }) - .flatten_stream(); + let collected = stream + .collect() + .and_then(move |mut collected| { + for order in orders_iter { + match order { + Order::ByValueAsc => { + collected.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap_or(Ordering::Equal)); + } + Order::ByValueDesc => { + collected.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(Ordering::Equal)); + } + Order::ByKeyAsc => { + collected.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or(Ordering::Equal)); + } + Order::ByKeyDesc => { + collected.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap_or(Ordering::Equal)); + } + } + } + Ok(iter_ok(collected.into_iter())) + }) + .flatten_stream(); - NaiveApplyOrdered { inner: NaiveApplyOrderedInner::Collected(Box::new(collected)) } + NaiveApplyOrdered { + inner: NaiveApplyOrderedInner::Collected(Box::new(collected)), + } } /// Returned by `naive_apply_ordered`. pub struct NaiveApplyOrdered<'a, S, T> { - inner: NaiveApplyOrderedInner<'a, S, T>, + inner: NaiveApplyOrderedInner<'a, S, T>, } enum NaiveApplyOrderedInner<'a, S, T> { - PassThrough(S), - Collected(Box + 'a>), + PassThrough(S), + Collected(Box + 'a>), } impl<'a, S, V> Stream for NaiveApplyOrdered<'a, S, V> - where S: Stream +where + S: Stream, { - type Item = (String, V); - type Error = IoError; + type Item = (String, V); + type Error = IoError; - #[inline] - fn poll(&mut self) -> Poll, Self::Error> { - match self.inner { - NaiveApplyOrderedInner::PassThrough(ref mut s) => s.poll(), - NaiveApplyOrderedInner::Collected(ref mut s) => s.poll(), - } - } + #[inline] + fn poll(&mut self) -> Poll, Self::Error> { + match self.inner { + NaiveApplyOrderedInner::PassThrough(ref mut s) => s.poll(), + NaiveApplyOrderedInner::Collected(ref mut s) => s.poll(), + } + } } /// Filters the result of a stream to apply a set of filters. #[inline] pub fn naive_apply_filters<'a, S, I, V>(stream: S, filters: I) -> NaiveFiltersApply<'a, S, I> - where S: Stream, - I: Iterator> + Clone, - V: 'a +where + S: Stream, + I: Iterator> + Clone, + V: 'a, { - NaiveFiltersApply { - filters: filters, - stream: stream, - marker: PhantomData, - } + NaiveFiltersApply { + filters: filters, + stream: stream, + marker: PhantomData, + } } /// Returned by `naive_apply_prefix`. #[derive(Debug, Clone)] pub struct NaiveFiltersApply<'a, S, I> { - filters: I, - stream: S, - marker: PhantomData<&'a ()>, + filters: I, + stream: S, + marker: PhantomData<&'a ()>, } impl<'a, S, I, T> Stream for NaiveFiltersApply<'a, S, I> - where S: Stream, - I: Iterator> + Clone, - T: PartialOrd + 'a +where + S: Stream, + I: Iterator> + Clone, + T: PartialOrd + 'a, { - type Item = (String, T); - type Error = IoError; + type Item = (String, T); + type Error = IoError; - #[inline] - fn poll(&mut self) -> Poll, Self::Error> { - 'outer: loop { - let item = try_ready!(self.stream.poll()); - match item { - Some(i) => { - for filter in self.filters.clone() { - if !naive_filter_test(&i, &filter) { - continue 'outer; - } - } - return Ok(Async::Ready(Some(i))); - } - None => return Ok(Async::Ready(None)), - } - } - } + #[inline] + fn poll(&mut self) -> Poll, Self::Error> { + 'outer: loop { + let item = try_ready!(self.stream.poll()); + match item { + Some(i) => { + for filter in self.filters.clone() { + if !naive_filter_test(&i, &filter) { + continue 'outer; + } + } + return Ok(Async::Ready(Some(i))); + } + None => return Ok(Async::Ready(None)), + } + } + } } #[inline] fn naive_filter_test(entry: &(String, T), filter: &Filter) -> bool - where T: PartialOrd +where + T: PartialOrd, { - let (expected_ordering, revert_expected) = match filter.operation { - FilterOp::Equal => (Ordering::Equal, false), - FilterOp::NotEqual => (Ordering::Equal, true), - FilterOp::Less => (Ordering::Less, false), - FilterOp::GreaterOrEqual => (Ordering::Less, true), - FilterOp::Greater => (Ordering::Greater, false), - FilterOp::LessOrEqual => (Ordering::Greater, true), - }; + let (expected_ordering, revert_expected) = match filter.operation { + FilterOp::Equal => (Ordering::Equal, false), + FilterOp::NotEqual => (Ordering::Equal, true), + FilterOp::Less => (Ordering::Less, false), + FilterOp::GreaterOrEqual => (Ordering::Less, true), + FilterOp::Greater => (Ordering::Greater, false), + FilterOp::LessOrEqual => (Ordering::Greater, true), + }; - match filter.ty { - FilterTy::KeyCompare(ref ref_value) => { - ((&*entry.0).cmp(&**ref_value) == expected_ordering) != revert_expected - } - FilterTy::ValueCompare(ref ref_value) => { - (entry.1.partial_cmp(&**ref_value) == Some(expected_ordering)) != revert_expected - } - } + match filter.ty { + FilterTy::KeyCompare(ref ref_value) => { + ((&*entry.0).cmp(&**ref_value) == expected_ordering) != revert_expected + } + FilterTy::ValueCompare(ref ref_value) => { + (entry.1.partial_cmp(&**ref_value) == Some(expected_ordering)) != revert_expected + } + } } diff --git a/example/examples/echo-dialer.rs b/example/examples/echo-dialer.rs index 7742c68f..5b119893 100644 --- a/example/examples/echo-dialer.rs +++ b/example/examples/echo-dialer.rs @@ -31,7 +31,7 @@ extern crate tokio_io; use futures::{Future, Sink, Stream}; use futures::sync::oneshot; use std::env; -use swarm::{UpgradeExt, SimpleProtocol, Transport, DeniedConnectionUpgrade}; +use swarm::{DeniedConnectionUpgrade, SimpleProtocol, Transport, UpgradeExt}; use tcp::TcpConfig; use tokio_core::reactor::Core; use tokio_io::AsyncRead; @@ -40,7 +40,9 @@ use websocket::WsConfig; fn main() { // Determine which address to dial. - let target_addr = env::args().nth(1).unwrap_or("/ip4/127.0.0.1/tcp/10333".to_owned()); + let target_addr = env::args() + .nth(1) + .unwrap_or("/ip4/127.0.0.1/tcp/10333".to_owned()); // We start by building the tokio engine that will run all the sockets. let mut core = Core::new().unwrap(); @@ -82,10 +84,13 @@ fn main() { // connections for us. The second parameter we pass is the connection upgrade that is accepted // by the listening part. We don't want to accept anything, so we pass a dummy object that // represents a connection that is always denied. - let (swarm_controller, swarm_future) = swarm::swarm(transport, DeniedConnectionUpgrade, + let (swarm_controller, swarm_future) = swarm::swarm( + transport, + DeniedConnectionUpgrade, |_socket, _client_addr| -> Result<(), _> { unreachable!("All incoming connections should have been denied") - }); + }, + ); // Building a struct that represents the protocol that we are going to use for dialing. let proto = SimpleProtocol::new("/echo/1.0.0", |socket| { diff --git a/example/examples/echo-server.rs b/example/examples/echo-server.rs index 06756fa0..c80087a7 100644 --- a/example/examples/echo-server.rs +++ b/example/examples/echo-server.rs @@ -1,21 +1,21 @@ // Copyright 2017 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. extern crate bytes; @@ -28,10 +28,10 @@ extern crate multiplex; extern crate tokio_core; extern crate tokio_io; -use futures::future::{Future, IntoFuture, loop_fn, Loop}; -use futures::{Stream, Sink}; +use futures::future::{loop_fn, Future, IntoFuture, Loop}; +use futures::{Sink, Stream}; use std::env; -use swarm::{Transport, UpgradeExt, SimpleProtocol}; +use swarm::{SimpleProtocol, Transport, UpgradeExt}; use tcp::TcpConfig; use tokio_core::reactor::Core; use tokio_io::AsyncRead; @@ -40,7 +40,9 @@ use websocket::WsConfig; fn main() { // Determine which address to listen to. - let listen_addr = env::args().nth(1).unwrap_or("/ip4/0.0.0.0/tcp/10333".to_owned()); + let listen_addr = env::args() + .nth(1) + .unwrap_or("/ip4/0.0.0.0/tcp/10333".to_owned()); // We start by building the tokio engine that will run all the sockets. let mut core = Core::new().unwrap(); @@ -107,14 +109,16 @@ fn main() { .and_then(move |(msg, rest)| { if let Some(msg) = msg { // One message has been received. We send it back to the client. - println!("Received a message from {}: {:?}\n => Sending back \ - identical message to remote", client_addr, msg); + println!( + "Received a message from {}: {:?}\n => Sending back \ + identical message to remote", + client_addr, msg + ); Box::new(rest.send(msg.freeze()).map(|m| Loop::Continue(m))) as Box> } else { // End of stream. Connection closed. Breaking the loop. - println!("Received EOF from {}\n => Dropping connection", - client_addr); + println!("Received EOF from {}\n => Dropping connection", client_addr); Box::new(Ok(Loop::Break(())).into_future()) as Box> } diff --git a/example/examples/ping-client.rs b/example/examples/ping-client.rs index 1c99acc7..d5abbbed 100644 --- a/example/examples/ping-client.rs +++ b/example/examples/ping-client.rs @@ -31,13 +31,15 @@ extern crate tokio_io; use futures::Future; use futures::sync::oneshot; use std::env; -use swarm::{UpgradeExt, Transport, DeniedConnectionUpgrade}; +use swarm::{DeniedConnectionUpgrade, Transport, UpgradeExt}; use tcp::TcpConfig; use tokio_core::reactor::Core; fn main() { // Determine which address to dial. - let target_addr = env::args().nth(1).unwrap_or("/ip4/127.0.0.1/tcp/4001".to_owned()); + let target_addr = env::args() + .nth(1) + .unwrap_or("/ip4/127.0.0.1/tcp/4001".to_owned()); // We start by building the tokio engine that will run all the sockets. let mut core = Core::new().unwrap(); @@ -74,10 +76,13 @@ fn main() { // connections for us. The second parameter we pass is the connection upgrade that is accepted // by the listening part. We don't want to accept anything, so we pass a dummy object that // represents a connection that is always denied. - let (swarm_controller, swarm_future) = swarm::swarm(transport, DeniedConnectionUpgrade, + let (swarm_controller, swarm_future) = swarm::swarm( + transport, + DeniedConnectionUpgrade, |_socket, _client_addr| -> Result<(), _> { unreachable!("All incoming connections should have been denied") - }); + }, + ); // We now use the controller to dial to the address. let (tx, rx) = oneshot::channel(); @@ -101,5 +106,9 @@ fn main() { // `swarm_future` is a future that contains all the behaviour that we want, but nothing has // actually started yet. Because we created the `TcpConfig` with tokio, we need to run the // future through the tokio core. - core.run(rx.select(swarm_future.map_err(|_| unreachable!())).map_err(|(e, _)| e).map(|_| ())).unwrap(); + core.run( + rx.select(swarm_future.map_err(|_| unreachable!())) + .map_err(|(e, _)| e) + .map(|_| ()), + ).unwrap(); } diff --git a/example/src/lib.rs b/example/src/lib.rs index 18a78c85..0190897a 100644 --- a/example/src/lib.rs +++ b/example/src/lib.rs @@ -22,16 +22,16 @@ extern crate libp2p_peerstore; extern crate libp2p_swarm; extern crate multiaddr; -use libp2p_peerstore::{PeerId, PeerAccess, Peerstore}; +use libp2p_peerstore::{PeerAccess, PeerId, Peerstore}; use multiaddr::Multiaddr; use std::time::Duration; /// Stores initial addresses on the given peer store. Uses a very large timeout. pub fn ipfs_bootstrap

(peer_store: P) where - P: Peerstore + Clone, + P: Peerstore + Clone, { - const ADDRESSES: &[&str] = &[ + const ADDRESSES: &[&str] = &[ "/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", "/ip4/104.236.179.241/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM", "/ip4/162.243.248.213/tcp/4001/ipfs/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm", @@ -43,22 +43,22 @@ where "/dns4/wss1.bootstrap.libp2p.io/tcp/443/wss/ipfs/Qmbut9Ywz9YEDrz8ySBSgWyJk41Uvm2QJPhwDJzJyGFsD6" ]; - let ttl = Duration::from_secs(100 * 365 * 24 * 3600); + let ttl = Duration::from_secs(100 * 365 * 24 * 3600); - for address in ADDRESSES.iter() { - let mut multiaddr = address - .parse::() - .expect("failed to parse hard-coded multiaddr"); + for address in ADDRESSES.iter() { + let mut multiaddr = address + .parse::() + .expect("failed to parse hard-coded multiaddr"); - let ipfs_component = multiaddr.pop().expect("hard-coded multiaddr is empty"); - let public_key = match ipfs_component { - multiaddr::AddrComponent::IPFS(key) => key, - _ => panic!("hard-coded multiaddr didn't end with /ipfs/"), - }; + let ipfs_component = multiaddr.pop().expect("hard-coded multiaddr is empty"); + let public_key = match ipfs_component { + multiaddr::AddrComponent::IPFS(key) => key, + _ => panic!("hard-coded multiaddr didn't end with /ipfs/"), + }; - peer_store - .clone() - .peer_or_create(&PeerId::from_bytes(public_key).unwrap()) - .add_addr(multiaddr, ttl.clone()); - } + peer_store + .clone() + .peer_or_create(&PeerId::from_bytes(public_key).unwrap()) + .add_addr(multiaddr, ttl.clone()); + } } diff --git a/libp2p-dns/src/lib.rs b/libp2p-dns/src/lib.rs index 77edb6cc..d050ef9b 100644 --- a/libp2p-dns/src/lib.rs +++ b/libp2p-dns/src/lib.rs @@ -62,221 +62,221 @@ use tokio_dns::{CpuPoolResolver, Resolver}; /// Listening is unaffected. #[derive(Clone)] pub struct DnsConfig { - inner: T, - resolver: CpuPoolResolver, + inner: T, + resolver: CpuPoolResolver, } impl DnsConfig { - /// Creates a new configuration object for DNS. - #[inline] - pub fn new(inner: T) -> DnsConfig { - DnsConfig::with_resolve_threads(inner, 1) - } + /// Creates a new configuration object for DNS. + #[inline] + pub fn new(inner: T) -> DnsConfig { + DnsConfig::with_resolve_threads(inner, 1) + } - /// Same as `new`, but allows specifying a number of threads for the resolving. - #[inline] - pub fn with_resolve_threads(inner: T, num_threads: usize) -> DnsConfig { - trace!(target: "libp2p-dns", "Created a CpuPoolResolver"); + /// Same as `new`, but allows specifying a number of threads for the resolving. + #[inline] + pub fn with_resolve_threads(inner: T, num_threads: usize) -> DnsConfig { + trace!(target: "libp2p-dns", "Created a CpuPoolResolver"); - DnsConfig { - inner, - resolver: CpuPoolResolver::new(num_threads), - } - } + DnsConfig { + inner, + resolver: CpuPoolResolver::new(num_threads), + } + } } impl fmt::Debug for DnsConfig where - T: fmt::Debug, + T: fmt::Debug, { - #[inline] - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.debug_tuple("DnsConfig").field(&self.inner).finish() - } + #[inline] + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_tuple("DnsConfig").field(&self.inner).finish() + } } impl Transport for DnsConfig where - T: Transport + 'static, // TODO: 'static :-/ + T: Transport + 'static, // TODO: 'static :-/ { - type RawConn = T::RawConn; - type Listener = T::Listener; - type ListenerUpgrade = T::ListenerUpgrade; - type Dial = Box>; + type RawConn = T::RawConn; + type Listener = T::Listener; + type ListenerUpgrade = T::ListenerUpgrade; + type Dial = Box>; - #[inline] - fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { - match self.inner.listen_on(addr) { - Ok(r) => Ok(r), - Err((inner, addr)) => Err(( - DnsConfig { - inner, - resolver: self.resolver, - }, - addr, - )), - } - } + #[inline] + fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { + match self.inner.listen_on(addr) { + Ok(r) => Ok(r), + Err((inner, addr)) => Err(( + DnsConfig { + inner, + resolver: self.resolver, + }, + addr, + )), + } + } - fn dial(self, addr: Multiaddr) -> Result { - let contains_dns = addr.iter().any(|cmp| match cmp { - AddrComponent::DNS4(_) => true, - AddrComponent::DNS6(_) => true, - _ => false, - }); + fn dial(self, addr: Multiaddr) -> Result { + let contains_dns = addr.iter().any(|cmp| match cmp { + AddrComponent::DNS4(_) => true, + AddrComponent::DNS6(_) => true, + _ => false, + }); - if !contains_dns { - trace!(target: "libp2p-dns", "Pass-through address without DNS: {}", addr); - return match self.inner.dial(addr) { - Ok(d) => Ok(Box::new(d.into_future()) as Box<_>), - Err((inner, addr)) => Err(( - DnsConfig { - inner, - resolver: self.resolver, - }, - addr, - )), - }; - } + if !contains_dns { + trace!(target: "libp2p-dns", "Pass-through address without DNS: {}", addr); + return match self.inner.dial(addr) { + Ok(d) => Ok(Box::new(d.into_future()) as Box<_>), + Err((inner, addr)) => Err(( + DnsConfig { + inner, + resolver: self.resolver, + }, + addr, + )), + }; + } - let resolver = self.resolver; + let resolver = self.resolver; - trace!(target: "libp2p-dns", "Dialing address with DNS: {}", addr); - let resolve_iters = addr.iter() - .map(move |cmp| match cmp { - AddrComponent::DNS4(ref name) => { - future::Either::A(resolve_dns(name, resolver.clone(), ResolveTy::Dns4)) - } - AddrComponent::DNS6(ref name) => { - future::Either::A(resolve_dns(name, resolver.clone(), ResolveTy::Dns6)) - } - cmp => future::Either::B(future::ok(cmp)), - }) - .collect::>() - .into_iter(); + trace!(target: "libp2p-dns", "Dialing address with DNS: {}", addr); + let resolve_iters = addr.iter() + .map(move |cmp| match cmp { + AddrComponent::DNS4(ref name) => { + future::Either::A(resolve_dns(name, resolver.clone(), ResolveTy::Dns4)) + } + AddrComponent::DNS6(ref name) => { + future::Either::A(resolve_dns(name, resolver.clone(), ResolveTy::Dns6)) + } + cmp => future::Either::B(future::ok(cmp)), + }) + .collect::>() + .into_iter(); - let new_addr = future::join_all(resolve_iters).map(move |outcome| { - let outcome: Multiaddr = outcome.into_iter().collect(); - debug!(target: "libp2p-dns", "DNS resolution outcome: {} => {}", addr, outcome); - outcome - }); + let new_addr = future::join_all(resolve_iters).map(move |outcome| { + let outcome: Multiaddr = outcome.into_iter().collect(); + debug!(target: "libp2p-dns", "DNS resolution outcome: {} => {}", addr, outcome); + outcome + }); - let inner = self.inner; - let future = new_addr - .and_then(move |addr| { - inner - .dial(addr) - .map_err(|_| IoError::new(IoErrorKind::Other, "multiaddr not supported")) - }) - .flatten(); + let inner = self.inner; + let future = new_addr + .and_then(move |addr| { + inner + .dial(addr) + .map_err(|_| IoError::new(IoErrorKind::Other, "multiaddr not supported")) + }) + .flatten(); - Ok(Box::new(future) as Box<_>) - } + Ok(Box::new(future) as Box<_>) + } - #[inline] - fn nat_traversal(&self, server: &Multiaddr, observed: &Multiaddr) -> Option { - // Since `listen_on` doesn't perform any resolution, we just pass through `nat_traversal` - // as well. - self.inner.nat_traversal(server, observed) - } + #[inline] + fn nat_traversal(&self, server: &Multiaddr, observed: &Multiaddr) -> Option { + // Since `listen_on` doesn't perform any resolution, we just pass through `nat_traversal` + // as well. + self.inner.nat_traversal(server, observed) + } } // How to resolve ; to an IPv4 address or an IPv6 address? #[derive(Debug, Copy, Clone, PartialEq, Eq)] enum ResolveTy { - Dns4, - Dns6, + Dns4, + Dns6, } // Resolve a DNS name and returns a future with the result. fn resolve_dns( - name: &str, - resolver: CpuPoolResolver, - ty: ResolveTy, + name: &str, + resolver: CpuPoolResolver, + ty: ResolveTy, ) -> Box> { - let debug_name = if log_enabled!(target: "libp2p-dns", Level::Trace) { - Some(name.to_owned()) - } else { - None - }; + let debug_name = if log_enabled!(target: "libp2p-dns", Level::Trace) { + Some(name.to_owned()) + } else { + None + }; - let future = resolver.resolve(name).and_then(move |addrs| { - trace!(target: "libp2p-dns", "DNS component resolution: {} => {:?}", - debug_name.expect("trace log level was enabled"), addrs); - addrs - .into_iter() - .filter_map(move |addr| match (addr, ty) { - (IpAddr::V4(addr), ResolveTy::Dns4) => Some(AddrComponent::IP4(addr)), - (IpAddr::V6(addr), ResolveTy::Dns6) => Some(AddrComponent::IP6(addr)), - _ => None, - }) - .next() - .ok_or(IoError::new( - IoErrorKind::Other, - "couldn't find any relevant IP address", - )) - }); + let future = resolver.resolve(name).and_then(move |addrs| { + trace!(target: "libp2p-dns", "DNS component resolution: {} => {:?}", + debug_name.expect("trace log level was enabled"), addrs); + addrs + .into_iter() + .filter_map(move |addr| match (addr, ty) { + (IpAddr::V4(addr), ResolveTy::Dns4) => Some(AddrComponent::IP4(addr)), + (IpAddr::V6(addr), ResolveTy::Dns6) => Some(AddrComponent::IP6(addr)), + _ => None, + }) + .next() + .ok_or(IoError::new( + IoErrorKind::Other, + "couldn't find any relevant IP address", + )) + }); - Box::new(future) + Box::new(future) } #[cfg(test)] mod tests { - extern crate libp2p_tcp_transport; - use self::libp2p_tcp_transport::TcpConfig; - use DnsConfig; - use futures::{future, Future}; - use multiaddr::{AddrComponent, Multiaddr}; - use std::io::Error as IoError; - use swarm::Transport; + extern crate libp2p_tcp_transport; + use self::libp2p_tcp_transport::TcpConfig; + use DnsConfig; + use futures::{future, Future}; + use multiaddr::{AddrComponent, Multiaddr}; + use std::io::Error as IoError; + use swarm::Transport; - #[test] - fn basic_resolve() { - #[derive(Clone)] - struct CustomTransport; - impl Transport for CustomTransport { - type RawConn = ::RawConn; - type Listener = ::Listener; - type ListenerUpgrade = ::ListenerUpgrade; - type Dial = Box>; + #[test] + fn basic_resolve() { + #[derive(Clone)] + struct CustomTransport; + impl Transport for CustomTransport { + type RawConn = ::RawConn; + type Listener = ::Listener; + type ListenerUpgrade = ::ListenerUpgrade; + type Dial = Box>; - #[inline] - fn listen_on( - self, - _addr: Multiaddr, - ) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { - unreachable!() - } + #[inline] + fn listen_on( + self, + _addr: Multiaddr, + ) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { + unreachable!() + } - fn dial(self, addr: Multiaddr) -> Result { - let addr = addr.iter().collect::>(); - assert_eq!(addr.len(), 2); - match addr[1] { - AddrComponent::TCP(_) => (), - _ => panic!(), - }; - match addr[0] { - AddrComponent::DNS4(_) => (), - AddrComponent::DNS6(_) => (), - _ => panic!(), - }; - Ok(Box::new(future::empty()) as Box<_>) - } + fn dial(self, addr: Multiaddr) -> Result { + let addr = addr.iter().collect::>(); + assert_eq!(addr.len(), 2); + match addr[1] { + AddrComponent::TCP(_) => (), + _ => panic!(), + }; + match addr[0] { + AddrComponent::DNS4(_) => (), + AddrComponent::DNS6(_) => (), + _ => panic!(), + }; + Ok(Box::new(future::empty()) as Box<_>) + } - #[inline] - fn nat_traversal(&self, _: &Multiaddr, _: &Multiaddr) -> Option { - panic!() - } - } + #[inline] + fn nat_traversal(&self, _: &Multiaddr, _: &Multiaddr) -> Option { + panic!() + } + } - let transport = DnsConfig::new(CustomTransport); + let transport = DnsConfig::new(CustomTransport); - let _ = transport - .clone() - .dial("/dns4/example.com/tcp/20000".parse().unwrap()) - .unwrap_or_else(|_| panic!()); - let _ = transport - .dial("/dns6/example.com/tcp/20000".parse().unwrap()) - .unwrap_or_else(|_| panic!()); - } + let _ = transport + .clone() + .dial("/dns4/example.com/tcp/20000".parse().unwrap()) + .unwrap_or_else(|_| panic!()); + let _ = transport + .dial("/dns6/example.com/tcp/20000".parse().unwrap()) + .unwrap_or_else(|_| panic!()); + } } diff --git a/libp2p-identify/src/protocol.rs b/libp2p-identify/src/protocol.rs index e3d02615..3d0c4ba4 100644 --- a/libp2p-identify/src/protocol.rs +++ b/libp2p-identify/src/protocol.rs @@ -39,276 +39,283 @@ pub struct IdentifyProtocolConfig; /// Output of the connection upgrade. pub enum IdentifyOutput { - /// We obtained information from the remote. Happens when we are the dialer. - RemoteInfo { - info: IdentifyInfo, - /// Address the remote sees for us. - observed_addr: Multiaddr, - }, + /// We obtained information from the remote. Happens when we are the dialer. + RemoteInfo { + info: IdentifyInfo, + /// Address the remote sees for us. + observed_addr: Multiaddr, + }, - /// We opened a connection to the remote and need to send it information. Happens when we are - /// the listener. - Sender { - /// Object used to send identify info to the client. - sender: IdentifySender, - /// Observed multiaddress of the client. - observed_addr: Multiaddr, - }, + /// We opened a connection to the remote and need to send it information. Happens when we are + /// the listener. + Sender { + /// Object used to send identify info to the client. + sender: IdentifySender, + /// Observed multiaddress of the client. + observed_addr: Multiaddr, + }, } /// Object used to send back information to the client. pub struct IdentifySender { - inner: Framed>>, + inner: Framed>>, } impl<'a, T> IdentifySender where - T: AsyncWrite + 'a, + T: AsyncWrite + 'a, { - /// Sends back information to the client. Returns a future that is signalled whenever the - /// info have been sent. - pub fn send( - self, - info: IdentifyInfo, - observed_addr: &Multiaddr, - ) -> Box + 'a> { - debug!(target: "libp2p-identify", "Sending identify info to client"); - trace!(target: "libp2p-identify", "Sending: {:?}", info); + /// Sends back information to the client. Returns a future that is signalled whenever the + /// info have been sent. + pub fn send( + self, + info: IdentifyInfo, + observed_addr: &Multiaddr, + ) -> Box + 'a> { + debug!(target: "libp2p-identify", "Sending identify info to client"); + trace!(target: "libp2p-identify", "Sending: {:?}", info); - let listen_addrs = info.listen_addrs - .into_iter() - .map(|addr| addr.into_bytes()) - .collect(); + let listen_addrs = info.listen_addrs + .into_iter() + .map(|addr| addr.into_bytes()) + .collect(); - let mut message = structs_proto::Identify::new(); - message.set_agentVersion(info.agent_version); - message.set_protocolVersion(info.protocol_version); - message.set_publicKey(info.public_key); - message.set_listenAddrs(listen_addrs); - message.set_observedAddr(observed_addr.to_bytes()); - message.set_protocols(RepeatedField::from_vec(info.protocols)); + let mut message = structs_proto::Identify::new(); + message.set_agentVersion(info.agent_version); + message.set_protocolVersion(info.protocol_version); + message.set_publicKey(info.public_key); + message.set_listenAddrs(listen_addrs); + message.set_observedAddr(observed_addr.to_bytes()); + message.set_protocols(RepeatedField::from_vec(info.protocols)); - let bytes = message - .write_to_bytes() - .expect("writing protobuf failed ; should never happen"); + let bytes = message + .write_to_bytes() + .expect("writing protobuf failed ; should never happen"); - let future = self.inner.send(bytes).map(|_| ()); - Box::new(future) as Box<_> - } + let future = self.inner.send(bytes).map(|_| ()); + Box::new(future) as Box<_> + } } /// Information sent from the listener to the dialer. #[derive(Debug, Clone)] pub struct IdentifyInfo { - /// Public key of the node in the DER format. - pub public_key: Vec, - /// Version of the "global" protocol, eg. `ipfs/1.0.0` or `polkadot/1.0.0`. - pub protocol_version: String, - /// Name and version of the client. Can be thought as similar to the `User-Agent` header - /// of HTTP. - pub agent_version: String, - /// Addresses that the node is listening on. - pub listen_addrs: Vec, - /// Protocols supported by the node, eg. `/ipfs/ping/1.0.0`. - pub protocols: Vec, + /// Public key of the node in the DER format. + pub public_key: Vec, + /// Version of the "global" protocol, eg. `ipfs/1.0.0` or `polkadot/1.0.0`. + pub protocol_version: String, + /// Name and version of the client. Can be thought as similar to the `User-Agent` header + /// of HTTP. + pub agent_version: String, + /// Addresses that the node is listening on. + pub listen_addrs: Vec, + /// Protocols supported by the node, eg. `/ipfs/ping/1.0.0`. + pub protocols: Vec, } impl ConnectionUpgrade for IdentifyProtocolConfig where - C: AsyncRead + AsyncWrite + 'static, + C: AsyncRead + AsyncWrite + 'static, { - type NamesIter = iter::Once<(Bytes, Self::UpgradeIdentifier)>; - type UpgradeIdentifier = (); - type Output = IdentifyOutput; - type Future = Box>; + type NamesIter = iter::Once<(Bytes, Self::UpgradeIdentifier)>; + type UpgradeIdentifier = (); + type Output = IdentifyOutput; + type Future = Box>; - #[inline] - fn protocol_names(&self) -> Self::NamesIter { - iter::once((Bytes::from("/ipfs/id/1.0.0"), ())) - } + #[inline] + fn protocol_names(&self) -> Self::NamesIter { + iter::once((Bytes::from("/ipfs/id/1.0.0"), ())) + } - fn upgrade(self, socket: C, _: (), ty: Endpoint, observed_addr: &Multiaddr) -> Self::Future { - trace!(target: "libp2p-identify", "Upgrading connection with {:?} as {:?}", - observed_addr, ty); + fn upgrade(self, socket: C, _: (), ty: Endpoint, observed_addr: &Multiaddr) -> Self::Future { + trace!(target: "libp2p-identify", "Upgrading connection with {:?} as {:?}", + observed_addr, ty); - let socket = socket.framed(VarintCodec::default()); - let observed_addr_log = if log_enabled!(target: "libp2p-identify", Level::Debug) { - Some(observed_addr.clone()) - } else { - None - }; + let socket = socket.framed(VarintCodec::default()); + let observed_addr_log = if log_enabled!(target: "libp2p-identify", Level::Debug) { + Some(observed_addr.clone()) + } else { + None + }; - match ty { - Endpoint::Dialer => { - let future = socket - .into_future() - .map(|(msg, _)| msg) - .map_err(|(err, _)| err) - .and_then(|msg| { - debug!(target: "libp2p-identify", "Received identify message from {:?}", - observed_addr_log - .expect("Programmer error: expected `observed_addr_log' to be \ - non-None since debug log level is enabled")); - if let Some(msg) = msg { - let (info, observed_addr) = match parse_proto_msg(msg) { - Ok(v) => v, - Err(err) => { - debug!(target: "libp2p-identify", - "Failed to parse protobuf message ; error = {:?}", err); - return Err(err.into()); - } - }; + match ty { + Endpoint::Dialer => { + let future = socket + .into_future() + .map(|(msg, _)| msg) + .map_err(|(err, _)| err) + .and_then(|msg| { + debug!(target: "libp2p-identify", "Received identify message from {:?}", + observed_addr_log + .expect("Programmer error: expected `observed_addr_log' to be \ + non-None since debug log level is enabled")); + if let Some(msg) = msg { + let (info, observed_addr) = match parse_proto_msg(msg) { + Ok(v) => v, + Err(err) => { + debug!(target: "libp2p-identify", + "Failed to parse protobuf message ; error = {:?}", err); + return Err(err.into()); + } + }; - trace!(target: "libp2p-identify", "Remote observes us as {:?}", - observed_addr); - trace!(target: "libp2p-identify", "Information received: {:?}", info); + trace!(target: "libp2p-identify", "Remote observes us as {:?}", + observed_addr); + trace!(target: "libp2p-identify", "Information received: {:?}", info); - Ok(IdentifyOutput::RemoteInfo { - info, - observed_addr, - }) + Ok(IdentifyOutput::RemoteInfo { + info, + observed_addr, + }) + } else { + debug!(target: "libp2p-identify", "Identify protocol stream closed \ + before receiving info"); + Err(IoErrorKind::InvalidData.into()) + } + }); - } else { - debug!(target: "libp2p-identify", "Identify protocol stream closed \ - before receiving info"); - Err(IoErrorKind::InvalidData.into()) - } - }); + Box::new(future) as Box<_> + } - Box::new(future) as Box<_> - } + Endpoint::Listener => { + let sender = IdentifySender { inner: socket }; - Endpoint::Listener => { - let sender = IdentifySender { inner: socket }; + let future = future::ok(IdentifyOutput::Sender { + sender, + observed_addr: observed_addr.clone(), + }); - let future = future::ok(IdentifyOutput::Sender { - sender, - observed_addr: observed_addr.clone(), - }); - - Box::new(future) as Box<_> - } - } - } + Box::new(future) as Box<_> + } + } + } } // Turns a protobuf message into an `IdentifyInfo` and an observed address. If something bad // happens, turn it into an `IoError`. fn parse_proto_msg(msg: BytesMut) -> Result<(IdentifyInfo, Multiaddr), IoError> { - match protobuf_parse_from_bytes::(&msg) { - Ok(mut msg) => { - // Turn a `Vec` into a `Multiaddr`. If something bad happens, turn it into - // an `IoError`. - fn bytes_to_multiaddr(bytes: Vec) -> Result { - Multiaddr::from_bytes(bytes) - .map_err(|err| IoError::new(IoErrorKind::InvalidData, err)) - } + match protobuf_parse_from_bytes::(&msg) { + Ok(mut msg) => { + // Turn a `Vec` into a `Multiaddr`. If something bad happens, turn it into + // an `IoError`. + fn bytes_to_multiaddr(bytes: Vec) -> Result { + Multiaddr::from_bytes(bytes) + .map_err(|err| IoError::new(IoErrorKind::InvalidData, err)) + } - let listen_addrs = { - let mut addrs = Vec::new(); - for addr in msg.take_listenAddrs().into_iter() { - addrs.push(bytes_to_multiaddr(addr)?); - } - addrs - }; + let listen_addrs = { + let mut addrs = Vec::new(); + for addr in msg.take_listenAddrs().into_iter() { + addrs.push(bytes_to_multiaddr(addr)?); + } + addrs + }; - let observed_addr = bytes_to_multiaddr(msg.take_observedAddr())?; + let observed_addr = bytes_to_multiaddr(msg.take_observedAddr())?; - let info = IdentifyInfo { - public_key: msg.take_publicKey(), - protocol_version: msg.take_protocolVersion(), - agent_version: msg.take_agentVersion(), - listen_addrs: listen_addrs, - protocols: msg.take_protocols().into_vec(), - }; + let info = IdentifyInfo { + public_key: msg.take_publicKey(), + protocol_version: msg.take_protocolVersion(), + agent_version: msg.take_agentVersion(), + listen_addrs: listen_addrs, + protocols: msg.take_protocols().into_vec(), + }; - Ok((info, observed_addr)) - } + Ok((info, observed_addr)) + } - Err(err) => Err(IoError::new(IoErrorKind::InvalidData, err)), - } + Err(err) => Err(IoError::new(IoErrorKind::InvalidData, err)), + } } #[cfg(test)] mod tests { - extern crate libp2p_tcp_transport; - extern crate tokio_core; + extern crate libp2p_tcp_transport; + extern crate tokio_core; - use self::libp2p_tcp_transport::TcpConfig; - use self::tokio_core::reactor::Core; - use {IdentifyProtocolConfig, IdentifyOutput, IdentifyInfo}; - use futures::{Future, Stream}; - use libp2p_swarm::Transport; - use std::sync::mpsc; - use std::thread; + use self::libp2p_tcp_transport::TcpConfig; + use self::tokio_core::reactor::Core; + use {IdentifyInfo, IdentifyOutput, IdentifyProtocolConfig}; + use futures::{Future, Stream}; + use libp2p_swarm::Transport; + use std::sync::mpsc; + use std::thread; - #[test] - fn correct_transfer() { - // We open a server and a client, send info from the server to the client, and check that - // they were successfully received. + #[test] + fn correct_transfer() { + // We open a server and a client, send info from the server to the client, and check that + // they were successfully received. - let (tx, rx) = mpsc::channel(); + let (tx, rx) = mpsc::channel(); - let bg_thread = thread::spawn(move || { - let mut core = Core::new().unwrap(); - let transport = TcpConfig::new(core.handle()) - .with_upgrade(IdentifyProtocolConfig); + let bg_thread = thread::spawn(move || { + let mut core = Core::new().unwrap(); + let transport = TcpConfig::new(core.handle()).with_upgrade(IdentifyProtocolConfig); - let (listener, addr) = transport - .listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap()).unwrap(); - tx.send(addr).unwrap(); + let (listener, addr) = transport + .listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap()) + .unwrap(); + tx.send(addr).unwrap(); - let future = listener - .into_future() - .map_err(|(err, _)| err) - .and_then(|(client, _)| client.unwrap().map(|v| v.0)) - .and_then(|identify| { - match identify { - IdentifyOutput::Sender { sender, .. } => { - sender.send(IdentifyInfo { - public_key: vec![1, 2, 3, 4, 5, 7], - protocol_version: "proto_version".to_owned(), - agent_version: "agent_version".to_owned(), - listen_addrs: vec![ - "/ip4/80.81.82.83/tcp/500".parse().unwrap(), - "/ip6/::1/udp/1000".parse().unwrap() - ], - protocols: vec!["proto1".to_string(), "proto2".to_string()], - }, &"/ip4/100.101.102.103/tcp/5000".parse().unwrap()) - }, - _ => panic!() - } - }); + let future = listener + .into_future() + .map_err(|(err, _)| err) + .and_then(|(client, _)| client.unwrap().map(|v| v.0)) + .and_then(|identify| match identify { + IdentifyOutput::Sender { sender, .. } => sender.send( + IdentifyInfo { + public_key: vec![1, 2, 3, 4, 5, 7], + protocol_version: "proto_version".to_owned(), + agent_version: "agent_version".to_owned(), + listen_addrs: vec![ + "/ip4/80.81.82.83/tcp/500".parse().unwrap(), + "/ip6/::1/udp/1000".parse().unwrap(), + ], + protocols: vec!["proto1".to_string(), "proto2".to_string()], + }, + &"/ip4/100.101.102.103/tcp/5000".parse().unwrap(), + ), + _ => panic!(), + }); - let _ = core.run(future).unwrap(); - }); + let _ = core.run(future).unwrap(); + }); - let mut core = Core::new().unwrap(); - let transport = TcpConfig::new(core.handle()) - .with_upgrade(IdentifyProtocolConfig); + let mut core = Core::new().unwrap(); + let transport = TcpConfig::new(core.handle()).with_upgrade(IdentifyProtocolConfig); - let future = transport - .dial(rx.recv().unwrap()) - .unwrap_or_else(|_| panic!()) - .and_then(|(identify, _)| { - match identify { - IdentifyOutput::RemoteInfo { info, observed_addr } => { - assert_eq!(observed_addr, "/ip4/100.101.102.103/tcp/5000".parse().unwrap()); - assert_eq!(info.public_key, &[1, 2, 3, 4, 5, 7]); - assert_eq!(info.protocol_version, "proto_version"); - assert_eq!(info.agent_version, "agent_version"); - assert_eq!(info.listen_addrs, &[ - "/ip4/80.81.82.83/tcp/500".parse().unwrap(), - "/ip6/::1/udp/1000".parse().unwrap() - ]); - assert_eq!(info.protocols, &["proto1".to_string(), "proto2".to_string()]); - Ok(()) - }, - _ => panic!() - } - }); + let future = transport + .dial(rx.recv().unwrap()) + .unwrap_or_else(|_| panic!()) + .and_then(|(identify, _)| match identify { + IdentifyOutput::RemoteInfo { + info, + observed_addr, + } => { + assert_eq!( + observed_addr, + "/ip4/100.101.102.103/tcp/5000".parse().unwrap() + ); + assert_eq!(info.public_key, &[1, 2, 3, 4, 5, 7]); + assert_eq!(info.protocol_version, "proto_version"); + assert_eq!(info.agent_version, "agent_version"); + assert_eq!( + info.listen_addrs, + &[ + "/ip4/80.81.82.83/tcp/500".parse().unwrap(), + "/ip6/::1/udp/1000".parse().unwrap() + ] + ); + assert_eq!( + info.protocols, + &["proto1".to_string(), "proto2".to_string()] + ); + Ok(()) + } + _ => panic!(), + }); - let _ = core.run(future).unwrap(); - bg_thread.join().unwrap(); - } + let _ = core.run(future).unwrap(); + bg_thread.join().unwrap(); + } } diff --git a/libp2p-identify/src/transport.rs b/libp2p-identify/src/transport.rs index cce1d08a..83ee1ef3 100644 --- a/libp2p-identify/src/transport.rs +++ b/libp2p-identify/src/transport.rs @@ -30,361 +30,358 @@ use std::time::Duration; /// Implementation of `Transport`. See [the crate root description](index.html). #[derive(Debug, Clone)] pub struct IdentifyTransport { - transport: Trans, - peerstore: PStoreRef, - addr_ttl: Duration, + transport: Trans, + peerstore: PStoreRef, + addr_ttl: Duration, } impl IdentifyTransport { - /// Creates an `IdentifyTransport` that wraps around the given transport and peerstore. - #[inline] - pub fn new(transport: Trans, peerstore: PStoreRef) -> Self { - IdentifyTransport::with_ttl(transport, peerstore, Duration::from_secs(3600)) - } + /// Creates an `IdentifyTransport` that wraps around the given transport and peerstore. + #[inline] + pub fn new(transport: Trans, peerstore: PStoreRef) -> Self { + IdentifyTransport::with_ttl(transport, peerstore, Duration::from_secs(3600)) + } - /// Same as `new`, but allows specifying a time-to-live for the addresses gathered from - /// remotes that connect to us. - /// - /// The default value is one hour. - #[inline] - pub fn with_ttl(transport: Trans, peerstore: PStoreRef, ttl: Duration) -> Self { - IdentifyTransport { - transport: transport, - peerstore: peerstore, - addr_ttl: ttl, - } - } + /// Same as `new`, but allows specifying a time-to-live for the addresses gathered from + /// remotes that connect to us. + /// + /// The default value is one hour. + #[inline] + pub fn with_ttl(transport: Trans, peerstore: PStoreRef, ttl: Duration) -> Self { + IdentifyTransport { + transport: transport, + peerstore: peerstore, + addr_ttl: ttl, + } + } } impl Transport for IdentifyTransport where - Trans: Transport + Clone + 'static, // TODO: 'static :( - PStoreRef: Deref + Clone + 'static, // TODO: 'static :( - for<'r> &'r PStore: Peerstore, + Trans: Transport + Clone + 'static, // TODO: 'static :( + PStoreRef: Deref + Clone + 'static, // TODO: 'static :( + for<'r> &'r PStore: Peerstore, { - type RawConn = Trans::RawConn; - type Listener = Box>; - type ListenerUpgrade = Box>; - type Dial = Box>; + type RawConn = Trans::RawConn; + type Listener = Box>; + type ListenerUpgrade = Box>; + type Dial = Box>; - #[inline] - fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { - // Note that `listen_on` expects a "regular" multiaddr (eg. `/ip/.../tcp/...`), - // and not `/p2p/`. + #[inline] + fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { + // Note that `listen_on` expects a "regular" multiaddr (eg. `/ip/.../tcp/...`), + // and not `/p2p/`. - let (listener, new_addr) = match self.transport.clone().listen_on(addr.clone()) { - Ok((l, a)) => (l, a), - Err((inner, addr)) => { - let id = IdentifyTransport { - transport: inner, - peerstore: self.peerstore, - addr_ttl: self.addr_ttl, - }; - return Err((id, addr)); - } - }; + let (listener, new_addr) = match self.transport.clone().listen_on(addr.clone()) { + Ok((l, a)) => (l, a), + Err((inner, addr)) => { + let id = IdentifyTransport { + transport: inner, + peerstore: self.peerstore, + addr_ttl: self.addr_ttl, + }; + return Err((id, addr)); + } + }; - let identify_upgrade = self.transport.with_upgrade(IdentifyProtocolConfig); - let peerstore = self.peerstore; - let addr_ttl = self.addr_ttl; + let identify_upgrade = self.transport.with_upgrade(IdentifyProtocolConfig); + let peerstore = self.peerstore; + let addr_ttl = self.addr_ttl; - let listener = listener.map(move |connec| { - let peerstore = peerstore.clone(); - let identify_upgrade = identify_upgrade.clone(); - let fut = connec - .and_then(move |(connec, client_addr)| { - // Dial the address that connected to us and try upgrade with the - // identify protocol. - identify_upgrade - .clone() - .dial(client_addr.clone()) - .map_err(|_| { - IoError::new(IoErrorKind::Other, "couldn't dial back incoming node") - }) - .map(move |id| (id, connec)) - }) - .and_then(move |(dial, connec)| dial.map(move |dial| (dial, connec))) - .and_then(move |((identify, original_addr), connec)| { - // Compute the "real" address of the node (in the form `/p2p/...`) and add - // it to the peerstore. - let real_addr = match identify { - IdentifyOutput::RemoteInfo { info, .. } => process_identify_info( - &info, - &*peerstore.clone(), - original_addr, - addr_ttl, - )?, - _ => unreachable!( - "the identify protocol guarantees that we receive \ - remote information when we dial a node" - ), - }; + let listener = listener.map(move |connec| { + let peerstore = peerstore.clone(); + let identify_upgrade = identify_upgrade.clone(); + let fut = connec + .and_then(move |(connec, client_addr)| { + // Dial the address that connected to us and try upgrade with the + // identify protocol. + identify_upgrade + .clone() + .dial(client_addr.clone()) + .map_err(|_| { + IoError::new(IoErrorKind::Other, "couldn't dial back incoming node") + }) + .map(move |id| (id, connec)) + }) + .and_then(move |(dial, connec)| dial.map(move |dial| (dial, connec))) + .and_then(move |((identify, original_addr), connec)| { + // Compute the "real" address of the node (in the form `/p2p/...`) and add + // it to the peerstore. + let real_addr = match identify { + IdentifyOutput::RemoteInfo { info, .. } => process_identify_info( + &info, + &*peerstore.clone(), + original_addr, + addr_ttl, + )?, + _ => unreachable!( + "the identify protocol guarantees that we receive \ + remote information when we dial a node" + ), + }; - Ok((connec, real_addr)) - }); + Ok((connec, real_addr)) + }); - Box::new(fut) as Box> - }); + Box::new(fut) as Box> + }); - Ok((Box::new(listener) as Box<_>, new_addr)) - } + Ok((Box::new(listener) as Box<_>, new_addr)) + } - #[inline] - fn dial(self, addr: Multiaddr) -> Result { - match multiaddr_to_peerid(addr.clone()) { - Ok(peer_id) => { - // If the multiaddress is a peer ID, try each known multiaddress (taken from the - // peerstore) one by one. - let addrs = self.peerstore - .deref() - .peer(&peer_id) - .into_iter() - .flat_map(|peer| peer.addrs()) - .collect::>() - .into_iter(); + #[inline] + fn dial(self, addr: Multiaddr) -> Result { + match multiaddr_to_peerid(addr.clone()) { + Ok(peer_id) => { + // If the multiaddress is a peer ID, try each known multiaddress (taken from the + // peerstore) one by one. + let addrs = self.peerstore + .deref() + .peer(&peer_id) + .into_iter() + .flat_map(|peer| peer.addrs()) + .collect::>() + .into_iter(); - let transport = self.transport; - let future = stream::iter_ok(addrs) - // Try to dial each address through the transport. - .filter_map(move |addr| transport.clone().dial(addr).ok()) - .and_then(move |dial| dial) - // Pick the first non-failing dial result. - .then(|res| Ok(res)) - .filter_map(|res| res.ok()) - .into_future() - .map_err(|(err, _)| err) - .and_then(|(val, _)| val.ok_or(IoErrorKind::InvalidData.into())) // TODO: wrong error - .map(move |(socket, _inner_client_addr)| (socket, addr)); + let transport = self.transport; + let future = stream::iter_ok(addrs) + // Try to dial each address through the transport. + .filter_map(move |addr| transport.clone().dial(addr).ok()) + .and_then(move |dial| dial) + // Pick the first non-failing dial result. + .then(|res| Ok(res)) + .filter_map(|res| res.ok()) + .into_future() + .map_err(|(err, _)| err) + .and_then(|(val, _)| val.ok_or(IoErrorKind::InvalidData.into())) // TODO: wrong error + .map(move |(socket, _inner_client_addr)| (socket, addr)); - Ok(Box::new(future) as Box<_>) - } + Ok(Box::new(future) as Box<_>) + } - Err(addr) => { - // If the multiaddress is something else, propagate it to the underlying transport - // and identify the node. - let transport = self.transport; - let identify_upgrade = transport.clone().with_upgrade(IdentifyProtocolConfig); + Err(addr) => { + // If the multiaddress is something else, propagate it to the underlying transport + // and identify the node. + let transport = self.transport; + let identify_upgrade = transport.clone().with_upgrade(IdentifyProtocolConfig); - // We dial a first time the node and upgrade it to identify. - let dial = match identify_upgrade.dial(addr) { - Ok(d) => d, - Err((_, addr)) => { - let id = IdentifyTransport { - transport, - peerstore: self.peerstore, - addr_ttl: self.addr_ttl, - }; - return Err((id, addr)); - } - }; + // We dial a first time the node and upgrade it to identify. + let dial = match identify_upgrade.dial(addr) { + Ok(d) => d, + Err((_, addr)) => { + let id = IdentifyTransport { + transport, + peerstore: self.peerstore, + addr_ttl: self.addr_ttl, + }; + return Err((id, addr)); + } + }; - let peerstore = self.peerstore; - let addr_ttl = self.addr_ttl; + let peerstore = self.peerstore; + let addr_ttl = self.addr_ttl; - let future = dial.and_then(move |identify| { - // On success, store the information in the peerstore and compute the - // "real" address of the node (of the form `/p2p/...`). - let (real_addr, old_addr); - match identify { - (IdentifyOutput::RemoteInfo { info, .. }, a) => { - old_addr = a.clone(); - real_addr = process_identify_info(&info, &*peerstore, a, addr_ttl)?; - } - _ => unreachable!( - "the identify protocol guarantees that we receive \ - remote information when we dial a node" - ), - }; + let future = dial.and_then(move |identify| { + // On success, store the information in the peerstore and compute the + // "real" address of the node (of the form `/p2p/...`). + let (real_addr, old_addr); + match identify { + (IdentifyOutput::RemoteInfo { info, .. }, a) => { + old_addr = a.clone(); + real_addr = process_identify_info(&info, &*peerstore, a, addr_ttl)?; + } + _ => unreachable!( + "the identify protocol guarantees that we receive \ + remote information when we dial a node" + ), + }; - // Then dial the same node again. - Ok(transport - .dial(old_addr) - .unwrap_or_else(|_| { - panic!("the same multiaddr was determined to be valid earlier") - }) - .into_future() - .map(move |(dial, _wrong_addr)| (dial, real_addr))) - }).flatten(); + // Then dial the same node again. + Ok(transport + .dial(old_addr) + .unwrap_or_else(|_| { + panic!("the same multiaddr was determined to be valid earlier") + }) + .into_future() + .map(move |(dial, _wrong_addr)| (dial, real_addr))) + }).flatten(); - Ok(Box::new(future) as Box<_>) - } - } - } + Ok(Box::new(future) as Box<_>) + } + } + } - #[inline] - fn nat_traversal(&self, a: &Multiaddr, b: &Multiaddr) -> Option { - self.transport.nat_traversal(a, b) - } + #[inline] + fn nat_traversal(&self, a: &Multiaddr, b: &Multiaddr) -> Option { + self.transport.nat_traversal(a, b) + } } impl MuxedTransport for IdentifyTransport where - Trans: MuxedTransport + Clone + 'static, - PStoreRef: Deref + Clone + 'static, - for<'r> &'r PStore: Peerstore, + Trans: MuxedTransport + Clone + 'static, + PStoreRef: Deref + Clone + 'static, + for<'r> &'r PStore: Peerstore, { - type Incoming = Box>; - type IncomingUpgrade = Box>; + type Incoming = Box>; + type IncomingUpgrade = Box>; - #[inline] - fn next_incoming(self) -> Self::Incoming { - let identify_upgrade = self.transport.clone().with_upgrade(IdentifyProtocolConfig); - let peerstore = self.peerstore; - let addr_ttl = self.addr_ttl; + #[inline] + fn next_incoming(self) -> Self::Incoming { + let identify_upgrade = self.transport.clone().with_upgrade(IdentifyProtocolConfig); + let peerstore = self.peerstore; + let addr_ttl = self.addr_ttl; - let future = self.transport - .next_incoming() - .map(move |incoming| { - let future = incoming - .and_then(move |(connec, client_addr)| { - // On an incoming connection, dial back the node and upgrade to the identify - // protocol. - identify_upgrade - .clone() - .dial(client_addr.clone()) - .map_err(|_| { - IoError::new(IoErrorKind::Other, "couldn't dial back incoming node") - }) - .map(move |id| (id, connec)) - }) - .and_then(move |(dial, connec)| dial.map(move |dial| (dial, connec))) - .and_then(move |(identify, connec)| { - // Add the info to the peerstore and compute the "real" address of the node (in - // the form `/p2p/...`). - let real_addr = match identify { - (IdentifyOutput::RemoteInfo { info, .. }, old_addr) => { - process_identify_info(&info, &*peerstore, old_addr, addr_ttl)? - } - _ => unreachable!( - "the identify protocol guarantees that we receive remote \ - information when we dial a node" - ), - }; + let future = self.transport.next_incoming().map(move |incoming| { + let future = incoming + .and_then(move |(connec, client_addr)| { + // On an incoming connection, dial back the node and upgrade to the identify + // protocol. + identify_upgrade + .clone() + .dial(client_addr.clone()) + .map_err(|_| { + IoError::new(IoErrorKind::Other, "couldn't dial back incoming node") + }) + .map(move |id| (id, connec)) + }) + .and_then(move |(dial, connec)| dial.map(move |dial| (dial, connec))) + .and_then(move |(identify, connec)| { + // Add the info to the peerstore and compute the "real" address of the node (in + // the form `/p2p/...`). + let real_addr = match identify { + (IdentifyOutput::RemoteInfo { info, .. }, old_addr) => { + process_identify_info(&info, &*peerstore, old_addr, addr_ttl)? + } + _ => unreachable!( + "the identify protocol guarantees that we receive remote \ + information when we dial a node" + ), + }; - Ok((connec, real_addr)) - }); + Ok((connec, real_addr)) + }); - Box::new(future) as Box> - }); + Box::new(future) as Box> + }); - Box::new(future) as Box<_> - } + Box::new(future) as Box<_> + } } // If the multiaddress is in the form `/p2p/...`, turn it into a `PeerId`. // Otherwise, return it as-is. fn multiaddr_to_peerid(addr: Multiaddr) -> Result { - let components = addr.iter().collect::>(); - if components.len() < 1 { - return Err(addr); - } + let components = addr.iter().collect::>(); + if components.len() < 1 { + return Err(addr); + } - match components.last() { - Some(&AddrComponent::P2P(ref peer_id)) | - Some(&AddrComponent::IPFS(ref peer_id)) => { - // TODO: `peer_id` is sometimes in fact a CID here - match PeerId::from_bytes(peer_id.clone()) { - Ok(peer_id) => Ok(peer_id), - Err(_) => Err(addr), - } - } - _ => Err(addr), - } + match components.last() { + Some(&AddrComponent::P2P(ref peer_id)) | Some(&AddrComponent::IPFS(ref peer_id)) => { + // TODO: `peer_id` is sometimes in fact a CID here + match PeerId::from_bytes(peer_id.clone()) { + Ok(peer_id) => Ok(peer_id), + Err(_) => Err(addr), + } + } + _ => Err(addr), + } } // When passed the information sent by a remote, inserts the remote into the given peerstore and // returns a multiaddr of the format `/p2p/...` corresponding to this node. // // > **Note**: This function is highly-specific, but this precise behaviour is needed in multiple -// > different places in the code. +// > different places in the code. fn process_identify_info

( - info: &IdentifyInfo, - peerstore: P, - client_addr: Multiaddr, - ttl: Duration, + info: &IdentifyInfo, + peerstore: P, + client_addr: Multiaddr, + ttl: Duration, ) -> Result where - P: Peerstore, + P: Peerstore, { - let peer_id = PeerId::from_public_key(&info.public_key); - peerstore - .peer_or_create(&peer_id) - .add_addr(client_addr, ttl); - Ok(AddrComponent::P2P(peer_id.into_bytes()).into()) + let peer_id = PeerId::from_public_key(&info.public_key); + peerstore + .peer_or_create(&peer_id) + .add_addr(client_addr, ttl); + Ok(AddrComponent::P2P(peer_id.into_bytes()).into()) } #[cfg(test)] mod tests { - extern crate libp2p_tcp_transport; - extern crate tokio_core; + extern crate libp2p_tcp_transport; + extern crate tokio_core; - use self::libp2p_tcp_transport::TcpConfig; - use self::tokio_core::reactor::Core; - use IdentifyTransport; - use futures::{Future, Stream}; - use libp2p_peerstore::{PeerAccess, PeerId, Peerstore}; - use libp2p_peerstore::memory_peerstore::MemoryPeerstore; - use libp2p_swarm::Transport; - use multiaddr::{AddrComponent, Multiaddr}; - use std::io::Error as IoError; - use std::iter; - use std::sync::Arc; - use std::time::Duration; + use self::libp2p_tcp_transport::TcpConfig; + use self::tokio_core::reactor::Core; + use IdentifyTransport; + use futures::{Future, Stream}; + use libp2p_peerstore::{PeerAccess, PeerId, Peerstore}; + use libp2p_peerstore::memory_peerstore::MemoryPeerstore; + use libp2p_swarm::Transport; + use multiaddr::{AddrComponent, Multiaddr}; + use std::io::Error as IoError; + use std::iter; + use std::sync::Arc; + use std::time::Duration; - #[test] - fn dial_peer_id() { - // When we dial an `/p2p/...` address, the `IdentifyTransport` should look into the - // peerstore and dial one of the known multiaddresses of the node instead. + #[test] + fn dial_peer_id() { + // When we dial an `/p2p/...` address, the `IdentifyTransport` should look into the + // peerstore and dial one of the known multiaddresses of the node instead. - #[derive(Debug, Clone)] - struct UnderlyingTrans { - inner: TcpConfig, - } - impl Transport for UnderlyingTrans { - type RawConn = ::RawConn; - type Listener = Box>; - type ListenerUpgrade = Box>; - type Dial = ::Dial; - #[inline] - fn listen_on( - self, - _: Multiaddr, - ) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { - unreachable!() - } - #[inline] - fn dial(self, addr: Multiaddr) -> Result { - assert_eq!( - addr, - "/ip4/127.0.0.1/tcp/12345".parse::().unwrap() - ); - Ok(self.inner.dial(addr).unwrap_or_else(|_| panic!())) - } - #[inline] - fn nat_traversal(&self, a: &Multiaddr, b: &Multiaddr) -> Option { - self.inner.nat_traversal(a, b) - } - } + #[derive(Debug, Clone)] + struct UnderlyingTrans { + inner: TcpConfig, + } + impl Transport for UnderlyingTrans { + type RawConn = ::RawConn; + type Listener = Box>; + type ListenerUpgrade = Box>; + type Dial = ::Dial; + #[inline] + fn listen_on( + self, + _: Multiaddr, + ) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { + unreachable!() + } + #[inline] + fn dial(self, addr: Multiaddr) -> Result { + assert_eq!( + addr, + "/ip4/127.0.0.1/tcp/12345".parse::().unwrap() + ); + Ok(self.inner.dial(addr).unwrap_or_else(|_| panic!())) + } + #[inline] + fn nat_traversal(&self, a: &Multiaddr, b: &Multiaddr) -> Option { + self.inner.nat_traversal(a, b) + } + } - let peer_id = PeerId::from_public_key(&vec![1, 2, 3, 4]); + let peer_id = PeerId::from_public_key(&vec![1, 2, 3, 4]); - let peerstore = MemoryPeerstore::empty(); - peerstore.peer_or_create(&peer_id).add_addr( - "/ip4/127.0.0.1/tcp/12345".parse().unwrap(), - Duration::from_secs(3600), - ); + let peerstore = MemoryPeerstore::empty(); + peerstore.peer_or_create(&peer_id).add_addr( + "/ip4/127.0.0.1/tcp/12345".parse().unwrap(), + Duration::from_secs(3600), + ); - let mut core = Core::new().unwrap(); - let underlying = UnderlyingTrans { - inner: TcpConfig::new(core.handle()), - }; - let transport = IdentifyTransport::new(underlying, Arc::new(peerstore)); + let mut core = Core::new().unwrap(); + let underlying = UnderlyingTrans { + inner: TcpConfig::new(core.handle()), + }; + let transport = IdentifyTransport::new(underlying, Arc::new(peerstore)); - let future = transport - .dial(iter::once(AddrComponent::P2P(peer_id.into_bytes())).collect()) - .unwrap_or_else(|_| panic!()) - .then::<_, Result<(), ()>>(|_| Ok(())); + let future = transport + .dial(iter::once(AddrComponent::P2P(peer_id.into_bytes())).collect()) + .unwrap_or_else(|_| panic!()) + .then::<_, Result<(), ()>>(|_| Ok(())); - let _ = core.run(future).unwrap(); - } + let _ = core.run(future).unwrap(); + } } diff --git a/libp2p-peerstore/src/json_peerstore.rs b/libp2p-peerstore/src/json_peerstore.rs index 231e450f..41069bdc 100644 --- a/libp2p-peerstore/src/json_peerstore.rs +++ b/libp2p-peerstore/src/json_peerstore.rs @@ -23,11 +23,11 @@ use super::TTL; use PeerId; use base58::{FromBase58, ToBase58}; -use datastore::{Datastore, Query, JsonFileDatastore, JsonFileDatastoreEntry}; +use datastore::{Datastore, JsonFileDatastore, JsonFileDatastoreEntry, Query}; use futures::{Future, Stream}; use multiaddr::Multiaddr; -use peer_info::{PeerInfo, AddAddrBehaviour}; -use peerstore::{Peerstore, PeerAccess}; +use peer_info::{AddAddrBehaviour, PeerInfo}; +use peerstore::{PeerAccess, Peerstore}; use std::io::Error as IoError; use std::iter; use std::path::PathBuf; @@ -35,106 +35,111 @@ use std::vec::IntoIter as VecIntoIter; /// Peerstore backend that uses a Json file. pub struct JsonPeerstore { - store: JsonFileDatastore, + store: JsonFileDatastore, } impl JsonPeerstore { - /// Opens a new peerstore tied to a JSON file at the given path. - /// - /// If the file exists, this function will open it. In any case, flushing the peerstore or - /// destroying it will write to the file. - #[inline] - pub fn new

(path: P) -> Result - where P: Into - { - Ok(JsonPeerstore { store: JsonFileDatastore::new(path)? }) - } + /// Opens a new peerstore tied to a JSON file at the given path. + /// + /// If the file exists, this function will open it. In any case, flushing the peerstore or + /// destroying it will write to the file. + #[inline] + pub fn new

(path: P) -> Result + where + P: Into, + { + Ok(JsonPeerstore { + store: JsonFileDatastore::new(path)?, + }) + } - /// Flushes the content of the peer store to the disk. - /// - /// This function can only fail in case of a disk access error. If an error occurs, any change - /// to the peerstore that was performed since the last successful flush will be lost. No data - /// will be corrupted. - #[inline] - pub fn flush(&self) -> Result<(), IoError> { - self.store.flush() - } + /// Flushes the content of the peer store to the disk. + /// + /// This function can only fail in case of a disk access error. If an error occurs, any change + /// to the peerstore that was performed since the last successful flush will be lost. No data + /// will be corrupted. + #[inline] + pub fn flush(&self) -> Result<(), IoError> { + self.store.flush() + } } impl<'a> Peerstore for &'a JsonPeerstore { - type PeerAccess = JsonPeerstoreAccess<'a>; - type PeersIter = Box>; + type PeerAccess = JsonPeerstoreAccess<'a>; + type PeersIter = Box>; - #[inline] - fn peer(self, peer_id: &PeerId) -> Option { - let hash = peer_id.as_bytes().to_base58(); - self.store.lock(hash.into()).map(JsonPeerstoreAccess) - } + #[inline] + fn peer(self, peer_id: &PeerId) -> Option { + let hash = peer_id.as_bytes().to_base58(); + self.store.lock(hash.into()).map(JsonPeerstoreAccess) + } - #[inline] - fn peer_or_create(self, peer_id: &PeerId) -> Self::PeerAccess { - let hash = peer_id.as_bytes().to_base58(); - JsonPeerstoreAccess(self.store.lock_or_create(hash.into())) - } + #[inline] + fn peer_or_create(self, peer_id: &PeerId) -> Self::PeerAccess { + let hash = peer_id.as_bytes().to_base58(); + JsonPeerstoreAccess(self.store.lock_or_create(hash.into())) + } - fn peers(self) -> Self::PeersIter { - let query = self.store.query(Query { - prefix: "".into(), - filters: vec![], - orders: vec![], - skip: 0, - limit: u64::max_value(), - keys_only: true, - }); + fn peers(self) -> Self::PeersIter { + let query = self.store.query(Query { + prefix: "".into(), + filters: vec![], + orders: vec![], + skip: 0, + limit: u64::max_value(), + keys_only: true, + }); - let list = query.filter_map(|(key, _)| { - // We filter out invalid elements. This can happen if the JSON storage file was - // corrupted or manually modified by the user. - PeerId::from_bytes(key.from_base58().ok()?).ok() - }) - .collect() - .wait(); // Wait can never block for the JSON datastore. + let list = query + .filter_map(|(key, _)| { + // We filter out invalid elements. This can happen if the JSON storage file was + // corrupted or manually modified by the user. + PeerId::from_bytes(key.from_base58().ok()?).ok() + }) + .collect() + .wait(); // Wait can never block for the JSON datastore. - // Need to handle I/O errors. Again we just ignore. - if let Ok(list) = list { - Box::new(list.into_iter()) as Box<_> - } else { - Box::new(iter::empty()) as Box<_> - } - } + // Need to handle I/O errors. Again we just ignore. + if let Ok(list) = list { + Box::new(list.into_iter()) as Box<_> + } else { + Box::new(iter::empty()) as Box<_> + } + } } pub struct JsonPeerstoreAccess<'a>(JsonFileDatastoreEntry<'a, PeerInfo>); impl<'a> PeerAccess for JsonPeerstoreAccess<'a> { - type AddrsIter = VecIntoIter; + type AddrsIter = VecIntoIter; - #[inline] - fn addrs(&self) -> Self::AddrsIter { - self.0.addrs().cloned().collect::>().into_iter() - } + #[inline] + fn addrs(&self) -> Self::AddrsIter { + self.0.addrs().cloned().collect::>().into_iter() + } - #[inline] - fn add_addr(&mut self, addr: Multiaddr, ttl: TTL) { - self.0.add_addr(addr, ttl, AddAddrBehaviour::IgnoreTtlIfInferior); - } + #[inline] + fn add_addr(&mut self, addr: Multiaddr, ttl: TTL) { + self.0 + .add_addr(addr, ttl, AddAddrBehaviour::IgnoreTtlIfInferior); + } - #[inline] - fn set_addr_ttl(&mut self, addr: Multiaddr, ttl: TTL) { - self.0.add_addr(addr, ttl, AddAddrBehaviour::OverwriteTtl); - } + #[inline] + fn set_addr_ttl(&mut self, addr: Multiaddr, ttl: TTL) { + self.0.add_addr(addr, ttl, AddAddrBehaviour::OverwriteTtl); + } - #[inline] - fn clear_addrs(&mut self) { - self.0.set_addrs(iter::empty()); - } + #[inline] + fn clear_addrs(&mut self) { + self.0.set_addrs(iter::empty()); + } } #[cfg(test)] mod tests { - extern crate tempfile; - peerstore_tests!( - {::json_peerstore::JsonPeerstore::new(temp_file.path()).unwrap()} - {let temp_file = self::tempfile::NamedTempFile::new().unwrap()} - ); + extern crate tempfile; + peerstore_tests!( + {::json_peerstore::JsonPeerstore::new(temp_file.path()).unwrap()} + {let temp_file = self::tempfile::NamedTempFile::new().unwrap()} + ); } diff --git a/libp2p-peerstore/src/lib.rs b/libp2p-peerstore/src/lib.rs index 9970d2f9..5b93ae7a 100644 --- a/libp2p-peerstore/src/lib.rs +++ b/libp2p-peerstore/src/lib.rs @@ -35,21 +35,21 @@ //! data rather than returning the error. //! //! # Example -//! +//! //! ``` //! extern crate multiaddr; //! extern crate libp2p_peerstore; -//! +//! //! # fn main() { //! use libp2p_peerstore::memory_peerstore::MemoryPeerstore; //! use libp2p_peerstore::{PeerId, Peerstore, PeerAccess}; //! use multiaddr::Multiaddr; //! use std::time::Duration; -//! +//! //! // In this example we use a `MemoryPeerstore`, but you can easily swap it for another backend. //! let mut peerstore = MemoryPeerstore::empty(); //! let peer_id = PeerId::from_public_key(&[1, 2, 3, 4]); -//! +//! //! // Let's write some information about a peer. //! { //! // `peer_or_create` mutably borrows the peerstore, so we have to do it in a local scope. @@ -57,7 +57,7 @@ //! peer.add_addr("/ip4/10.11.12.13/tcp/20000".parse::().unwrap(), //! Duration::from_millis(5000)); //! } -//! +//! //! // Now let's load back the info. //! { //! let mut peer = peerstore.peer(&peer_id).expect("peer doesn't exist in the peerstore"); @@ -80,7 +80,7 @@ extern crate serde_derive; use std::fmt; use base58::ToBase58; -pub use self::peerstore::{Peerstore, PeerAccess}; +pub use self::peerstore::{PeerAccess, Peerstore}; #[macro_use] mod peerstore_tests; @@ -141,17 +141,16 @@ impl PeerId { /// Returns the raw bytes of the hash of this `PeerId`. #[inline] pub fn hash(&self) -> &[u8] { - let multihash::Multihash { digest, .. } = multihash::decode(&self.multihash) - .expect("our inner value should always be valid"); + let multihash::Multihash { digest, .. } = + multihash::decode(&self.multihash).expect("our inner value should always be valid"); digest } /// Checks whether the public key passed as parameter matches the public key of this `PeerId`. pub fn is_public_key(&self, public_key: &[u8]) -> bool { - let multihash::Multihash { alg, .. } = multihash::decode(&self.multihash) - .expect("our inner value should always be valid"); - let compare = multihash::encode(alg, public_key) - .expect("unsupported multihash algorithm"); // TODO: what to do here? + let multihash::Multihash { alg, .. } = + multihash::decode(&self.multihash).expect("our inner value should always be valid"); + let compare = multihash::encode(alg, public_key).expect("unsupported multihash algorithm"); // TODO: what to do here? compare == self.multihash } } diff --git a/libp2p-peerstore/src/memory_peerstore.rs b/libp2p-peerstore/src/memory_peerstore.rs index d2aff6ef..36b47f41 100644 --- a/libp2p-peerstore/src/memory_peerstore.rs +++ b/libp2p-peerstore/src/memory_peerstore.rs @@ -24,8 +24,8 @@ use super::TTL; use PeerId; use multiaddr::Multiaddr; use owning_ref::OwningRefMut; -use peer_info::{PeerInfo, AddAddrBehaviour}; -use peerstore::{Peerstore, PeerAccess}; +use peer_info::{AddAddrBehaviour, PeerInfo}; +use peerstore::{PeerAccess, Peerstore}; use std::collections::HashMap; use std::iter; use std::sync::{Mutex, MutexGuard}; @@ -34,80 +34,83 @@ use std::vec::IntoIter as VecIntoIter; /// Implementation of the `Peerstore` trait that simply stores the peer information in memory. #[derive(Debug)] pub struct MemoryPeerstore { - store: Mutex>, + store: Mutex>, } impl MemoryPeerstore { - /// Initializes a new `MemoryPeerstore`. The database is initially empty. - #[inline] - pub fn empty() -> MemoryPeerstore { - MemoryPeerstore { store: Mutex::new(HashMap::new()) } - } + /// Initializes a new `MemoryPeerstore`. The database is initially empty. + #[inline] + pub fn empty() -> MemoryPeerstore { + MemoryPeerstore { + store: Mutex::new(HashMap::new()), + } + } } impl Default for MemoryPeerstore { - #[inline] - fn default() -> MemoryPeerstore { - MemoryPeerstore::empty() - } + #[inline] + fn default() -> MemoryPeerstore { + MemoryPeerstore::empty() + } } impl<'a> Peerstore for &'a MemoryPeerstore { - type PeerAccess = MemoryPeerstoreAccess<'a>; - type PeersIter = VecIntoIter; + type PeerAccess = MemoryPeerstoreAccess<'a>; + type PeersIter = VecIntoIter; - fn peer(self, peer_id: &PeerId) -> Option { - let lock = self.store.lock().unwrap(); - OwningRefMut::new(lock) - .try_map_mut(|n| n.get_mut(peer_id).ok_or(())) - .ok() - .map(MemoryPeerstoreAccess) - } + fn peer(self, peer_id: &PeerId) -> Option { + let lock = self.store.lock().unwrap(); + OwningRefMut::new(lock) + .try_map_mut(|n| n.get_mut(peer_id).ok_or(())) + .ok() + .map(MemoryPeerstoreAccess) + } - fn peer_or_create(self, peer_id: &PeerId) -> Self::PeerAccess { - let lock = self.store.lock().unwrap(); - let r = OwningRefMut::new(lock) - .map_mut(|n| n.entry(peer_id.clone()).or_insert_with(|| PeerInfo::new())); - MemoryPeerstoreAccess(r) - } + fn peer_or_create(self, peer_id: &PeerId) -> Self::PeerAccess { + let lock = self.store.lock().unwrap(); + let r = OwningRefMut::new(lock) + .map_mut(|n| n.entry(peer_id.clone()).or_insert_with(|| PeerInfo::new())); + MemoryPeerstoreAccess(r) + } - fn peers(self) -> Self::PeersIter { - let lock = self.store.lock().unwrap(); - lock.keys().cloned().collect::>().into_iter() - } + fn peers(self) -> Self::PeersIter { + let lock = self.store.lock().unwrap(); + lock.keys().cloned().collect::>().into_iter() + } } // Note: Rust doesn't provide a `MutexGuard::map` method, otherwise we could directly store a -// `MutexGuard<'a, (&'a PeerId, &'a PeerInfo)>`. -pub struct MemoryPeerstoreAccess<'a>(OwningRefMut>, PeerInfo>); +// `MutexGuard<'a, (&'a PeerId, &'a PeerInfo)>`. +pub struct MemoryPeerstoreAccess<'a>( + OwningRefMut>, PeerInfo>, +); impl<'a> PeerAccess for MemoryPeerstoreAccess<'a> { - type AddrsIter = VecIntoIter; + type AddrsIter = VecIntoIter; - #[inline] - fn addrs(&self) -> Self::AddrsIter { - self.0.addrs().cloned().collect::>().into_iter() - } + #[inline] + fn addrs(&self) -> Self::AddrsIter { + self.0.addrs().cloned().collect::>().into_iter() + } - #[inline] - fn add_addr(&mut self, addr: Multiaddr, ttl: TTL) { - self.0.add_addr(addr, ttl, AddAddrBehaviour::IgnoreTtlIfInferior); - } + #[inline] + fn add_addr(&mut self, addr: Multiaddr, ttl: TTL) { + self.0 + .add_addr(addr, ttl, AddAddrBehaviour::IgnoreTtlIfInferior); + } - #[inline] - fn set_addr_ttl(&mut self, addr: Multiaddr, ttl: TTL) { - self.0.add_addr(addr, ttl, AddAddrBehaviour::OverwriteTtl); - } + #[inline] + fn set_addr_ttl(&mut self, addr: Multiaddr, ttl: TTL) { + self.0.add_addr(addr, ttl, AddAddrBehaviour::OverwriteTtl); + } - #[inline] - fn clear_addrs(&mut self) { - self.0.set_addrs(iter::empty()); - } + #[inline] + fn clear_addrs(&mut self) { + self.0.set_addrs(iter::empty()); + } } #[cfg(test)] mod tests { - peerstore_tests!({ - ::memory_peerstore::MemoryPeerstore::empty() - }); + peerstore_tests!({ ::memory_peerstore::MemoryPeerstore::empty() }); } diff --git a/libp2p-peerstore/src/peer_info.rs b/libp2p-peerstore/src/peer_info.rs index cd651b76..187ca71c 100644 --- a/libp2p-peerstore/src/peer_info.rs +++ b/libp2p-peerstore/src/peer_info.rs @@ -28,7 +28,7 @@ use TTL; use multiaddr::Multiaddr; -use serde::{Serialize, Deserialize, Serializer, Deserializer}; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::de::Error as DeserializerError; use serde::ser::SerializeStruct; use std::cmp::Ordering; @@ -37,130 +37,133 @@ use std::time::{Duration, SystemTime, UNIX_EPOCH}; /// Information about a peer. #[derive(Debug, Clone, Default, PartialEq, Eq)] pub struct PeerInfo { - // Adresses, and the time at which they will be considered expired. - addrs: Vec<(Multiaddr, SystemTime)>, + // Adresses, and the time at which they will be considered expired. + addrs: Vec<(Multiaddr, SystemTime)>, } impl PeerInfo { - /// Builds a new empty `PeerInfo`. - #[inline] - pub fn new() -> PeerInfo { - PeerInfo { addrs: vec![] } - } + /// Builds a new empty `PeerInfo`. + #[inline] + pub fn new() -> PeerInfo { + PeerInfo { addrs: vec![] } + } - /// Returns the list of the non-expired addresses stored in this `PeerInfo`. - /// - /// > **Note**: Keep in mind that this function is racy because addresses can expire between - /// > the moment when you get them and the moment when you process them. - // TODO: use -> impl Iterator eventually - #[inline] - pub fn addrs<'a>(&'a self) -> Box + 'a> { - let now = SystemTime::now(); - Box::new(self.addrs.iter().filter_map(move |&(ref addr, ref expires)| if *expires >= now { - Some(addr) - } else { - None - })) - } + /// Returns the list of the non-expired addresses stored in this `PeerInfo`. + /// + /// > **Note**: Keep in mind that this function is racy because addresses can expire between + /// > the moment when you get them and the moment when you process them. + // TODO: use -> impl Iterator eventually + #[inline] + pub fn addrs<'a>(&'a self) -> Box + 'a> { + let now = SystemTime::now(); + Box::new(self.addrs.iter().filter_map( + move |&(ref addr, ref expires)| if *expires >= now { Some(addr) } else { None }, + )) + } - /// Sets the list of addresses and their time-to-live. - /// - /// This removes all previously-stored addresses and replaces them with new ones. - #[inline] - pub fn set_addrs(&mut self, addrs: I) - where I: IntoIterator - { - let now = SystemTime::now(); - self.addrs = addrs.into_iter().map(move |(addr, ttl)| (addr, now + ttl)).collect(); - } + /// Sets the list of addresses and their time-to-live. + /// + /// This removes all previously-stored addresses and replaces them with new ones. + #[inline] + pub fn set_addrs(&mut self, addrs: I) + where + I: IntoIterator, + { + let now = SystemTime::now(); + self.addrs = addrs + .into_iter() + .map(move |(addr, ttl)| (addr, now + ttl)) + .collect(); + } - /// Adds a single address and its time-to-live. - /// - /// If the peer info already knows about that address, then what happens depends on the - /// `behaviour` parameter. - pub fn add_addr(&mut self, addr: Multiaddr, ttl: TTL, behaviour: AddAddrBehaviour) { - let expires = SystemTime::now() + ttl; + /// Adds a single address and its time-to-live. + /// + /// If the peer info already knows about that address, then what happens depends on the + /// `behaviour` parameter. + pub fn add_addr(&mut self, addr: Multiaddr, ttl: TTL, behaviour: AddAddrBehaviour) { + let expires = SystemTime::now() + ttl; - if let Some(&mut (_, ref mut existing_expires)) = - self.addrs.iter_mut().find(|&&mut (ref a, _)| a == &addr) - { - if behaviour == AddAddrBehaviour::OverwriteTtl || *existing_expires < expires { - *existing_expires = expires; - } - return; - } + if let Some(&mut (_, ref mut existing_expires)) = + self.addrs.iter_mut().find(|&&mut (ref a, _)| a == &addr) + { + if behaviour == AddAddrBehaviour::OverwriteTtl || *existing_expires < expires { + *existing_expires = expires; + } + return; + } - self.addrs.push((addr, expires)); - } + self.addrs.push((addr, expires)); + } } /// Behaviour of the `add_addr` function. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum AddAddrBehaviour { - /// Always overwrite the existing TTL. - OverwriteTtl, - /// Don't overwrite if the TTL is larger. - IgnoreTtlIfInferior, + /// Always overwrite the existing TTL. + OverwriteTtl, + /// Don't overwrite if the TTL is larger. + IgnoreTtlIfInferior, } impl Serialize for PeerInfo { - fn serialize(&self, serializer: S) -> Result - where S: Serializer - { - let mut s = serializer.serialize_struct("PeerInfo", 2)?; - s.serialize_field( - "addrs", - &self.addrs - .iter() - .map(|&(ref addr, ref expires)| { - let addr = addr.to_bytes(); - let from_epoch = expires.duration_since(UNIX_EPOCH) - // This `unwrap_or` case happens if the user has their system time set to - // before EPOCH. Times-to-live will be be longer than expected, but it's a very - // improbable corner case and is not attackable in any way, so we don't really - // care. - .unwrap_or(Duration::new(0, 0)); - let secs = from_epoch.as_secs() - .saturating_mul(1_000) - .saturating_add(from_epoch.subsec_nanos() as u64 / 1_000_000); - (addr, secs) - }) - .collect::>(), - )?; - s.end() - } + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut s = serializer.serialize_struct("PeerInfo", 2)?; + s.serialize_field( + "addrs", + &self.addrs + .iter() + .map(|&(ref addr, ref expires)| { + let addr = addr.to_bytes(); + let from_epoch = expires.duration_since(UNIX_EPOCH) + // This `unwrap_or` case happens if the user has their system time set to + // before EPOCH. Times-to-live will be be longer than expected, but it's a very + // improbable corner case and is not attackable in any way, so we don't really + // care. + .unwrap_or(Duration::new(0, 0)); + let secs = from_epoch + .as_secs() + .saturating_mul(1_000) + .saturating_add(from_epoch.subsec_nanos() as u64 / 1_000_000); + (addr, secs) + }) + .collect::>(), + )?; + s.end() + } } impl<'de> Deserialize<'de> for PeerInfo { - fn deserialize(deserializer: D) -> Result - where D: Deserializer<'de> - { - // We deserialize to an intermdiate struct first, then turn that struct into a `PeerInfo`. - let interm = { - #[derive(Deserialize)] - struct Interm { - addrs: Vec<(String, u64)>, - } - Interm::deserialize(deserializer)? - }; + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + // We deserialize to an intermdiate struct first, then turn that struct into a `PeerInfo`. + let interm = { + #[derive(Deserialize)] + struct Interm { + addrs: Vec<(String, u64)>, + } + Interm::deserialize(deserializer)? + }; - let addrs = { - let mut out = Vec::with_capacity(interm.addrs.len()); - for (addr, since_epoch) in interm.addrs { - let addr = match addr.parse::() { - Ok(a) => a, - Err(err) => return Err(DeserializerError::custom(err)), - }; - let expires = UNIX_EPOCH + Duration::from_millis(since_epoch); - out.push((addr, expires)); - } - out - }; + let addrs = { + let mut out = Vec::with_capacity(interm.addrs.len()); + for (addr, since_epoch) in interm.addrs { + let addr = match addr.parse::() { + Ok(a) => a, + Err(err) => return Err(DeserializerError::custom(err)), + }; + let expires = UNIX_EPOCH + Duration::from_millis(since_epoch); + out.push((addr, expires)); + } + out + }; - Ok(PeerInfo { - addrs: addrs, - }) - } + Ok(PeerInfo { addrs: addrs }) + } } // The reason why we need to implement the PartialOrd trait is that the datastore library (a @@ -169,8 +172,8 @@ impl<'de> Deserialize<'de> for PeerInfo { // Since the struct that implements PartialOrd is internal and since we never use this ordering // feature, I think it's ok to have this code. impl PartialOrd for PeerInfo { - #[inline] - fn partial_cmp(&self, _other: &Self) -> Option { - None - } + #[inline] + fn partial_cmp(&self, _other: &Self) -> Option { + None + } } diff --git a/libp2p-peerstore/src/peerstore.rs b/libp2p-peerstore/src/peerstore.rs index c2210517..ab82ac76 100644 --- a/libp2p-peerstore/src/peerstore.rs +++ b/libp2p-peerstore/src/peerstore.rs @@ -30,69 +30,71 @@ use multiaddr::Multiaddr; /// Therefore this trait should likely be implemented on `&'a ConcretePeerstore` instead of /// on `ConcretePeerstore`. pub trait Peerstore { - /// Grants access to the a peer inside the peer store. - type PeerAccess: PeerAccess; - /// List of the peers in this peer store. - type PeersIter: Iterator; + /// Grants access to the a peer inside the peer store. + type PeerAccess: PeerAccess; + /// List of the peers in this peer store. + type PeersIter: Iterator; - /// Grants access to a peer by its ID. - fn peer(self, peer_id: &PeerId) -> Option; + /// Grants access to a peer by its ID. + fn peer(self, peer_id: &PeerId) -> Option; - /// Grants access to a peer by its ID or creates it. - fn peer_or_create(self, peer_id: &PeerId) -> Self::PeerAccess; + /// Grants access to a peer by its ID or creates it. + fn peer_or_create(self, peer_id: &PeerId) -> Self::PeerAccess; - /// Returns a list of peers in this peer store. - /// - /// Keep in mind that the trait implementation may allow new peers to be added or removed at - /// any time. If that is the case, you have to take into account that this is only an - /// indication. - fn peers(self) -> Self::PeersIter; + /// Returns a list of peers in this peer store. + /// + /// Keep in mind that the trait implementation may allow new peers to be added or removed at + /// any time. If that is the case, you have to take into account that this is only an + /// indication. + fn peers(self) -> Self::PeersIter; } /// Implemented on objects that represent an open access to a peer stored in a peer store. /// /// The exact semantics of "open access" depend on the trait implementation. pub trait PeerAccess { - /// Iterator returned by `addrs`. - type AddrsIter: Iterator; + /// Iterator returned by `addrs`. + type AddrsIter: Iterator; - /// Returns all known and non-expired addresses for a given peer. - /// - /// > **Note**: Keep in mind that this function is racy because addresses can expire between - /// > the moment when you get them and the moment when you process them. - fn addrs(&self) -> Self::AddrsIter; + /// Returns all known and non-expired addresses for a given peer. + /// + /// > **Note**: Keep in mind that this function is racy because addresses can expire between + /// > the moment when you get them and the moment when you process them. + fn addrs(&self) -> Self::AddrsIter; - /// Adds an address to a peer. - /// - /// If the manager already has this address stored and with a longer TTL, then the operation - /// is a no-op. - fn add_addr(&mut self, addr: Multiaddr, ttl: TTL); + /// Adds an address to a peer. + /// + /// If the manager already has this address stored and with a longer TTL, then the operation + /// is a no-op. + fn add_addr(&mut self, addr: Multiaddr, ttl: TTL); - // Similar to calling `add_addr` multiple times in a row. - #[inline] - fn add_addrs(&mut self, addrs: I, ttl: TTL) - where I: IntoIterator - { - for addr in addrs.into_iter() { - self.add_addr(addr, ttl); - } - } + // Similar to calling `add_addr` multiple times in a row. + #[inline] + fn add_addrs(&mut self, addrs: I, ttl: TTL) + where + I: IntoIterator, + { + for addr in addrs.into_iter() { + self.add_addr(addr, ttl); + } + } - /// Sets the TTL of an address of a peer. Adds the address if it is currently unknown. - /// - /// Contrary to `add_addr`, this operation is never a no-op. - #[inline] - fn set_addr_ttl(&mut self, addr: Multiaddr, ttl: TTL); + /// Sets the TTL of an address of a peer. Adds the address if it is currently unknown. + /// + /// Contrary to `add_addr`, this operation is never a no-op. + #[inline] + fn set_addr_ttl(&mut self, addr: Multiaddr, ttl: TTL); - // Similar to calling `set_addr_ttl` multiple times in a row. - fn set_addrs_ttl(&mut self, addrs: I, ttl: TTL) - where I: IntoIterator - { - for addr in addrs.into_iter() { - self.add_addr(addr, ttl); - } - } + // Similar to calling `set_addr_ttl` multiple times in a row. + fn set_addrs_ttl(&mut self, addrs: I, ttl: TTL) + where + I: IntoIterator, + { + for addr in addrs.into_iter() { + self.add_addr(addr, ttl); + } + } - /// Removes all previously stored addresses. - fn clear_addrs(&mut self); + /// Removes all previously stored addresses. + fn clear_addrs(&mut self); } diff --git a/libp2p-peerstore/src/peerstore_tests.rs b/libp2p-peerstore/src/peerstore_tests.rs index 96c95d9f..9f2a4edb 100644 --- a/libp2p-peerstore/src/peerstore_tests.rs +++ b/libp2p-peerstore/src/peerstore_tests.rs @@ -79,7 +79,8 @@ macro_rules! peerstore_tests { let peer_id = PeerId::from_public_key(&[1, 2, 3]); let addr = "/ip4/0.0.0.0/tcp/0".parse::().unwrap(); - peer_store.peer_or_create(&peer_id).add_addr(addr.clone(), Duration::from_millis(5000)); + peer_store.peer_or_create(&peer_id) + .add_addr(addr.clone(), Duration::from_millis(5000)); peer_store.peer(&peer_id).unwrap().clear_addrs(); let addrs = peer_store.peer(&peer_id).unwrap().addrs(); @@ -95,8 +96,10 @@ macro_rules! peerstore_tests { let addr1 = "/ip4/0.0.0.0/tcp/0".parse::().unwrap(); let addr2 = "/ip4/0.0.0.1/tcp/0".parse::().unwrap(); - peer_store.peer_or_create(&peer_id).add_addr(addr1.clone(), Duration::from_millis(5000)); - peer_store.peer_or_create(&peer_id).add_addr(addr2.clone(), Duration::from_millis(5000)); + peer_store.peer_or_create(&peer_id) + .add_addr(addr1.clone(), Duration::from_millis(5000)); + peer_store.peer_or_create(&peer_id) + .add_addr(addr2.clone(), Duration::from_millis(5000)); assert_eq!(peer_store.peer(&peer_id).unwrap().addrs().count(), 2); // `add_addr` must not overwrite the TTL because it's already higher @@ -114,11 +117,14 @@ macro_rules! peerstore_tests { let addr1 = "/ip4/0.0.0.0/tcp/0".parse::().unwrap(); let addr2 = "/ip4/0.0.0.1/tcp/0".parse::().unwrap(); - peer_store.peer_or_create(&peer_id).add_addr(addr1.clone(), Duration::from_millis(5000)); - peer_store.peer_or_create(&peer_id).add_addr(addr2.clone(), Duration::from_millis(5000)); + peer_store.peer_or_create(&peer_id) + .add_addr(addr1.clone(), Duration::from_millis(5000)); + peer_store.peer_or_create(&peer_id) + .add_addr(addr2.clone(), Duration::from_millis(5000)); assert_eq!(peer_store.peer(&peer_id).unwrap().addrs().count(), 2); - peer_store.peer_or_create(&peer_id).set_addr_ttl(addr1.clone(), Duration::from_millis(0)); + peer_store.peer_or_create(&peer_id) + .set_addr_ttl(addr1.clone(), Duration::from_millis(0)); thread::sleep(Duration::from_millis(2)); assert_eq!(peer_store.peer(&peer_id).unwrap().addrs().count(), 1); } diff --git a/libp2p-ping/src/lib.rs b/libp2p-ping/src/lib.rs index 05b120aa..4fd49648 100644 --- a/libp2p-ping/src/lib.rs +++ b/libp2p-ping/src/lib.rs @@ -57,21 +57,21 @@ //! extern crate libp2p_swarm; //! extern crate libp2p_tcp_transport; //! extern crate tokio_core; -//! +//! //! use futures::Future; //! use libp2p_ping::Ping; //! use libp2p_swarm::Transport; -//! +//! //! # fn main() { //! let mut core = tokio_core::reactor::Core::new().unwrap(); -//! +//! //! let ping_finished_future = libp2p_tcp_transport::TcpConfig::new(core.handle()) //! .with_upgrade(Ping) //! .dial("127.0.0.1:12345".parse::().unwrap()).unwrap_or_else(|_| panic!()) //! .and_then(|((mut pinger, service), _)| { //! pinger.ping().map_err(|_| panic!()).select(service).map_err(|_| panic!()) //! }); -//! +//! //! // Runs until the ping arrives. //! core.run(ping_finished_future).unwrap(); //! # } @@ -88,9 +88,9 @@ extern crate parking_lot; extern crate rand; extern crate tokio_io; -use bytes::{Bytes, BytesMut, BufMut}; +use bytes::{BufMut, Bytes, BytesMut}; use futures::{Future, Sink, Stream}; -use futures::future::{FutureResult, IntoFuture, loop_fn, Loop}; +use futures::future::{loop_fn, FutureResult, IntoFuture, Loop}; use futures::sync::{mpsc, oneshot}; use libp2p_swarm::Multiaddr; use libp2p_swarm::transport::{ConnectionUpgrade, Endpoint}; @@ -104,7 +104,7 @@ use std::io::Error as IoError; use std::iter; use std::sync::Arc; use tokio_io::{AsyncRead, AsyncWrite}; -use tokio_io::codec::{Encoder, Decoder}; +use tokio_io::codec::{Decoder, Encoder}; /// Represents a prototype for an upgrade to handle the ping protocol. /// @@ -114,136 +114,152 @@ use tokio_io::codec::{Encoder, Decoder}; pub struct Ping; impl ConnectionUpgrade for Ping - where C: AsyncRead + AsyncWrite + 'static +where + C: AsyncRead + AsyncWrite + 'static, { - type NamesIter = iter::Once<(Bytes, Self::UpgradeIdentifier)>; - type UpgradeIdentifier = (); + type NamesIter = iter::Once<(Bytes, Self::UpgradeIdentifier)>; + type UpgradeIdentifier = (); - #[inline] - fn protocol_names(&self) -> Self::NamesIter { - iter::once(("/ipfs/ping/1.0.0".into(), ())) - } + #[inline] + fn protocol_names(&self) -> Self::NamesIter { + iter::once(("/ipfs/ping/1.0.0".into(), ())) + } - type Output = (Pinger, Box>); - type Future = FutureResult; + type Output = (Pinger, Box>); + type Future = FutureResult; - #[inline] - fn upgrade(self, socket: C, _: Self::UpgradeIdentifier, _: Endpoint, remote_addr: &Multiaddr) - -> Self::Future - { - // # How does it work? - // - // All the actual processing is performed by the *ponger*. - // We use a channel in order to send ping requests from the pinger to the ponger. + #[inline] + fn upgrade( + self, + socket: C, + _: Self::UpgradeIdentifier, + _: Endpoint, + remote_addr: &Multiaddr, + ) -> Self::Future { + // # How does it work? + // + // All the actual processing is performed by the *ponger*. + // We use a channel in order to send ping requests from the pinger to the ponger. - let (tx, rx) = mpsc::channel(8); - // Ignore the errors if `tx` closed. `tx` is only ever closed if the ponger is closed, - // which means that the connection to the remote is closed. Therefore we make the `rx` - // never produce anything. - let rx = rx.then(|r| Ok(r.ok())).filter_map(|a| a); + let (tx, rx) = mpsc::channel(8); + // Ignore the errors if `tx` closed. `tx` is only ever closed if the ponger is closed, + // which means that the connection to the remote is closed. Therefore we make the `rx` + // never produce anything. + let rx = rx.then(|r| Ok(r.ok())).filter_map(|a| a); - let os_rng = match OsRng::new() { - Ok(r) => r, - Err(err) => return Err(err).into_future(), - }; + let os_rng = match OsRng::new() { + Ok(r) => r, + Err(err) => return Err(err).into_future(), + }; - let pinger = Pinger { - send: tx, - os_rng: os_rng, - }; + let pinger = Pinger { + send: tx, + os_rng: os_rng, + }; - // Hashmap that associates outgoing payloads to one-shot senders. - // TODO: can't figure out how to make it work without using an Arc/Mutex - let expected_pongs = Arc::new(Mutex::new(HashMap::with_capacity(4))); + // Hashmap that associates outgoing payloads to one-shot senders. + // TODO: can't figure out how to make it work without using an Arc/Mutex + let expected_pongs = Arc::new(Mutex::new(HashMap::with_capacity(4))); - let sink_stream = socket.framed(Codec).map(|msg| Message::Received(msg.freeze())); - let (sink, stream) = sink_stream.split(); + let sink_stream = socket + .framed(Codec) + .map(|msg| Message::Received(msg.freeze())); + let (sink, stream) = sink_stream.split(); - let remote_addr = if log_enabled!(target: "libp2p-ping", Level::Debug) { - Some(remote_addr.clone()) - } else { - None - }; + let remote_addr = if log_enabled!(target: "libp2p-ping", Level::Debug) { + Some(remote_addr.clone()) + } else { + None + }; - let future = loop_fn((sink, stream.select(rx)), move |(sink, stream)| { - let expected_pongs = expected_pongs.clone(); - let remote_addr = remote_addr.clone(); + let future = loop_fn((sink, stream.select(rx)), move |(sink, stream)| { + let expected_pongs = expected_pongs.clone(); + let remote_addr = remote_addr.clone(); - stream.into_future().map_err(|(err, _)| err).and_then(move |(message, stream)| { - let mut expected_pongs = expected_pongs.lock(); + stream + .into_future() + .map_err(|(err, _)| err) + .and_then(move |(message, stream)| { + let mut expected_pongs = expected_pongs.lock(); - if let Some(message) = message { - match message { - Message::Ping(payload, finished) => { - // Ping requested by the user through the `Pinger`. - debug!(target: "libp2p-ping", "Sending ping to {:?} with payload {:?}", - remote_addr.expect("debug log level is enabled"), payload); - expected_pongs.insert(payload.clone(), finished); - Box::new( - sink.send(payload).map(|sink| Loop::Continue((sink, stream))), - ) as Box> - } - Message::Received(payload) => { - // Received a payload from the remote. - if let Some(fut) = expected_pongs.remove(&payload) { - // Payload was ours. Signalling future. - // Errors can happen if the user closed the receiving end of - // the future, which is fine to ignore. - debug!(target: "libp2p-ping", "Received pong from {:?} \ - (payload={:?}) ; ping fufilled", - remote_addr.expect("debug log level is enabled"), payload); - let _ = fut.send(()); - Box::new(Ok(Loop::Continue((sink, stream))).into_future()) as - Box> - } else { - // Payload was not ours. Sending it back. - debug!(target: "libp2p-ping", "Received ping from {:?} \ - (payload={:?}) ; sending back", - remote_addr.expect("debug log level is enabled"), payload); - Box::new( - sink.send(payload).map(|sink| Loop::Continue((sink, stream))), - ) as Box> - } - } - } + if let Some(message) = message { + match message { + Message::Ping(payload, finished) => { + // Ping requested by the user through the `Pinger`. + debug!(target: "libp2p-ping", "Sending ping to {:?} with payload {:?}", + remote_addr.expect("debug log level is enabled"), payload); + expected_pongs.insert(payload.clone(), finished); + Box::new( + sink.send(payload) + .map(|sink| Loop::Continue((sink, stream))), + ) + as Box> + } + Message::Received(payload) => { + // Received a payload from the remote. + if let Some(fut) = expected_pongs.remove(&payload) { + // Payload was ours. Signalling future. + // Errors can happen if the user closed the receiving end of + // the future, which is fine to ignore. + debug!(target: "libp2p-ping", "Received pong from {:?} \ + (payload={:?}) ; ping fufilled", + remote_addr.expect("debug log level is enabled"), payload); + let _ = fut.send(()); + Box::new(Ok(Loop::Continue((sink, stream))).into_future()) + as Box> + } else { + // Payload was not ours. Sending it back. + debug!(target: "libp2p-ping", "Received ping from {:?} \ + (payload={:?}) ; sending back", + remote_addr.expect("debug log level is enabled"), payload); + Box::new( + sink.send(payload) + .map(|sink| Loop::Continue((sink, stream))), + ) + as Box> + } + } + } + } else { + Box::new(Ok(Loop::Break(())).into_future()) + as Box> + } + }) + }); - } else { - Box::new(Ok(Loop::Break(())).into_future()) as Box> - } - }) - }); - - Ok((pinger, Box::new(future) as Box<_>)).into_future() - } + Ok((pinger, Box::new(future) as Box<_>)).into_future() + } } /// Controller for the ping service. Makes it possible to send pings to the remote. pub struct Pinger { - send: mpsc::Sender, - os_rng: OsRng, + send: mpsc::Sender, + os_rng: OsRng, } impl Pinger { - /// Sends a ping. Returns a future that is signaled when a pong is received. - /// - /// **Note**: Please be aware that there is no timeout on the ping. You should handle the - /// timeout yourself when you call this function. - pub fn ping(&mut self) -> Box>> { - let (tx, rx) = oneshot::channel(); - let payload: [u8; 32] = Rand::rand(&mut self.os_rng); - debug!(target: "libp2p-ping", "Preparing for ping with payload {:?}", payload); - // Ignore errors if the ponger has been already destroyed. The returned future will never - // be signalled. - let fut = self.send.clone().send(Message::Ping(Bytes::from(payload.to_vec()), tx)) - .from_err() - .and_then(|_| rx.from_err()); - Box::new(fut) as Box<_> - } + /// Sends a ping. Returns a future that is signaled when a pong is received. + /// + /// **Note**: Please be aware that there is no timeout on the ping. You should handle the + /// timeout yourself when you call this function. + pub fn ping(&mut self) -> Box>> { + let (tx, rx) = oneshot::channel(); + let payload: [u8; 32] = Rand::rand(&mut self.os_rng); + debug!(target: "libp2p-ping", "Preparing for ping with payload {:?}", payload); + // Ignore errors if the ponger has been already destroyed. The returned future will never + // be signalled. + let fut = self.send + .clone() + .send(Message::Ping(Bytes::from(payload.to_vec()), tx)) + .from_err() + .and_then(|_| rx.from_err()); + Box::new(fut) as Box<_> + } } enum Message { - Ping(Bytes, oneshot::Sender<()>), - Received(Bytes), + Ping(Bytes, oneshot::Sender<()>), + Received(Bytes), } // Implementation of the `Codec` trait of tokio-io. Splits frames into groups of 32 bytes. @@ -251,102 +267,137 @@ enum Message { struct Codec; impl Decoder for Codec { - type Item = BytesMut; - type Error = IoError; + type Item = BytesMut; + type Error = IoError; - #[inline] - fn decode(&mut self, buf: &mut BytesMut) -> Result, IoError> { - if buf.len() >= 32 { Ok(Some(buf.split_to(32))) } else { Ok(None) } - } + #[inline] + fn decode(&mut self, buf: &mut BytesMut) -> Result, IoError> { + if buf.len() >= 32 { + Ok(Some(buf.split_to(32))) + } else { + Ok(None) + } + } } impl Encoder for Codec { - type Item = Bytes; - type Error = IoError; + type Item = Bytes; + type Error = IoError; - #[inline] - fn encode(&mut self, mut data: Bytes, buf: &mut BytesMut) -> Result<(), IoError> { - if data.len() != 0 { - let split = 32 * (1 + ((data.len() - 1) / 32)); - buf.put(data.split_to(split)); - } - Ok(()) - } + #[inline] + fn encode(&mut self, mut data: Bytes, buf: &mut BytesMut) -> Result<(), IoError> { + if data.len() != 0 { + let split = 32 * (1 + ((data.len() - 1) / 32)); + buf.put(data.split_to(split)); + } + Ok(()) + } } #[cfg(test)] mod tests { - extern crate tokio_core; + extern crate tokio_core; - use self::tokio_core::net::TcpListener; - use self::tokio_core::net::TcpStream; - use self::tokio_core::reactor::Core; - use super::Ping; - use futures::future::join_all; - use futures::Future; - use futures::Stream; - use libp2p_swarm::transport::{ConnectionUpgrade, Endpoint}; + use self::tokio_core::net::TcpListener; + use self::tokio_core::net::TcpStream; + use self::tokio_core::reactor::Core; + use super::Ping; + use futures::future::join_all; + use futures::Future; + use futures::Stream; + use libp2p_swarm::transport::{ConnectionUpgrade, Endpoint}; - #[test] - fn ping_pong() { - let mut core = Core::new().unwrap(); + #[test] + fn ping_pong() { + let mut core = Core::new().unwrap(); - let listener = TcpListener::bind(&"127.0.0.1:0".parse().unwrap(), &core.handle()).unwrap(); - let listener_addr = listener.local_addr().unwrap(); + let listener = TcpListener::bind(&"127.0.0.1:0".parse().unwrap(), &core.handle()).unwrap(); + let listener_addr = listener.local_addr().unwrap(); - let server = listener.incoming() - .into_future() - .map_err(|(e, _)| e.into()) - .and_then(|(c, _)| { - Ping.upgrade(c.unwrap().0, (), Endpoint::Listener, - &"/ip4/127.0.0.1/tcp/10000".parse().unwrap()) - }) - .and_then(|(mut pinger, service)| { - pinger.ping().map_err(|_| panic!()).select(service).map_err(|_| panic!()) - }); + let server = listener + .incoming() + .into_future() + .map_err(|(e, _)| e.into()) + .and_then(|(c, _)| { + Ping.upgrade( + c.unwrap().0, + (), + Endpoint::Listener, + &"/ip4/127.0.0.1/tcp/10000".parse().unwrap(), + ) + }) + .and_then(|(mut pinger, service)| { + pinger + .ping() + .map_err(|_| panic!()) + .select(service) + .map_err(|_| panic!()) + }); - let client = TcpStream::connect(&listener_addr, &core.handle()) - .map_err(|e| e.into()) - .and_then(|c| { - Ping.upgrade(c, (), Endpoint::Dialer, &"/ip4/127.0.0.1/tcp/10000".parse().unwrap()) - }) - .and_then(|(mut pinger, service)| { - pinger.ping().map_err(|_| panic!()).select(service).map_err(|_| panic!()) - }); + let client = TcpStream::connect(&listener_addr, &core.handle()) + .map_err(|e| e.into()) + .and_then(|c| { + Ping.upgrade( + c, + (), + Endpoint::Dialer, + &"/ip4/127.0.0.1/tcp/10000".parse().unwrap(), + ) + }) + .and_then(|(mut pinger, service)| { + pinger + .ping() + .map_err(|_| panic!()) + .select(service) + .map_err(|_| panic!()) + }); - core.run(server.join(client)).unwrap(); - } + core.run(server.join(client)).unwrap(); + } - #[test] - fn multipings() { - // Check that we can send multiple pings in a row and it will still work. - let mut core = Core::new().unwrap(); + #[test] + fn multipings() { + // Check that we can send multiple pings in a row and it will still work. + let mut core = Core::new().unwrap(); - let listener = TcpListener::bind(&"127.0.0.1:0".parse().unwrap(), &core.handle()).unwrap(); - let listener_addr = listener.local_addr().unwrap(); + let listener = TcpListener::bind(&"127.0.0.1:0".parse().unwrap(), &core.handle()).unwrap(); + let listener_addr = listener.local_addr().unwrap(); - let server = listener.incoming() - .into_future() - .map_err(|(e, _)| e.into()) - .and_then(|(c, _)| { - Ping.upgrade(c.unwrap().0, (), Endpoint::Listener, - &"/ip4/127.0.0.1/tcp/10000".parse().unwrap()) - }) - .and_then(|(_, service)| service.map_err(|_| panic!())); + let server = listener + .incoming() + .into_future() + .map_err(|(e, _)| e.into()) + .and_then(|(c, _)| { + Ping.upgrade( + c.unwrap().0, + (), + Endpoint::Listener, + &"/ip4/127.0.0.1/tcp/10000".parse().unwrap(), + ) + }) + .and_then(|(_, service)| service.map_err(|_| panic!())); - let client = TcpStream::connect(&listener_addr, &core.handle()) - .map_err(|e| e.into()) - .and_then(|c| Ping.upgrade(c, (), Endpoint::Dialer, - &"/ip4/127.0.0.1/tcp/1000".parse().unwrap())) - .and_then(|(mut pinger, service)| { - let pings = (0 .. 20).map(move |_| { - pinger.ping().map_err(|_| ()) - }); + let client = TcpStream::connect(&listener_addr, &core.handle()) + .map_err(|e| e.into()) + .and_then(|c| { + Ping.upgrade( + c, + (), + Endpoint::Dialer, + &"/ip4/127.0.0.1/tcp/1000".parse().unwrap(), + ) + }) + .and_then(|(mut pinger, service)| { + let pings = (0..20).map(move |_| pinger.ping().map_err(|_| ())); - join_all(pings).map(|_| ()).map_err(|_| panic!()) - .select(service).map(|_| ()).map_err(|_| panic!()) - }); + join_all(pings) + .map(|_| ()) + .map_err(|_| panic!()) + .select(service) + .map(|_| ()) + .map_err(|_| panic!()) + }); - core.run(server.select(client)).unwrap_or_else(|_| panic!()); - } + core.run(server.select(client)).unwrap_or_else(|_| panic!()); + } } diff --git a/libp2p-secio/src/algo_support.rs b/libp2p-secio/src/algo_support.rs index a7afb637..454060cc 100644 --- a/libp2p-secio/src/algo_support.rs +++ b/libp2p-secio/src/algo_support.rs @@ -24,72 +24,72 @@ //! helps you with. macro_rules! supported_impl { - ($mod_name:ident: $ty:ty, $($name:expr => $val:expr),*,) => ( - pub mod $mod_name { - use std::cmp::Ordering; - #[allow(unused_imports)] - use crypto::aes::KeySize; - #[allow(unused_imports)] - use ring::{agreement, digest}; - use error::SecioError; + ($mod_name:ident: $ty:ty, $($name:expr => $val:expr),*,) => ( + pub mod $mod_name { + use std::cmp::Ordering; + #[allow(unused_imports)] + use crypto::aes::KeySize; + #[allow(unused_imports)] + use ring::{agreement, digest}; + use error::SecioError; - /// String to advertise to the remote. - pub const PROPOSITION_STRING: &'static str = concat_comma!($($name),*); + /// String to advertise to the remote. + pub const PROPOSITION_STRING: &'static str = concat_comma!($($name),*); - /// Choose which algorithm to use based on the remote's advertised list. - pub fn select_best(hashes_ordering: Ordering, input: &str) -> Result<$ty, SecioError> { - match hashes_ordering { - Ordering::Less | Ordering::Equal => { - for second_elem in input.split(',') { - $( - if $name == second_elem { - return Ok($val); - } - )+ - } - }, - Ordering::Greater => { - $( - for second_elem in input.split(',') { - if $name == second_elem { - return Ok($val); - } - } - )+ - }, - }; + /// Choose which algorithm to use based on the remote's advertised list. + pub fn select_best(hashes_ordering: Ordering, input: &str) -> Result<$ty, SecioError> { + match hashes_ordering { + Ordering::Less | Ordering::Equal => { + for second_elem in input.split(',') { + $( + if $name == second_elem { + return Ok($val); + } + )+ + } + }, + Ordering::Greater => { + $( + for second_elem in input.split(',') { + if $name == second_elem { + return Ok($val); + } + } + )+ + }, + }; - Err(SecioError::NoSupportIntersection(PROPOSITION_STRING, input.to_owned())) - } - } - ); + Err(SecioError::NoSupportIntersection(PROPOSITION_STRING, input.to_owned())) + } + } + ); } // Concatenates several strings with commas. macro_rules! concat_comma { - ($first:expr, $($rest:expr),*) => ( - concat!($first $(, ',', $rest)*) - ); + ($first:expr, $($rest:expr),*) => ( + concat!($first $(, ',', $rest)*) + ); } // TODO: there's no library in the Rust ecosystem that supports P-521, but the Go & JS // implementations advertise it supported_impl!( - exchanges: &'static agreement::Algorithm, - "P-256" => &agreement::ECDH_P256, - "P-384" => &agreement::ECDH_P384, + exchanges: &'static agreement::Algorithm, + "P-256" => &agreement::ECDH_P256, + "P-384" => &agreement::ECDH_P384, ); // TODO: the Go & JS implementations advertise Blowfish ; however doing so in Rust leads to // runtime errors supported_impl!( - ciphers: KeySize, - "AES-128" => KeySize::KeySize128, - "AES-256" => KeySize::KeySize256, + ciphers: KeySize, + "AES-128" => KeySize::KeySize128, + "AES-256" => KeySize::KeySize256, ); supported_impl!( - hashes: &'static digest::Algorithm, - "SHA256" => &digest::SHA256, - "SHA512" => &digest::SHA512, + hashes: &'static digest::Algorithm, + "SHA256" => &digest::SHA256, + "SHA512" => &digest::SHA512, ); diff --git a/libp2p-secio/src/codec/decode.rs b/libp2p-secio/src/codec/decode.rs index 3bfac4e0..890653e6 100644 --- a/libp2p-secio/src/codec/decode.rs +++ b/libp2p-secio/src/codec/decode.rs @@ -40,78 +40,81 @@ use ring::hmac; /// /// Also implements `Sink` for convenience. pub struct DecoderMiddleware { - cipher_state: Box, - hmac_key: hmac::VerificationKey, - raw_stream: S, + cipher_state: Box, + hmac_key: hmac::VerificationKey, + raw_stream: S, } impl DecoderMiddleware { - #[inline] - pub fn new( - raw_stream: S, - cipher: Box, - hmac_key: hmac::VerificationKey, - ) -> DecoderMiddleware { - DecoderMiddleware { - cipher_state: cipher, - hmac_key: hmac_key, - raw_stream: raw_stream, - } - } + #[inline] + pub fn new( + raw_stream: S, + cipher: Box, + hmac_key: hmac::VerificationKey, + ) -> DecoderMiddleware { + DecoderMiddleware { + cipher_state: cipher, + hmac_key: hmac_key, + raw_stream: raw_stream, + } + } } impl Stream for DecoderMiddleware - where S: Stream, - S::Error: Into +where + S: Stream, + S::Error: Into, { - type Item = Vec; - type Error = SecioError; + type Item = Vec; + type Error = SecioError; - #[inline] - fn poll(&mut self) -> Poll, Self::Error> { - let frame = match self.raw_stream.poll() { - Ok(Async::Ready(Some(t))) => t, - Ok(Async::Ready(None)) => return Ok(Async::Ready(None)), - Ok(Async::NotReady) => return Ok(Async::NotReady), - Err(err) => return Err(err.into()), - }; + #[inline] + fn poll(&mut self) -> Poll, Self::Error> { + let frame = match self.raw_stream.poll() { + Ok(Async::Ready(Some(t))) => t, + Ok(Async::Ready(None)) => return Ok(Async::Ready(None)), + Ok(Async::NotReady) => return Ok(Async::NotReady), + Err(err) => return Err(err.into()), + }; - let hmac_num_bytes = self.hmac_key.digest_algorithm().output_len; + let hmac_num_bytes = self.hmac_key.digest_algorithm().output_len; - if frame.len() < hmac_num_bytes { - debug!(target: "libp2p-secio", "frame too short when decoding secio frame"); - return Err(SecioError::FrameTooShort); - } + if frame.len() < hmac_num_bytes { + debug!(target: "libp2p-secio", "frame too short when decoding secio frame"); + return Err(SecioError::FrameTooShort); + } - let (crypted_data, expected_hash) = frame.split_at(frame.len() - hmac_num_bytes); - debug_assert_eq!(expected_hash.len(), hmac_num_bytes); + let (crypted_data, expected_hash) = frame.split_at(frame.len() - hmac_num_bytes); + debug_assert_eq!(expected_hash.len(), hmac_num_bytes); - if let Err(_) = hmac::verify(&self.hmac_key, crypted_data, expected_hash) { - debug!(target: "libp2p-secio", "hmac mismatch when decoding secio frame"); - return Err(SecioError::HmacNotMatching); - } + if let Err(_) = hmac::verify(&self.hmac_key, crypted_data, expected_hash) { + debug!(target: "libp2p-secio", "hmac mismatch when decoding secio frame"); + return Err(SecioError::HmacNotMatching); + } - // Note that there is no way to decipher in place with rust-crypto right now. - let mut decrypted_data = crypted_data.to_vec(); - self.cipher_state.process(&crypted_data, &mut decrypted_data); + // Note that there is no way to decipher in place with rust-crypto right now. + let mut decrypted_data = crypted_data.to_vec(); + self.cipher_state + .process(&crypted_data, &mut decrypted_data); - Ok(Async::Ready(Some(decrypted_data))) - } + Ok(Async::Ready(Some(decrypted_data))) + } } impl Sink for DecoderMiddleware - where S: Sink +where + S: Sink, { - type SinkItem = S::SinkItem; - type SinkError = S::SinkError; + type SinkItem = S::SinkItem; + type SinkError = S::SinkError; - #[inline] - fn start_send(&mut self, item: Self::SinkItem) -> StartSend { - self.raw_stream.start_send(item) - } + #[inline] + fn start_send(&mut self, item: Self::SinkItem) -> StartSend { + self.raw_stream.start_send(item) + } - #[inline] - fn poll_complete(&mut self) -> Poll<(), Self::SinkError> { - self.raw_stream.poll_complete() - } + #[inline] + fn poll_complete(&mut self) -> Poll<(), Self::SinkError> { + self.raw_stream.poll_complete() + } } diff --git a/libp2p-secio/src/codec/encode.rs b/libp2p-secio/src/codec/encode.rs index e5e7d8d7..a0d1a7ff 100644 --- a/libp2p-secio/src/codec/encode.rs +++ b/libp2p-secio/src/codec/encode.rs @@ -36,63 +36,65 @@ use ring::hmac; /// /// Also implements `Stream` for convenience. pub struct EncoderMiddleware { - cipher_state: Box, - hmac_key: hmac::SigningKey, - raw_sink: S, + cipher_state: Box, + hmac_key: hmac::SigningKey, + raw_sink: S, } impl EncoderMiddleware { - pub fn new( - raw_sink: S, - cipher: Box, - hmac_key: hmac::SigningKey, - ) -> EncoderMiddleware { - EncoderMiddleware { - cipher_state: cipher, - hmac_key: hmac_key, - raw_sink: raw_sink, - } - } + pub fn new( + raw_sink: S, + cipher: Box, + hmac_key: hmac::SigningKey, + ) -> EncoderMiddleware { + EncoderMiddleware { + cipher_state: cipher, + hmac_key: hmac_key, + raw_sink: raw_sink, + } + } } impl Sink for EncoderMiddleware - where S: Sink +where + S: Sink, { - type SinkItem = BytesMut; - type SinkError = S::SinkError; + type SinkItem = BytesMut; + type SinkError = S::SinkError; - fn start_send(&mut self, item: Self::SinkItem) -> StartSend { - let capacity = item.len() + self.hmac_key.digest_algorithm().output_len; + fn start_send(&mut self, item: Self::SinkItem) -> StartSend { + let capacity = item.len() + self.hmac_key.digest_algorithm().output_len; - // Apparently this is the fastest way of doing. - // See https://gist.github.com/kirushik/e0d93759b0cd102f814408595c20a9d0 - let mut out_buffer = BytesMut::from(vec![0; capacity]); + // Apparently this is the fastest way of doing. + // See https://gist.github.com/kirushik/e0d93759b0cd102f814408595c20a9d0 + let mut out_buffer = BytesMut::from(vec![0; capacity]); - { - let (out_data, out_sign) = out_buffer.split_at_mut(item.len()); - self.cipher_state.process(&item, out_data); + { + let (out_data, out_sign) = out_buffer.split_at_mut(item.len()); + self.cipher_state.process(&item, out_data); - let signature = hmac::sign(&self.hmac_key, out_data); - out_sign.copy_from_slice(signature.as_ref()); - } + let signature = hmac::sign(&self.hmac_key, out_data); + out_sign.copy_from_slice(signature.as_ref()); + } - self.raw_sink.start_send(out_buffer) - } + self.raw_sink.start_send(out_buffer) + } - #[inline] - fn poll_complete(&mut self) -> Poll<(), Self::SinkError> { - self.raw_sink.poll_complete() - } + #[inline] + fn poll_complete(&mut self) -> Poll<(), Self::SinkError> { + self.raw_sink.poll_complete() + } } impl Stream for EncoderMiddleware - where S: Stream +where + S: Stream, { - type Item = S::Item; - type Error = S::Error; + type Item = S::Item; + type Error = S::Error; - #[inline] - fn poll(&mut self) -> Poll, Self::Error> { - self.raw_sink.poll() - } + #[inline] + fn poll(&mut self) -> Poll, Self::Error> { + self.raw_sink.poll() + } } diff --git a/libp2p-secio/src/codec/mod.rs b/libp2p-secio/src/codec/mod.rs index 5b934409..afc876b4 100644 --- a/libp2p-secio/src/codec/mod.rs +++ b/libp2p-secio/src/codec/mod.rs @@ -41,124 +41,148 @@ pub type FullCodec = DecoderMiddleware( - socket: length_delimited::Framed, - cipher_encoding: Box, - encoding_hmac: hmac::SigningKey, - cipher_decoder: Box, - decoding_hmac: hmac::VerificationKey, + socket: length_delimited::Framed, + cipher_encoding: Box, + encoding_hmac: hmac::SigningKey, + cipher_decoder: Box, + decoding_hmac: hmac::VerificationKey, ) -> FullCodec - where S: AsyncRead + AsyncWrite +where + S: AsyncRead + AsyncWrite, { - let encoder = EncoderMiddleware::new(socket, cipher_encoding, encoding_hmac); - let codec = DecoderMiddleware::new(encoder, cipher_decoder, decoding_hmac); + let encoder = EncoderMiddleware::new(socket, cipher_encoding, encoding_hmac); + let codec = DecoderMiddleware::new(encoder, cipher_decoder, decoding_hmac); - codec + codec } #[cfg(test)] mod tests { - extern crate tokio_core; - use super::DecoderMiddleware; - use super::EncoderMiddleware; - use super::full_codec; - use bytes::BytesMut; - use crypto::aessafe::AesSafe256Encryptor; - use crypto::blockmodes::CtrMode; - use error::SecioError; - use futures::{Future, Sink, Stream}; - use futures::sync::mpsc::channel; - use rand; - use ring::digest::SHA256; - use ring::hmac::SigningKey; - use ring::hmac::VerificationKey; - use std::io::Error as IoError; - use self::tokio_core::net::TcpListener; - use self::tokio_core::net::TcpStream; - use self::tokio_core::reactor::Core; - use tokio_io::codec::length_delimited::Framed; + extern crate tokio_core; + use super::DecoderMiddleware; + use super::EncoderMiddleware; + use super::full_codec; + use bytes::BytesMut; + use crypto::aessafe::AesSafe256Encryptor; + use crypto::blockmodes::CtrMode; + use error::SecioError; + use futures::{Future, Sink, Stream}; + use futures::sync::mpsc::channel; + use rand; + use ring::digest::SHA256; + use ring::hmac::SigningKey; + use ring::hmac::VerificationKey; + use std::io::Error as IoError; + use self::tokio_core::net::TcpListener; + use self::tokio_core::net::TcpStream; + use self::tokio_core::reactor::Core; + use tokio_io::codec::length_delimited::Framed; - #[test] - fn raw_encode_then_decode() { - let (data_tx, data_rx) = channel::(256); - let data_tx = data_tx.sink_map_err::<_, IoError>(|_| panic!()); - let data_rx = data_rx.map_err::(|_| panic!()); + #[test] + fn raw_encode_then_decode() { + let (data_tx, data_rx) = channel::(256); + let data_tx = data_tx.sink_map_err::<_, IoError>(|_| panic!()); + let data_rx = data_rx.map_err::(|_| panic!()); - let cipher_key: [u8; 32] = rand::random(); - let hmac_key: [u8; 32] = rand::random(); + let cipher_key: [u8; 32] = rand::random(); + let hmac_key: [u8; 32] = rand::random(); - let encoder = - EncoderMiddleware::new( - data_tx, - Box::new(CtrMode::new(AesSafe256Encryptor::new(&cipher_key), vec![0; 16])), - SigningKey::new(&SHA256, &hmac_key), - ); - let decoder = - DecoderMiddleware::new( - data_rx, - Box::new(CtrMode::new(AesSafe256Encryptor::new(&cipher_key), vec![0; 16])), - VerificationKey::new(&SHA256, &hmac_key), - ); + let encoder = EncoderMiddleware::new( + data_tx, + Box::new(CtrMode::new( + AesSafe256Encryptor::new(&cipher_key), + vec![0; 16], + )), + SigningKey::new(&SHA256, &hmac_key), + ); + let decoder = DecoderMiddleware::new( + data_rx, + Box::new(CtrMode::new( + AesSafe256Encryptor::new(&cipher_key), + vec![0; 16], + )), + VerificationKey::new(&SHA256, &hmac_key), + ); - let data = b"hello world"; + let data = b"hello world"; - let data_sent = encoder.send(BytesMut::from(data.to_vec())).from_err(); - let data_received = decoder.into_future().map(|(n, _)| n).map_err(|(e, _)| e); + let data_sent = encoder.send(BytesMut::from(data.to_vec())).from_err(); + let data_received = decoder.into_future().map(|(n, _)| n).map_err(|(e, _)| e); - let mut core = Core::new().unwrap(); - let (_, decoded) = core.run(data_sent.join(data_received)).map_err(|_| ()).unwrap(); - assert_eq!(decoded.unwrap(), data); - } + let mut core = Core::new().unwrap(); + let (_, decoded) = core.run(data_sent.join(data_received)) + .map_err(|_| ()) + .unwrap(); + assert_eq!(decoded.unwrap(), data); + } - #[test] - fn full_codec_encode_then_decode() { - let mut core = Core::new().unwrap(); + #[test] + fn full_codec_encode_then_decode() { + let mut core = Core::new().unwrap(); - let cipher_key: [u8; 32] = rand::random(); - let cipher_key_clone = cipher_key.clone(); - let hmac_key: [u8; 32] = rand::random(); - let hmac_key_clone = hmac_key.clone(); - let data = b"hello world"; - let data_clone = data.clone(); + let cipher_key: [u8; 32] = rand::random(); + let cipher_key_clone = cipher_key.clone(); + let hmac_key: [u8; 32] = rand::random(); + let hmac_key_clone = hmac_key.clone(); + let data = b"hello world"; + let data_clone = data.clone(); - let listener = TcpListener::bind(&"127.0.0.1:0".parse().unwrap(), &core.handle()).unwrap(); - let listener_addr = listener.local_addr().unwrap(); + let listener = TcpListener::bind(&"127.0.0.1:0".parse().unwrap(), &core.handle()).unwrap(); + let listener_addr = listener.local_addr().unwrap(); - let server = - listener.incoming().into_future().map_err(|(e, _)| e).map(move |(connec, _)| { - let connec = Framed::new(connec.unwrap().0); + let server = listener.incoming().into_future().map_err(|(e, _)| e).map( + move |(connec, _)| { + let connec = Framed::new(connec.unwrap().0); - full_codec( - connec, - Box::new(CtrMode::new(AesSafe256Encryptor::new(&cipher_key), vec![0; 16])), - SigningKey::new(&SHA256, &hmac_key), - Box::new(CtrMode::new(AesSafe256Encryptor::new(&cipher_key), vec![0; 16])), - VerificationKey::new(&SHA256, &hmac_key), - ) - }); + full_codec( + connec, + Box::new(CtrMode::new( + AesSafe256Encryptor::new(&cipher_key), + vec![0; 16], + )), + SigningKey::new(&SHA256, &hmac_key), + Box::new(CtrMode::new( + AesSafe256Encryptor::new(&cipher_key), + vec![0; 16], + )), + VerificationKey::new(&SHA256, &hmac_key), + ) + }, + ); - let client = TcpStream::connect(&listener_addr, &core.handle()) - .map_err(|e| e.into()) - .map(move |stream| { - let stream = Framed::new(stream); + let client = TcpStream::connect(&listener_addr, &core.handle()) + .map_err(|e| e.into()) + .map(move |stream| { + let stream = Framed::new(stream); - full_codec( - stream, - Box::new(CtrMode::new(AesSafe256Encryptor::new(&cipher_key_clone), vec![0; 16])), - SigningKey::new(&SHA256, &hmac_key_clone), - Box::new(CtrMode::new(AesSafe256Encryptor::new(&cipher_key_clone), vec![0; 16])), - VerificationKey::new(&SHA256, &hmac_key_clone), - ) - }); + full_codec( + stream, + Box::new(CtrMode::new( + AesSafe256Encryptor::new(&cipher_key_clone), + vec![0; 16], + )), + SigningKey::new(&SHA256, &hmac_key_clone), + Box::new(CtrMode::new( + AesSafe256Encryptor::new(&cipher_key_clone), + vec![0; 16], + )), + VerificationKey::new(&SHA256, &hmac_key_clone), + ) + }); - let fin = server.join(client) - .from_err::() - .and_then(|(server, client)| { - client.send(BytesMut::from(&data_clone[..])).map(move |_| server).from_err() - }) - .and_then(|server| server.into_future().map_err(|(e, _)| e.into())) - .map(|recved| recved.0.unwrap().to_vec()); + let fin = server + .join(client) + .from_err::() + .and_then(|(server, client)| { + client + .send(BytesMut::from(&data_clone[..])) + .map(move |_| server) + .from_err() + }) + .and_then(|server| server.into_future().map_err(|(e, _)| e.into())) + .map(|recved| recved.0.unwrap().to_vec()); - let received = core.run(fin).unwrap(); - assert_eq!(received, data); - } + let received = core.run(fin).unwrap(); + assert_eq!(received, data); + } } diff --git a/libp2p-secio/src/error.rs b/libp2p-secio/src/error.rs index bba96a02..dd6adf31 100644 --- a/libp2p-secio/src/error.rs +++ b/libp2p-secio/src/error.rs @@ -28,117 +28,99 @@ use std::io::Error as IoError; /// Error at the SECIO layer communication. #[derive(Debug)] pub enum SecioError { - /// I/O error. - IoError(IoError), + /// I/O error. + IoError(IoError), - /// Failed to parse one of the handshake protobuf messages. - HandshakeParsingFailure, + /// Failed to parse one of the handshake protobuf messages. + HandshakeParsingFailure, - /// There is no protocol supported by both the local and remote hosts. - NoSupportIntersection(&'static str, String), + /// There is no protocol supported by both the local and remote hosts. + NoSupportIntersection(&'static str, String), - /// Failed to generate nonce. - NonceGenerationFailed, + /// Failed to generate nonce. + NonceGenerationFailed, - /// Failed to generate ephemeral key. - EphemeralKeyGenerationFailed, + /// Failed to generate ephemeral key. + EphemeralKeyGenerationFailed, - /// Failed to sign a message with our local private key. - SigningFailure, + /// Failed to sign a message with our local private key. + SigningFailure, - /// The signature of the exchange packet doesn't verify the remote public key. - SignatureVerificationFailed, + /// The signature of the exchange packet doesn't verify the remote public key. + SignatureVerificationFailed, - /// Failed to generate the secret shared key from the ephemeral key. - SecretGenerationFailed, + /// Failed to generate the secret shared key from the ephemeral key. + SecretGenerationFailed, - /// The final check of the handshake failed. - NonceVerificationFailed, + /// The final check of the handshake failed. + NonceVerificationFailed, - /// Error while decoding/encoding data. - CipherError(SymmetricCipherError), + /// Error while decoding/encoding data. + CipherError(SymmetricCipherError), - /// The received frame was of invalid length. - FrameTooShort, + /// The received frame was of invalid length. + FrameTooShort, - /// The hashes of the message didn't match. - HmacNotMatching, + /// The hashes of the message didn't match. + HmacNotMatching, } impl error::Error for SecioError { - #[inline] - fn description(&self) -> &str { - match *self { - SecioError::IoError(_) => { - "I/O error" - } - SecioError::HandshakeParsingFailure => { - "Failed to parse one of the handshake protobuf messages" - } - SecioError::NoSupportIntersection(_, _) => { - "There is no protocol supported by both the local and remote hosts" - } - SecioError::NonceGenerationFailed => { - "Failed to generate nonce" - } - SecioError::EphemeralKeyGenerationFailed => { - "Failed to generate ephemeral key" - } - SecioError::SigningFailure => { - "Failed to sign a message with our local private key" - } - SecioError::SignatureVerificationFailed => { - "The signature of the exchange packet doesn't verify the remote public key" - } - SecioError::SecretGenerationFailed => { - "Failed to generate the secret shared key from the ephemeral key" - } - SecioError::NonceVerificationFailed => { - "The final check of the handshake failed" - } - SecioError::CipherError(_) => { - "Error while decoding/encoding data" - } - SecioError::FrameTooShort => { - "The received frame was of invalid length" - } - SecioError::HmacNotMatching => { - "The hashes of the message didn't match" - } - } - } + #[inline] + fn description(&self) -> &str { + match *self { + SecioError::IoError(_) => "I/O error", + SecioError::HandshakeParsingFailure => { + "Failed to parse one of the handshake protobuf messages" + } + SecioError::NoSupportIntersection(_, _) => { + "There is no protocol supported by both the local and remote hosts" + } + SecioError::NonceGenerationFailed => "Failed to generate nonce", + SecioError::EphemeralKeyGenerationFailed => "Failed to generate ephemeral key", + SecioError::SigningFailure => "Failed to sign a message with our local private key", + SecioError::SignatureVerificationFailed => { + "The signature of the exchange packet doesn't verify the remote public key" + } + SecioError::SecretGenerationFailed => { + "Failed to generate the secret shared key from the ephemeral key" + } + SecioError::NonceVerificationFailed => "The final check of the handshake failed", + SecioError::CipherError(_) => "Error while decoding/encoding data", + SecioError::FrameTooShort => "The received frame was of invalid length", + SecioError::HmacNotMatching => "The hashes of the message didn't match", + } + } - fn cause(&self) -> Option<&error::Error> { - match *self { - SecioError::IoError(ref err) => { - Some(err) - } - // TODO: The type doesn't implement `Error` - /*SecioError::CipherError(ref err) => { - Some(err) - },*/ - _ => None, - } - } + fn cause(&self) -> Option<&error::Error> { + match *self { + SecioError::IoError(ref err) => Some(err), + // TODO: The type doesn't implement `Error` + /*SecioError::CipherError(ref err) => { + Some(err) + },*/ + _ => None, + } + } } impl fmt::Display for SecioError { - #[inline] - fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write!(fmt, "{}", error::Error::description(self)) - } + #[inline] + fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + write!(fmt, "{}", error::Error::description(self)) + } } impl From for SecioError { - #[inline] - fn from(err: SymmetricCipherError) -> SecioError { - SecioError::CipherError(err) - } + #[inline] + fn from(err: SymmetricCipherError) -> SecioError { + SecioError::CipherError(err) + } } impl From for SecioError { - #[inline] - fn from(err: IoError) -> SecioError { - SecioError::IoError(err) - } + #[inline] + fn from(err: IoError) -> SecioError { + SecioError::IoError(err) + } } diff --git a/libp2p-secio/src/handshake.rs b/libp2p-secio/src/handshake.rs index 9eb9d436..d03d9683 100644 --- a/libp2p-secio/src/handshake.rs +++ b/libp2p-secio/src/handshake.rs @@ -27,20 +27,20 @@ use futures::Future; use futures::future; use futures::sink::Sink; use futures::stream::Stream; -use keys_proto::{PublicKey as PublicKeyProtobuf, KeyType as KeyTypeProtobuf}; +use keys_proto::{KeyType as KeyTypeProtobuf, PublicKey as PublicKeyProtobuf}; use protobuf::Message as ProtobufMessage; use protobuf::core::parse_from_bytes as protobuf_parse_from_bytes; use ring::{agreement, digest, rand}; use ring::agreement::EphemeralPrivateKey; -use ring::hmac::{SigningKey, SigningContext, VerificationKey}; +use ring::hmac::{SigningContext, SigningKey, VerificationKey}; use ring::rand::SecureRandom; -use ring::signature::{RSAKeyPair, RSASigningState, RSA_PKCS1_SHA256, RSA_PKCS1_2048_8192_SHA256}; +use ring::signature::{RSAKeyPair, RSASigningState, RSA_PKCS1_2048_8192_SHA256, RSA_PKCS1_SHA256}; use ring::signature::verify as signature_verify; use std::cmp::{self, Ordering}; use std::io::{Error as IoError, ErrorKind as IoErrorKind}; use std::mem; use std::sync::Arc; -use structs_proto::{Propose, Exchange}; +use structs_proto::{Exchange, Propose}; use tokio_io::{AsyncRead, AsyncWrite}; use tokio_io::codec::length_delimited; use untrusted::Input as UntrustedInput; @@ -54,777 +54,571 @@ use untrusted::Input as UntrustedInput; /// On success, returns an object that implements the `Sink` and `Stream` trait whose items are /// buffers of data, plus the public key of the remote. pub fn handshake<'a, S: 'a>( - socket: S, - local_public_key: Vec, - local_private_key: Arc, + socket: S, + local_public_key: Vec, + local_private_key: Arc, ) -> Box, Vec), Error = SecioError> + 'a> - where S: AsyncRead + AsyncWrite +where + S: AsyncRead + AsyncWrite, { - // TODO: could be rewritten as a coroutine once coroutines land in stable Rust + // TODO: could be rewritten as a coroutine once coroutines land in stable Rust - // This struct contains the whole context of a handshake, and is filled progressively - // throughout the various parts of the handshake. - struct HandshakeContext { - // Filled with this function's parameters. - local_public_key: Vec, - local_private_key: Arc, + // This struct contains the whole context of a handshake, and is filled progressively + // throughout the various parts of the handshake. + struct HandshakeContext { + // Filled with this function's parameters. + local_public_key: Vec, + local_private_key: Arc, - rng: rand::SystemRandom, - // Locally-generated random number. The array size can be changed without any repercussion. - local_nonce: [u8; 16], + rng: rand::SystemRandom, + // Locally-generated random number. The array size can be changed without any repercussion. + local_nonce: [u8; 16], - // Our local proposition's raw bytes. - local_public_key_in_protobuf_bytes: Vec, - local_proposition_bytes: Vec, + // Our local proposition's raw bytes. + local_public_key_in_protobuf_bytes: Vec, + local_proposition_bytes: Vec, - // The remote proposition's raw bytes. - remote_proposition_bytes: BytesMut, - remote_public_key_in_protobuf_bytes: Vec, - remote_public_key: Vec, + // The remote proposition's raw bytes. + remote_proposition_bytes: BytesMut, + remote_public_key_in_protobuf_bytes: Vec, + remote_public_key: Vec, - // The remote peer's version of `local_nonce`. - // If the NONCE size is actually part of the protocol, we can change this to a fixed-size - // array instead of a `Vec`. - remote_nonce: Vec, + // The remote peer's version of `local_nonce`. + // If the NONCE size is actually part of the protocol, we can change this to a fixed-size + // array instead of a `Vec`. + remote_nonce: Vec, - // Set to `ordering( - // hash(concat(remote-pubkey, local-none)), - // hash(concat(local-pubkey, remote-none)) - // )`. - // `Ordering::Equal` is an invalid value (as it would mean we're talking to ourselves). - // - // Since everything is symmetrical, this value is used to determine what should be ours - // and what should be the remote's. - hashes_ordering: Ordering, + // Set to `ordering( + // hash(concat(remote-pubkey, local-none)), + // hash(concat(local-pubkey, remote-none)) + // )`. + // `Ordering::Equal` is an invalid value (as it would mean we're talking to ourselves). + // + // Since everything is symmetrical, this value is used to determine what should be ours + // and what should be the remote's. + hashes_ordering: Ordering, - // Crypto algorithms chosen for the communication. - chosen_exchange: Option<&'static agreement::Algorithm>, - // We only support AES for now, so store just a key size. - chosen_cipher: Option, - chosen_hash: Option<&'static digest::Algorithm>, + // Crypto algorithms chosen for the communication. + chosen_exchange: Option<&'static agreement::Algorithm>, + // We only support AES for now, so store just a key size. + chosen_cipher: Option, + chosen_hash: Option<&'static digest::Algorithm>, - // Ephemeral key generated for the handshake and then thrown away. - local_tmp_priv_key: Option, - local_tmp_pub_key: [u8; agreement::PUBLIC_KEY_MAX_LEN], - } + // Ephemeral key generated for the handshake and then thrown away. + local_tmp_priv_key: Option, + local_tmp_pub_key: [u8; agreement::PUBLIC_KEY_MAX_LEN], + } - let context = HandshakeContext { - local_public_key: local_public_key, - local_private_key: local_private_key, - rng: rand::SystemRandom::new(), - local_nonce: Default::default(), - local_public_key_in_protobuf_bytes: Vec::new(), - local_proposition_bytes: Vec::new(), - remote_proposition_bytes: BytesMut::new(), - remote_public_key_in_protobuf_bytes: Vec::new(), - remote_public_key: Vec::new(), - remote_nonce: Vec::new(), - hashes_ordering: Ordering::Equal, - chosen_exchange: None, - chosen_cipher: None, - chosen_hash: None, - local_tmp_priv_key: None, - local_tmp_pub_key: [0; agreement::PUBLIC_KEY_MAX_LEN], - }; + let context = HandshakeContext { + local_public_key: local_public_key, + local_private_key: local_private_key, + rng: rand::SystemRandom::new(), + local_nonce: Default::default(), + local_public_key_in_protobuf_bytes: Vec::new(), + local_proposition_bytes: Vec::new(), + remote_proposition_bytes: BytesMut::new(), + remote_public_key_in_protobuf_bytes: Vec::new(), + remote_public_key: Vec::new(), + remote_nonce: Vec::new(), + hashes_ordering: Ordering::Equal, + chosen_exchange: None, + chosen_cipher: None, + chosen_hash: None, + local_tmp_priv_key: None, + local_tmp_pub_key: [0; agreement::PUBLIC_KEY_MAX_LEN], + }; - // The handshake messages all start with a 4-bytes message length prefix. - let socket = - length_delimited::Builder::new().big_endian().length_field_length(4).new_framed(socket); + // The handshake messages all start with a 4-bytes message length prefix. + let socket = length_delimited::Builder::new() + .big_endian() + .length_field_length(4) + .new_framed(socket); - let future = future::ok::<_, SecioError>(context) - // Generate our nonce. - .and_then(|mut context| { - context.rng.fill(&mut context.local_nonce) - .map_err(|_| SecioError::NonceGenerationFailed)?; - trace!(target: "libp2p-secio", "starting handshake ; local pubkey = {:?} ; \ - local nonce = {:?}", - context.local_public_key, context.local_nonce); - Ok(context) - }) + let future = future::ok::<_, SecioError>(context) + // Generate our nonce. + .and_then(|mut context| { + context.rng.fill(&mut context.local_nonce) + .map_err(|_| SecioError::NonceGenerationFailed)?; + trace!(target: "libp2p-secio", "starting handshake ; local pubkey = {:?} ; \ + local nonce = {:?}", + context.local_public_key, context.local_nonce); + Ok(context) + }) - // Send our proposition with our nonce, public key and supported protocols. - .and_then(|mut context| { - let mut public_key = PublicKeyProtobuf::new(); - public_key.set_Type(KeyTypeProtobuf::RSA); - public_key.set_Data(context.local_public_key.clone()); - context.local_public_key_in_protobuf_bytes = public_key.write_to_bytes().unwrap(); + // Send our proposition with our nonce, public key and supported protocols. + .and_then(|mut context| { + let mut public_key = PublicKeyProtobuf::new(); + public_key.set_Type(KeyTypeProtobuf::RSA); + public_key.set_Data(context.local_public_key.clone()); + context.local_public_key_in_protobuf_bytes = public_key.write_to_bytes().unwrap(); - let mut proposition = Propose::new(); - proposition.set_rand(context.local_nonce.clone().to_vec()); - proposition.set_pubkey(context.local_public_key_in_protobuf_bytes.clone()); - proposition.set_exchanges(algo_support::exchanges::PROPOSITION_STRING.into()); - proposition.set_ciphers(algo_support::ciphers::PROPOSITION_STRING.into()); - proposition.set_hashes(algo_support::hashes::PROPOSITION_STRING.into()); - let proposition_bytes = proposition.write_to_bytes().unwrap(); - context.local_proposition_bytes = proposition_bytes.clone(); + let mut proposition = Propose::new(); + proposition.set_rand(context.local_nonce.clone().to_vec()); + proposition.set_pubkey(context.local_public_key_in_protobuf_bytes.clone()); + proposition.set_exchanges(algo_support::exchanges::PROPOSITION_STRING.into()); + proposition.set_ciphers(algo_support::ciphers::PROPOSITION_STRING.into()); + proposition.set_hashes(algo_support::hashes::PROPOSITION_STRING.into()); + let proposition_bytes = proposition.write_to_bytes().unwrap(); + context.local_proposition_bytes = proposition_bytes.clone(); - trace!(target: "libp2p-secio", "sending proposition to remote"); + trace!(target: "libp2p-secio", "sending proposition to remote"); - socket.send(BytesMut::from(proposition_bytes.clone())) - .from_err() - .map(|s| (s, context)) - }) + socket.send(BytesMut::from(proposition_bytes.clone())) + .from_err() + .map(|s| (s, context)) + }) - // Receive the remote's proposition. - .and_then(move |(socket, mut context)| { - socket.into_future() - .map_err(|(e, _)| e.into()) - .and_then(move |(prop_raw, socket)| { - match prop_raw { - Some(p) => context.remote_proposition_bytes = p, - None => { - let err = IoError::new(IoErrorKind::BrokenPipe, "unexpected eof"); - debug!(target: "libp2p-secio", "unexpected eof while waiting for \ - remote's proposition"); - return Err(err.into()) - }, - }; + // Receive the remote's proposition. + .and_then(move |(socket, mut context)| { + socket.into_future() + .map_err(|(e, _)| e.into()) + .and_then(move |(prop_raw, socket)| { + match prop_raw { + Some(p) => context.remote_proposition_bytes = p, + None => { + let err = IoError::new(IoErrorKind::BrokenPipe, "unexpected eof"); + debug!(target: "libp2p-secio", "unexpected eof while waiting for \ + remote's proposition"); + return Err(err.into()) + }, + }; - let mut prop = match protobuf_parse_from_bytes::(&context.remote_proposition_bytes) { - Ok(prop) => prop, - Err(_) => { - debug!(target: "libp2p-secio", "failed to parse remote's proposition \ - protobuf message"); - return Err(SecioError::HandshakeParsingFailure); - } - }; - context.remote_public_key_in_protobuf_bytes = prop.take_pubkey(); - let mut pubkey = { - let bytes = &context.remote_public_key_in_protobuf_bytes; - match protobuf_parse_from_bytes::(bytes) { - Ok(p) => p, - Err(_) => { - debug!(target: "libp2p-secio", "failed to parse remote's \ - proposition's pubkey protobuf"); - return Err(SecioError::HandshakeParsingFailure); - }, - } - }; + let mut prop = match protobuf_parse_from_bytes::( + &context.remote_proposition_bytes + ) { + Ok(prop) => prop, + Err(_) => { + debug!(target: "libp2p-secio", "failed to parse remote's proposition \ + protobuf message"); + return Err(SecioError::HandshakeParsingFailure); + } + }; + context.remote_public_key_in_protobuf_bytes = prop.take_pubkey(); + let mut pubkey = { + let bytes = &context.remote_public_key_in_protobuf_bytes; + match protobuf_parse_from_bytes::(bytes) { + Ok(p) => p, + Err(_) => { + debug!(target: "libp2p-secio", "failed to parse remote's \ + proposition's pubkey protobuf"); + return Err(SecioError::HandshakeParsingFailure); + }, + } + }; - // TODO: For now we suppose that the key is in the RSA format because that's - // the only thing the Go and JS implementations support. - match pubkey.get_Type() { - KeyTypeProtobuf::RSA => (), - format => { - let err = IoError::new(IoErrorKind::Other, "unsupported protocol"); - debug!(target: "libp2p-secio", "unsupported remote pubkey format {:?}", - format); - return Err(err.into()); - }, - }; - context.remote_public_key = pubkey.take_Data(); - context.remote_nonce = prop.take_rand(); - trace!(target: "libp2p-secio", "received proposition from remote ; \ - pubkey = {:?} ; nonce = {:?}", - context.remote_public_key, context.remote_nonce); - Ok((prop, socket, context)) - }) - }) + // TODO: For now we suppose that the key is in the RSA format because that's + // the only thing the Go and JS implementations support. + match pubkey.get_Type() { + KeyTypeProtobuf::RSA => (), + format => { + let err = IoError::new(IoErrorKind::Other, "unsupported protocol"); + debug!(target: "libp2p-secio", "unsupported remote pubkey format {:?}", + format); + return Err(err.into()); + }, + }; + context.remote_public_key = pubkey.take_Data(); + context.remote_nonce = prop.take_rand(); + trace!(target: "libp2p-secio", "received proposition from remote ; \ + pubkey = {:?} ; nonce = {:?}", + context.remote_public_key, context.remote_nonce); + Ok((prop, socket, context)) + }) + }) - // Decide which algorithms to use (thanks to the remote's proposition). - .and_then(move |(remote_prop, socket, mut context)| { - // In order to determine which protocols to use, we compute two hashes and choose - // based on which hash is larger. - context.hashes_ordering = { - let oh1 = { - let mut ctx = digest::Context::new(&digest::SHA256); - ctx.update(&context.remote_public_key_in_protobuf_bytes); - ctx.update(&context.local_nonce); - ctx.finish() - }; + // Decide which algorithms to use (thanks to the remote's proposition). + .and_then(move |(remote_prop, socket, mut context)| { + // In order to determine which protocols to use, we compute two hashes and choose + // based on which hash is larger. + context.hashes_ordering = { + let oh1 = { + let mut ctx = digest::Context::new(&digest::SHA256); + ctx.update(&context.remote_public_key_in_protobuf_bytes); + ctx.update(&context.local_nonce); + ctx.finish() + }; - let oh2 = { - let mut ctx = digest::Context::new(&digest::SHA256); - ctx.update(&context.local_public_key_in_protobuf_bytes); - ctx.update(&context.remote_nonce); - ctx.finish() - }; + let oh2 = { + let mut ctx = digest::Context::new(&digest::SHA256); + ctx.update(&context.local_public_key_in_protobuf_bytes); + ctx.update(&context.remote_nonce); + ctx.finish() + }; - oh1.as_ref().cmp(&oh2.as_ref()) - }; + oh1.as_ref().cmp(&oh2.as_ref()) + }; - context.chosen_exchange = { - let list = &remote_prop.get_exchanges(); - Some(match algo_support::exchanges::select_best(context.hashes_ordering, list) { - Ok(a) => a, - Err(err) => { - debug!(target: "libp2p-secio", "failed to select an exchange protocol"); - return Err(err); - } - }) - }; - context.chosen_cipher = { - let list = &remote_prop.get_ciphers(); - Some(match algo_support::ciphers::select_best(context.hashes_ordering, list) { - Ok(a) => a, - Err(err) => { - debug!(target: "libp2p-secio", "failed to select a cipher protocol"); - return Err(err); - } - }) - }; - context.chosen_hash = { - let list = &remote_prop.get_hashes(); - Some(match algo_support::hashes::select_best(context.hashes_ordering, list) { - Ok(a) => a, - Err(err) => { - debug!(target: "libp2p-secio", "failed to select a hash protocol"); - return Err(err); - } - }) - }; + context.chosen_exchange = { + let list = &remote_prop.get_exchanges(); + Some(match algo_support::exchanges::select_best(context.hashes_ordering, list) { + Ok(a) => a, + Err(err) => { + debug!(target: "libp2p-secio", "failed to select an exchange protocol"); + return Err(err); + } + }) + }; + context.chosen_cipher = { + let list = &remote_prop.get_ciphers(); + Some(match algo_support::ciphers::select_best(context.hashes_ordering, list) { + Ok(a) => a, + Err(err) => { + debug!(target: "libp2p-secio", "failed to select a cipher protocol"); + return Err(err); + } + }) + }; + context.chosen_hash = { + let list = &remote_prop.get_hashes(); + Some(match algo_support::hashes::select_best(context.hashes_ordering, list) { + Ok(a) => a, + Err(err) => { + debug!(target: "libp2p-secio", "failed to select a hash protocol"); + return Err(err); + } + }) + }; - Ok((socket, context)) - }) + Ok((socket, context)) + }) - // Generate an ephemeral key for the negotiation. - .and_then(|(socket, context)| { - match EphemeralPrivateKey::generate(&agreement::ECDH_P256, &context.rng) { - Ok(tmp_priv_key) => Ok((socket, context, tmp_priv_key)), - Err(_) => { - debug!(target: "libp2p-secio", "failed to generate ECDH key"); - Err(SecioError::EphemeralKeyGenerationFailed) - }, - } - }) + // Generate an ephemeral key for the negotiation. + .and_then(|(socket, context)| { + match EphemeralPrivateKey::generate(&agreement::ECDH_P256, &context.rng) { + Ok(tmp_priv_key) => Ok((socket, context, tmp_priv_key)), + Err(_) => { + debug!(target: "libp2p-secio", "failed to generate ECDH key"); + Err(SecioError::EphemeralKeyGenerationFailed) + }, + } + }) - // Send the ephemeral pub key to the remote in an `Exchange` struct. The `Exchange` also - // contains a signature of the two propositions encoded with our static public key. - .and_then(|(socket, mut context, tmp_priv)| { - let exchange = { - let local_tmp_pub_key = &mut context.local_tmp_pub_key[..tmp_priv.public_key_len()]; - tmp_priv.compute_public_key(local_tmp_pub_key).unwrap(); - context.local_tmp_priv_key = Some(tmp_priv); + // Send the ephemeral pub key to the remote in an `Exchange` struct. The `Exchange` also + // contains a signature of the two propositions encoded with our static public key. + .and_then(|(socket, mut context, tmp_priv)| { + let exchange = { + let local_tmp_pub_key = &mut context.local_tmp_pub_key[..tmp_priv.public_key_len()]; + tmp_priv.compute_public_key(local_tmp_pub_key).unwrap(); + context.local_tmp_priv_key = Some(tmp_priv); - let mut data_to_sign = context.local_proposition_bytes.clone(); - data_to_sign.extend_from_slice(&context.remote_proposition_bytes); - data_to_sign.extend_from_slice(local_tmp_pub_key); + let mut data_to_sign = context.local_proposition_bytes.clone(); + data_to_sign.extend_from_slice(&context.remote_proposition_bytes); + data_to_sign.extend_from_slice(local_tmp_pub_key); - let mut exchange = Exchange::new(); - exchange.set_epubkey(local_tmp_pub_key.to_vec()); - exchange.set_signature({ - let mut state = match RSASigningState::new(context.local_private_key.clone()) { - Ok(s) => s, - Err(_) => { - debug!(target: "libp2p-secio", "failed to sign local exchange"); - return Err(SecioError::SigningFailure); - }, - }; - let mut signature = vec![0; context.local_private_key.public_modulus_len()]; - match state.sign(&RSA_PKCS1_SHA256, &context.rng, &data_to_sign, - &mut signature) - { - Ok(_) => (), - Err(_) => { - debug!(target: "libp2p-secio", "failed to sign local exchange"); - return Err(SecioError::SigningFailure); - }, - }; + let mut exchange = Exchange::new(); + exchange.set_epubkey(local_tmp_pub_key.to_vec()); + exchange.set_signature({ + let mut state = match RSASigningState::new(context.local_private_key.clone()) { + Ok(s) => s, + Err(_) => { + debug!(target: "libp2p-secio", "failed to sign local exchange"); + return Err(SecioError::SigningFailure); + }, + }; + let mut signature = vec![0; context.local_private_key.public_modulus_len()]; + match state.sign(&RSA_PKCS1_SHA256, &context.rng, &data_to_sign, + &mut signature) + { + Ok(_) => (), + Err(_) => { + debug!(target: "libp2p-secio", "failed to sign local exchange"); + return Err(SecioError::SigningFailure); + }, + }; - signature - }); - exchange - }; + signature + }); + exchange + }; - let local_exch = exchange.write_to_bytes() - .expect("can only fail if the protobuf msg is malformed, which can't happen for \ - this message in particular"); - Ok((BytesMut::from(local_exch), socket, context)) - }) + let local_exch = exchange.write_to_bytes() + .expect("can only fail if the protobuf msg is malformed, which can't happen for \ + this message in particular"); + Ok((BytesMut::from(local_exch), socket, context)) + }) - // Send our local `Exchange`. - .and_then(|(local_exch, socket, context)| { - trace!(target: "libp2p-secio", "sending exchange to remote"); - socket.send(local_exch) - .from_err() - .map(|s| (s, context)) - }) + // Send our local `Exchange`. + .and_then(|(local_exch, socket, context)| { + trace!(target: "libp2p-secio", "sending exchange to remote"); + socket.send(local_exch) + .from_err() + .map(|s| (s, context)) + }) - // Receive the remote's `Exchange`. - .and_then(move |(socket, context)| { - socket.into_future() - .map_err(|(e, _)| e.into()) - .and_then(move |(raw, socket)| { - let raw = match raw { - Some(r) => r, - None => { - let err = IoError::new(IoErrorKind::BrokenPipe, "unexpected eof"); - debug!(target: "libp2p-secio", "unexpected eof while waiting for \ - remote's exchange"); - return Err(err.into()) - }, - }; + // Receive the remote's `Exchange`. + .and_then(move |(socket, context)| { + socket.into_future() + .map_err(|(e, _)| e.into()) + .and_then(move |(raw, socket)| { + let raw = match raw { + Some(r) => r, + None => { + let err = IoError::new(IoErrorKind::BrokenPipe, "unexpected eof"); + debug!(target: "libp2p-secio", "unexpected eof while waiting for \ + remote's exchange"); + return Err(err.into()) + }, + }; - let remote_exch = match protobuf_parse_from_bytes::(&raw) { - Ok(e) => e, - Err(err) => { - debug!(target: "libp2p-secio", "failed to parse remote's exchange \ - protobuf ; {:?}", err); - return Err(SecioError::HandshakeParsingFailure); - } - }; + let remote_exch = match protobuf_parse_from_bytes::(&raw) { + Ok(e) => e, + Err(err) => { + debug!(target: "libp2p-secio", "failed to parse remote's exchange \ + protobuf ; {:?}", err); + return Err(SecioError::HandshakeParsingFailure); + } + }; - trace!(target: "libp2p-secio", "received and decoded the remote's exchange"); - Ok((remote_exch, socket, context)) - }) - }) + trace!(target: "libp2p-secio", "received and decoded the remote's exchange"); + Ok((remote_exch, socket, context)) + }) + }) - // Check the validity of the remote's `Exchange`. This verifies that the remote was really - // the sender of its proposition, and that it is the owner of both its global and ephemeral - // keys. - .and_then(|(remote_exch, socket, context)| { - let mut data_to_verify = context.remote_proposition_bytes.clone(); - data_to_verify.extend_from_slice(&context.local_proposition_bytes); - data_to_verify.extend_from_slice(remote_exch.get_epubkey()); + // Check the validity of the remote's `Exchange`. This verifies that the remote was really + // the sender of its proposition, and that it is the owner of both its global and ephemeral + // keys. + .and_then(|(remote_exch, socket, context)| { + let mut data_to_verify = context.remote_proposition_bytes.clone(); + data_to_verify.extend_from_slice(&context.local_proposition_bytes); + data_to_verify.extend_from_slice(remote_exch.get_epubkey()); - // TODO: The ring library doesn't like some stuff in our DER public key, therefore - // we scrap the first 24 bytes of the key. A proper fix would be to write a DER - // parser, but that's not trivial. - match signature_verify(&RSA_PKCS1_2048_8192_SHA256, - UntrustedInput::from(&context.remote_public_key[24..]), - UntrustedInput::from(&data_to_verify), - UntrustedInput::from(remote_exch.get_signature())) - { - Ok(()) => (), - Err(_) => { - debug!(target: "libp2p-secio", "failed to verify the remote's signature"); - return Err(SecioError::SignatureVerificationFailed) - }, - } + // TODO: The ring library doesn't like some stuff in our DER public key, therefore + // we scrap the first 24 bytes of the key. A proper fix would be to write a DER + // parser, but that's not trivial. + match signature_verify(&RSA_PKCS1_2048_8192_SHA256, + UntrustedInput::from(&context.remote_public_key[24..]), + UntrustedInput::from(&data_to_verify), + UntrustedInput::from(remote_exch.get_signature())) + { + Ok(()) => (), + Err(_) => { + debug!(target: "libp2p-secio", "failed to verify the remote's signature"); + return Err(SecioError::SignatureVerificationFailed) + }, + } - trace!(target: "libp2p-secio", "successfully verified the remote's signature"); - Ok((remote_exch, socket, context)) - }) + trace!(target: "libp2p-secio", "successfully verified the remote's signature"); + Ok((remote_exch, socket, context)) + }) - // Generate a key from the local ephemeral private key and the remote ephemeral public key, - // derive from it a ciper key, an iv, and a hmac key, and build the encoder/decoder. - .and_then(|(remote_exch, socket, mut context)| { - let local_priv_key = context.local_tmp_priv_key.take() - .expect("we filled this Option earlier, and extract it now"); - let codec = agreement::agree_ephemeral(local_priv_key, - &context.chosen_exchange.clone().unwrap(), - UntrustedInput::from(remote_exch.get_epubkey()), - SecioError::SecretGenerationFailed, - |key_material| { - let key = SigningKey::new(context.chosen_hash.unwrap(), key_material); + // Generate a key from the local ephemeral private key and the remote ephemeral public key, + // derive from it a ciper key, an iv, and a hmac key, and build the encoder/decoder. + .and_then(|(remote_exch, socket, mut context)| { + let local_priv_key = context.local_tmp_priv_key.take() + .expect("we filled this Option earlier, and extract it now"); + let codec = agreement::agree_ephemeral(local_priv_key, + &context.chosen_exchange.clone().unwrap(), + UntrustedInput::from(remote_exch.get_epubkey()), + SecioError::SecretGenerationFailed, + |key_material| { + let key = SigningKey::new(context.chosen_hash.unwrap(), key_material); - let chosen_cipher = context.chosen_cipher.unwrap(); - let (cipher_key_size, iv_size) = match chosen_cipher { - KeySize::KeySize128 => (16, 16), - KeySize::KeySize256 => (32, 16), - _ => panic!() - }; + let chosen_cipher = context.chosen_cipher.unwrap(); + let (cipher_key_size, iv_size) = match chosen_cipher { + KeySize::KeySize128 => (16, 16), + KeySize::KeySize256 => (32, 16), + _ => panic!() + }; - let mut longer_key = vec![0u8; 2 * (iv_size + cipher_key_size + 20)]; - stretch_key(&key, &mut longer_key); + let mut longer_key = vec![0u8; 2 * (iv_size + cipher_key_size + 20)]; + stretch_key(&key, &mut longer_key); - let (local_infos, remote_infos) = { - let (first_half, second_half) = longer_key.split_at(longer_key.len() / 2); - match context.hashes_ordering { - Ordering::Equal => panic!(), - Ordering::Less => (second_half, first_half), - Ordering::Greater => (first_half, second_half), - } - }; + let (local_infos, remote_infos) = { + let (first_half, second_half) = longer_key.split_at(longer_key.len() / 2); + match context.hashes_ordering { + Ordering::Equal => panic!(), + Ordering::Less => (second_half, first_half), + Ordering::Greater => (first_half, second_half), + } + }; - let (encoding_cipher, encoding_hmac) = { - let (iv, rest) = local_infos.split_at(iv_size); - let (cipher_key, mac_key) = rest.split_at(cipher_key_size); - let hmac = SigningKey::new(&context.chosen_hash.clone().unwrap(), mac_key); - let cipher = ctr(chosen_cipher, cipher_key, iv); - (cipher, hmac) - }; + let (encoding_cipher, encoding_hmac) = { + let (iv, rest) = local_infos.split_at(iv_size); + let (cipher_key, mac_key) = rest.split_at(cipher_key_size); + let hmac = SigningKey::new(&context.chosen_hash.clone().unwrap(), mac_key); + let cipher = ctr(chosen_cipher, cipher_key, iv); + (cipher, hmac) + }; - let (decoding_cipher, decoding_hmac) = { - let (iv, rest) = remote_infos.split_at(iv_size); - let (cipher_key, mac_key) = rest.split_at(cipher_key_size); - let hmac = VerificationKey::new(&context.chosen_hash.clone().unwrap(), mac_key); - let cipher = ctr(chosen_cipher, cipher_key, iv); - (cipher, hmac) - }; + let (decoding_cipher, decoding_hmac) = { + let (iv, rest) = remote_infos.split_at(iv_size); + let (cipher_key, mac_key) = rest.split_at(cipher_key_size); + let hmac = VerificationKey::new(&context.chosen_hash.clone().unwrap(), mac_key); + let cipher = ctr(chosen_cipher, cipher_key, iv); + (cipher, hmac) + }; - Ok(full_codec(socket, Box::new(encoding_cipher), encoding_hmac, - Box::new(decoding_cipher), decoding_hmac)) - }); + Ok(full_codec(socket, Box::new(encoding_cipher), encoding_hmac, + Box::new(decoding_cipher), decoding_hmac)) + }); - match codec { - Ok(c) => Ok((c, context)), - Err(err) => { - debug!(target: "libp2p-secio", "failed to generate shared secret with remote"); - return Err(err); - }, - } - }) + match codec { + Ok(c) => Ok((c, context)), + Err(err) => { + debug!(target: "libp2p-secio", "failed to generate shared secret with remote"); + return Err(err); + }, + } + }) - // We send back their nonce to check if the connection works. - .and_then(|(codec, mut context)| { - let remote_nonce = mem::replace(&mut context.remote_nonce, Vec::new()); - trace!(target: "libp2p-secio", "checking encryption by sending back remote's nonce"); - codec.send(BytesMut::from(remote_nonce)) - .map(|s| (s, context)) - .from_err() - }) + // We send back their nonce to check if the connection works. + .and_then(|(codec, mut context)| { + let remote_nonce = mem::replace(&mut context.remote_nonce, Vec::new()); + trace!(target: "libp2p-secio", "checking encryption by sending back remote's nonce"); + codec.send(BytesMut::from(remote_nonce)) + .map(|s| (s, context)) + .from_err() + }) - // Check that the received nonce is correct. - .and_then(|(codec, context)| { - codec.into_future() - .map_err(|(e, _)| e) - .and_then(move |(nonce, rest)| { - match nonce { - Some(ref n) if n == &context.local_nonce => { - trace!(target: "libp2p-secio", "secio handshake success"); - Ok((rest, context.remote_public_key)) - }, - None => { - debug!(target: "libp2p-secio", "unexpected eof during nonce check"); - Err(IoError::new(IoErrorKind::BrokenPipe, "unexpected eof").into()) - }, - _ => { - debug!(target: "libp2p-secio", "failed nonce verification with remote"); - Err(SecioError::NonceVerificationFailed) - } - } - }) - }); + // Check that the received nonce is correct. + .and_then(|(codec, context)| { + codec.into_future() + .map_err(|(e, _)| e) + .and_then(move |(nonce, rest)| { + match nonce { + Some(ref n) if n == &context.local_nonce => { + trace!(target: "libp2p-secio", "secio handshake success"); + Ok((rest, context.remote_public_key)) + }, + None => { + debug!(target: "libp2p-secio", "unexpected eof during nonce check"); + Err(IoError::new(IoErrorKind::BrokenPipe, "unexpected eof").into()) + }, + _ => { + debug!(target: "libp2p-secio", "failed nonce verification with remote"); + Err(SecioError::NonceVerificationFailed) + } + } + }) + }); - Box::new(future) + Box::new(future) } // Custom algorithm translated from reference implementations. Needs to be the same algorithm // amongst all implementations. fn stretch_key(key: &SigningKey, result: &mut [u8]) { - const SEED: &'static [u8] = b"key expansion"; + const SEED: &'static [u8] = b"key expansion"; - let mut init_ctxt = SigningContext::with_key(key); - init_ctxt.update(SEED); - let mut a = init_ctxt.sign(); + let mut init_ctxt = SigningContext::with_key(key); + init_ctxt.update(SEED); + let mut a = init_ctxt.sign(); - let mut j = 0; - while j < result.len() { - let mut context = SigningContext::with_key(key); - context.update(a.as_ref()); - context.update(SEED); - let b = context.sign(); + let mut j = 0; + while j < result.len() { + let mut context = SigningContext::with_key(key); + context.update(a.as_ref()); + context.update(SEED); + let b = context.sign(); - let todo = cmp::min(b.as_ref().len(), result.len() - j); + let todo = cmp::min(b.as_ref().len(), result.len() - j); - result[j..j + todo].copy_from_slice(&b.as_ref()[..todo]); + result[j..j + todo].copy_from_slice(&b.as_ref()[..todo]); - j += todo; + j += todo; - let mut context = SigningContext::with_key(key); - context.update(a.as_ref()); - a = context.sign(); - } + let mut context = SigningContext::with_key(key); + context.update(a.as_ref()); + a = context.sign(); + } } #[cfg(test)] mod tests { - extern crate tokio_core; - use super::handshake; - use super::stretch_key; - use futures::Future; - use futures::Stream; - use ring::digest::SHA256; - use ring::hmac::SigningKey; - use ring::signature::RSAKeyPair; - use std::sync::Arc; - use self::tokio_core::net::TcpListener; - use self::tokio_core::net::TcpStream; - use self::tokio_core::reactor::Core; - use untrusted::Input; + extern crate tokio_core; + use super::handshake; + use super::stretch_key; + use futures::Future; + use futures::Stream; + use ring::digest::SHA256; + use ring::hmac::SigningKey; + use ring::signature::RSAKeyPair; + use std::sync::Arc; + use self::tokio_core::net::TcpListener; + use self::tokio_core::net::TcpStream; + use self::tokio_core::reactor::Core; + use untrusted::Input; - #[test] - fn handshake_with_self_succeeds() { - let mut core = Core::new().unwrap(); + #[test] + fn handshake_with_self_succeeds() { + let mut core = Core::new().unwrap(); - let private_key1 = { - let pkcs8 = include_bytes!("../tests/test-private-key.pk8"); - Arc::new(RSAKeyPair::from_pkcs8(Input::from(&pkcs8[..])).unwrap()) - }; - let public_key1 = include_bytes!("../tests/test-public-key.der").to_vec(); + let private_key1 = { + let pkcs8 = include_bytes!("../tests/test-private-key.pk8"); + Arc::new(RSAKeyPair::from_pkcs8(Input::from(&pkcs8[..])).unwrap()) + }; + let public_key1 = include_bytes!("../tests/test-public-key.der").to_vec(); - let private_key2 = { - let pkcs8 = include_bytes!("../tests/test-private-key-2.pk8"); - Arc::new(RSAKeyPair::from_pkcs8(Input::from(&pkcs8[..])).unwrap()) - }; - let public_key2 = include_bytes!("../tests/test-public-key-2.der").to_vec(); + let private_key2 = { + let pkcs8 = include_bytes!("../tests/test-private-key-2.pk8"); + Arc::new(RSAKeyPair::from_pkcs8(Input::from(&pkcs8[..])).unwrap()) + }; + let public_key2 = include_bytes!("../tests/test-public-key-2.der").to_vec(); - let listener = TcpListener::bind(&"127.0.0.1:0".parse().unwrap(), &core.handle()).unwrap(); - let listener_addr = listener.local_addr().unwrap(); + let listener = TcpListener::bind(&"127.0.0.1:0".parse().unwrap(), &core.handle()).unwrap(); + let listener_addr = listener.local_addr().unwrap(); - let server = listener.incoming() - .into_future() - .map_err(|(e, _)| e.into()) - .and_then(move |(connec, _)| { - handshake(connec.unwrap().0, public_key1, private_key1) - }); + let server = listener + .incoming() + .into_future() + .map_err(|(e, _)| e.into()) + .and_then(move |(connec, _)| handshake(connec.unwrap().0, public_key1, private_key1)); - let client = TcpStream::connect(&listener_addr, &core.handle()) - .map_err(|e| e.into()) - .and_then(move |stream| handshake(stream, public_key2, private_key2)); + let client = TcpStream::connect(&listener_addr, &core.handle()) + .map_err(|e| e.into()) + .and_then(move |stream| handshake(stream, public_key2, private_key2)); - core.run(server.join(client)).unwrap(); - } + core.run(server.join(client)).unwrap(); + } - #[test] - fn stretch() { - let mut output = [0u8; 32]; + #[test] + fn stretch() { + let mut output = [0u8; 32]; - let key1 = SigningKey::new(&SHA256, &[]); - stretch_key(&key1, &mut output); - assert_eq!( - &output, - &[ - 103, - 144, - 60, - 199, - 85, - 145, - 239, - 71, - 79, - 198, - 85, - 164, - 32, - 53, - 143, - 205, - 50, - 48, - 153, - 10, - 37, - 32, - 85, - 1, - 226, - 61, - 193, - 1, - 154, - 120, - 207, - 80, - ] - ); + let key1 = SigningKey::new(&SHA256, &[]); + stretch_key(&key1, &mut output); + assert_eq!( + &output, + &[ + 103, 144, 60, 199, 85, 145, 239, 71, 79, 198, 85, 164, 32, 53, 143, 205, 50, 48, + 153, 10, 37, 32, 85, 1, 226, 61, 193, 1, 154, 120, 207, 80, + ] + ); - let key2 = SigningKey::new( - &SHA256, - &[ - 157, - 166, - 80, - 144, - 77, - 193, - 198, - 6, - 23, - 220, - 87, - 220, - 191, - 72, - 168, - 197, - 54, - 33, - 219, - 225, - 84, - 156, - 165, - 37, - 149, - 224, - 244, - 32, - 170, - 79, - 125, - 35, - 171, - 26, - 178, - 176, - 92, - 168, - 22, - 27, - 205, - 44, - 229, - 61, - 152, - 21, - 222, - 81, - 241, - 81, - 116, - 236, - 74, - 166, - 89, - 145, - 5, - 162, - 108, - 230, - 55, - 54, - 9, - 17, - ], - ); - stretch_key(&key2, &mut output); - assert_eq!( - &output, - &[ - 39, - 151, - 182, - 63, - 180, - 175, - 224, - 139, - 42, - 131, - 130, - 116, - 55, - 146, - 62, - 31, - 157, - 95, - 217, - 15, - 73, - 81, - 10, - 83, - 243, - 141, - 64, - 227, - 103, - 144, - 99, - 121, - ] - ); + let key2 = SigningKey::new( + &SHA256, + &[ + 157, 166, 80, 144, 77, 193, 198, 6, 23, 220, 87, 220, 191, 72, 168, 197, 54, 33, + 219, 225, 84, 156, 165, 37, 149, 224, 244, 32, 170, 79, 125, 35, 171, 26, 178, 176, + 92, 168, 22, 27, 205, 44, 229, 61, 152, 21, 222, 81, 241, 81, 116, 236, 74, 166, + 89, 145, 5, 162, 108, 230, 55, 54, 9, 17, + ], + ); + stretch_key(&key2, &mut output); + assert_eq!( + &output, + &[ + 39, 151, 182, 63, 180, 175, 224, 139, 42, 131, 130, 116, 55, 146, 62, 31, 157, 95, + 217, 15, 73, 81, 10, 83, 243, 141, 64, 227, 103, 144, 99, 121, + ] + ); - let key3 = SigningKey::new( - &SHA256, - &[ - 98, - 219, - 94, - 104, - 97, - 70, - 139, - 13, - 185, - 110, - 56, - 36, - 66, - 3, - 80, - 224, - 32, - 205, - 102, - 170, - 59, - 32, - 140, - 245, - 86, - 102, - 231, - 68, - 85, - 249, - 227, - 243, - 57, - 53, - 171, - 36, - 62, - 225, - 178, - 74, - 89, - 142, - 151, - 94, - 183, - 231, - 208, - 166, - 244, - 130, - 130, - 209, - 248, - 65, - 19, - 48, - 127, - 127, - 55, - 82, - 117, - 154, - 124, - 108, - ], - ); - stretch_key(&key3, &mut output); - assert_eq!( - &output, - &[ - 28, - 39, - 158, - 206, - 164, - 16, - 211, - 194, - 99, - 43, - 208, - 36, - 24, - 141, - 90, - 93, - 157, - 236, - 238, - 111, - 170, - 0, - 60, - 11, - 49, - 174, - 177, - 121, - 30, - 12, - 182, - 25, - ] - ); - } + let key3 = SigningKey::new( + &SHA256, + &[ + 98, 219, 94, 104, 97, 70, 139, 13, 185, 110, 56, 36, 66, 3, 80, 224, 32, 205, 102, + 170, 59, 32, 140, 245, 86, 102, 231, 68, 85, 249, 227, 243, 57, 53, 171, 36, 62, + 225, 178, 74, 89, 142, 151, 94, 183, 231, 208, 166, 244, 130, 130, 209, 248, 65, + 19, 48, 127, 127, 55, 82, 117, 154, 124, 108, + ], + ); + stretch_key(&key3, &mut output); + assert_eq!( + &output, + &[ + 28, 39, 158, 206, 164, 16, 211, 194, 99, 43, 208, 36, 24, 141, 90, 93, 157, 236, + 238, 111, 170, 0, 60, 11, 49, 174, 177, 121, 30, 12, 182, 25, + ] + ); + } } diff --git a/libp2p-secio/src/lib.rs b/libp2p-secio/src/lib.rs index b28f06ec..23c88417 100644 --- a/libp2p-secio/src/lib.rs +++ b/libp2p-secio/src/lib.rs @@ -22,12 +22,12 @@ //! through a socket (or anything that implements `AsyncRead + AsyncWrite`). //! //! # Connection upgrade -//! +//! //! The `SecioConfig` struct implements the `ConnectionUpgrade` trait. You can apply it over a //! `Transport` by using the `with_upgrade` method. The returned object will also implement //! `Transport` and will automatically apply the secio protocol over any connection that is opened //! through it. -//! +//! //! ```no_run //! extern crate futures; //! extern crate tokio_core; @@ -35,7 +35,7 @@ //! extern crate libp2p_swarm; //! extern crate libp2p_secio; //! extern crate libp2p_tcp_transport; -//! +//! //! # fn main() { //! use futures::Future; //! use libp2p_secio::{SecioConfig, SecioKeyPair}; @@ -43,28 +43,28 @@ //! use libp2p_tcp_transport::TcpConfig; //! use tokio_core::reactor::Core; //! use tokio_io::io::write_all; -//! +//! //! let mut core = Core::new().unwrap(); -//! +//! //! let transport = TcpConfig::new(core.handle()) -//! .with_upgrade({ -//! # let private_key = b""; -//! //let private_key = include_bytes!("test-private-key.pk8"); -//! # let public_key = vec![]; -//! //let public_key = include_bytes!("test-public-key.der").to_vec(); -//! SecioConfig { -//! // See the documentation of `SecioKeyPair`. -//! key: SecioKeyPair::rsa_from_pkcs8(private_key, public_key).unwrap(), -//! } -//! }); -//! +//! .with_upgrade({ +//! # let private_key = b""; +//! //let private_key = include_bytes!("test-private-key.pk8"); +//! # let public_key = vec![]; +//! //let public_key = include_bytes!("test-public-key.der").to_vec(); +//! SecioConfig { +//! // See the documentation of `SecioKeyPair`. +//! key: SecioKeyPair::rsa_from_pkcs8(private_key, public_key).unwrap(), +//! } +//! }); +//! //! let future = transport.dial("/ip4/127.0.0.1/tcp/12345".parse::().unwrap()) -//! .unwrap_or_else(|_| panic!("Unable to dial node")) -//! .and_then(|(connection, _)| { -//! // Sends "hello world" on the connection, will be encrypted. -//! write_all(connection, "hello world") -//! }); -//! +//! .unwrap_or_else(|_| panic!("Unable to dial node")) +//! .and_then(|(connection, _)| { +//! // Sends "hello world" on the connection, will be encrypted. +//! write_all(connection, "hello world") +//! }); +//! //! core.run(future).unwrap(); //! # } //! ``` @@ -95,7 +95,7 @@ extern crate untrusted; pub use self::error::SecioError; use bytes::{Bytes, BytesMut}; -use futures::{Future, Poll, StartSend, Sink, Stream}; +use futures::{Future, Poll, Sink, StartSend, Stream}; use futures::stream::MapErr as StreamMapErr; use libp2p_swarm::Multiaddr; use ring::signature::RSAKeyPair; @@ -118,8 +118,8 @@ mod structs_proto; /// secio on any connection. #[derive(Clone)] pub struct SecioConfig { - /// Private and public keys of the local node. - pub key: SecioKeyPair, + /// Private and public keys of the local node. + pub key: SecioKeyPair, } /// Private and public keys of the local node. @@ -141,86 +141,86 @@ pub struct SecioConfig { /// /// ```ignore /// let key_pair = SecioKeyPair::rsa_from_pkcs8(include_bytes!("private.pk8"), -/// include_bytes!("public.der")); +/// include_bytes!("public.der")); /// ``` /// #[derive(Clone)] pub struct SecioKeyPair { - inner: SecioKeyPairInner, + inner: SecioKeyPairInner, } impl SecioKeyPair { - pub fn rsa_from_pkcs8

(private: &[u8], public: P) - -> Result> - where P: Into> - { - let private = RSAKeyPair::from_pkcs8(Input::from(&private[..])) - .map_err(|err| Box::new(err))?; + pub fn rsa_from_pkcs8

( + private: &[u8], + public: P, + ) -> Result> + where + P: Into>, + { + let private = + RSAKeyPair::from_pkcs8(Input::from(&private[..])).map_err(|err| Box::new(err))?; - Ok(SecioKeyPair { - inner: SecioKeyPairInner::Rsa { - public: public.into(), - private: Arc::new(private), - } - }) - } + Ok(SecioKeyPair { + inner: SecioKeyPairInner::Rsa { + public: public.into(), + private: Arc::new(private), + }, + }) + } } // Inner content of `SecioKeyPair`. #[derive(Clone)] enum SecioKeyPairInner { - Rsa { - public: Vec, - private: Arc, - } + Rsa { + public: Vec, + private: Arc, + }, } #[derive(Debug, Clone)] pub enum SecioPublicKey<'a> { - /// DER format. - Rsa(&'a [u8]), + /// DER format. + Rsa(&'a [u8]), } impl libp2p_swarm::ConnectionUpgrade for SecioConfig - where S: AsyncRead + AsyncWrite + 'static +where + S: AsyncRead + AsyncWrite + 'static, { - type Output = RwStreamSink< - StreamMapErr< - SecioMiddleware, - fn(SecioError) -> IoError, - >, - >; - type Future = Box>; - type NamesIter = iter::Once<(Bytes, ())>; - type UpgradeIdentifier = (); + type Output = RwStreamSink, fn(SecioError) -> IoError>>; + type Future = Box>; + type NamesIter = iter::Once<(Bytes, ())>; + type UpgradeIdentifier = (); - #[inline] - fn protocol_names(&self) -> Self::NamesIter { - iter::once(("/secio/1.0.0".into(), ())) - } + #[inline] + fn protocol_names(&self) -> Self::NamesIter { + iter::once(("/secio/1.0.0".into(), ())) + } - #[inline] - fn upgrade(self, incoming: S, _: (), _: libp2p_swarm::Endpoint, remote_addr: &Multiaddr) - -> Self::Future - { - info!(target: "libp2p-secio", "starting secio upgrade with {:?}", remote_addr); + #[inline] + fn upgrade( + self, + incoming: S, + _: (), + _: libp2p_swarm::Endpoint, + remote_addr: &Multiaddr, + ) -> Self::Future { + info!(target: "libp2p-secio", "starting secio upgrade with {:?}", remote_addr); - let fut = SecioMiddleware::handshake( - incoming, - self.key, - ); - let wrapped = fut.map(|stream_sink| { - let mapped = stream_sink.map_err(map_err as fn(_) -> _); - RwStreamSink::new(mapped) - }).map_err(map_err); - Box::new(wrapped) - } + let fut = SecioMiddleware::handshake(incoming, self.key); + let wrapped = fut.map(|stream_sink| { + let mapped = stream_sink.map_err(map_err as fn(_) -> _); + RwStreamSink::new(mapped) + }).map_err(map_err); + Box::new(wrapped) + } } #[inline] fn map_err(err: SecioError) -> IoError { - debug!(target: "libp2p-secio", "error during secio handshake {:?}", err); - IoError::new(IoErrorKind::InvalidData, err) + debug!(target: "libp2p-secio", "error during secio handshake {:?}", err); + IoError::new(IoErrorKind::InvalidData, err) } /// Wraps around an object that implements `AsyncRead` and `AsyncWrite`. @@ -228,67 +228,69 @@ fn map_err(err: SecioError) -> IoError { /// Implements `Sink` and `Stream` whose items are frames of data. Each frame is encoded /// individually, so you are encouraged to group data in few frames if possible. pub struct SecioMiddleware { - inner: codec::FullCodec, - remote_pubkey_der: Vec, + inner: codec::FullCodec, + remote_pubkey_der: Vec, } impl SecioMiddleware - where S: AsyncRead + AsyncWrite +where + S: AsyncRead + AsyncWrite, { - /// Attempts to perform a handshake on the given socket. - /// - /// On success, produces a `SecioMiddleware` that can then be used to encode/decode - /// communications. - pub fn handshake<'a>( - socket: S, - key_pair: SecioKeyPair, - ) -> Box, Error = SecioError> + 'a> - where S: 'a - { - let SecioKeyPairInner::Rsa { private, public } = key_pair.inner; + /// Attempts to perform a handshake on the given socket. + /// + /// On success, produces a `SecioMiddleware` that can then be used to encode/decode + /// communications. + pub fn handshake<'a>( + socket: S, + key_pair: SecioKeyPair, + ) -> Box, Error = SecioError> + 'a> + where + S: 'a, + { + let SecioKeyPairInner::Rsa { private, public } = key_pair.inner; - let fut = handshake::handshake(socket, public, private) - .map(|(inner, pubkey)| { - SecioMiddleware { - inner: inner, - remote_pubkey_der: pubkey, - } - }); - Box::new(fut) - } + let fut = + handshake::handshake(socket, public, private).map(|(inner, pubkey)| SecioMiddleware { + inner: inner, + remote_pubkey_der: pubkey, + }); + Box::new(fut) + } - /// Returns the public key of the remote in the `DER` format. - #[inline] - pub fn remote_public_key_der(&self) -> SecioPublicKey { - SecioPublicKey::Rsa(&self.remote_pubkey_der) - } + /// Returns the public key of the remote in the `DER` format. + #[inline] + pub fn remote_public_key_der(&self) -> SecioPublicKey { + SecioPublicKey::Rsa(&self.remote_pubkey_der) + } } impl Sink for SecioMiddleware - where S: AsyncRead + AsyncWrite +where + S: AsyncRead + AsyncWrite, { - type SinkItem = BytesMut; - type SinkError = IoError; + type SinkItem = BytesMut; + type SinkError = IoError; - #[inline] - fn start_send(&mut self, item: Self::SinkItem) -> StartSend { - self.inner.start_send(item) - } + #[inline] + fn start_send(&mut self, item: Self::SinkItem) -> StartSend { + self.inner.start_send(item) + } - #[inline] - fn poll_complete(&mut self) -> Poll<(), Self::SinkError> { - self.inner.poll_complete() - } + #[inline] + fn poll_complete(&mut self) -> Poll<(), Self::SinkError> { + self.inner.poll_complete() + } } impl Stream for SecioMiddleware - where S: AsyncRead + AsyncWrite +where + S: AsyncRead + AsyncWrite, { - type Item = Vec; - type Error = SecioError; + type Item = Vec; + type Error = SecioError; - #[inline] - fn poll(&mut self) -> Poll, Self::Error> { - self.inner.poll() - } + #[inline] + fn poll(&mut self) -> Poll, Self::Error> { + self.inner.poll() + } } diff --git a/libp2p-swarm/src/connection_reuse.rs b/libp2p-swarm/src/connection_reuse.rs index f0b0a977..49bf8daa 100644 --- a/libp2p-swarm/src/connection_reuse.rs +++ b/libp2p-swarm/src/connection_reuse.rs @@ -40,7 +40,7 @@ //! `MuxedTransport` trait. use fnv::FnvHashMap; -use futures::future::{self, IntoFuture, FutureResult}; +use futures::future::{self, FutureResult, IntoFuture}; use futures::{Async, Future, Poll, Stream}; use futures::stream::Fuse as StreamFuse; use futures::sync::mpsc; @@ -59,289 +59,323 @@ use transport::{ConnectionUpgrade, MuxedTransport, Transport, UpgradedNode}; #[derive(Clone)] pub struct ConnectionReuse where - T: Transport, - C: ConnectionUpgrade, - C::Output: StreamMuxer, + T: Transport, + C: ConnectionUpgrade, + C::Output: StreamMuxer, { - // Underlying transport and connection upgrade for when we need to dial or listen. - inner: UpgradedNode, + // Underlying transport and connection upgrade for when we need to dial or listen. + inner: UpgradedNode, - // Struct shared between most of the `ConnectionReuse` infrastructure. - shared: Arc>>, + // Struct shared between most of the `ConnectionReuse` infrastructure. + shared: Arc>>, } -struct Shared where M: StreamMuxer { - // List of active muxers. - active_connections: FnvHashMap, +struct Shared +where + M: StreamMuxer, +{ + // List of active muxers. + active_connections: FnvHashMap, - // List of pending inbound substreams from dialed nodes. - // Only add to this list elements received through `add_to_next_rx`. - next_incoming: Vec<(M, M::InboundSubstream, Multiaddr)>, + // List of pending inbound substreams from dialed nodes. + // Only add to this list elements received through `add_to_next_rx`. + next_incoming: Vec<(M, M::InboundSubstream, Multiaddr)>, - // New elements are not directly added to `next_incoming`. Instead they are sent to this - // channel. This is done so that we can wake up tasks whenever a new element is added. - add_to_next_rx: mpsc::UnboundedReceiver<(M, M::InboundSubstream, Multiaddr)>, + // New elements are not directly added to `next_incoming`. Instead they are sent to this + // channel. This is done so that we can wake up tasks whenever a new element is added. + add_to_next_rx: mpsc::UnboundedReceiver<(M, M::InboundSubstream, Multiaddr)>, - // Other side of `add_to_next_rx`. - add_to_next_tx: mpsc::UnboundedSender<(M, M::InboundSubstream, Multiaddr)>, + // Other side of `add_to_next_rx`. + add_to_next_tx: mpsc::UnboundedSender<(M, M::InboundSubstream, Multiaddr)>, } impl From> for ConnectionReuse where - T: Transport, - C: ConnectionUpgrade, - C::Output: StreamMuxer, + T: Transport, + C: ConnectionUpgrade, + C::Output: StreamMuxer, { - #[inline] - fn from(node: UpgradedNode) -> ConnectionReuse { - let (tx, rx) = mpsc::unbounded(); + #[inline] + fn from(node: UpgradedNode) -> ConnectionReuse { + let (tx, rx) = mpsc::unbounded(); - ConnectionReuse { - inner: node, - shared: Arc::new(Mutex::new(Shared { - active_connections: Default::default(), - next_incoming: Vec::new(), - add_to_next_rx: rx, - add_to_next_tx: tx, - })), - } - } + ConnectionReuse { + inner: node, + shared: Arc::new(Mutex::new(Shared { + active_connections: Default::default(), + next_incoming: Vec::new(), + add_to_next_rx: rx, + add_to_next_tx: tx, + })), + } + } } impl Transport for ConnectionReuse where - T: Transport + 'static, // TODO: 'static :( - C: ConnectionUpgrade + 'static, // TODO: 'static :( - C: Clone, - C::Output: StreamMuxer + Clone, - C::NamesIter: Clone, // TODO: not elegant + T: Transport + 'static, // TODO: 'static :( + C: ConnectionUpgrade + 'static, // TODO: 'static :( + C: Clone, + C::Output: StreamMuxer + Clone, + C::NamesIter: Clone, // TODO: not elegant { - type RawConn = ::Substream; - type Listener = Box>; - type ListenerUpgrade = FutureResult<(Self::RawConn, Multiaddr), IoError>; - type Dial = Box>; + type RawConn = ::Substream; + type Listener = Box>; + type ListenerUpgrade = FutureResult<(Self::RawConn, Multiaddr), IoError>; + type Dial = Box>; - fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { - let (listener, new_addr) = match self.inner.listen_on(addr.clone()) { - Ok((l, a)) => (l, a), - Err((inner, addr)) => { - return Err((ConnectionReuse { inner: inner, shared: self.shared }, addr)); - } - }; + fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { + let (listener, new_addr) = match self.inner.listen_on(addr.clone()) { + Ok((l, a)) => (l, a), + Err((inner, addr)) => { + return Err(( + ConnectionReuse { + inner: inner, + shared: self.shared, + }, + addr, + )); + } + }; - let listener = ConnectionReuseListener { - shared: self.shared.clone(), - listener: listener.fuse(), - current_upgrades: Vec::new(), - connections: Vec::new(), - }; + let listener = ConnectionReuseListener { + shared: self.shared.clone(), + listener: listener.fuse(), + current_upgrades: Vec::new(), + connections: Vec::new(), + }; - Ok((Box::new(listener) as Box<_>, new_addr)) - } + Ok((Box::new(listener) as Box<_>, new_addr)) + } - fn dial(self, addr: Multiaddr) -> Result { - // If we already have an active connection, use it! - if let Some(connec) = self.shared.lock().active_connections.get(&addr).map(|c| c.clone()) { - let future = connec.outbound().map(|s| (s, addr)); - return Ok(Box::new(future) as Box<_>); - } + fn dial(self, addr: Multiaddr) -> Result { + // If we already have an active connection, use it! + if let Some(connec) = self.shared + .lock() + .active_connections + .get(&addr) + .map(|c| c.clone()) + { + let future = connec.outbound().map(|s| (s, addr)); + return Ok(Box::new(future) as Box<_>); + } - // TODO: handle if we're already in the middle in dialing that same node? - // TODO: try dialing again if the existing connection has dropped + // TODO: handle if we're already in the middle in dialing that same node? + // TODO: try dialing again if the existing connection has dropped - let dial = match self.inner.dial(addr) { - Ok(l) => l, - Err((inner, addr)) => { - return Err((ConnectionReuse { inner: inner, shared: self.shared }, addr)); - } - }; + let dial = match self.inner.dial(addr) { + Ok(l) => l, + Err((inner, addr)) => { + return Err(( + ConnectionReuse { + inner: inner, + shared: self.shared, + }, + addr, + )); + } + }; - let shared = self.shared.clone(); - let dial = dial - .into_future() - .and_then(move |(connec, addr)| { - // Always replace the active connection because we are the most recent. - let mut lock = shared.lock(); - lock.active_connections.insert(addr.clone(), connec.clone()); - // TODO: doesn't need locking ; the sender could be extracted - let _ = lock.add_to_next_tx - .unbounded_send((connec.clone(), connec.clone().inbound(), addr.clone())); - connec.outbound().map(|s| (s, addr)) - }); + let shared = self.shared.clone(); + let dial = dial.into_future().and_then(move |(connec, addr)| { + // Always replace the active connection because we are the most recent. + let mut lock = shared.lock(); + lock.active_connections.insert(addr.clone(), connec.clone()); + // TODO: doesn't need locking ; the sender could be extracted + let _ = lock.add_to_next_tx.unbounded_send(( + connec.clone(), + connec.clone().inbound(), + addr.clone(), + )); + connec.outbound().map(|s| (s, addr)) + }); - Ok(Box::new(dial) as Box<_>) - } + Ok(Box::new(dial) as Box<_>) + } - #[inline] - fn nat_traversal(&self, server: &Multiaddr, observed: &Multiaddr) -> Option { - self.inner.transport().nat_traversal(server, observed) - } + #[inline] + fn nat_traversal(&self, server: &Multiaddr, observed: &Multiaddr) -> Option { + self.inner.transport().nat_traversal(server, observed) + } } impl MuxedTransport for ConnectionReuse where - T: Transport + 'static, // TODO: 'static :( - C: ConnectionUpgrade + 'static, // TODO: 'static :( - C: Clone, - C::Output: StreamMuxer + Clone, - C::NamesIter: Clone, // TODO: not elegant + T: Transport + 'static, // TODO: 'static :( + C: ConnectionUpgrade + 'static, // TODO: 'static :( + C: Clone, + C::Output: StreamMuxer + Clone, + C::NamesIter: Clone, // TODO: not elegant { - type Incoming = ConnectionReuseIncoming; - type IncomingUpgrade = future::FutureResult<(::Substream, Multiaddr), IoError>; + type Incoming = ConnectionReuseIncoming; + type IncomingUpgrade = + future::FutureResult<(::Substream, Multiaddr), IoError>; - #[inline] - fn next_incoming(self) -> Self::Incoming { - ConnectionReuseIncoming { shared: self.shared.clone() } - } + #[inline] + fn next_incoming(self) -> Self::Incoming { + ConnectionReuseIncoming { + shared: self.shared.clone(), + } + } } /// Implementation of `Stream` for the connections incoming from listening on a specific address. pub struct ConnectionReuseListener where - S: Stream, - F: Future, - M: StreamMuxer, + S: Stream, + F: Future, + M: StreamMuxer, { - // The main listener. `S` is from the underlying transport. - listener: StreamFuse, - current_upgrades: Vec, - connections: Vec<(M, ::InboundSubstream, Multiaddr)>, + // The main listener. `S` is from the underlying transport. + listener: StreamFuse, + current_upgrades: Vec, + connections: Vec<(M, ::InboundSubstream, Multiaddr)>, - // Shared between the whole connection reuse mechanism. - shared: Arc>>, + // Shared between the whole connection reuse mechanism. + shared: Arc>>, } impl Stream for ConnectionReuseListener -where S: Stream, - F: Future, - M: StreamMuxer + Clone + 'static // TODO: 'static :( +where + S: Stream, + F: Future, + M: StreamMuxer + Clone + 'static, // TODO: 'static :( { - type Item = FutureResult<(M::Substream, Multiaddr), IoError>; - type Error = IoError; + type Item = FutureResult<(M::Substream, Multiaddr), IoError>; + type Error = IoError; - fn poll(&mut self) -> Poll, Self::Error> { - // Check for any incoming connection on the listening socket. - // Note that since `self.listener` is a `Fuse`, it's not a problem to continue polling even - // after it is finished or after it error'ed. - match self.listener.poll() { - Ok(Async::Ready(Some(upgrade))) => { - self.current_upgrades.push(upgrade); - } - Ok(Async::NotReady) => {}, - Ok(Async::Ready(None)) => { - if self.connections.is_empty() && self.current_upgrades.is_empty() { - return Ok(Async::Ready(None)); - } - } - Err(err) => { - if self.connections.is_empty() && self.current_upgrades.is_empty() { - return Err(err); - } - } - }; + fn poll(&mut self) -> Poll, Self::Error> { + // Check for any incoming connection on the listening socket. + // Note that since `self.listener` is a `Fuse`, it's not a problem to continue polling even + // after it is finished or after it error'ed. + match self.listener.poll() { + Ok(Async::Ready(Some(upgrade))) => { + self.current_upgrades.push(upgrade); + } + Ok(Async::NotReady) => {} + Ok(Async::Ready(None)) => { + if self.connections.is_empty() && self.current_upgrades.is_empty() { + return Ok(Async::Ready(None)); + } + } + Err(err) => { + if self.connections.is_empty() && self.current_upgrades.is_empty() { + return Err(err); + } + } + }; - // Check whether any upgrade (to a muxer) on an incoming connection is ready. - // We extract everything at the start, then insert back the elements that we still want at - // the next iteration. - for n in (0 .. self.current_upgrades.len()).rev() { + // Check whether any upgrade (to a muxer) on an incoming connection is ready. + // We extract everything at the start, then insert back the elements that we still want at + // the next iteration. + for n in (0..self.current_upgrades.len()).rev() { let mut current_upgrade = self.current_upgrades.swap_remove(n); - match current_upgrade.poll() { - Ok(Async::Ready((muxer, client_addr))) => { - let next_incoming = muxer.clone().inbound(); - self.connections.push((muxer.clone(), next_incoming, client_addr.clone())); - // We overwrite any current active connection to that multiaddr because we - // are the freshest possible connection. - self.shared.lock().active_connections.insert(client_addr, muxer); - }, - Ok(Async::NotReady) => { - self.current_upgrades.push(current_upgrade); - }, - Err(err) => { - // Insert the rest of the pending upgrades, but not the current one. - return Ok(Async::Ready(Some(future::err(err)))); - }, - } - } + match current_upgrade.poll() { + Ok(Async::Ready((muxer, client_addr))) => { + let next_incoming = muxer.clone().inbound(); + self.connections + .push((muxer.clone(), next_incoming, client_addr.clone())); + // We overwrite any current active connection to that multiaddr because we + // are the freshest possible connection. + self.shared + .lock() + .active_connections + .insert(client_addr, muxer); + } + Ok(Async::NotReady) => { + self.current_upgrades.push(current_upgrade); + } + Err(err) => { + // Insert the rest of the pending upgrades, but not the current one. + return Ok(Async::Ready(Some(future::err(err)))); + } + } + } - // Check whether any incoming substream is ready. - for n in (0 .. self.connections.len()).rev() { - let (muxer, mut next_incoming, client_addr) = self.connections.swap_remove(n); - match next_incoming.poll() { - Ok(Async::Ready(incoming)) => { - // A new substream is ready. - let mut new_next = muxer.clone().inbound(); - self.connections.push((muxer, new_next, client_addr.clone())); - return Ok(Async::Ready(Some(Ok((incoming, client_addr)).into_future()))); - } - Ok(Async::NotReady) => { - self.connections.push((muxer, next_incoming, client_addr)); - } - Err(err) => { - // Insert the rest of the pending connections, but not the current one. - return Ok(Async::Ready(Some(future::err(err)))); - } - } - } + // Check whether any incoming substream is ready. + for n in (0..self.connections.len()).rev() { + let (muxer, mut next_incoming, client_addr) = self.connections.swap_remove(n); + match next_incoming.poll() { + Ok(Async::Ready(incoming)) => { + // A new substream is ready. + let mut new_next = muxer.clone().inbound(); + self.connections + .push((muxer, new_next, client_addr.clone())); + return Ok(Async::Ready(Some( + Ok((incoming, client_addr)).into_future(), + ))); + } + Ok(Async::NotReady) => { + self.connections.push((muxer, next_incoming, client_addr)); + } + Err(err) => { + // Insert the rest of the pending connections, but not the current one. + return Ok(Async::Ready(Some(future::err(err)))); + } + } + } - // Nothing is ready, return `NotReady`. - Ok(Async::NotReady) - } + // Nothing is ready, return `NotReady`. + Ok(Async::NotReady) + } } /// Implementation of `Future` that yields the next incoming substream from a dialed connection. pub struct ConnectionReuseIncoming - where M: StreamMuxer +where + M: StreamMuxer, { - // Shared between the whole connection reuse system. - shared: Arc>>, + // Shared between the whole connection reuse system. + shared: Arc>>, } impl Future for ConnectionReuseIncoming - where M: Clone + StreamMuxer, +where + M: Clone + StreamMuxer, { - type Item = future::FutureResult<(M::Substream, Multiaddr), IoError>; - type Error = IoError; + type Item = future::FutureResult<(M::Substream, Multiaddr), IoError>; + type Error = IoError; - fn poll(&mut self) -> Poll { - let mut lock = self.shared.lock(); + fn poll(&mut self) -> Poll { + let mut lock = self.shared.lock(); - // Try to get any new muxer from `add_to_next_rx`. - // We push the new muxers to a channel instead of adding them to `next_incoming`, so that - // tasks are notified when something is pushed. - loop { - match lock.add_to_next_rx.poll() { - Ok(Async::Ready(Some(elem))) => { - lock.next_incoming.push(elem); - }, - Ok(Async::NotReady) => break, - Ok(Async::Ready(None)) | Err(_) => { - unreachable!("the sender and receiver are both in the same struct, therefore \ - the link can never break") - }, - } - } + // Try to get any new muxer from `add_to_next_rx`. + // We push the new muxers to a channel instead of adding them to `next_incoming`, so that + // tasks are notified when something is pushed. + loop { + match lock.add_to_next_rx.poll() { + Ok(Async::Ready(Some(elem))) => { + lock.next_incoming.push(elem); + } + Ok(Async::NotReady) => break, + Ok(Async::Ready(None)) | Err(_) => unreachable!( + "the sender and receiver are both in the same struct, therefore \ + the link can never break" + ), + } + } - // Check whether any incoming substream is ready. - for n in (0 .. lock.next_incoming.len()).rev() { - let (muxer, mut future, addr) = lock.next_incoming.swap_remove(n); - match future.poll() { - Ok(Async::Ready(value)) => { - // A substream is ready ; push back the muxer for the next time this function - // is called, then return. - let next = muxer.clone().inbound(); - lock.next_incoming.push((muxer, next, addr.clone())); - return Ok(Async::Ready(future::ok((value, addr)))); - }, - Ok(Async::NotReady) => { - lock.next_incoming.push((muxer, future, addr)); - }, - Err(_) => { - // In case of error, we just not push back the element, which drops it. - }, - } - } + // Check whether any incoming substream is ready. + for n in (0..lock.next_incoming.len()).rev() { + let (muxer, mut future, addr) = lock.next_incoming.swap_remove(n); + match future.poll() { + Ok(Async::Ready(value)) => { + // A substream is ready ; push back the muxer for the next time this function + // is called, then return. + let next = muxer.clone().inbound(); + lock.next_incoming.push((muxer, next, addr.clone())); + return Ok(Async::Ready(future::ok((value, addr)))); + } + Ok(Async::NotReady) => { + lock.next_incoming.push((muxer, future, addr)); + } + Err(_) => { + // In case of error, we just not push back the element, which drops it. + } + } + } - // Nothing is ready. - Ok(Async::NotReady) - } + // Nothing is ready. + Ok(Async::NotReady) + } } diff --git a/libp2p-swarm/src/lib.rs b/libp2p-swarm/src/lib.rs index 1ede217a..ffc80432 100644 --- a/libp2p-swarm/src/lib.rs +++ b/libp2p-swarm/src/lib.rs @@ -22,60 +22,60 @@ //#![doc(include = "../README.md")] //! Transport, protocol upgrade and swarm systems of *libp2p*. -//! +//! //! This crate contains all the core traits and mechanisms of the transport and swarm systems //! of *libp2p*. -//! +//! //! # The `Transport` trait -//! +//! //! The main trait that this crate provides is `Transport`, which provides the `dial` and //! `listen_on` methods and can be used to dial or listen on a multiaddress. The `swarm` crate //! itself does not provide any concrete (ie. non-dummy, non-adapter) implementation of this trait. //! It is implemented on structs that are provided by external crates, such as `TcpConfig` from //! `tcp-transport`, `UdpConfig`, or `WebsocketConfig` (note: as of the writing of this //! documentation, the last two structs don't exist yet). -//! +//! //! Each implementation of `Transport` only supports *some* multiaddress protocols, for example //! the `TcpConfig` struct only supports multiaddresses that look like `/ip*/*.*.*.*/tcp/*`. It is //! possible to group two implementations of `Transport` with the `or_transport` method, in order //! to obtain a single object that supports the protocols of both objects at once. This can be done //! multiple times in a row in order to chain as many implementations as you want. -//! +//! //! // TODO: right now only tcp-transport exists, we need to add an example for chaining //! // multiple transports once that makes sense -//! +//! //! ## The `MuxedTransport` trait -//! +//! //! The `MuxedTransport` trait is an extension to the `Transport` trait, and is implemented on //! transports that can receive incoming connections on streams that have been opened with `dial()`. -//! +//! //! The trait provides the `next_incoming()` method, which returns a future that will resolve to //! the next substream that arrives from a dialed node. -//! +//! //! > **Note**: This trait is mainly implemented for transports that provide stream muxing //! > capabilities, but it can also be implemented in a dummy way by returning an empty //! > iterator. -//! +//! //! # Connection upgrades -//! +//! //! Once a socket has been opened with a remote through a `Transport`, it can be *upgraded*. This //! consists in negotiating a protocol with the remote (through `multistream-select`), and applying //! that protocol on the socket. -//! +//! //! A potential connection upgrade is represented with the `ConnectionUpgrade` trait. The trait //! consists in a protocol name plus a method that turns the socket into an `Output` object whose //! nature and type is specific to each upgrade. -//! +//! //! There exists three kinds of connection upgrades: middlewares, muxers, and actual protocols. -//! +//! //! ## Middlewares -//! +//! //! Examples of middleware connection upgrades include `PlainTextConfig` (dummy upgrade) or //! `SecioConfig` (encyption layer, provided by the `secio` crate). -//! +//! //! The output of a middleware connection upgrade implements the `AsyncRead` and `AsyncWrite` //! traits, just like sockets do. -//! +//! //! A middleware can be applied on a transport by using the `with_upgrade` method of the //! `Transport` trait. The return value of this method also implements the `Transport` trait, which //! means that you can call `dial()` and `listen_on()` on it in order to directly obtain an @@ -83,66 +83,66 @@ //! `next_incoming()` method will automatically apply the upgrade on both the dialer and the //! listener. An error is produced if the remote doesn't support the protocol corresponding to the //! connection upgrade. -//! +//! //! ``` //! extern crate libp2p_swarm; //! extern crate libp2p_tcp_transport; //! extern crate tokio_core; -//! +//! //! use libp2p_swarm::Transport; -//! +//! //! # fn main() { //! let tokio_core = tokio_core::reactor::Core::new().unwrap(); //! let tcp_transport = libp2p_tcp_transport::TcpConfig::new(tokio_core.handle()); //! let upgraded = tcp_transport.with_upgrade(libp2p_swarm::PlainTextConfig); -//! +//! //! // upgraded.dial(...) // automatically applies the plain text protocol on the socket //! # } //! ``` //! //! ## Muxers -//! +//! //! The concept of *muxing* consists in using a single stream as if it was multiple substreams. -//! +//! //! If the output of the connection upgrade instead implements the `StreamMuxer` and `Clone` //! traits, then you can turn the `UpgradedNode` struct into a `ConnectionReuse` struct by calling //! `ConnectionReuse::from(upgraded_node)`. -//! +//! //! The `ConnectionReuse` struct then implements the `Transport` and `MuxedTransport` traits, and //! can be used to dial or listen to multiaddresses, just like any other transport. The only //! difference is that dialing a node will try to open a new substream on an existing connection //! instead of opening a new one every time. -//! +//! //! > **Note**: Right now the `ConnectionReuse` struct is not fully implemented. -//! +//! //! TODO: add an example once the multiplex pull request is merged -//! +//! //! ## Actual protocols -//! +//! //! *Actual protocols* work the same way as middlewares, except that their `Output` doesn't //! implement the `AsyncRead` and `AsyncWrite` traits. This means that that the return value of //! `with_upgrade` does **not** implement the `Transport` trait and thus cannot be used as a //! transport. -//! +//! //! However the `UpgradedNode` struct returned by `with_upgrade` still provides methods named //! `dial`, `listen_on`, and `next_incoming`, which will yield you a `Future` or a `Stream`, //! which you can use to obtain the `Output`. This `Output` can then be used in a protocol-specific //! way to use the protocol. -//! +//! //! ```no_run //! extern crate futures; //! extern crate libp2p_ping; //! extern crate libp2p_swarm; //! extern crate libp2p_tcp_transport; //! extern crate tokio_core; -//! +//! //! use futures::Future; //! use libp2p_ping::Ping; //! use libp2p_swarm::Transport; -//! +//! //! # fn main() { //! let mut core = tokio_core::reactor::Core::new().unwrap(); -//! +//! //! let ping_finished_future = libp2p_tcp_transport::TcpConfig::new(core.handle()) //! // We have a `TcpConfig` struct that implements `Transport`, and apply a `Ping` upgrade on it. //! .with_upgrade(Ping) @@ -152,14 +152,14 @@ //! .and_then(|((mut pinger, service), _)| { //! pinger.ping().map_err(|_| panic!()).select(service).map_err(|_| panic!()) //! }); -//! +//! //! // Runs until the ping arrives. //! core.run(ping_finished_future).unwrap(); //! # } //! ``` -//! +//! //! ## Grouping protocols -//! +//! //! You can use the `.or_upgrade()` method to group multiple upgrades together. The return value //! also implements the `ConnectionUpgrade` trait and will choose one of the protocols amongst the //! ones supported. @@ -177,26 +177,26 @@ //! extern crate libp2p_swarm; //! extern crate libp2p_tcp_transport; //! extern crate tokio_core; -//! +//! //! use futures::Future; //! use libp2p_ping::Ping; //! use libp2p_swarm::Transport; -//! +//! //! # fn main() { //! let mut core = tokio_core::reactor::Core::new().unwrap(); -//! +//! //! let transport = libp2p_tcp_transport::TcpConfig::new(core.handle()) //! .with_dummy_muxing(); -//! +//! //! let (swarm_controller, swarm_future) = libp2p_swarm::swarm(transport, Ping, |(mut pinger, service), client_addr| { //! pinger.ping().map_err(|_| panic!()) //! .select(service).map_err(|_| panic!()) //! .map(|_| ()) //! }); -//! +//! //! // The `swarm_controller` can then be used to do some operations. //! swarm_controller.listen_on("/ip4/0.0.0.0/tcp/0".parse().unwrap()); -//! +//! //! // Runs until everything is finished. //! core.run(swarm_future).unwrap(); //! # } @@ -223,6 +223,6 @@ pub use self::connection_reuse::ConnectionReuse; pub use self::multiaddr::Multiaddr; pub use self::muxing::StreamMuxer; pub use self::swarm::{swarm, SwarmController, SwarmFuture}; -pub use self::transport::{ConnectionUpgrade, PlainTextConfig, Transport, UpgradedNode, OrUpgrade}; -pub use self::transport::{Endpoint, SimpleProtocol, MuxedTransport, UpgradeExt}; -pub use self::transport::{DeniedConnectionUpgrade}; +pub use self::transport::{ConnectionUpgrade, OrUpgrade, PlainTextConfig, Transport, UpgradedNode}; +pub use self::transport::{Endpoint, MuxedTransport, SimpleProtocol, UpgradeExt}; +pub use self::transport::DeniedConnectionUpgrade; diff --git a/libp2p-swarm/src/muxing.rs b/libp2p-swarm/src/muxing.rs index 62d2e6fd..d4a6fadf 100644 --- a/libp2p-swarm/src/muxing.rs +++ b/libp2p-swarm/src/muxing.rs @@ -27,17 +27,17 @@ use tokio_io::{AsyncRead, AsyncWrite}; /// > **Note**: The methods of this trait consume the object, but if the object implements `Clone` /// > then you can clone it and keep the original in order to open additional substreams. pub trait StreamMuxer { - /// Type of the object that represents the raw substream where data can be read and written. - type Substream: AsyncRead + AsyncWrite; - /// Future that will be resolved when a new incoming substream is open. - type InboundSubstream: Future; - /// Future that will be resolved when the outgoing substream is open. - type OutboundSubstream: Future; + /// Type of the object that represents the raw substream where data can be read and written. + type Substream: AsyncRead + AsyncWrite; + /// Future that will be resolved when a new incoming substream is open. + type InboundSubstream: Future; + /// Future that will be resolved when the outgoing substream is open. + type OutboundSubstream: Future; - /// Produces a future that will be resolved when a new incoming substream arrives. - fn inbound(self) -> Self::InboundSubstream; + /// Produces a future that will be resolved when a new incoming substream arrives. + fn inbound(self) -> Self::InboundSubstream; - /// Opens a new outgoing substream, and produces a future that will be resolved when it becomes - /// available. - fn outbound(self) -> Self::OutboundSubstream; + /// Opens a new outgoing substream, and produces a future that will be resolved when it becomes + /// available. + fn outbound(self) -> Self::OutboundSubstream; } diff --git a/libp2p-swarm/src/swarm.rs b/libp2p-swarm/src/swarm.rs index b654cba4..da80c02f 100644 --- a/libp2p-swarm/src/swarm.rs +++ b/libp2p-swarm/src/swarm.rs @@ -19,7 +19,7 @@ // DEALINGS IN THE SOFTWARE. use std::io::Error as IoError; -use futures::{IntoFuture, Future, Stream, Async, Poll, future}; +use futures::{future, Async, Future, IntoFuture, Poll, Stream}; use futures::sync::mpsc; use {ConnectionUpgrade, Multiaddr, MuxedTransport, UpgradedNode}; @@ -31,13 +31,17 @@ use {ConnectionUpgrade, Multiaddr, MuxedTransport, UpgradedNode}; /// Produces a `SwarmController` and an implementation of `Future`. The controller can be used to /// control, and the `Future` must be driven to completion in order for things to work. /// -pub fn swarm(transport: T, upgrade: C, handler: H) - -> (SwarmController, SwarmFuture) - where T: MuxedTransport + Clone + 'static, // TODO: 'static :-/ - C: ConnectionUpgrade + Clone + 'static, // TODO: 'static :-/ - C::NamesIter: Clone, // TODO: not elegant - H: FnMut(C::Output, Multiaddr) -> F, - F: IntoFuture, +pub fn swarm( + transport: T, + upgrade: C, + handler: H, +) -> (SwarmController, SwarmFuture) +where + T: MuxedTransport + Clone + 'static, // TODO: 'static :-/ + C: ConnectionUpgrade + Clone + 'static, // TODO: 'static :-/ + C::NamesIter: Clone, // TODO: not elegant + H: FnMut(C::Output, Multiaddr) -> F, + F: IntoFuture, { let (new_dialers_tx, new_dialers_rx) = mpsc::unbounded(); let (new_listeners_tx, new_listeners_rx) = mpsc::unbounded(); @@ -71,40 +75,53 @@ pub fn swarm(transport: T, upgrade: C, handler: H) /// Allows control of what the swarm is doing. pub struct SwarmController - where T: MuxedTransport + 'static, // TODO: 'static :-/ - C: ConnectionUpgrade + 'static, // TODO: 'static :-/ +where + T: MuxedTransport + 'static, // TODO: 'static :-/ + C: ConnectionUpgrade + 'static, // TODO: 'static :-/ { transport: T, upgraded: UpgradedNode, - new_listeners: mpsc::UnboundedSender>, Error = IoError>>>, + new_listeners: mpsc::UnboundedSender< + Box< + Stream< + Item = Box>, + Error = IoError, + >, + >, + >, new_dialers: mpsc::UnboundedSender>>, new_toprocess: mpsc::UnboundedSender>>, } impl SwarmController - where T: MuxedTransport + Clone + 'static, // TODO: 'static :-/ - C: ConnectionUpgrade + Clone + 'static, // TODO: 'static :-/ - C::NamesIter: Clone, // TODO: not elegant +where + T: MuxedTransport + Clone + 'static, // TODO: 'static :-/ + C: ConnectionUpgrade + Clone + 'static, // TODO: 'static :-/ + C::NamesIter: Clone, // TODO: not elegant { /// Asks the swarm to dial the node with the given multiaddress. The connection is then /// upgraded using the `upgrade`, and the output is sent to the handler that was passed when /// calling `swarm`. // TODO: consider returning a future so that errors can be processed? pub fn dial_to_handler(&self, multiaddr: Multiaddr, upgrade: Du) -> Result<(), Multiaddr> - where Du: ConnectionUpgrade + Clone + 'static, // TODO: 'static :-/ - Du::Output: Into, + where + Du: ConnectionUpgrade + Clone + 'static, // TODO: 'static :-/ + Du::Output: Into, { - match self.transport.clone().with_upgrade(upgrade).dial(multiaddr.clone()) { + match self.transport + .clone() + .with_upgrade(upgrade) + .dial(multiaddr.clone()) + { Ok(dial) => { - let dial = Box::new(dial.map(|(d, client_addr)| (d.into(), client_addr))) as Box>; + let dial = Box::new(dial.map(|(d, client_addr)| (d.into(), client_addr))) + as Box>; // Ignoring errors if the receiver has been closed, because in that situation // nothing is going to be processed anyway. let _ = self.new_dialers.unbounded_send(dial); Ok(()) - }, - Err((_, multiaddr)) => { - Err(multiaddr) - }, + } + Err((_, multiaddr)) => Err(multiaddr), } } @@ -114,11 +131,16 @@ impl SwarmController /// Contrary to `dial_to_handler`, the output of the upgrade is not given to the handler that /// was passed at initialization. // TODO: consider returning a future so that errors can be processed? - pub fn dial_custom_handler(&self, multiaddr: Multiaddr, upgrade: Du, and_then: Df) - -> Result<(), Multiaddr> - where Du: ConnectionUpgrade + 'static, // TODO: 'static :-/ - Df: FnOnce(Du::Output, Multiaddr) -> Dfu + 'static, // TODO: 'static :-/ - Dfu: IntoFuture + 'static, // TODO: 'static :-/ + pub fn dial_custom_handler( + &self, + multiaddr: Multiaddr, + upgrade: Du, + and_then: Df, + ) -> Result<(), Multiaddr> + where + Du: ConnectionUpgrade + 'static, // TODO: 'static :-/ + Df: FnOnce(Du::Output, Multiaddr) -> Dfu + 'static, // TODO: 'static :-/ + Dfu: IntoFuture + 'static, // TODO: 'static :-/ { match self.transport.clone().with_upgrade(upgrade).dial(multiaddr) { Ok(dial) => { @@ -127,10 +149,8 @@ impl SwarmController // nothing is going to be processed anyway. let _ = self.new_toprocess.unbounded_send(dial); Ok(()) - }, - Err((_, multiaddr)) => { - Err(multiaddr) - }, + } + Err((_, multiaddr)) => Err(multiaddr), } } @@ -143,38 +163,55 @@ impl SwarmController // nothing is going to be processed anyway. let _ = self.new_listeners.unbounded_send(listener); Ok(new_addr) - }, - Err((_, multiaddr)) => { - Err(multiaddr) - }, + } + Err((_, multiaddr)) => Err(multiaddr), } } } /// Future that must be driven to completion in order for the swarm to work. pub struct SwarmFuture - where T: MuxedTransport + 'static, // TODO: 'static :-/ - C: ConnectionUpgrade + 'static, // TODO: 'static :-/ +where + T: MuxedTransport + 'static, // TODO: 'static :-/ + C: ConnectionUpgrade + 'static, // TODO: 'static :-/ { upgraded: UpgradedNode, handler: H, - new_listeners: mpsc::UnboundedReceiver>, Error = IoError>>>, - next_incoming: Box>, Error = IoError>>, - listeners: Vec>, Error = IoError>>>, + new_listeners: mpsc::UnboundedReceiver< + Box< + Stream< + Item = Box>, + Error = IoError, + >, + >, + >, + next_incoming: Box< + Future>, Error = IoError>, + >, + listeners: Vec< + Box< + Stream< + Item = Box>, + Error = IoError, + >, + >, + >, listeners_upgrade: Vec>>, dialers: Vec>>, - new_dialers: mpsc::UnboundedReceiver>>, + new_dialers: + mpsc::UnboundedReceiver>>, to_process: Vec>>>, new_toprocess: mpsc::UnboundedReceiver>>, } impl Future for SwarmFuture - where T: MuxedTransport + Clone + 'static, // TODO: 'static :-/, - C: ConnectionUpgrade + Clone + 'static, // TODO: 'static :-/ - C::NamesIter: Clone, // TODO: not elegant - H: FnMut(C::Output, Multiaddr) -> If, - If: IntoFuture, - F: Future, +where + T: MuxedTransport + Clone + 'static, // TODO: 'static :-/, + C: ConnectionUpgrade + Clone + 'static, // TODO: 'static :-/ + C::NamesIter: Clone, // TODO: not elegant + H: FnMut(C::Output, Multiaddr) -> If, + If: IntoFuture, + F: Future, { type Item = (); type Error = IoError; @@ -186,91 +223,94 @@ impl Future for SwarmFuture Ok(Async::Ready(connec)) => { self.next_incoming = self.upgraded.clone().next_incoming(); self.listeners_upgrade.push(connec); - }, - Ok(Async::NotReady) => {}, + } + Ok(Async::NotReady) => {} // TODO: may not be the best idea because we're killing the whole server Err(_err) => { self.next_incoming = self.upgraded.clone().next_incoming(); - }, + } }; match self.new_listeners.poll() { Ok(Async::Ready(Some(new_listener))) => { self.listeners.push(new_listener); - }, + } Ok(Async::Ready(None)) | Err(_) => { // New listener sender has been closed. - }, - Ok(Async::NotReady) => {}, + } + Ok(Async::NotReady) => {} }; match self.new_dialers.poll() { Ok(Async::Ready(Some(new_dialer))) => { self.dialers.push(new_dialer); - }, + } Ok(Async::Ready(None)) | Err(_) => { // New dialers sender has been closed. - }, - Ok(Async::NotReady) => {}, + } + Ok(Async::NotReady) => {} }; match self.new_toprocess.poll() { Ok(Async::Ready(Some(new_toprocess))) => { self.to_process.push(future::Either::B(new_toprocess)); - }, + } Ok(Async::Ready(None)) | Err(_) => { // New to-process sender has been closed. - }, - Ok(Async::NotReady) => {}, + } + Ok(Async::NotReady) => {} }; - for n in (0 .. self.listeners.len()).rev() { + for n in (0..self.listeners.len()).rev() { let mut listener = self.listeners.swap_remove(n); match listener.poll() { Ok(Async::Ready(Some(upgrade))) => { self.listeners.push(listener); self.listeners_upgrade.push(upgrade); - }, + } Ok(Async::NotReady) => { self.listeners.push(listener); - }, - Ok(Async::Ready(None)) => {}, - Err(_err) => {}, // Ignoring errors + } + Ok(Async::Ready(None)) => {} + Err(_err) => {} // Ignoring errors }; } - for n in (0 .. self.listeners_upgrade.len()).rev() { + for n in (0..self.listeners_upgrade.len()).rev() { let mut upgrade = self.listeners_upgrade.swap_remove(n); match upgrade.poll() { Ok(Async::Ready((output, client_addr))) => { - self.to_process.push(future::Either::A(handler(output, client_addr).into_future())); - }, + self.to_process.push(future::Either::A( + handler(output, client_addr).into_future(), + )); + } Ok(Async::NotReady) => { self.listeners_upgrade.push(upgrade); - }, - Err(_err) => {}, // Ignoring errors + } + Err(_err) => {} // Ignoring errors } } - for n in (0 .. self.dialers.len()).rev() { + for n in (0..self.dialers.len()).rev() { let mut dialer = self.dialers.swap_remove(n); match dialer.poll() { Ok(Async::Ready((output, addr))) => { - self.to_process.push(future::Either::A(handler(output, addr).into_future())); - }, + self.to_process + .push(future::Either::A(handler(output, addr).into_future())); + } Ok(Async::NotReady) => { self.dialers.push(dialer); - }, - Err(_err) => {}, // Ignoring errors + } + Err(_err) => {} // Ignoring errors } } - for n in (0 .. self.to_process.len()).rev() { + for n in (0..self.to_process.len()).rev() { let mut to_process = self.to_process.swap_remove(n); match to_process.poll() { - Ok(Async::Ready(())) => {}, + Ok(Async::Ready(())) => {} Ok(Async::NotReady) => self.to_process.push(to_process), - Err(_err) => {}, // Ignoring errors + Err(_err) => {} // Ignoring errors } } diff --git a/libp2p-swarm/src/transport.rs b/libp2p-swarm/src/transport.rs index 6dac3a12..176eab9a 100644 --- a/libp2p-swarm/src/transport.rs +++ b/libp2p-swarm/src/transport.rs @@ -31,7 +31,7 @@ use bytes::Bytes; use connection_reuse::ConnectionReuse; -use futures::{Async, Poll, stream, Stream}; +use futures::{stream, Async, Poll, Stream}; use futures::future::{self, FromErr, Future, FutureResult, IntoFuture}; use multiaddr::Multiaddr; use multistream_select; @@ -52,121 +52,125 @@ use tokio_io::{AsyncRead, AsyncWrite}; /// > so that you would implement this trait on `&Foo` or `&mut Foo` instead of directly /// > on `Foo`. pub trait Transport { - /// The raw connection to a peer. - type RawConn: AsyncRead + AsyncWrite; + /// The raw connection to a peer. + type RawConn: AsyncRead + AsyncWrite; - /// The listener produces incoming connections. - /// - /// An item should be produced whenever a connection is received at the lowest level of the - /// transport stack. The item is a `Future` that is signalled once some pre-processing has - /// taken place, and that connection has been upgraded to the wanted protocols. - type Listener: Stream; + /// The listener produces incoming connections. + /// + /// An item should be produced whenever a connection is received at the lowest level of the + /// transport stack. The item is a `Future` that is signalled once some pre-processing has + /// taken place, and that connection has been upgraded to the wanted protocols. + type Listener: Stream; - /// After a connection has been received, we may need to do some asynchronous pre-processing - /// on it (eg. an intermediary protocol negotiation). While this pre-processing takes place, we - /// want to be able to continue polling on the listener. - type ListenerUpgrade: Future; + /// After a connection has been received, we may need to do some asynchronous pre-processing + /// on it (eg. an intermediary protocol negotiation). While this pre-processing takes place, we + /// want to be able to continue polling on the listener. + type ListenerUpgrade: Future; - /// A future which indicates that we are currently dialing to a peer. - type Dial: IntoFuture; + /// A future which indicates that we are currently dialing to a peer. + type Dial: IntoFuture; - /// Listen on the given multiaddr. Returns a stream of incoming connections, plus a modified - /// version of the `Multiaddr`. This new `Multiaddr` is the one that that should be advertised - /// to other nodes, instead of the one passed as parameter. - /// - /// Returns the address back if it isn't supported. - /// - /// > **Note**: The reason why we need to change the `Multiaddr` on success is to handle - /// > situations such as turning `/ip4/127.0.0.1/tcp/0` into - /// > `/ip4/127.0.0.1/tcp/`. - fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> - where - Self: Sized; + /// Listen on the given multiaddr. Returns a stream of incoming connections, plus a modified + /// version of the `Multiaddr`. This new `Multiaddr` is the one that that should be advertised + /// to other nodes, instead of the one passed as parameter. + /// + /// Returns the address back if it isn't supported. + /// + /// > **Note**: The reason why we need to change the `Multiaddr` on success is to handle + /// > situations such as turning `/ip4/127.0.0.1/tcp/0` into + /// > `/ip4/127.0.0.1/tcp/`. + fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> + where + Self: Sized; - /// Dial to the given multi-addr. - /// - /// Returns either a future which may resolve to a connection, or gives back the multiaddress. - fn dial(self, addr: Multiaddr) -> Result - where - Self: Sized; + /// Dial to the given multi-addr. + /// + /// Returns either a future which may resolve to a connection, or gives back the multiaddress. + fn dial(self, addr: Multiaddr) -> Result + where + Self: Sized; - /// Takes a multiaddress we're listening on (`server`), and tries to convert it to an - /// externally-visible multiaddress. In order to do so, we pass an `observed` address which - /// a remote node observes for one of our dialers. - /// - /// For example, if `server` is `/ip4/0.0.0.0/tcp/3000` and `observed` is - /// `/ip4/80.81.82.83/tcp/29601`, then we should return `/ip4/80.81.82.83/tcp/3000`. Each - /// implementation of `Transport` is only responsible for handling the protocols it supports. - /// - /// Returns `None` if nothing can be determined. This happens if this trait implementation - /// doesn't recognize the protocols, or if `server` and `observed` are related. - fn nat_traversal(&self, server: &Multiaddr, observed: &Multiaddr) -> Option; + /// Takes a multiaddress we're listening on (`server`), and tries to convert it to an + /// externally-visible multiaddress. In order to do so, we pass an `observed` address which + /// a remote node observes for one of our dialers. + /// + /// For example, if `server` is `/ip4/0.0.0.0/tcp/3000` and `observed` is + /// `/ip4/80.81.82.83/tcp/29601`, then we should return `/ip4/80.81.82.83/tcp/3000`. Each + /// implementation of `Transport` is only responsible for handling the protocols it supports. + /// + /// Returns `None` if nothing can be determined. This happens if this trait implementation + /// doesn't recognize the protocols, or if `server` and `observed` are related. + fn nat_traversal(&self, server: &Multiaddr, observed: &Multiaddr) -> Option; - /// Builds a new struct that implements `Transport` that contains both `self` and `other`. - /// - /// The returned object will redirect its calls to `self`, except that if `listen_on` or `dial` - /// return an error then `other` will be tried. - #[inline] - fn or_transport(self, other: T) -> OrTransport - where - Self: Sized, - { - OrTransport(self, other) - } + /// Builds a new struct that implements `Transport` that contains both `self` and `other`. + /// + /// The returned object will redirect its calls to `self`, except that if `listen_on` or `dial` + /// return an error then `other` will be tried. + #[inline] + fn or_transport(self, other: T) -> OrTransport + where + Self: Sized, + { + OrTransport(self, other) + } - /// Wraps this transport inside an upgrade. Whenever a connection that uses this transport - /// is established, it is wrapped inside the upgrade. - /// - /// > **Note**: The concept of an *upgrade* for example includes middlewares such *secio* - /// > (communication encryption), *multiplex*, but also a protocol handler. - #[inline] - fn with_upgrade(self, upgrade: U) -> UpgradedNode - where - Self: Sized, - U: ConnectionUpgrade, - { - UpgradedNode { - transports: self, - upgrade: upgrade, - } - } + /// Wraps this transport inside an upgrade. Whenever a connection that uses this transport + /// is established, it is wrapped inside the upgrade. + /// + /// > **Note**: The concept of an *upgrade* for example includes middlewares such *secio* + /// > (communication encryption), *multiplex*, but also a protocol handler. + #[inline] + fn with_upgrade(self, upgrade: U) -> UpgradedNode + where + Self: Sized, + U: ConnectionUpgrade, + { + UpgradedNode { + transports: self, + upgrade: upgrade, + } + } - /// Builds a dummy implementation of `MuxedTransport` that uses this transport. - /// - /// The resulting object will not actually use muxing. This means that dialing the same node - /// twice will result in two different connections instead of two substreams on the same - /// connection. - #[inline] - fn with_dummy_muxing(self) -> DummyMuxing - where Self: Sized - { - DummyMuxing { inner: self } - } + /// Builds a dummy implementation of `MuxedTransport` that uses this transport. + /// + /// The resulting object will not actually use muxing. This means that dialing the same node + /// twice will result in two different connections instead of two substreams on the same + /// connection. + #[inline] + fn with_dummy_muxing(self) -> DummyMuxing + where + Self: Sized, + { + DummyMuxing { inner: self } + } } /// Extension trait for `Transport`. Implemented on structs that provide a `Transport` on which /// the dialed node can dial you back. pub trait MuxedTransport: Transport { - /// Future resolving to a future that will resolve to an incoming connection. - type Incoming: Future; - /// Future resolving to an incoming connection. - type IncomingUpgrade: Future; + /// Future resolving to a future that will resolve to an incoming connection. + type Incoming: Future; + /// Future resolving to an incoming connection. + type IncomingUpgrade: Future; - /// Returns the next incoming substream opened by a node that we dialed ourselves. - /// - /// > **Note**: Doesn't produce incoming substreams coming from addresses we are listening on. - /// > This only concerns nodes that we dialed with `dial()`. - fn next_incoming(self) -> Self::Incoming - where Self: Sized; + /// Returns the next incoming substream opened by a node that we dialed ourselves. + /// + /// > **Note**: Doesn't produce incoming substreams coming from addresses we are listening on. + /// > This only concerns nodes that we dialed with `dial()`. + fn next_incoming(self) -> Self::Incoming + where + Self: Sized; - /// Returns a stream of incoming connections. - #[inline] - fn incoming(self) -> stream::AndThen, fn(Self) -> Self::Incoming, - Self::Incoming> - where Self: Sized + Clone - { - stream::repeat(self).and_then(|me| me.next_incoming()) - } + /// Returns a stream of incoming connections. + #[inline] + fn incoming( + self, + ) -> stream::AndThen, fn(Self) -> Self::Incoming, Self::Incoming> + where + Self: Sized + Clone, + { + stream::repeat(self).and_then(|me| me.next_incoming()) + } } /// Dummy implementation of `Transport` that just denies every single attempt. @@ -174,36 +178,36 @@ pub trait MuxedTransport: Transport { pub struct DeniedTransport; impl Transport for DeniedTransport { - // TODO: could use `!` for associated types once stable - type RawConn = Cursor>; - type Listener = Box>; - type ListenerUpgrade = Box>; - type Dial = Box>; + // TODO: could use `!` for associated types once stable + type RawConn = Cursor>; + type Listener = Box>; + type ListenerUpgrade = Box>; + type Dial = Box>; - #[inline] - fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { - Err((DeniedTransport, addr)) - } + #[inline] + fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { + Err((DeniedTransport, addr)) + } - #[inline] - fn dial(self, addr: Multiaddr) -> Result { - Err((DeniedTransport, addr)) - } + #[inline] + fn dial(self, addr: Multiaddr) -> Result { + Err((DeniedTransport, addr)) + } - #[inline] - fn nat_traversal(&self, _: &Multiaddr, _: &Multiaddr) -> Option { - None - } + #[inline] + fn nat_traversal(&self, _: &Multiaddr, _: &Multiaddr) -> Option { + None + } } impl MuxedTransport for DeniedTransport { - type Incoming = future::Empty; - type IncomingUpgrade = future::Empty<(Self::RawConn, Multiaddr), IoError>; + type Incoming = future::Empty; + type IncomingUpgrade = future::Empty<(Self::RawConn, Multiaddr), IoError>; - #[inline] - fn next_incoming(self) -> Self::Incoming { - future::empty() - } + #[inline] + fn next_incoming(self) -> Self::Incoming { + future::empty() + } } /// Struct returned by `or_transport()`. @@ -212,354 +216,354 @@ pub struct OrTransport(A, B); impl Transport for OrTransport where - A: Transport, - B: Transport, + A: Transport, + B: Transport, { - type RawConn = EitherSocket; - type Listener = EitherListenStream; - type ListenerUpgrade = EitherListenUpgrade; - type Dial = EitherListenUpgrade<::Future, ::Future>; + type RawConn = EitherSocket; + type Listener = EitherListenStream; + type ListenerUpgrade = EitherListenUpgrade; + type Dial = + EitherListenUpgrade<::Future, ::Future>; - fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { - let (first, addr) = match self.0.listen_on(addr) { - Ok((connec, addr)) => return Ok((EitherListenStream::First(connec), addr)), - Err(err) => err, - }; + fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { + let (first, addr) = match self.0.listen_on(addr) { + Ok((connec, addr)) => return Ok((EitherListenStream::First(connec), addr)), + Err(err) => err, + }; - match self.1.listen_on(addr) { - Ok((connec, addr)) => Ok((EitherListenStream::Second(connec), addr)), - Err((second, addr)) => Err((OrTransport(first, second), addr)), - } - } + match self.1.listen_on(addr) { + Ok((connec, addr)) => Ok((EitherListenStream::Second(connec), addr)), + Err((second, addr)) => Err((OrTransport(first, second), addr)), + } + } - fn dial(self, addr: Multiaddr) -> Result { - let (first, addr) = match self.0.dial(addr) { - Ok(connec) => return Ok(EitherListenUpgrade::First(connec.into_future())), - Err(err) => err, - }; + fn dial(self, addr: Multiaddr) -> Result { + let (first, addr) = match self.0.dial(addr) { + Ok(connec) => return Ok(EitherListenUpgrade::First(connec.into_future())), + Err(err) => err, + }; - match self.1.dial(addr) { - Ok(connec) => Ok(EitherListenUpgrade::Second(connec.into_future())), - Err((second, addr)) => Err((OrTransport(first, second), addr)), - } - } + match self.1.dial(addr) { + Ok(connec) => Ok(EitherListenUpgrade::Second(connec.into_future())), + Err((second, addr)) => Err((OrTransport(first, second), addr)), + } + } - #[inline] - fn nat_traversal(&self, server: &Multiaddr, observed: &Multiaddr) -> Option { - let first = self.0.nat_traversal(server, observed); - if let Some(first) = first { - return Some(first); - } + #[inline] + fn nat_traversal(&self, server: &Multiaddr, observed: &Multiaddr) -> Option { + let first = self.0.nat_traversal(server, observed); + if let Some(first) = first { + return Some(first); + } - self.1.nat_traversal(server, observed) - } + self.1.nat_traversal(server, observed) + } } /// Implementation of `ConnectionUpgrade`. Convenient to use with small protocols. #[derive(Debug)] pub struct SimpleProtocol { - name: Bytes, - // Note: we put the closure `F` in an `Arc` because Rust closures aren't automatically clonable - // yet. - upgrade: Arc, + name: Bytes, + // Note: we put the closure `F` in an `Arc` because Rust closures aren't automatically clonable + // yet. + upgrade: Arc, } impl SimpleProtocol { - /// Builds a `SimpleProtocol`. - #[inline] - pub fn new(name: N, upgrade: F) -> SimpleProtocol - where - N: Into, - { - SimpleProtocol { - name: name.into(), - upgrade: Arc::new(upgrade), - } - } + /// Builds a `SimpleProtocol`. + #[inline] + pub fn new(name: N, upgrade: F) -> SimpleProtocol + where + N: Into, + { + SimpleProtocol { + name: name.into(), + upgrade: Arc::new(upgrade), + } + } } impl Clone for SimpleProtocol { - #[inline] - fn clone(&self) -> Self { - SimpleProtocol { - name: self.name.clone(), - upgrade: self.upgrade.clone(), - } - } + #[inline] + fn clone(&self) -> Self { + SimpleProtocol { + name: self.name.clone(), + upgrade: self.upgrade.clone(), + } + } } impl MuxedTransport for OrTransport where - A: MuxedTransport, - B: MuxedTransport, - A::Incoming: 'static, // TODO: meh :-/ - B::Incoming: 'static, // TODO: meh :-/ - A::IncomingUpgrade: 'static, // TODO: meh :-/ - B::IncomingUpgrade: 'static, // TODO: meh :-/ - A::RawConn: 'static, // TODO: meh :-/ - B::RawConn: 'static, // TODO: meh :-/ + A: MuxedTransport, + B: MuxedTransport, + A::Incoming: 'static, // TODO: meh :-/ + B::Incoming: 'static, // TODO: meh :-/ + A::IncomingUpgrade: 'static, // TODO: meh :-/ + B::IncomingUpgrade: 'static, // TODO: meh :-/ + A::RawConn: 'static, // TODO: meh :-/ + B::RawConn: 'static, // TODO: meh :-/ { - type Incoming = Box>; - type IncomingUpgrade = Box, Multiaddr), Error = IoError>>; + type Incoming = Box>; + type IncomingUpgrade = + Box, Multiaddr), Error = IoError>>; - #[inline] - fn next_incoming(self) -> Self::Incoming { - let first = self.0.next_incoming().map(|out| { - let fut = out.map(move |(v, addr)| (EitherSocket::First(v), addr)); - Box::new(fut) as Box> - }); - let second = self.1.next_incoming().map(|out| { - let fut = out.map(move |(v, addr)| (EitherSocket::Second(v), addr)); - Box::new(fut) as Box> - }); - let future = first.select(second) - .map(|(i, _)| i) - .map_err(|(e, _)| e); - Box::new(future) as Box<_> - } + #[inline] + fn next_incoming(self) -> Self::Incoming { + let first = self.0.next_incoming().map(|out| { + let fut = out.map(move |(v, addr)| (EitherSocket::First(v), addr)); + Box::new(fut) as Box> + }); + let second = self.1.next_incoming().map(|out| { + let fut = out.map(move |(v, addr)| (EitherSocket::Second(v), addr)); + Box::new(fut) as Box> + }); + let future = first.select(second).map(|(i, _)| i).map_err(|(e, _)| e); + Box::new(future) as Box<_> + } } impl ConnectionUpgrade for SimpleProtocol where - C: AsyncRead + AsyncWrite, - F: Fn(C) -> O, - O: IntoFuture, + C: AsyncRead + AsyncWrite, + F: Fn(C) -> O, + O: IntoFuture, { - type NamesIter = iter::Once<(Bytes, ())>; - type UpgradeIdentifier = (); + type NamesIter = iter::Once<(Bytes, ())>; + type UpgradeIdentifier = (); - #[inline] - fn protocol_names(&self) -> Self::NamesIter { - iter::once((self.name.clone(), ())) - } + #[inline] + fn protocol_names(&self) -> Self::NamesIter { + iter::once((self.name.clone(), ())) + } - type Output = O::Item; - type Future = FromErr; + type Output = O::Item; + type Future = FromErr; - #[inline] - fn upgrade(self, socket: C, _: (), _: Endpoint, _: &Multiaddr) -> Self::Future { - let upgrade = &self.upgrade; - upgrade(socket).into_future().from_err() - } + #[inline] + fn upgrade(self, socket: C, _: (), _: Endpoint, _: &Multiaddr) -> Self::Future { + let upgrade = &self.upgrade; + upgrade(socket).into_future().from_err() + } } /// Implements `Stream` and dispatches all method calls to either `First` or `Second`. #[derive(Debug, Copy, Clone)] pub enum EitherListenStream { - First(A), - Second(B), + First(A), + Second(B), } impl Stream for EitherListenStream where - AStream: Stream, - BStream: Stream, + AStream: Stream, + BStream: Stream, { - type Item = EitherListenUpgrade; - type Error = IoError; + type Item = EitherListenUpgrade; + type Error = IoError; - #[inline] - fn poll(&mut self) -> Poll, Self::Error> { - match self { - &mut EitherListenStream::First(ref mut a) => a.poll() - .map(|i| i.map(|v| v.map(EitherListenUpgrade::First))), - &mut EitherListenStream::Second(ref mut a) => a.poll() - .map(|i| i.map(|v| v.map(EitherListenUpgrade::Second))), - } - } + #[inline] + fn poll(&mut self) -> Poll, Self::Error> { + match self { + &mut EitherListenStream::First(ref mut a) => a.poll() + .map(|i| i.map(|v| v.map(EitherListenUpgrade::First))), + &mut EitherListenStream::Second(ref mut a) => a.poll() + .map(|i| i.map(|v| v.map(EitherListenUpgrade::Second))), + } + } } /// Implements `Stream` and dispatches all method calls to either `First` or `Second`. #[derive(Debug, Copy, Clone)] pub enum EitherIncomingStream { - First(A), - Second(B), + First(A), + Second(B), } impl Stream for EitherIncomingStream where - A: Stream, - B: Stream, + A: Stream, + B: Stream, { - type Item = EitherSocket; - type Error = IoError; + type Item = EitherSocket; + type Error = IoError; - #[inline] - fn poll(&mut self) -> Poll, Self::Error> { - match self { - &mut EitherIncomingStream::First(ref mut a) => { - a.poll().map(|i| i.map(|v| v.map(EitherSocket::First))) - } - &mut EitherIncomingStream::Second(ref mut a) => { - a.poll().map(|i| i.map(|v| v.map(EitherSocket::Second))) - } - } - } + #[inline] + fn poll(&mut self) -> Poll, Self::Error> { + match self { + &mut EitherIncomingStream::First(ref mut a) => { + a.poll().map(|i| i.map(|v| v.map(EitherSocket::First))) + } + &mut EitherIncomingStream::Second(ref mut a) => { + a.poll().map(|i| i.map(|v| v.map(EitherSocket::Second))) + } + } + } } // TODO: This type is needed because of the lack of `impl Trait` in stable Rust. -// If Rust had impl Trait we could use the Either enum from the futures crate and add some -// modifiers to it. This custom enum is a combination of Either and these modifiers. +// If Rust had impl Trait we could use the Either enum from the futures crate and add some +// modifiers to it. This custom enum is a combination of Either and these modifiers. #[derive(Debug, Copy, Clone)] pub enum EitherListenUpgrade { - First(A), - Second(B), + First(A), + Second(B), } impl Future for EitherListenUpgrade where - A: Future, - B: Future, + A: Future, + B: Future, { - type Item = (EitherSocket, Multiaddr); - type Error = IoError; + type Item = (EitherSocket, Multiaddr); + type Error = IoError; - #[inline] - fn poll(&mut self) -> Poll { - match self { - &mut EitherListenUpgrade::First(ref mut a) => { - let (item, addr) = try_ready!(a.poll()); - Ok(Async::Ready((EitherSocket::First(item), addr))) - } - &mut EitherListenUpgrade::Second(ref mut b) => { - let (item, addr) = try_ready!(b.poll()); - Ok(Async::Ready((EitherSocket::Second(item), addr))) - } - } - } + #[inline] + fn poll(&mut self) -> Poll { + match self { + &mut EitherListenUpgrade::First(ref mut a) => { + let (item, addr) = try_ready!(a.poll()); + Ok(Async::Ready((EitherSocket::First(item), addr))) + } + &mut EitherListenUpgrade::Second(ref mut b) => { + let (item, addr) = try_ready!(b.poll()); + Ok(Async::Ready((EitherSocket::Second(item), addr))) + } + } + } } /// Implements `Future` and redirects calls to either `First` or `Second`. /// /// Additionally, the output will be wrapped inside a `EitherSocket`. // TODO: This type is needed because of the lack of `impl Trait` in stable Rust. -// If Rust had impl Trait we could use the Either enum from the futures crate and add some -// modifiers to it. This custom enum is a combination of Either and these modifiers. +// If Rust had impl Trait we could use the Either enum from the futures crate and add some +// modifiers to it. This custom enum is a combination of Either and these modifiers. #[derive(Debug, Copy, Clone)] pub enum EitherTransportFuture { - First(A), - Second(B), + First(A), + Second(B), } impl Future for EitherTransportFuture where - A: Future, - B: Future, + A: Future, + B: Future, { - type Item = EitherSocket; - type Error = IoError; + type Item = EitherSocket; + type Error = IoError; - #[inline] - fn poll(&mut self) -> Poll { - match self { - &mut EitherTransportFuture::First(ref mut a) => { - let item = try_ready!(a.poll()); - Ok(Async::Ready(EitherSocket::First(item))) - } - &mut EitherTransportFuture::Second(ref mut b) => { - let item = try_ready!(b.poll()); - Ok(Async::Ready(EitherSocket::Second(item))) - } - } - } + #[inline] + fn poll(&mut self) -> Poll { + match self { + &mut EitherTransportFuture::First(ref mut a) => { + let item = try_ready!(a.poll()); + Ok(Async::Ready(EitherSocket::First(item))) + } + &mut EitherTransportFuture::Second(ref mut b) => { + let item = try_ready!(b.poll()); + Ok(Async::Ready(EitherSocket::Second(item))) + } + } + } } /// Implements `AsyncRead` and `AsyncWrite` and dispatches all method calls to either `First` or /// `Second`. #[derive(Debug, Copy, Clone)] pub enum EitherSocket { - First(A), - Second(B), + First(A), + Second(B), } impl AsyncRead for EitherSocket where - A: AsyncRead, - B: AsyncRead, + A: AsyncRead, + B: AsyncRead, { - #[inline] - unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool { - match self { - &EitherSocket::First(ref a) => a.prepare_uninitialized_buffer(buf), - &EitherSocket::Second(ref b) => b.prepare_uninitialized_buffer(buf), - } - } + #[inline] + unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool { + match self { + &EitherSocket::First(ref a) => a.prepare_uninitialized_buffer(buf), + &EitherSocket::Second(ref b) => b.prepare_uninitialized_buffer(buf), + } + } } impl Read for EitherSocket where - A: Read, - B: Read, + A: Read, + B: Read, { - #[inline] - fn read(&mut self, buf: &mut [u8]) -> Result { - match self { - &mut EitherSocket::First(ref mut a) => a.read(buf), - &mut EitherSocket::Second(ref mut b) => b.read(buf), - } - } + #[inline] + fn read(&mut self, buf: &mut [u8]) -> Result { + match self { + &mut EitherSocket::First(ref mut a) => a.read(buf), + &mut EitherSocket::Second(ref mut b) => b.read(buf), + } + } } impl AsyncWrite for EitherSocket where - A: AsyncWrite, - B: AsyncWrite, + A: AsyncWrite, + B: AsyncWrite, { - #[inline] - fn shutdown(&mut self) -> Poll<(), IoError> { - match self { - &mut EitherSocket::First(ref mut a) => a.shutdown(), - &mut EitherSocket::Second(ref mut b) => b.shutdown(), - } - } + #[inline] + fn shutdown(&mut self) -> Poll<(), IoError> { + match self { + &mut EitherSocket::First(ref mut a) => a.shutdown(), + &mut EitherSocket::Second(ref mut b) => b.shutdown(), + } + } } impl Write for EitherSocket where - A: Write, - B: Write, + A: Write, + B: Write, { - #[inline] - fn write(&mut self, buf: &[u8]) -> Result { - match self { - &mut EitherSocket::First(ref mut a) => a.write(buf), - &mut EitherSocket::Second(ref mut b) => b.write(buf), - } - } + #[inline] + fn write(&mut self, buf: &[u8]) -> Result { + match self { + &mut EitherSocket::First(ref mut a) => a.write(buf), + &mut EitherSocket::Second(ref mut b) => b.write(buf), + } + } - #[inline] - fn flush(&mut self) -> Result<(), IoError> { - match self { - &mut EitherSocket::First(ref mut a) => a.flush(), - &mut EitherSocket::Second(ref mut b) => b.flush(), - } - } + #[inline] + fn flush(&mut self) -> Result<(), IoError> { + match self { + &mut EitherSocket::First(ref mut a) => a.flush(), + &mut EitherSocket::Second(ref mut b) => b.flush(), + } + } } impl StreamMuxer for EitherSocket where - A: StreamMuxer, - B: StreamMuxer, + A: StreamMuxer, + B: StreamMuxer, { - type Substream = EitherSocket; - type InboundSubstream = EitherTransportFuture; - type OutboundSubstream = EitherTransportFuture; + type Substream = EitherSocket; + type InboundSubstream = EitherTransportFuture; + type OutboundSubstream = EitherTransportFuture; - #[inline] - fn inbound(self) -> Self::InboundSubstream { - match self { - EitherSocket::First(a) => EitherTransportFuture::First(a.inbound()), - EitherSocket::Second(b) => EitherTransportFuture::Second(b.inbound()), - } - } + #[inline] + fn inbound(self) -> Self::InboundSubstream { + match self { + EitherSocket::First(a) => EitherTransportFuture::First(a.inbound()), + EitherSocket::Second(b) => EitherTransportFuture::Second(b.inbound()), + } + } - #[inline] - fn outbound(self) -> Self::OutboundSubstream { - match self { - EitherSocket::First(a) => EitherTransportFuture::First(a.outbound()), - EitherSocket::Second(b) => EitherTransportFuture::Second(b.outbound()), - } - } + #[inline] + fn outbound(self) -> Self::OutboundSubstream { + match self { + EitherSocket::First(a) => EitherTransportFuture::First(a.outbound()), + EitherSocket::Second(b) => EitherTransportFuture::Second(b.outbound()), + } + } } /// Implemented on structs that describe a possible upgrade to a connection between two peers. @@ -570,41 +574,46 @@ where /// > This has been designed so that you would implement this trait on `&Foo` or /// > `&mut Foo` instead of directly on `Foo`. pub trait ConnectionUpgrade { - /// Iterator returned by `protocol_names`. - type NamesIter: Iterator; - /// Type that serves as an identifier for the protocol. This type only exists to be returned - /// by the `NamesIter` and then be passed to `upgrade`. - /// - /// This is only useful on implementations that dispatch between multiple possible upgrades. - /// Any basic implementation will probably just use the `()` type. - type UpgradeIdentifier; + /// Iterator returned by `protocol_names`. + type NamesIter: Iterator; + /// Type that serves as an identifier for the protocol. This type only exists to be returned + /// by the `NamesIter` and then be passed to `upgrade`. + /// + /// This is only useful on implementations that dispatch between multiple possible upgrades. + /// Any basic implementation will probably just use the `()` type. + type UpgradeIdentifier; - /// Returns the name of the protocols to advertise to the remote. - fn protocol_names(&self) -> Self::NamesIter; + /// Returns the name of the protocols to advertise to the remote. + fn protocol_names(&self) -> Self::NamesIter; - /// Type of the stream that has been upgraded. Generally wraps around `C` and `Self`. - /// - /// > **Note**: For upgrades that add an intermediary layer (such as `secio` or `multiplex`), - /// > this associated type must implement `AsyncRead + AsyncWrite`. - type Output; - /// Type of the future that will resolve to `Self::Output`. - type Future: Future; + /// Type of the stream that has been upgraded. Generally wraps around `C` and `Self`. + /// + /// > **Note**: For upgrades that add an intermediary layer (such as `secio` or `multiplex`), + /// > this associated type must implement `AsyncRead + AsyncWrite`. + type Output; + /// Type of the future that will resolve to `Self::Output`. + type Future: Future; - /// This method is called after protocol negotiation has been performed. - /// - /// Because performing the upgrade may not be instantaneous (eg. it may require a handshake), - /// this function returns a future instead of the direct output. - fn upgrade(self, socket: C, id: Self::UpgradeIdentifier, ty: Endpoint, - remote_addr: &Multiaddr) -> Self::Future; + /// This method is called after protocol negotiation has been performed. + /// + /// Because performing the upgrade may not be instantaneous (eg. it may require a handshake), + /// this function returns a future instead of the direct output. + fn upgrade( + self, + socket: C, + id: Self::UpgradeIdentifier, + ty: Endpoint, + remote_addr: &Multiaddr, + ) -> Self::Future; } /// Type of connection for the upgrade. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum Endpoint { - /// The socket comes from a dialer. - Dialer, - /// The socket comes from a listener. - Listener, + /// The socket comes from a dialer. + Dialer, + /// The socket comes from a listener. + Listener, } /// Implementation of `ConnectionUpgrade` that always fails to negotiate. @@ -612,34 +621,36 @@ pub enum Endpoint { pub struct DeniedConnectionUpgrade; impl ConnectionUpgrade for DeniedConnectionUpgrade - where C: AsyncRead + AsyncWrite +where + C: AsyncRead + AsyncWrite, { - type NamesIter = iter::Empty<(Bytes, ())>; - type UpgradeIdentifier = (); // TODO: could use `!` - type Output = (); // TODO: could use `!` - type Future = Box>; // TODO: could use `!` + type NamesIter = iter::Empty<(Bytes, ())>; + type UpgradeIdentifier = (); // TODO: could use `!` + type Output = (); // TODO: could use `!` + type Future = Box>; // TODO: could use `!` - #[inline] - fn protocol_names(&self) -> Self::NamesIter { - iter::empty() - } + #[inline] + fn protocol_names(&self) -> Self::NamesIter { + iter::empty() + } - #[inline] - fn upgrade(self, _: C, _: Self::UpgradeIdentifier, _: Endpoint, _: &Multiaddr) -> Self::Future { - unreachable!("the denied connection upgrade always fails to negotiate") - } + #[inline] + fn upgrade(self, _: C, _: Self::UpgradeIdentifier, _: Endpoint, _: &Multiaddr) -> Self::Future { + unreachable!("the denied connection upgrade always fails to negotiate") + } } /// Extension trait for `ConnectionUpgrade`. Automatically implemented on everything. pub trait UpgradeExt { - /// Builds a struct that will choose an upgrade between `self` and `other`, depending on what - /// the remote supports. + /// Builds a struct that will choose an upgrade between `self` and `other`, depending on what + /// the remote supports. fn or_upgrade(self, other: T) -> OrUpgrade - where Self: Sized; + where + Self: Sized; } impl UpgradeExt for T { - #[inline] + #[inline] fn or_upgrade(self, other: U) -> OrUpgrade { OrUpgrade(self, other) } @@ -651,44 +662,48 @@ pub struct OrUpgrade(A, B); impl ConnectionUpgrade for OrUpgrade where - C: AsyncRead + AsyncWrite, - A: ConnectionUpgrade, - B: ConnectionUpgrade, + C: AsyncRead + AsyncWrite, + A: ConnectionUpgrade, + B: ConnectionUpgrade, { - type NamesIter = NamesIterChain; - type UpgradeIdentifier = EitherUpgradeIdentifier; + type NamesIter = NamesIterChain; + type UpgradeIdentifier = EitherUpgradeIdentifier; - #[inline] - fn protocol_names(&self) -> Self::NamesIter { - NamesIterChain { - first: self.0.protocol_names(), - second: self.1.protocol_names(), - } - } + #[inline] + fn protocol_names(&self) -> Self::NamesIter { + NamesIterChain { + first: self.0.protocol_names(), + second: self.1.protocol_names(), + } + } - type Output = EitherSocket; - type Future = EitherConnUpgrFuture; + type Output = EitherSocket; + type Future = EitherConnUpgrFuture; - #[inline] - fn upgrade(self, socket: C, id: Self::UpgradeIdentifier, ty: Endpoint, - remote_addr: &Multiaddr) -> Self::Future - { - match id { - EitherUpgradeIdentifier::First(id) => { - EitherConnUpgrFuture::First(self.0.upgrade(socket, id, ty, remote_addr)) - } - EitherUpgradeIdentifier::Second(id) => { - EitherConnUpgrFuture::Second(self.1.upgrade(socket, id, ty, remote_addr)) - } - } - } + #[inline] + fn upgrade( + self, + socket: C, + id: Self::UpgradeIdentifier, + ty: Endpoint, + remote_addr: &Multiaddr, + ) -> Self::Future { + match id { + EitherUpgradeIdentifier::First(id) => { + EitherConnUpgrFuture::First(self.0.upgrade(socket, id, ty, remote_addr)) + } + EitherUpgradeIdentifier::Second(id) => { + EitherConnUpgrFuture::Second(self.1.upgrade(socket, id, ty, remote_addr)) + } + } + } } /// Internal struct used by the `OrUpgrade` trait. #[derive(Debug, Copy, Clone)] pub enum EitherUpgradeIdentifier { - First(A), - Second(B), + First(A), + Second(B), } /// Implements `Future` and redirects calls to either `First` or `Second`. @@ -696,35 +711,35 @@ pub enum EitherUpgradeIdentifier { /// Additionally, the output will be wrapped inside a `EitherSocket`. /// // TODO: This type is needed because of the lack of `impl Trait` in stable Rust. -// If Rust had impl Trait we could use the Either enum from the futures crate and add some -// modifiers to it. This custom enum is a combination of Either and these modifiers. +// If Rust had impl Trait we could use the Either enum from the futures crate and add some +// modifiers to it. This custom enum is a combination of Either and these modifiers. #[derive(Debug, Copy, Clone)] pub enum EitherConnUpgrFuture { - First(A), - Second(B), + First(A), + Second(B), } impl Future for EitherConnUpgrFuture where - A: Future, - B: Future, + A: Future, + B: Future, { - type Item = EitherSocket; - type Error = IoError; + type Item = EitherSocket; + type Error = IoError; - #[inline] - fn poll(&mut self) -> Poll { - match self { - &mut EitherConnUpgrFuture::First(ref mut a) => { - let item = try_ready!(a.poll()); - Ok(Async::Ready(EitherSocket::First(item))) - } - &mut EitherConnUpgrFuture::Second(ref mut b) => { - let item = try_ready!(b.poll()); - Ok(Async::Ready(EitherSocket::Second(item))) - } - } - } + #[inline] + fn poll(&mut self) -> Poll { + match self { + &mut EitherConnUpgrFuture::First(ref mut a) => { + let item = try_ready!(a.poll()); + Ok(Async::Ready(EitherSocket::First(item))) + } + &mut EitherConnUpgrFuture::Second(ref mut b) => { + let item = try_ready!(b.poll()); + Ok(Async::Ready(EitherSocket::Second(item))) + } + } + } } /// Internal type used by the `OrUpgrade` struct. @@ -733,38 +748,38 @@ where /// > removed eventually. #[derive(Debug, Copy, Clone)] pub struct NamesIterChain { - first: A, - second: B, + first: A, + second: B, } impl Iterator for NamesIterChain where - A: Iterator, - B: Iterator, + A: Iterator, + B: Iterator, { - type Item = (Bytes, EitherUpgradeIdentifier); + type Item = (Bytes, EitherUpgradeIdentifier); - #[inline] - fn next(&mut self) -> Option { - if let Some((name, id)) = self.first.next() { - return Some((name, EitherUpgradeIdentifier::First(id))); - } - if let Some((name, id)) = self.second.next() { - return Some((name, EitherUpgradeIdentifier::Second(id))); - } - None - } + #[inline] + fn next(&mut self) -> Option { + if let Some((name, id)) = self.first.next() { + return Some((name, EitherUpgradeIdentifier::First(id))); + } + if let Some((name, id)) = self.second.next() { + return Some((name, EitherUpgradeIdentifier::Second(id))); + } + None + } - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (min1, max1) = self.first.size_hint(); - let (min2, max2) = self.second.size_hint(); - let max = match (max1, max2) { - (Some(max1), Some(max2)) => max1.checked_add(max2), - _ => None, - }; - (min1.saturating_add(min2), max) - } + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (min1, max1) = self.first.size_hint(); + let (min2, max2) = self.second.size_hint(); + let max = match (max1, max2) { + (Some(max1), Some(max2)) => max1.checked_add(max2), + _ => None, + }; + (min1.saturating_add(min2), max) + } } /// Implementation of the `ConnectionUpgrade` that negotiates the `/plaintext/1.0.0` protocol and @@ -777,75 +792,78 @@ pub struct PlainTextConfig; impl ConnectionUpgrade for PlainTextConfig where - C: AsyncRead + AsyncWrite, + C: AsyncRead + AsyncWrite, { - type Output = C; - type Future = FutureResult; - type UpgradeIdentifier = (); - type NamesIter = iter::Once<(Bytes, ())>; + type Output = C; + type Future = FutureResult; + type UpgradeIdentifier = (); + type NamesIter = iter::Once<(Bytes, ())>; - #[inline] - fn upgrade(self, i: C, _: (), _: Endpoint, _: &Multiaddr) -> Self::Future { - future::ok(i) - } + #[inline] + fn upgrade(self, i: C, _: (), _: Endpoint, _: &Multiaddr) -> Self::Future { + future::ok(i) + } - #[inline] - fn protocol_names(&self) -> Self::NamesIter { - iter::once((Bytes::from("/plaintext/1.0.0"), ())) - } + #[inline] + fn protocol_names(&self) -> Self::NamesIter { + iter::once((Bytes::from("/plaintext/1.0.0"), ())) + } } /// Dummy implementation of `MuxedTransport` that uses an inner `Transport`. #[derive(Debug, Copy, Clone)] pub struct DummyMuxing { - inner: T, + inner: T, } impl MuxedTransport for DummyMuxing - where T: Transport +where + T: Transport, { - type Incoming = future::Empty; - type IncomingUpgrade = future::Empty<(T::RawConn, Multiaddr), IoError>; + type Incoming = future::Empty; + type IncomingUpgrade = future::Empty<(T::RawConn, Multiaddr), IoError>; - fn next_incoming(self) -> Self::Incoming - where Self: Sized - { - future::empty() - } + fn next_incoming(self) -> Self::Incoming + where + Self: Sized, + { + future::empty() + } } impl Transport for DummyMuxing - where T: Transport +where + T: Transport, { - type RawConn = T::RawConn; - type Listener = T::Listener; - type ListenerUpgrade = T::ListenerUpgrade; - type Dial = T::Dial; + type RawConn = T::RawConn; + type Listener = T::Listener; + type ListenerUpgrade = T::ListenerUpgrade; + type Dial = T::Dial; - #[inline] - fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> - where - Self: Sized - { - self.inner.listen_on(addr).map_err(|(inner, addr)| { - (DummyMuxing { inner }, addr) - }) - } + #[inline] + fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> + where + Self: Sized, + { + self.inner + .listen_on(addr) + .map_err(|(inner, addr)| (DummyMuxing { inner }, addr)) + } - #[inline] - fn dial(self, addr: Multiaddr) -> Result - where - Self: Sized - { - self.inner.dial(addr).map_err(|(inner, addr)| { - (DummyMuxing { inner }, addr) - }) - } + #[inline] + fn dial(self, addr: Multiaddr) -> Result + where + Self: Sized, + { + self.inner + .dial(addr) + .map_err(|(inner, addr)| (DummyMuxing { inner }, addr)) + } - #[inline] - fn nat_traversal(&self, server: &Multiaddr, observed: &Multiaddr) -> Option { - self.inner.nat_traversal(server, observed) - } + #[inline] + fn nat_traversal(&self, server: &Multiaddr, observed: &Multiaddr) -> Option { + self.inner.nat_traversal(server, observed) + } } /// Implements the `Transport` trait. Dials or listens, then upgrades any dialed or received @@ -854,55 +872,57 @@ impl Transport for DummyMuxing /// See the `Transport::with_upgrade` method. #[derive(Debug, Clone)] pub struct UpgradedNode { - transports: T, - upgrade: C, + transports: T, + upgrade: C, } impl<'a, T, C> UpgradedNode where - T: Transport + 'a, - C: ConnectionUpgrade + 'a, + T: Transport + 'a, + C: ConnectionUpgrade + 'a, { - /// Turns this upgraded node into a `ConnectionReuse`. If the `Output` implements the - /// `StreamMuxer` trait, the returned object will implement `Transport` and `MuxedTransport`. - #[inline] - pub fn into_connection_reuse(self) -> ConnectionReuse - where C::Output: StreamMuxer - { - From::from(self) - } + /// Turns this upgraded node into a `ConnectionReuse`. If the `Output` implements the + /// `StreamMuxer` trait, the returned object will implement `Transport` and `MuxedTransport`. + #[inline] + pub fn into_connection_reuse(self) -> ConnectionReuse + where + C::Output: StreamMuxer, + { + From::from(self) + } - /// Returns a reference to the inner `Transport`. - #[inline] - pub fn transport(&self) -> &T { - &self.transports - } + /// Returns a reference to the inner `Transport`. + #[inline] + pub fn transport(&self) -> &T { + &self.transports + } - /// Tries to dial on the `Multiaddr` using the transport that was passed to `new`, then upgrade - /// the connection. - /// - /// Note that this does the same as `Transport::dial`, but with less restrictions on the trait - /// requirements. - #[inline] - pub fn dial( - self, - addr: Multiaddr, - ) -> Result + 'a>, (Self, Multiaddr)> { - let upgrade = self.upgrade; + /// Tries to dial on the `Multiaddr` using the transport that was passed to `new`, then upgrade + /// the connection. + /// + /// Note that this does the same as `Transport::dial`, but with less restrictions on the trait + /// requirements. + #[inline] + pub fn dial( + self, + addr: Multiaddr, + ) -> Result + 'a>, (Self, Multiaddr)> + { + let upgrade = self.upgrade; - let dialed_fut = match self.transports.dial(addr.clone()) { - Ok(f) => f.into_future(), - Err((trans, addr)) => { - let builder = UpgradedNode { - transports: trans, - upgrade: upgrade, - }; + let dialed_fut = match self.transports.dial(addr.clone()) { + Ok(f) => f.into_future(), + Err((trans, addr)) => { + let builder = UpgradedNode { + transports: trans, + upgrade: upgrade, + }; - return Err((builder, addr)); - } - }; + return Err((builder, addr)); + } + }; - let future = dialed_fut + let future = dialed_fut // Try to negotiate the protocol. .and_then(move |(connection, client_addr)| { let iter = upgrade.protocol_names() @@ -913,148 +933,169 @@ where }) .and_then(move |(upgrade_id, connection, upgrade, client_addr)| { let f = upgrade.upgrade(connection, upgrade_id, Endpoint::Dialer, &client_addr); - f.map(|v| (v, client_addr)) + f.map(|v| (v, client_addr)) }); - Ok(Box::new(future)) - } + Ok(Box::new(future)) + } - /// If the underlying transport is a `MuxedTransport`, then after calling `dial` we may receive - /// substreams opened by the dialed nodes. - /// - /// This function returns the next incoming substream. You are strongly encouraged to call it - /// if you have a muxed transport. - pub fn next_incoming(self) -> Box + 'a>, Error = IoError> + 'a> - where T: MuxedTransport, - C::NamesIter: Clone, // TODO: not elegant - C: Clone, - { - let upgrade = self.upgrade; + /// If the underlying transport is a `MuxedTransport`, then after calling `dial` we may receive + /// substreams opened by the dialed nodes. + /// + /// This function returns the next incoming substream. You are strongly encouraged to call it + /// if you have a muxed transport. + pub fn next_incoming( + self, + ) -> Box< + Future< + Item = Box + 'a>, + Error = IoError, + > + + 'a, + > + where + T: MuxedTransport, + C::NamesIter: Clone, // TODO: not elegant + C: Clone, + { + let upgrade = self.upgrade; - let future = self.transports.next_incoming() - .map(|future| { - // Try to negotiate the protocol. - let future = future - .and_then(move |(connection, addr)| { - let iter = upgrade.protocol_names() - .map::<_, fn(_) -> _>(|(name, id)| (name, ::eq, id)); - let negotiated = multistream_select::listener_select_proto(connection, iter) - .map_err(|err| IoError::new(IoErrorKind::Other, err)); - negotiated.map(move |(upgrade_id, conn)| (upgrade_id, conn, upgrade, addr)) - }) - .and_then(move |(upgrade_id, connection, upgrade, addr)| { - let upg = upgrade.upgrade(connection, upgrade_id, Endpoint::Dialer, &addr); - upg.map(|u| (u, addr)) - }); + let future = self.transports.next_incoming().map(|future| { + // Try to negotiate the protocol. + let future = future + .and_then(move |(connection, addr)| { + let iter = upgrade + .protocol_names() + .map::<_, fn(_) -> _>(|(name, id)| (name, ::eq, id)); + let negotiated = multistream_select::listener_select_proto(connection, iter) + .map_err(|err| IoError::new(IoErrorKind::Other, err)); + negotiated.map(move |(upgrade_id, conn)| (upgrade_id, conn, upgrade, addr)) + }) + .and_then(move |(upgrade_id, connection, upgrade, addr)| { + let upg = upgrade.upgrade(connection, upgrade_id, Endpoint::Dialer, &addr); + upg.map(|u| (u, addr)) + }); - Box::new(future) as Box> - }); + Box::new(future) as Box> + }); - Box::new(future) as Box<_> - } + Box::new(future) as Box<_> + } - /// Start listening on the multiaddr using the transport that was passed to `new`. - /// Then whenever a connection is opened, it is upgraded. - /// - /// Note that this does the same as `Transport::listen_on`, but with less restrictions on the - /// trait requirements. - #[inline] - pub fn listen_on( - self, - addr: Multiaddr, - ) -> Result< - (Box + 'a>, Error = IoError> + 'a>, Multiaddr), - (Self, Multiaddr), - > - where - C::NamesIter: Clone, // TODO: not elegant - C: Clone, - { - let upgrade = self.upgrade; + /// Start listening on the multiaddr using the transport that was passed to `new`. + /// Then whenever a connection is opened, it is upgraded. + /// + /// Note that this does the same as `Transport::listen_on`, but with less restrictions on the + /// trait requirements. + #[inline] + pub fn listen_on( + self, + addr: Multiaddr, + ) -> Result< + ( + Box< + Stream< + Item = Box + 'a>, + Error = IoError, + > + + 'a, + >, + Multiaddr, + ), + (Self, Multiaddr), + > + where + C::NamesIter: Clone, // TODO: not elegant + C: Clone, + { + let upgrade = self.upgrade; - let (listening_stream, new_addr) = match self.transports.listen_on(addr) { - Ok((l, new_addr)) => (l, new_addr), - Err((trans, addr)) => { - let builder = UpgradedNode { - transports: trans, - upgrade: upgrade, - }; + let (listening_stream, new_addr) = match self.transports.listen_on(addr) { + Ok((l, new_addr)) => (l, new_addr), + Err((trans, addr)) => { + let builder = UpgradedNode { + transports: trans, + upgrade: upgrade, + }; - return Err((builder, addr)); - } - }; + return Err((builder, addr)); + } + }; - // Try to negotiate the protocol. - // Note that failing to negotiate a protocol will never produce a future with an error. - // Instead the `stream` will produce `Ok(Err(...))`. - // `stream` can only produce an `Err` if `listening_stream` produces an `Err`. - let stream = listening_stream - .map(move |connection| { - let upgrade = upgrade.clone(); - let connection = connection - // Try to negotiate the protocol - .and_then(move |(connection, remote_addr)| { - let iter = upgrade.protocol_names() - .map::<_, fn(_) -> _>(|(n, t)| (n, ::eq, t)); - multistream_select::listener_select_proto(connection, iter) - .map_err(|err| IoError::new(IoErrorKind::Other, err)) - .and_then(move |(upgrade_id, connection)| { - let fut = upgrade.upgrade(connection, upgrade_id, Endpoint::Listener, - &remote_addr); - fut.map(move |c| (c, remote_addr)) - }) - .into_future() - }); + // Try to negotiate the protocol. + // Note that failing to negotiate a protocol will never produce a future with an error. + // Instead the `stream` will produce `Ok(Err(...))`. + // `stream` can only produce an `Err` if `listening_stream` produces an `Err`. + let stream = listening_stream.map(move |connection| { + let upgrade = upgrade.clone(); + let connection = connection + // Try to negotiate the protocol + .and_then(move |(connection, remote_addr)| { + let iter = upgrade.protocol_names() + .map::<_, fn(_) -> _>(|(n, t)| (n, ::eq, t)); + multistream_select::listener_select_proto(connection, iter) + .map_err(|err| IoError::new(IoErrorKind::Other, err)) + .and_then(move |(upgrade_id, connection)| { + let fut = upgrade.upgrade( + connection, + upgrade_id, + Endpoint::Listener, + &remote_addr, + ); + fut.map(move |c| (c, remote_addr)) + }) + .into_future() + }); - Box::new(connection) as Box<_> - }); + Box::new(connection) as Box<_> + }); - Ok((Box::new(stream), new_addr)) - } + Ok((Box::new(stream), new_addr)) + } } impl Transport for UpgradedNode where - T: Transport + 'static, - C: ConnectionUpgrade + 'static, - C::Output: AsyncRead + AsyncWrite, - C::NamesIter: Clone, // TODO: not elegant - C: Clone, + T: Transport + 'static, + C: ConnectionUpgrade + 'static, + C::Output: AsyncRead + AsyncWrite, + C::NamesIter: Clone, // TODO: not elegant + C: Clone, { - type RawConn = C::Output; - type Listener = Box>; - type ListenerUpgrade = Box>; - type Dial = Box>; + type RawConn = C::Output; + type Listener = Box>; + type ListenerUpgrade = Box>; + type Dial = Box>; - #[inline] - fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { - self.listen_on(addr) - } + #[inline] + fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { + self.listen_on(addr) + } - #[inline] - fn dial(self, addr: Multiaddr) -> Result { - self.dial(addr) - } + #[inline] + fn dial(self, addr: Multiaddr) -> Result { + self.dial(addr) + } - #[inline] - fn nat_traversal(&self, server: &Multiaddr, observed: &Multiaddr) -> Option { - self.transports.nat_traversal(server, observed) - } + #[inline] + fn nat_traversal(&self, server: &Multiaddr, observed: &Multiaddr) -> Option { + self.transports.nat_traversal(server, observed) + } } impl MuxedTransport for UpgradedNode where - T: MuxedTransport + 'static, - C: ConnectionUpgrade + 'static, - C::Output: AsyncRead + AsyncWrite, - C::NamesIter: Clone, // TODO: not elegant - C: Clone, + T: MuxedTransport + 'static, + C: ConnectionUpgrade + 'static, + C::Output: AsyncRead + AsyncWrite, + C::NamesIter: Clone, // TODO: not elegant + C: Clone, { - type Incoming = Box>; - type IncomingUpgrade = Box>; + type Incoming = Box>; + type IncomingUpgrade = Box>; - #[inline] - fn next_incoming(self) -> Self::Incoming { - self.next_incoming() - } + #[inline] + fn next_incoming(self) -> Self::Incoming { + self.next_incoming() + } } diff --git a/libp2p-swarm/tests/multiplex.rs b/libp2p-swarm/tests/multiplex.rs index 224d02ad..97ff2557 100644 --- a/libp2p-swarm/tests/multiplex.rs +++ b/libp2p-swarm/tests/multiplex.rs @@ -28,8 +28,8 @@ extern crate tokio_io; use bytes::BytesMut; use futures::future::Future; -use futures::{Stream, Sink}; -use libp2p_swarm::{Multiaddr, Transport, StreamMuxer, MuxedTransport}; +use futures::{Sink, Stream}; +use libp2p_swarm::{Multiaddr, MuxedTransport, StreamMuxer, Transport}; use libp2p_tcp_transport::TcpConfig; use tokio_core::reactor::Core; use tokio_io::codec::length_delimited::Framed; @@ -46,7 +46,10 @@ impl From for OnlyOnce { } impl Clone for OnlyOnce { fn clone(&self) -> Self { - OnlyOnce(self.0.clone(), atomic::AtomicBool::new(self.1.load(atomic::Ordering::SeqCst))) + OnlyOnce( + self.0.clone(), + atomic::AtomicBool::new(self.1.load(atomic::Ordering::SeqCst)), + ) } } impl Transport for OnlyOnce { @@ -80,7 +83,8 @@ fn client_to_server_outbound() { .into_connection_reuse(); let (listener, addr) = transport - .listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap()).unwrap_or_else(|_| panic!()); + .listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap()) + .unwrap_or_else(|_| panic!()); tx.send(addr).unwrap(); let future = listener @@ -90,7 +94,8 @@ fn client_to_server_outbound() { .map(|client| client.0) .map(|client| Framed::<_, BytesMut>::new(client)) .and_then(|client| { - client.into_future() + client + .into_future() .map_err(|(err, _)| err) .map(|(msg, _)| msg) }) @@ -104,10 +109,11 @@ fn client_to_server_outbound() { }); let mut core = Core::new().unwrap(); - let transport = TcpConfig::new(core.handle()) - .with_upgrade(multiplex::MultiplexConfig); + let transport = TcpConfig::new(core.handle()).with_upgrade(multiplex::MultiplexConfig); - let future = transport.dial(rx.recv().unwrap()).unwrap() + let future = transport + .dial(rx.recv().unwrap()) + .unwrap() .and_then(|client| client.0.outbound()) .map(|server| Framed::<_, BytesMut>::new(server)) .and_then(|server| server.send("hello world".into())) @@ -131,7 +137,8 @@ fn connection_reused_for_dialing() { .into_connection_reuse(); let (listener, addr) = transport - .listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap()).unwrap_or_else(|_| panic!()); + .listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap()) + .unwrap_or_else(|_| panic!()); tx.send(addr).unwrap(); let future = listener @@ -140,7 +147,8 @@ fn connection_reused_for_dialing() { .and_then(|(client, rest)| client.unwrap().map(move |c| (c.0, rest))) .map(|(client, rest)| (Framed::<_, BytesMut>::new(client), rest)) .and_then(|(client, rest)| { - client.into_future() + client + .into_future() .map(|v| (v, rest)) .map_err(|(err, _)| err) }) @@ -155,10 +163,7 @@ fn connection_reused_for_dialing() { .and_then(|(client, _)| client.unwrap()) .map(|client| client.0) .map(|client| Framed::<_, BytesMut>::new(client)) - .and_then(|client| { - client.into_future() - .map_err(|(err, _)| err) - }) + .and_then(|client| client.into_future().map_err(|(err, _)| err)) .and_then(|(msg, _)| { let msg = msg.unwrap(); assert_eq!(msg, "second message"); @@ -175,19 +180,21 @@ fn connection_reused_for_dialing() { let listen_addr = rx.recv().unwrap(); - let future = transport.clone().dial(listen_addr.clone()).unwrap_or_else(|_| panic!()) + let future = transport + .clone() + .dial(listen_addr.clone()) + .unwrap_or_else(|_| panic!()) .map(|server| Framed::<_, BytesMut>::new(server.0)) - .and_then(|server| { - server.send("hello world".into()) - }) + .and_then(|server| server.send("hello world".into())) .and_then(|first_connec| { - transport.clone().dial(listen_addr.clone()).unwrap_or_else(|_| panic!()) + transport + .clone() + .dial(listen_addr.clone()) + .unwrap_or_else(|_| panic!()) .map(|server| Framed::<_, BytesMut>::new(server.0)) .map(|server| (first_connec, server)) }) - .and_then(|(_first, second)| { - second.send("second message".into()) - }) + .and_then(|(_first, second)| second.send("second message".into())) .map(|_| ()); core.run(future).unwrap(); @@ -204,11 +211,13 @@ fn use_opened_listen_to_dial() { let bg_thread = thread::spawn(move || { let mut core = Core::new().unwrap(); - let transport = OnlyOnce::from(TcpConfig::new(core.handle())) - .with_upgrade(multiplex::MultiplexConfig); + let transport = + OnlyOnce::from(TcpConfig::new(core.handle())).with_upgrade(multiplex::MultiplexConfig); - let (listener, addr) = transport.clone() - .listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap()).unwrap_or_else(|_| panic!()); + let (listener, addr) = transport + .clone() + .listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap()) + .unwrap_or_else(|_| panic!()); tx.send(addr).unwrap(); let future = listener @@ -220,11 +229,10 @@ fn use_opened_listen_to_dial() { let c2 = c.clone(); c.clone().inbound().map(move |i| (c2, i)) }) - .map(|(muxer, client)| { - (muxer, Framed::<_, BytesMut>::new(client)) - }) + .map(|(muxer, client)| (muxer, Framed::<_, BytesMut>::new(client))) .and_then(|(muxer, client)| { - client.into_future() + client + .into_future() .map(move |msg| (muxer, msg)) .map_err(|(err, _)| err) }) @@ -233,13 +241,8 @@ fn use_opened_listen_to_dial() { assert_eq!(msg, "hello world"); muxer.outbound() }) - .map(|client| { - Framed::<_, BytesMut>::new(client) - }) - .and_then(|client| { - client.into_future() - .map_err(|(err, _)| err) - }) + .map(|client| Framed::<_, BytesMut>::new(client)) + .and_then(|client| client.into_future().map_err(|(err, _)| err)) .and_then(|(msg, _)| { let msg = msg.unwrap(); assert_eq!(msg, "second message"); @@ -256,20 +259,21 @@ fn use_opened_listen_to_dial() { let listen_addr = rx.recv().unwrap(); - let future = transport.clone().dial(listen_addr.clone()).unwrap_or_else(|_| panic!()) + let future = transport + .clone() + .dial(listen_addr.clone()) + .unwrap_or_else(|_| panic!()) .map(|server| Framed::<_, BytesMut>::new(server.0)) - .and_then(|server| { - server.send("hello world".into()) - }) + .and_then(|server| server.send("hello world".into())) .and_then(|first_connec| { - transport.clone().next_incoming() + transport + .clone() + .next_incoming() .and_then(|server| server) .map(|server| Framed::<_, BytesMut>::new(server.0)) .map(|server| (first_connec, server)) }) - .and_then(|(_first, second)| { - second.send("second message".into()) - }) + .and_then(|(_first, second)| second.send("second message".into())) .map(|_| ()); core.run(future).unwrap(); diff --git a/libp2p-tcp-transport/src/lib.rs b/libp2p-tcp-transport/src/lib.rs index 7ee44ecb..90f88e86 100644 --- a/libp2p-tcp-transport/src/lib.rs +++ b/libp2p-tcp-transport/src/lib.rs @@ -1,21 +1,21 @@ // Copyright 2017 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. // TODO: use this once stable ; for now we just copy-paste the content of the README.md @@ -24,9 +24,9 @@ //! Implementation of the libp2p `Transport` trait for TCP/IP. //! //! Uses [the *tokio* library](https://tokio.rs). -//! +//! //! # Usage -//! +//! //! Create [a tokio `Core`](https://docs.rs/tokio-core/0.1/tokio_core/reactor/struct.Core.html), //! then grab a handle by calling the `handle()` method on it, then create a `TcpConfig` and pass //! the handle. @@ -49,20 +49,20 @@ //! The `TcpConfig` structs implements the `Transport` trait of the `swarm` library. See the //! documentation of `swarm` and of libp2p in general to learn how to use the `Transport` trait. +extern crate futures; extern crate libp2p_swarm as swarm; +extern crate multiaddr; extern crate tokio_core; extern crate tokio_io; -extern crate multiaddr; -extern crate futures; use std::io::Error as IoError; use std::iter; use std::net::SocketAddr; use tokio_core::reactor::Handle; -use tokio_core::net::{TcpStream, TcpListener}; +use tokio_core::net::{TcpListener, TcpStream}; use futures::future::{self, Future, FutureResult, IntoFuture}; use futures::stream::Stream; -use multiaddr::{Multiaddr, AddrComponent, ToMultiaddr}; +use multiaddr::{AddrComponent, Multiaddr, ToMultiaddr}; use swarm::Transport; /// Represents the configuration for a TCP/IP transport capability for libp2p. @@ -99,15 +99,18 @@ impl Transport for TcpConfig { // just return the original multiaddr. let new_addr = match listener { Ok(ref l) => if let Ok(new_s_addr) = l.local_addr() { - new_s_addr.to_multiaddr().expect("multiaddr generated from socket addr is \ - always valid") + new_s_addr.to_multiaddr().expect( + "multiaddr generated from socket addr is \ + always valid", + ) } else { addr - } + }, Err(_) => addr, }; - let future = future::result(listener).map(|listener| { + let future = future::result(listener) + .map(|listener| { // Pull out a stream of sockets for incoming connections listener.incoming().map(|(sock, addr)| { let addr = addr.to_multiaddr() @@ -115,7 +118,7 @@ impl Transport for TcpConfig { Ok((sock, addr)).into_future() }) }) - .flatten_stream(); + .flatten_stream(); Ok((Box::new(future), new_addr)) } else { Err((self, addr)) @@ -127,8 +130,7 @@ impl Transport for TcpConfig { /// or gives back the multiaddress. fn dial(self, addr: Multiaddr) -> Result { if let Ok(socket_addr) = multiaddr_to_socketaddr(&addr) { - let fut = TcpStream::connect(&socket_addr, &self.event_loop) - .map(|t| (t, addr)); + let fut = TcpStream::connect(&socket_addr, &self.event_loop).map(|t| (t, addr)); Ok(Box::new(fut) as Box<_>) } else { Err((self, addr)) @@ -145,15 +147,15 @@ impl Transport for TcpConfig { // Check that `server` is a valid TCP/IP address. match (&server_protocols[0], &server_protocols[1]) { - (&AddrComponent::IP4(_), &AddrComponent::TCP(_)) | - (&AddrComponent::IP6(_), &AddrComponent::TCP(_)) => {} + (&AddrComponent::IP4(_), &AddrComponent::TCP(_)) + | (&AddrComponent::IP6(_), &AddrComponent::TCP(_)) => {} _ => return None, } // Check that `observed` is a valid TCP/IP address. match (&observed_protocols[0], &observed_protocols[1]) { - (&AddrComponent::IP4(_), &AddrComponent::TCP(_)) | - (&AddrComponent::IP6(_), &AddrComponent::TCP(_)) => {} + (&AddrComponent::IP4(_), &AddrComponent::TCP(_)) + | (&AddrComponent::IP6(_), &AddrComponent::TCP(_)) => {} _ => return None, } @@ -186,7 +188,7 @@ fn multiaddr_to_socketaddr(addr: &Multiaddr) -> Result { #[cfg(test)] mod tests { - use super::{TcpConfig, multiaddr_to_socketaddr}; + use super::{multiaddr_to_socketaddr, TcpConfig}; use std; use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use tokio_core::reactor::Core; @@ -200,7 +202,10 @@ mod tests { fn multiaddr_to_tcp_conversion() { use std::net::Ipv6Addr; - assert!(multiaddr_to_socketaddr(&"/ip4/127.0.0.1/udp/1234".parse::().unwrap()).is_err()); + assert!( + multiaddr_to_socketaddr(&"/ip4/127.0.0.1/udp/1234".parse::().unwrap()) + .is_err() + ); assert_eq!( multiaddr_to_socketaddr(&"/ip4/127.0.0.1/tcp/12345".parse::().unwrap()), @@ -210,7 +215,9 @@ mod tests { )) ); assert_eq!( - multiaddr_to_socketaddr(&"/ip4/255.255.255.255/tcp/8080".parse::().unwrap()), + multiaddr_to_socketaddr(&"/ip4/255.255.255.255/tcp/8080" + .parse::() + .unwrap()), Ok(SocketAddr::new( IpAddr::V4(Ipv4Addr::new(255, 255, 255, 255)), 8080, @@ -225,7 +232,8 @@ mod tests { ); assert_eq!( multiaddr_to_socketaddr(&"/ip6/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/tcp/8080" - .parse::().unwrap()), + .parse::() + .unwrap()), Ok(SocketAddr::new( IpAddr::V6(Ipv6Addr::new( 65535, @@ -316,7 +324,9 @@ mod tests { let core = Core::new().unwrap(); let tcp = TcpConfig::new(core.handle()); - let addr = "/ip4/127.0.0.1/tcp/12345/tcp/12345".parse::().unwrap(); + let addr = "/ip4/127.0.0.1/tcp/12345/tcp/12345" + .parse::() + .unwrap(); assert!(tcp.listen_on(addr).is_err()); } @@ -329,6 +339,9 @@ mod tests { let observed = "/ip4/80.81.82.83/tcp/25000".parse::().unwrap(); let out = tcp.nat_traversal(&server, &observed); - assert_eq!(out.unwrap(), "/ip4/80.81.82.83/tcp/10000".parse::().unwrap()); + assert_eq!( + out.unwrap(), + "/ip4/80.81.82.83/tcp/10000".parse::().unwrap() + ); } } diff --git a/libp2p-websocket/src/browser.rs b/libp2p-websocket/src/browser.rs index 81891164..681c528c 100644 --- a/libp2p-websocket/src/browser.rs +++ b/libp2p-websocket/src/browser.rs @@ -40,305 +40,305 @@ use tokio_io::{AsyncRead, AsyncWrite}; pub struct BrowserWsConfig; impl BrowserWsConfig { - /// Creates a new configuration object for websocket. - #[inline] - pub fn new() -> BrowserWsConfig { - BrowserWsConfig - } + /// Creates a new configuration object for websocket. + #[inline] + pub fn new() -> BrowserWsConfig { + BrowserWsConfig + } } impl Transport for BrowserWsConfig { - type RawConn = BrowserWsConn; - type Listener = Box>; // TODO: use `!` - type ListenerUpgrade = Box>; // TODO: use `!` - type Dial = Box>; + type RawConn = BrowserWsConn; + type Listener = Box>; // TODO: use `!` + type ListenerUpgrade = Box>; // TODO: use `!` + type Dial = Box>; - #[inline] - fn listen_on(self, a: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { - // Listening is never supported. - Err((self, a)) - } + #[inline] + fn listen_on(self, a: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { + // Listening is never supported. + Err((self, a)) + } - fn dial(self, original_addr: Multiaddr) -> Result { - // Making sure we are initialized before we dial. Initialization is protected by a simple - // boolean static variable, so it's not a problem to call it multiple times and the cost - // is negligible. - stdweb::initialize(); + fn dial(self, original_addr: Multiaddr) -> Result { + // Making sure we are initialized before we dial. Initialization is protected by a simple + // boolean static variable, so it's not a problem to call it multiple times and the cost + // is negligible. + stdweb::initialize(); - // Tries to interpret the multiaddr, and returns a corresponding `ws://x.x.x.x/` URL (as - // a string) on success. - let inner_addr = match multiaddr_to_target(&original_addr) { - Ok(a) => a, - Err(_) => return Err((self, original_addr)), - }; + // Tries to interpret the multiaddr, and returns a corresponding `ws://x.x.x.x/` URL (as + // a string) on success. + let inner_addr = match multiaddr_to_target(&original_addr) { + Ok(a) => a, + Err(_) => return Err((self, original_addr)), + }; - // Create the JS `WebSocket` object. - let websocket = { - let val = js! { - try { - return new WebSocket(@{inner_addr}); - } catch(e) { - return false; - } - }; - match val.into_reference() { - Some(ws) => ws, - None => return Err((self, original_addr)), // `false` was returned by `js!` - } - }; + // Create the JS `WebSocket` object. + let websocket = { + let val = js! { + try { + return new WebSocket(@{inner_addr}); + } catch(e) { + return false; + } + }; + match val.into_reference() { + Some(ws) => ws, + None => return Err((self, original_addr)), // `false` was returned by `js!` + } + }; - // Create a `message` channel that will be used for both bytes messages and errors, and a - // `message_cb` used for the `message` event on the WebSocket. - // `message_tx` is grabbed by `message_cb` and `close_cb`, and `message_rx` is grabbed - // by `open_cb`. - let (message_tx, message_rx) = mpsc::unbounded::, IoError>>(); - let message_tx = Arc::new(message_tx); - let mut message_rx = Some(message_rx); - let message_cb = { - let message_tx = message_tx.clone(); - move |message_data: Reference| { - if let Some(buffer) = message_data.downcast::>() { - let _ = message_tx.unbounded_send(Ok(buffer.to_vec())); - } else { - let _ = message_tx.unbounded_send(Err(IoError::new( - IoErrorKind::InvalidData, - "received ws message of unknown type", - ))); - } - } - }; + // Create a `message` channel that will be used for both bytes messages and errors, and a + // `message_cb` used for the `message` event on the WebSocket. + // `message_tx` is grabbed by `message_cb` and `close_cb`, and `message_rx` is grabbed + // by `open_cb`. + let (message_tx, message_rx) = mpsc::unbounded::, IoError>>(); + let message_tx = Arc::new(message_tx); + let mut message_rx = Some(message_rx); + let message_cb = { + let message_tx = message_tx.clone(); + move |message_data: Reference| { + if let Some(buffer) = message_data.downcast::>() { + let _ = message_tx.unbounded_send(Ok(buffer.to_vec())); + } else { + let _ = message_tx.unbounded_send(Err(IoError::new( + IoErrorKind::InvalidData, + "received ws message of unknown type", + ))); + } + } + }; - // Create a `open` channel that will be used to communicate the `BrowserWsConn` that represents - // the open dialing websocket. Also create a `open_cb` callback that will be used for the - // `open` message of the websocket. - let (open_tx, open_rx) = oneshot::channel::>(); - let open_tx = Arc::new(Mutex::new(Some(open_tx))); - let websocket_clone = websocket.clone(); - let open_cb = { - let open_tx = open_tx.clone(); - move || { - // Note that `open_tx` can be empty (and a panic happens) if the `open` event - // is triggered twice, or is triggered after the `close` event. We never reuse the - // same websocket twice, so this is not supposed to happen. - let tx = open_tx - .lock() - .unwrap() - .take() - .expect("the websocket can only open once"); - // `message_rx` can be empty if the `open` event is triggered twice, which again - // is not supposed to happen. - let message_rx = message_rx.take().expect("the websocket can only open once"); + // Create a `open` channel that will be used to communicate the `BrowserWsConn` that represents + // the open dialing websocket. Also create a `open_cb` callback that will be used for the + // `open` message of the websocket. + let (open_tx, open_rx) = oneshot::channel::>(); + let open_tx = Arc::new(Mutex::new(Some(open_tx))); + let websocket_clone = websocket.clone(); + let open_cb = { + let open_tx = open_tx.clone(); + move || { + // Note that `open_tx` can be empty (and a panic happens) if the `open` event + // is triggered twice, or is triggered after the `close` event. We never reuse the + // same websocket twice, so this is not supposed to happen. + let tx = open_tx + .lock() + .unwrap() + .take() + .expect("the websocket can only open once"); + // `message_rx` can be empty if the `open` event is triggered twice, which again + // is not supposed to happen. + let message_rx = message_rx.take().expect("the websocket can only open once"); - // Send a `BrowserWsConn` to the future that was returned by `dial`. Ignoring errors that - // would happen the future has been dropped by the user. - let _ = tx.send(Ok(BrowserWsConn { - websocket: websocket_clone.clone(), - incoming_data: RwStreamSink::new(message_rx.then(|result| { - // An `Err` happens here if `message_tx` has been dropped. However - // `message_tx` is grabbed by the websocket, which stays alive for as - // long as the `BrowserWsConn` is alive. - match result { - Ok(r) => r, - Err(_) => { - unreachable!("the message channel outlives the BrowserWsConn") - } - } - })), - })); - } - }; + // Send a `BrowserWsConn` to the future that was returned by `dial`. Ignoring errors that + // would happen the future has been dropped by the user. + let _ = tx.send(Ok(BrowserWsConn { + websocket: websocket_clone.clone(), + incoming_data: RwStreamSink::new(message_rx.then(|result| { + // An `Err` happens here if `message_tx` has been dropped. However + // `message_tx` is grabbed by the websocket, which stays alive for as + // long as the `BrowserWsConn` is alive. + match result { + Ok(r) => r, + Err(_) => { + unreachable!("the message channel outlives the BrowserWsConn") + } + } + })), + })); + } + }; - // Used for the `close` message of the websocket. - // The websocket can be closed either before or after being opened, so we send an error - // to both the `open` and `message` channels if that happens. - let close_cb = move || { - if let Some(tx) = open_tx.lock().unwrap().take() { - let _ = tx.send(Err(IoError::new( - IoErrorKind::ConnectionRefused, - "close event on the websocket", - ))); - } + // Used for the `close` message of the websocket. + // The websocket can be closed either before or after being opened, so we send an error + // to both the `open` and `message` channels if that happens. + let close_cb = move || { + if let Some(tx) = open_tx.lock().unwrap().take() { + let _ = tx.send(Err(IoError::new( + IoErrorKind::ConnectionRefused, + "close event on the websocket", + ))); + } - let _ = message_tx.unbounded_send(Err(IoError::new( - IoErrorKind::ConnectionRefused, - "close event on the websocket", - ))); - }; + let _ = message_tx.unbounded_send(Err(IoError::new( + IoErrorKind::ConnectionRefused, + "close event on the websocket", + ))); + }; - js! { - var socket = @{websocket}; - var open_cb = @{open_cb}; - var message_cb = @{message_cb}; - var close_cb = @{close_cb}; - socket.addEventListener("open", function(event) { - open_cb(); - }); - socket.addEventListener("message", function(event) { - var reader = new FileReader(); - reader.addEventListener("loadend", function() { - var typed = new Uint8Array(reader.result); - message_cb(typed); - }); - reader.readAsArrayBuffer(event.data); - }); - socket.addEventListener("close", function(event) { - close_cb(); - }); - }; + js! { + var socket = @{websocket}; + var open_cb = @{open_cb}; + var message_cb = @{message_cb}; + var close_cb = @{close_cb}; + socket.addEventListener("open", function(event) { + open_cb(); + }); + socket.addEventListener("message", function(event) { + var reader = new FileReader(); + reader.addEventListener("loadend", function() { + var typed = new Uint8Array(reader.result); + message_cb(typed); + }); + reader.readAsArrayBuffer(event.data); + }); + socket.addEventListener("close", function(event) { + close_cb(); + }); + }; - Ok(Box::new(open_rx.then(|result| { - match result { - Ok(Ok(r)) => Ok((r, original_addr)), - Ok(Err(e)) => Err(e), - // `Err` would happen here if `open_tx` is destroyed. `open_tx` is captured by - // the `WebSocket`, and the `WebSocket` is captured by `open_cb`, which is itself - // captured by the `WebSocket`. Due to this cyclic dependency, `open_tx` should - // never be destroyed. - // TODO: how do we break this cyclic dependency? difficult question - Err(_) => unreachable!("the sending side will only close when we drop the future"), - } - })) as Box<_>) - } + Ok(Box::new(open_rx.then(|result| { + match result { + Ok(Ok(r)) => Ok((r, original_addr)), + Ok(Err(e)) => Err(e), + // `Err` would happen here if `open_tx` is destroyed. `open_tx` is captured by + // the `WebSocket`, and the `WebSocket` is captured by `open_cb`, which is itself + // captured by the `WebSocket`. Due to this cyclic dependency, `open_tx` should + // never be destroyed. + // TODO: how do we break this cyclic dependency? difficult question + Err(_) => unreachable!("the sending side will only close when we drop the future"), + } + })) as Box<_>) + } - fn nat_traversal(&self, server: &Multiaddr, observed: &Multiaddr) -> Option { - let mut server_protocols = server.iter(); - let server_proto0 = server_protocols.next()?; - let server_proto1 = server_protocols.next()?; - let server_proto2 = server_protocols.next()?; - if server_protocols.next().is_some() { - return None; - } + fn nat_traversal(&self, server: &Multiaddr, observed: &Multiaddr) -> Option { + let mut server_protocols = server.iter(); + let server_proto0 = server_protocols.next()?; + let server_proto1 = server_protocols.next()?; + let server_proto2 = server_protocols.next()?; + if server_protocols.next().is_some() { + return None; + } - let mut observed_protocols = observed.iter(); - let obs_proto0 = observed_protocols.next()?; - let obs_proto1 = observed_protocols.next()?; - let obs_proto2 = observed_protocols.next()?; - if observed_protocols.next().is_some() { - return None; - } + let mut observed_protocols = observed.iter(); + let obs_proto0 = observed_protocols.next()?; + let obs_proto1 = observed_protocols.next()?; + let obs_proto2 = observed_protocols.next()?; + if observed_protocols.next().is_some() { + return None; + } - // Check that `server` is a valid TCP/IP address. - match (&server_proto0, &server_proto1, &server_proto2) { - (&AddrComponent::IP4(_), &AddrComponent::TCP(_), &AddrComponent::WS) | - (&AddrComponent::IP6(_), &AddrComponent::TCP(_), &AddrComponent::WS) | - (&AddrComponent::IP4(_), &AddrComponent::TCP(_), &AddrComponent::WSS) | - (&AddrComponent::IP6(_), &AddrComponent::TCP(_), &AddrComponent::WSS) => {} - _ => return None, - } + // Check that `server` is a valid TCP/IP address. + match (&server_proto0, &server_proto1, &server_proto2) { + (&AddrComponent::IP4(_), &AddrComponent::TCP(_), &AddrComponent::WS) + | (&AddrComponent::IP6(_), &AddrComponent::TCP(_), &AddrComponent::WS) + | (&AddrComponent::IP4(_), &AddrComponent::TCP(_), &AddrComponent::WSS) + | (&AddrComponent::IP6(_), &AddrComponent::TCP(_), &AddrComponent::WSS) => {} + _ => return None, + } - // Check that `observed` is a valid TCP/IP address. - match (&obs_proto0, &obs_proto1, &obs_proto2) { - (&AddrComponent::IP4(_), &AddrComponent::TCP(_), &AddrComponent::WS) | - (&AddrComponent::IP6(_), &AddrComponent::TCP(_), &AddrComponent::WS) | - (&AddrComponent::IP4(_), &AddrComponent::TCP(_), &AddrComponent::WSS) | - (&AddrComponent::IP6(_), &AddrComponent::TCP(_), &AddrComponent::WSS) => {} - _ => return None, - } + // Check that `observed` is a valid TCP/IP address. + match (&obs_proto0, &obs_proto1, &obs_proto2) { + (&AddrComponent::IP4(_), &AddrComponent::TCP(_), &AddrComponent::WS) + | (&AddrComponent::IP6(_), &AddrComponent::TCP(_), &AddrComponent::WS) + | (&AddrComponent::IP4(_), &AddrComponent::TCP(_), &AddrComponent::WSS) + | (&AddrComponent::IP6(_), &AddrComponent::TCP(_), &AddrComponent::WSS) => {} + _ => return None, + } - // Note that it will still work if the server uses WSS while the client uses WS, - // or vice-versa. + // Note that it will still work if the server uses WSS while the client uses WS, + // or vice-versa. - let result = iter::once(obs_proto0) - .chain(iter::once(server_proto1)) - .chain(iter::once(server_proto2)) - .collect(); + let result = iter::once(obs_proto0) + .chain(iter::once(server_proto1)) + .chain(iter::once(server_proto2)) + .collect(); - Some(result) - } + Some(result) + } } pub struct BrowserWsConn { - websocket: Reference, - // Stream of messages that goes through a `RwStreamSink` in order to become a `AsyncRead`. - incoming_data: RwStreamSink< - StreamThen< - mpsc::UnboundedReceiver, IoError>>, - fn(Result, IoError>, ()>) -> Result, IoError>, - Result, IoError>, - >, - >, + websocket: Reference, + // Stream of messages that goes through a `RwStreamSink` in order to become a `AsyncRead`. + incoming_data: RwStreamSink< + StreamThen< + mpsc::UnboundedReceiver, IoError>>, + fn(Result, IoError>, ()>) -> Result, IoError>, + Result, IoError>, + >, + >, } impl Drop for BrowserWsConn { - #[inline] - fn drop(&mut self) { - // TODO: apparently there's a memory leak related to callbacks? - js! { @{&self.websocket}.close(); } - } + #[inline] + fn drop(&mut self) { + // TODO: apparently there's a memory leak related to callbacks? + js! { @{&self.websocket}.close(); } + } } impl AsyncRead for BrowserWsConn {} impl Read for BrowserWsConn { - #[inline] - fn read(&mut self, buf: &mut [u8]) -> Result { - self.incoming_data.read(buf) - } + #[inline] + fn read(&mut self, buf: &mut [u8]) -> Result { + self.incoming_data.read(buf) + } } impl AsyncWrite for BrowserWsConn { - #[inline] - fn shutdown(&mut self) -> Poll<(), IoError> { - Ok(Async::Ready(())) - } + #[inline] + fn shutdown(&mut self) -> Poll<(), IoError> { + Ok(Async::Ready(())) + } } impl Write for BrowserWsConn { - fn write(&mut self, buf: &[u8]) -> Result { - let typed_array = TypedArray::from(buf); + fn write(&mut self, buf: &[u8]) -> Result { + let typed_array = TypedArray::from(buf); - // `send` can throw if the websocket isn't open (which can happen if it was closed by the - // remote). - let returned = js! { - try { - @{&self.websocket}.send(@{typed_array.buffer()}); - return true; - } catch(e) { - return false; - } - }; + // `send` can throw if the websocket isn't open (which can happen if it was closed by the + // remote). + let returned = js! { + try { + @{&self.websocket}.send(@{typed_array.buffer()}); + return true; + } catch(e) { + return false; + } + }; - match returned { - stdweb::Value::Bool(true) => Ok(buf.len()), - stdweb::Value::Bool(false) => Err(IoError::new( - IoErrorKind::BrokenPipe, - "websocket has been closed by the remote", - )), - _ => unreachable!(), - } - } + match returned { + stdweb::Value::Bool(true) => Ok(buf.len()), + stdweb::Value::Bool(false) => Err(IoError::new( + IoErrorKind::BrokenPipe, + "websocket has been closed by the remote", + )), + _ => unreachable!(), + } + } - #[inline] - fn flush(&mut self) -> Result<(), IoError> { - // Everything is always considered flushed. - Ok(()) - } + #[inline] + fn flush(&mut self) -> Result<(), IoError> { + // Everything is always considered flushed. + Ok(()) + } } // Tries to interpret the `Multiaddr` as a `/ipN/.../tcp/.../ws` multiaddress, and if so returns // the corresponding `ws://.../` URL. fn multiaddr_to_target(addr: &Multiaddr) -> Result { - let protocols: Vec<_> = addr.iter().collect(); + let protocols: Vec<_> = addr.iter().collect(); - if protocols.len() != 3 { - return Err(()); - } + if protocols.len() != 3 { + return Err(()); + } - match (&protocols[0], &protocols[1], &protocols[2]) { - (&AddrComponent::IP4(ref ip), &AddrComponent::TCP(port), &AddrComponent::WS) => { - Ok(format!("ws://{}:{}/", ip, port)) - } - (&AddrComponent::IP6(ref ip), &AddrComponent::TCP(port), &AddrComponent::WS) => { - Ok(format!("ws://[{}]:{}/", ip, port)) - } - (&AddrComponent::IP4(ref ip), &AddrComponent::TCP(port), &AddrComponent::WSS) => { - Ok(format!("wss://{}:{}/", ip, port)) - } - (&AddrComponent::IP6(ref ip), &AddrComponent::TCP(port), &AddrComponent::WSS) => { - Ok(format!("wss://[{}]:{}/", ip, port)) - } - _ => Err(()), - } + match (&protocols[0], &protocols[1], &protocols[2]) { + (&AddrComponent::IP4(ref ip), &AddrComponent::TCP(port), &AddrComponent::WS) => { + Ok(format!("ws://{}:{}/", ip, port)) + } + (&AddrComponent::IP6(ref ip), &AddrComponent::TCP(port), &AddrComponent::WS) => { + Ok(format!("ws://[{}]:{}/", ip, port)) + } + (&AddrComponent::IP4(ref ip), &AddrComponent::TCP(port), &AddrComponent::WSS) => { + Ok(format!("wss://{}:{}/", ip, port)) + } + (&AddrComponent::IP6(ref ip), &AddrComponent::TCP(port), &AddrComponent::WSS) => { + Ok(format!("wss://[{}]:{}/", ip, port)) + } + _ => Err(()), + } } // TODO: write tests (tests are very difficult to write with emscripten) diff --git a/libp2p-websocket/src/desktop.rs b/libp2p-websocket/src/desktop.rs index 76f8c40c..f5271098 100644 --- a/libp2p-websocket/src/desktop.rs +++ b/libp2p-websocket/src/desktop.rs @@ -37,268 +37,301 @@ use websocket::stream::async::Stream as AsyncStream; /// > **Note**: `/wss` is only supported for dialing and not listening. #[derive(Debug, Clone)] pub struct WsConfig { - transport: T, + transport: T, } impl WsConfig { - /// Creates a new configuration object for websocket. - /// - /// The websockets will run on top of the `Transport` you pass as parameter. - #[inline] - pub fn new(inner: T) -> WsConfig { - WsConfig { transport: inner } - } + /// Creates a new configuration object for websocket. + /// + /// The websockets will run on top of the `Transport` you pass as parameter. + #[inline] + pub fn new(inner: T) -> WsConfig { + WsConfig { transport: inner } + } } impl Transport for WsConfig where - T: Transport + 'static, // TODO: this 'static is pretty arbitrary and is necessary because of the websocket library - T::RawConn: Send, // TODO: this Send is pretty arbitrary and is necessary because of the websocket library + // TODO: this 'static is pretty arbitrary and is necessary because of the websocket library + T: Transport + 'static, + // TODO: this Send is pretty arbitrary and is necessary because of the websocket library + T::RawConn: Send, { - type RawConn = Box; - type Listener = stream::Map< - T::Listener, - fn(::ListenerUpgrade) -> Self::ListenerUpgrade, - >; - type ListenerUpgrade = Box>; - type Dial = Box>; + type RawConn = Box; + type Listener = + stream::Map::ListenerUpgrade) -> Self::ListenerUpgrade>; + type ListenerUpgrade = Box>; + type Dial = Box>; - fn listen_on( - self, - original_addr: Multiaddr, - ) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { - let mut inner_addr = original_addr.clone(); - match inner_addr.pop() { - Some(AddrComponent::WS) => {} - _ => return Err((self, original_addr)), - }; + fn listen_on( + self, + original_addr: Multiaddr, + ) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> { + let mut inner_addr = original_addr.clone(); + match inner_addr.pop() { + Some(AddrComponent::WS) => {} + _ => return Err((self, original_addr)), + }; - let (inner_listen, new_addr) = match self.transport.listen_on(inner_addr) { - Ok((listen, mut new_addr)) => { - // Need to suffix `/ws` to the listening address. - new_addr.append(AddrComponent::WS); - (listen, new_addr) - } - Err((transport, _)) => { - return Err(( - WsConfig { - transport: transport, - }, - original_addr, - )); - } - }; + let (inner_listen, new_addr) = match self.transport.listen_on(inner_addr) { + Ok((listen, mut new_addr)) => { + // Need to suffix `/ws` to the listening address. + new_addr.append(AddrComponent::WS); + (listen, new_addr) + } + Err((transport, _)) => { + return Err(( + WsConfig { + transport: transport, + }, + original_addr, + )); + } + }; - let listen = inner_listen.map::<_, fn(_) -> _>(|stream| { - // Upgrade the listener to websockets like the websockets library requires us to do. - let upgraded = stream.and_then(|(stream, mut client_addr)| { - // Need to suffix `/ws` to each client address. - client_addr.append(AddrComponent::WS); + let listen = inner_listen.map::<_, fn(_) -> _>(|stream| { + // Upgrade the listener to websockets like the websockets library requires us to do. + let upgraded = stream.and_then(|(stream, mut client_addr)| { + // Need to suffix `/ws` to each client address. + client_addr.append(AddrComponent::WS); - stream - .into_ws() - .map_err(|e| IoError::new(IoErrorKind::Other, e.3)) - .and_then(|stream| { - // Accept the next incoming connection. - stream - .accept() - .map_err(|err| IoError::new(IoErrorKind::Other, err)) - .map(|(client, _http_headers)| { - // Plug our own API on top of the `websockets` API. - let framed_data = client - .map_err(|err| IoError::new(IoErrorKind::Other, err)) - .sink_map_err(|err| IoError::new(IoErrorKind::Other, err)) - .with(|data| Ok(OwnedMessage::Binary(data))) - .and_then(|recv| { - match recv { - OwnedMessage::Binary(data) => Ok(Some(data)), - OwnedMessage::Text(data) => Ok(Some(data.into_bytes())), - OwnedMessage::Close(_) => Ok(None), - // TODO: handle pings and pongs, which is freaking hard - // for now we close the socket when that happens - _ => Ok(None) - } - }) - // TODO: is there a way to merge both lines into one? - .take_while(|v| Ok(v.is_some())) - .map(|v| v.expect("we only take while this is Some")); + stream + .into_ws() + .map_err(|e| IoError::new(IoErrorKind::Other, e.3)) + .and_then(|stream| { + // Accept the next incoming connection. + stream + .accept() + .map_err(|err| IoError::new(IoErrorKind::Other, err)) + .map(|(client, _http_headers)| { + // Plug our own API on top of the `websockets` API. + let framed_data = client + .map_err(|err| IoError::new(IoErrorKind::Other, err)) + .sink_map_err(|err| IoError::new(IoErrorKind::Other, err)) + .with(|data| Ok(OwnedMessage::Binary(data))) + .and_then(|recv| { + match recv { + OwnedMessage::Binary(data) => Ok(Some(data)), + OwnedMessage::Text(data) => Ok(Some(data.into_bytes())), + OwnedMessage::Close(_) => Ok(None), + // TODO: handle pings and pongs, which is freaking hard + // for now we close the socket when that happens + _ => Ok(None) + } + }) + // TODO: is there a way to merge both lines into one? + .take_while(|v| Ok(v.is_some())) + .map(|v| v.expect("we only take while this is Some")); - let read_write = RwStreamSink::new(framed_data); - Box::new(read_write) as Box - }) - }) - .map(|s| Box::new(Ok(s).into_future()) as Box>) - .into_future() - .flatten() - .map(move |v| (v, client_addr)) - }); + let read_write = RwStreamSink::new(framed_data); + Box::new(read_write) as Box + }) + }) + .map(|s| Box::new(Ok(s).into_future()) as Box>) + .into_future() + .flatten() + .map(move |v| (v, client_addr)) + }); - Box::new(upgraded) as Box> - }); + Box::new(upgraded) as Box> + }); - Ok((listen, new_addr)) - } + Ok((listen, new_addr)) + } - fn dial(self, original_addr: Multiaddr) -> Result { - let mut inner_addr = original_addr.clone(); - let is_wss = match inner_addr.pop() { - Some(AddrComponent::WS) => false, - Some(AddrComponent::WSS) => true, - _ => return Err((self, original_addr)), - }; + fn dial(self, original_addr: Multiaddr) -> Result { + let mut inner_addr = original_addr.clone(); + let is_wss = match inner_addr.pop() { + Some(AddrComponent::WS) => false, + Some(AddrComponent::WSS) => true, + _ => return Err((self, original_addr)), + }; - let inner_dial = match self.transport.dial(inner_addr) { - Ok(d) => d, - Err((transport, _)) => { - return Err(( - WsConfig { - transport: transport, - }, - original_addr, - )); - } - }; + let inner_dial = match self.transport.dial(inner_addr) { + Ok(d) => d, + Err((transport, _)) => { + return Err(( + WsConfig { + transport: transport, + }, + original_addr, + )); + } + }; - let dial = inner_dial.into_future().and_then(move |(connec, client_addr)| { - // We pass a dummy address to `ClientBuilder` because it is never used anywhere - // in the negotiation anyway, and we use `async_connect_on` to pass a stream. - ClientBuilder::new(if is_wss { "wss://127.0.0.1" } else { "ws://127.0.0.1" }) - .expect("hard-coded ws address is always valid") - .async_connect_on(connec) - .map_err(|err| IoError::new(IoErrorKind::Other, err)) - .map(|(client, _)| { - // Plug our own API on top of the API of the websockets library. - let framed_data = client - .map_err(|err| IoError::new(IoErrorKind::Other, err)) - .sink_map_err(|err| IoError::new(IoErrorKind::Other, err)) - .with(|data| Ok(OwnedMessage::Binary(data))) - .and_then(|recv| { - match recv { - OwnedMessage::Binary(data) => Ok(data), - OwnedMessage::Text(data) => Ok(data.into_bytes()), - // TODO: pings and pongs and close messages need to be - // answered ; and this is really hard ; for now we produce - // an error when that happens - _ => Err(IoError::new(IoErrorKind::Other, "unimplemented")), - } - }); - let read_write = RwStreamSink::new(framed_data); - Box::new(read_write) as Box - }) - .map(|c| (c, client_addr)) - }); + let dial = inner_dial + .into_future() + .and_then(move |(connec, client_addr)| { + // We pass a dummy address to `ClientBuilder` because it is never used anywhere + // in the negotiation anyway, and we use `async_connect_on` to pass a stream. + ClientBuilder::new(if is_wss { + "wss://127.0.0.1" + } else { + "ws://127.0.0.1" + }).expect("hard-coded ws address is always valid") + .async_connect_on(connec) + .map_err(|err| IoError::new(IoErrorKind::Other, err)) + .map(|(client, _)| { + // Plug our own API on top of the API of the websockets library. + let framed_data = client + .map_err(|err| IoError::new(IoErrorKind::Other, err)) + .sink_map_err(|err| IoError::new(IoErrorKind::Other, err)) + .with(|data| Ok(OwnedMessage::Binary(data))) + .and_then(|recv| { + match recv { + OwnedMessage::Binary(data) => Ok(data), + OwnedMessage::Text(data) => Ok(data.into_bytes()), + // TODO: pings and pongs and close messages need to be + // answered ; and this is really hard ; for now we produce + // an error when that happens + _ => Err(IoError::new(IoErrorKind::Other, "unimplemented")), + } + }); + let read_write = RwStreamSink::new(framed_data); + Box::new(read_write) as Box + }) + .map(|c| (c, client_addr)) + }); - Ok(Box::new(dial) as Box<_>) - } + Ok(Box::new(dial) as Box<_>) + } - fn nat_traversal(&self, server: &Multiaddr, observed: &Multiaddr) -> Option { - let mut server = server.clone(); - let last_proto = match server.pop() { - Some(v @ AddrComponent::WS) | Some(v @ AddrComponent::WSS) => v, - _ => return None, - }; + fn nat_traversal(&self, server: &Multiaddr, observed: &Multiaddr) -> Option { + let mut server = server.clone(); + let last_proto = match server.pop() { + Some(v @ AddrComponent::WS) | Some(v @ AddrComponent::WSS) => v, + _ => return None, + }; - let mut observed = observed.clone(); - match observed.pop() { - Some(AddrComponent::WS) => false, - Some(AddrComponent::WSS) => true, - _ => return None, - }; + let mut observed = observed.clone(); + match observed.pop() { + Some(AddrComponent::WS) => false, + Some(AddrComponent::WSS) => true, + _ => return None, + }; - self.transport.nat_traversal(&server, &observed) - .map(move |mut result| { result.append(last_proto); result }) - } + self.transport + .nat_traversal(&server, &observed) + .map(move |mut result| { + result.append(last_proto); + result + }) + } } #[cfg(test)] mod tests { - extern crate libp2p_tcp_transport as tcp; - extern crate tokio_core; - use self::tokio_core::reactor::Core; - use WsConfig; - use futures::{Future, Stream}; - use multiaddr::Multiaddr; - use swarm::Transport; + extern crate libp2p_tcp_transport as tcp; + extern crate tokio_core; + use self::tokio_core::reactor::Core; + use WsConfig; + use futures::{Future, Stream}; + use multiaddr::Multiaddr; + use swarm::Transport; - #[test] - fn dialer_connects_to_listener_ipv4() { - let mut core = Core::new().unwrap(); - let ws_config = WsConfig::new(tcp::TcpConfig::new(core.handle())); + #[test] + fn dialer_connects_to_listener_ipv4() { + let mut core = Core::new().unwrap(); + let ws_config = WsConfig::new(tcp::TcpConfig::new(core.handle())); - let (listener, addr) = ws_config - .clone() - .listen_on("/ip4/0.0.0.0/tcp/0/ws".parse().unwrap()) - .unwrap(); - assert!(addr.to_string().ends_with("/ws")); - assert!(!addr.to_string().ends_with("/0/ws")); - let listener = listener - .into_future() - .map_err(|(e, _)| e) - .and_then(|(c, _)| c.unwrap().map(|v| v.0)); - let dialer = ws_config.clone().dial(addr).unwrap().map(|v| v.0); + let (listener, addr) = ws_config + .clone() + .listen_on("/ip4/0.0.0.0/tcp/0/ws".parse().unwrap()) + .unwrap(); + assert!(addr.to_string().ends_with("/ws")); + assert!(!addr.to_string().ends_with("/0/ws")); + let listener = listener + .into_future() + .map_err(|(e, _)| e) + .and_then(|(c, _)| c.unwrap().map(|v| v.0)); + let dialer = ws_config.clone().dial(addr).unwrap().map(|v| v.0); - let future = listener - .select(dialer) - .map_err(|(e, _)| e) - .and_then(|(_, n)| n); - core.run(future).unwrap(); - } + let future = listener + .select(dialer) + .map_err(|(e, _)| e) + .and_then(|(_, n)| n); + core.run(future).unwrap(); + } - #[test] - fn dialer_connects_to_listener_ipv6() { - let mut core = Core::new().unwrap(); - let ws_config = WsConfig::new(tcp::TcpConfig::new(core.handle())); + #[test] + fn dialer_connects_to_listener_ipv6() { + let mut core = Core::new().unwrap(); + let ws_config = WsConfig::new(tcp::TcpConfig::new(core.handle())); - let (listener, addr) = ws_config - .clone() - .listen_on("/ip6/::1/tcp/0/ws".parse().unwrap()) - .unwrap(); - assert!(addr.to_string().ends_with("/ws")); - assert!(!addr.to_string().ends_with("/0/ws")); - let listener = listener - .into_future() - .map_err(|(e, _)| e) - .and_then(|(c, _)| c.unwrap().map(|v| v.0)); - let dialer = ws_config.clone().dial(addr).unwrap().map(|v| v.0); + let (listener, addr) = ws_config + .clone() + .listen_on("/ip6/::1/tcp/0/ws".parse().unwrap()) + .unwrap(); + assert!(addr.to_string().ends_with("/ws")); + assert!(!addr.to_string().ends_with("/0/ws")); + let listener = listener + .into_future() + .map_err(|(e, _)| e) + .and_then(|(c, _)| c.unwrap().map(|v| v.0)); + let dialer = ws_config.clone().dial(addr).unwrap().map(|v| v.0); - let future = listener - .select(dialer) - .map_err(|(e, _)| e) - .and_then(|(_, n)| n); - core.run(future).unwrap(); - } + let future = listener + .select(dialer) + .map_err(|(e, _)| e) + .and_then(|(_, n)| n); + core.run(future).unwrap(); + } - #[test] - fn nat_traversal() { - let core = Core::new().unwrap(); - let ws_config = WsConfig::new(tcp::TcpConfig::new(core.handle())); + #[test] + fn nat_traversal() { + let core = Core::new().unwrap(); + let ws_config = WsConfig::new(tcp::TcpConfig::new(core.handle())); - { - let server = "/ip4/127.0.0.1/tcp/10000/ws".parse::().unwrap(); - let observed = "/ip4/80.81.82.83/tcp/25000/ws".parse::().unwrap(); - assert_eq!(ws_config.nat_traversal(&server, &observed).unwrap(), - "/ip4/80.81.82.83/tcp/10000/ws".parse::().unwrap()); - } + { + let server = "/ip4/127.0.0.1/tcp/10000/ws".parse::().unwrap(); + let observed = "/ip4/80.81.82.83/tcp/25000/ws" + .parse::() + .unwrap(); + assert_eq!( + ws_config.nat_traversal(&server, &observed).unwrap(), + "/ip4/80.81.82.83/tcp/10000/ws" + .parse::() + .unwrap() + ); + } - { - let server = "/ip4/127.0.0.1/tcp/10000/wss".parse::().unwrap(); - let observed = "/ip4/80.81.82.83/tcp/25000/wss".parse::().unwrap(); - assert_eq!(ws_config.nat_traversal(&server, &observed).unwrap(), - "/ip4/80.81.82.83/tcp/10000/wss".parse::().unwrap()); - } + { + let server = "/ip4/127.0.0.1/tcp/10000/wss".parse::().unwrap(); + let observed = "/ip4/80.81.82.83/tcp/25000/wss" + .parse::() + .unwrap(); + assert_eq!( + ws_config.nat_traversal(&server, &observed).unwrap(), + "/ip4/80.81.82.83/tcp/10000/wss" + .parse::() + .unwrap() + ); + } - { - let server = "/ip4/127.0.0.1/tcp/10000/ws".parse::().unwrap(); - let observed = "/ip4/80.81.82.83/tcp/25000/wss".parse::().unwrap(); - assert_eq!(ws_config.nat_traversal(&server, &observed).unwrap(), - "/ip4/80.81.82.83/tcp/10000/ws".parse::().unwrap()); - } + { + let server = "/ip4/127.0.0.1/tcp/10000/ws".parse::().unwrap(); + let observed = "/ip4/80.81.82.83/tcp/25000/wss" + .parse::() + .unwrap(); + assert_eq!( + ws_config.nat_traversal(&server, &observed).unwrap(), + "/ip4/80.81.82.83/tcp/10000/ws" + .parse::() + .unwrap() + ); + } - { - let server = "/ip4/127.0.0.1/tcp/10000/wss".parse::().unwrap(); - let observed = "/ip4/80.81.82.83/tcp/25000/ws".parse::().unwrap(); - assert_eq!(ws_config.nat_traversal(&server, &observed).unwrap(), - "/ip4/80.81.82.83/tcp/10000/wss".parse::().unwrap()); - } - } + { + let server = "/ip4/127.0.0.1/tcp/10000/wss".parse::().unwrap(); + let observed = "/ip4/80.81.82.83/tcp/25000/ws" + .parse::() + .unwrap(); + assert_eq!( + ws_config.nat_traversal(&server, &observed).unwrap(), + "/ip4/80.81.82.83/tcp/10000/wss" + .parse::() + .unwrap() + ); + } + } } diff --git a/multiplex-rs/src/lib.rs b/multiplex-rs/src/lib.rs index ca17e29e..2a6d665e 100644 --- a/multiplex-rs/src/lib.rs +++ b/multiplex-rs/src/lib.rs @@ -381,7 +381,7 @@ mod tests { assert_eq!( substream .name() - .and_then(|bytes| { String::from_utf8(bytes.to_vec()).ok() }), + .and_then(|bytes| String::from_utf8(bytes.to_vec()).ok()), Some(id.to_string()) ); @@ -395,7 +395,7 @@ mod tests { assert_eq!( substream .name() - .and_then(|bytes| { String::from_utf8(bytes.to_vec()).ok() }), + .and_then(|bytes| String::from_utf8(bytes.to_vec()).ok()), Some(id.to_string()) ); @@ -445,7 +445,7 @@ mod tests { assert_eq!( substream .name() - .and_then(|bytes| { String::from_utf8(bytes.to_vec()).ok() }), + .and_then(|bytes| String::from_utf8(bytes.to_vec()).ok()), Some(id.to_string()) ); diff --git a/multiplex-rs/tests/two_peers.rs b/multiplex-rs/tests/two_peers.rs index c05c0b31..ad30f22c 100644 --- a/multiplex-rs/tests/two_peers.rs +++ b/multiplex-rs/tests/two_peers.rs @@ -27,10 +27,10 @@ extern crate tokio_core; extern crate tokio_io; use futures::future::Future; -use futures::{Stream, Sink}; +use futures::{Sink, Stream}; use std::sync::mpsc; use std::thread; -use swarm::{Transport, StreamMuxer}; +use swarm::{StreamMuxer, Transport}; use tcp::TcpConfig; use tokio_core::reactor::Core; use tokio_io::codec::length_delimited::Framed; @@ -43,11 +43,11 @@ fn client_to_server_outbound() { let bg_thread = thread::spawn(move || { let mut core = Core::new().unwrap(); - let transport = TcpConfig::new(core.handle()) - .with_upgrade(multiplex::MultiplexConfig); + let transport = TcpConfig::new(core.handle()).with_upgrade(multiplex::MultiplexConfig); let (listener, addr) = transport - .listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap()).unwrap(); + .listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap()) + .unwrap(); tx.send(addr).unwrap(); let future = listener @@ -57,7 +57,8 @@ fn client_to_server_outbound() { .and_then(|client| client.outbound()) .map(|client| Framed::<_, bytes::BytesMut>::new(client)) .and_then(|client| { - client.into_future() + client + .into_future() .map_err(|(err, _)| err) .map(|(msg, _)| msg) }) @@ -71,10 +72,11 @@ fn client_to_server_outbound() { }); let mut core = Core::new().unwrap(); - let transport = TcpConfig::new(core.handle()) - .with_upgrade(multiplex::MultiplexConfig); + let transport = TcpConfig::new(core.handle()).with_upgrade(multiplex::MultiplexConfig); - let future = transport.dial(rx.recv().unwrap()).unwrap() + let future = transport + .dial(rx.recv().unwrap()) + .unwrap() .and_then(|client| client.0.inbound()) .map(|server| Framed::<_, bytes::BytesMut>::new(server)) .and_then(|server| server.send("hello world".into())) @@ -92,11 +94,11 @@ fn client_to_server_inbound() { let bg_thread = thread::spawn(move || { let mut core = Core::new().unwrap(); - let transport = TcpConfig::new(core.handle()) - .with_upgrade(multiplex::MultiplexConfig); + let transport = TcpConfig::new(core.handle()).with_upgrade(multiplex::MultiplexConfig); let (listener, addr) = transport - .listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap()).unwrap(); + .listen_on("/ip4/127.0.0.1/tcp/0".parse().unwrap()) + .unwrap(); tx.send(addr).unwrap(); let future = listener @@ -106,7 +108,8 @@ fn client_to_server_inbound() { .and_then(|client| client.inbound()) .map(|client| Framed::<_, bytes::BytesMut>::new(client)) .and_then(|client| { - client.into_future() + client + .into_future() .map_err(|(err, _)| err) .map(|(msg, _)| msg) }) @@ -120,10 +123,11 @@ fn client_to_server_inbound() { }); let mut core = Core::new().unwrap(); - let transport = TcpConfig::new(core.handle()) - .with_upgrade(multiplex::MultiplexConfig); + let transport = TcpConfig::new(core.handle()).with_upgrade(multiplex::MultiplexConfig); - let future = transport.dial(rx.recv().unwrap()).unwrap() + let future = transport + .dial(rx.recv().unwrap()) + .unwrap() .and_then(|(client, _)| client.outbound()) .map(|server| Framed::<_, bytes::BytesMut>::new(server)) .and_then(|server| server.send("hello world".into())) diff --git a/multistream-select/src/dialer_select.rs b/multistream-select/src/dialer_select.rs index ff949a3c..e138da40 100644 --- a/multistream-select/src/dialer_select.rs +++ b/multistream-select/src/dialer_select.rs @@ -1,21 +1,21 @@ // Copyright 2017 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. //! Contains the `dialer_select_proto` code, which allows selecting a protocol thanks to @@ -24,7 +24,7 @@ use ProtocolChoiceError; use bytes::Bytes; use futures::{Future, Sink, Stream}; -use futures::future::{result, loop_fn, Loop}; +use futures::future::{loop_fn, result, Loop}; use protocol::Dialer; use protocol::DialerToListenerMessage; @@ -45,20 +45,21 @@ use tokio_io::{AsyncRead, AsyncWrite}; // TODO: remove the Box once -> impl Trait lands #[inline] pub fn dialer_select_proto<'a, R, I, M, P>( - inner: R, - protocols: I, + inner: R, + protocols: I, ) -> Box + 'a> - where R: AsyncRead + AsyncWrite + 'a, - I: Iterator + 'a, - M: FnMut(&Bytes, &Bytes) -> bool + 'a, - P: 'a +where + R: AsyncRead + AsyncWrite + 'a, + I: Iterator + 'a, + M: FnMut(&Bytes, &Bytes) -> bool + 'a, + P: 'a, { - // We choose between the "serial" and "parallel" strategies based on the number of protocols. - if protocols.size_hint().1.map(|n| n <= 3).unwrap_or(false) { - dialer_select_proto_serial(inner, protocols.map(|(n, _, id)| (n, id))) - } else { - dialer_select_proto_parallel(inner, protocols) - } + // We choose between the "serial" and "parallel" strategies based on the number of protocols. + if protocols.size_hint().1.map(|n| n <= 3).unwrap_or(false) { + dialer_select_proto_serial(inner, protocols.map(|(n, _, id)| (n, id))) + } else { + dialer_select_proto_parallel(inner, protocols) + } } /// Helps selecting a protocol amongst the ones supported. @@ -67,22 +68,24 @@ pub fn dialer_select_proto<'a, R, I, M, P>( /// match functions, because it's not needed. // TODO: remove the Box once -> impl Trait lands pub fn dialer_select_proto_serial<'a, R, I, P>( - inner: R, - mut protocols: I, + inner: R, + mut protocols: I, ) -> Box + 'a> - where R: AsyncRead + AsyncWrite + 'a, - I: Iterator + 'a, - P: 'a +where + R: AsyncRead + AsyncWrite + 'a, + I: Iterator + 'a, + P: 'a, { - let future = Dialer::new(inner) - .from_err() - .and_then(move |dialer| { - // Similar to a `loop` keyword. - loop_fn(dialer, move |dialer| { - result(protocols.next().ok_or(ProtocolChoiceError::NoProtocolFound)) + let future = Dialer::new(inner).from_err().and_then(move |dialer| { + // Similar to a `loop` keyword. + loop_fn(dialer, move |dialer| { + result(protocols.next().ok_or(ProtocolChoiceError::NoProtocolFound)) // If the `protocols` iterator produced an element, send it to the dialer .and_then(|(proto_name, proto_value)| { - dialer.send(DialerToListenerMessage::ProtocolRequest { name: proto_name.clone() }) + let req = DialerToListenerMessage::ProtocolRequest { + name: proto_name.clone() + }; + dialer.send(req) .map(|d| (d, proto_name, proto_value)) .from_err() }) @@ -110,11 +113,11 @@ pub fn dialer_select_proto_serial<'a, R, I, P>( _ => Err(ProtocolChoiceError::UnexpectedMessage), } }) - }) - }); + }) + }); - // The "Rust doesn't have impl Trait yet" tax. - Box::new(future) + // The "Rust doesn't have impl Trait yet" tax. + Box::new(future) } /// Helps selecting a protocol amongst the ones supported. @@ -123,60 +126,67 @@ pub fn dialer_select_proto_serial<'a, R, I, P>( /// chooses the most appropriate one. // TODO: remove the Box once -> impl Trait lands pub fn dialer_select_proto_parallel<'a, R, I, M, P>( - inner: R, - protocols: I, + inner: R, + protocols: I, ) -> Box + 'a> - where R: AsyncRead + AsyncWrite + 'a, - I: Iterator + 'a, - M: FnMut(&Bytes, &Bytes) -> bool + 'a, - P: 'a +where + R: AsyncRead + AsyncWrite + 'a, + I: Iterator + 'a, + M: FnMut(&Bytes, &Bytes) -> bool + 'a, + P: 'a, { - let future = Dialer::new(inner) - .from_err() - .and_then( - move |dialer| dialer.send(DialerToListenerMessage::ProtocolsListRequest).from_err(), - ) - .and_then(move |dialer| dialer.into_future().map_err(|(e, _)| e.into())) - .and_then(move |(msg, dialer)| { - let list = match msg { - Some(ListenerToDialerMessage::ProtocolsListResponse { list }) => list, - _ => return Err(ProtocolChoiceError::UnexpectedMessage), - }; + let future = Dialer::new(inner) + .from_err() + .and_then(move |dialer| { + dialer + .send(DialerToListenerMessage::ProtocolsListRequest) + .from_err() + }) + .and_then(move |dialer| dialer.into_future().map_err(|(e, _)| e.into())) + .and_then(move |(msg, dialer)| { + let list = match msg { + Some(ListenerToDialerMessage::ProtocolsListResponse { list }) => list, + _ => return Err(ProtocolChoiceError::UnexpectedMessage), + }; - let mut found = None; - for (local_name, mut match_fn, ident) in protocols { - for remote_name in &list { - if match_fn(remote_name, &local_name) { - found = Some((remote_name.clone(), ident)); - break; - } - } + let mut found = None; + for (local_name, mut match_fn, ident) in protocols { + for remote_name in &list { + if match_fn(remote_name, &local_name) { + found = Some((remote_name.clone(), ident)); + break; + } + } - if found.is_some() { - break; - } - } + if found.is_some() { + break; + } + } - let (proto_name, proto_val) = found.ok_or(ProtocolChoiceError::NoProtocolFound)?; - Ok((proto_name, proto_val, dialer)) - }) - .and_then(|(proto_name, proto_val, dialer)| { - dialer.send(DialerToListenerMessage::ProtocolRequest { name: proto_name.clone() }) - .from_err() - .map(|dialer| (proto_name, proto_val, dialer)) - }) - .and_then(|(proto_name, proto_val, dialer)| { - dialer.into_future() - .map(|(msg, rest)| (proto_name, proto_val, msg, rest)) - .map_err(|(err, _)| err.into()) - }) - .and_then(|(proto_name, proto_val, msg, dialer)| match msg { - Some(ListenerToDialerMessage::ProtocolAck { ref name }) if name == &proto_name => { - Ok((proto_val, dialer.into_inner())) - } - _ => Err(ProtocolChoiceError::UnexpectedMessage), - }); + let (proto_name, proto_val) = found.ok_or(ProtocolChoiceError::NoProtocolFound)?; + Ok((proto_name, proto_val, dialer)) + }) + .and_then(|(proto_name, proto_val, dialer)| { + dialer + .send(DialerToListenerMessage::ProtocolRequest { + name: proto_name.clone(), + }) + .from_err() + .map(|dialer| (proto_name, proto_val, dialer)) + }) + .and_then(|(proto_name, proto_val, dialer)| { + dialer + .into_future() + .map(|(msg, rest)| (proto_name, proto_val, msg, rest)) + .map_err(|(err, _)| err.into()) + }) + .and_then(|(proto_name, proto_val, msg, dialer)| match msg { + Some(ListenerToDialerMessage::ProtocolAck { ref name }) if name == &proto_name => { + Ok((proto_val, dialer.into_inner())) + } + _ => Err(ProtocolChoiceError::UnexpectedMessage), + }); - // The "Rust doesn't have impl Trait yet" tax. - Box::new(future) + // The "Rust doesn't have impl Trait yet" tax. + Box::new(future) } diff --git a/multistream-select/src/error.rs b/multistream-select/src/error.rs index 8f8d5fa2..5106622a 100644 --- a/multistream-select/src/error.rs +++ b/multistream-select/src/error.rs @@ -1,21 +1,21 @@ // Copyright 2017 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. //! Main `ProtocolChoiceError` error. @@ -28,59 +28,55 @@ use std::io::Error as IoError; /// Error that can happen when negotiating a protocol with the remote. #[derive(Debug)] pub enum ProtocolChoiceError { - /// Error in the protocol. - MultistreamSelectError(MultistreamSelectError), + /// Error in the protocol. + MultistreamSelectError(MultistreamSelectError), - /// Received a message from the remote that makes no sense in the current context. - UnexpectedMessage, + /// Received a message from the remote that makes no sense in the current context. + UnexpectedMessage, - /// We don't support any protocol in common with the remote. - NoProtocolFound, + /// We don't support any protocol in common with the remote. + NoProtocolFound, } impl From for ProtocolChoiceError { - #[inline] - fn from(err: MultistreamSelectError) -> ProtocolChoiceError { - ProtocolChoiceError::MultistreamSelectError(err) - } + #[inline] + fn from(err: MultistreamSelectError) -> ProtocolChoiceError { + ProtocolChoiceError::MultistreamSelectError(err) + } } impl From for ProtocolChoiceError { - #[inline] - fn from(err: IoError) -> ProtocolChoiceError { - MultistreamSelectError::from(err).into() - } + #[inline] + fn from(err: IoError) -> ProtocolChoiceError { + MultistreamSelectError::from(err).into() + } } impl error::Error for ProtocolChoiceError { - #[inline] - fn description(&self) -> &str { - match *self { - ProtocolChoiceError::MultistreamSelectError(_) => { - "error in the protocol" - }, - ProtocolChoiceError::UnexpectedMessage => { - "received a message from the remote that makes no sense in the current context" - }, - ProtocolChoiceError::NoProtocolFound => { - "we don't support any protocol in common with the remote" - }, - } - } + #[inline] + fn description(&self) -> &str { + match *self { + ProtocolChoiceError::MultistreamSelectError(_) => "error in the protocol", + ProtocolChoiceError::UnexpectedMessage => { + "received a message from the remote that makes no sense in the current context" + } + ProtocolChoiceError::NoProtocolFound => { + "we don't support any protocol in common with the remote" + } + } + } - fn cause(&self) -> Option<&error::Error> { - match *self { - ProtocolChoiceError::MultistreamSelectError(ref err) => { - Some(err) - } - _ => None, - } - } + fn cause(&self) -> Option<&error::Error> { + match *self { + ProtocolChoiceError::MultistreamSelectError(ref err) => Some(err), + _ => None, + } + } } impl fmt::Display for ProtocolChoiceError { - #[inline] - fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write!(fmt, "{}", error::Error::description(self)) - } + #[inline] + fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + write!(fmt, "{}", error::Error::description(self)) + } } diff --git a/multistream-select/src/length_delimited.rs b/multistream-select/src/length_delimited.rs index 3aeafff8..9ba5fac9 100644 --- a/multistream-select/src/length_delimited.rs +++ b/multistream-select/src/length_delimited.rs @@ -1,34 +1,34 @@ // Copyright 2017 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. //! Alternative implementation for `tokio_io::codec::length_delimited::FramedRead` with an //! additional property: the `into_inner()` method is guarateed not to drop any data. //! //! Also has the length field length hardcoded. -//! +//! //! We purposely only support a frame length of under 64kiB. Frames most consist in a short //! protocol name, which is highly unlikely to be more than 64kiB long. use std::io::{Error as IoError, ErrorKind as IoErrorKind}; use std::marker::PhantomData; -use futures::{Async, StartSend, Poll, Sink, Stream}; +use futures::{Async, Poll, Sink, StartSend, Stream}; use smallvec::SmallVec; use tokio_io::AsyncRead; @@ -56,16 +56,18 @@ enum State { // We are currently reading the length of the next frame of data. ReadingLength, // We are currently reading the frame of data itself. - ReadingData { - frame_len: u16 - }, + ReadingData { frame_len: u16 }, } impl LengthDelimitedFramedRead { pub fn new(inner: S) -> LengthDelimitedFramedRead { LengthDelimitedFramedRead { inner: inner, - internal_buffer: { let mut v = SmallVec::new(); v.push(0); v }, + internal_buffer: { + let mut v = SmallVec::new(); + v.push(0); + v + }, internal_buffer_pos: 0, state: State::ReadingLength, marker: PhantomData, @@ -92,8 +94,9 @@ impl LengthDelimitedFramedRead { } impl Stream for LengthDelimitedFramedRead - where S: AsyncRead, - I: for<'r> From<&'r [u8]> +where + S: AsyncRead, + I: for<'r> From<&'r [u8]>, { type Item = I; type Error = IoError; @@ -105,26 +108,27 @@ impl Stream for LengthDelimitedFramedRead match self.state { State::ReadingLength => { - match self.inner.read(&mut self.internal_buffer[self.internal_buffer_pos..]) { + match self.inner + .read(&mut self.internal_buffer[self.internal_buffer_pos..]) + { Ok(0) => { // EOF if self.internal_buffer_pos == 0 { return Ok(Async::Ready(None)); } else { - return Err(IoError::new(IoErrorKind::BrokenPipe, - "unexpected eof")); + return Err(IoError::new(IoErrorKind::BrokenPipe, "unexpected eof")); } - }, + } Ok(n) => { debug_assert_eq!(n, 1); self.internal_buffer_pos += n; - }, + } Err(ref err) if err.kind() == IoErrorKind::WouldBlock => { return Ok(Async::NotReady); - }, + } Err(err) => { return Err(err); - }, + } }; debug_assert_eq!(self.internal_buffer.len(), self.internal_buffer_pos); @@ -135,12 +139,13 @@ impl Stream for LengthDelimitedFramedRead let frame_len = decode_length_prefix(&self.internal_buffer); if frame_len >= 1 { - self.state = State::ReadingData { frame_len: frame_len }; + self.state = State::ReadingData { + frame_len: frame_len, + }; self.internal_buffer.clear(); self.internal_buffer.reserve(frame_len as usize); - self.internal_buffer.extend((0 .. frame_len).map(|_| 0)); + self.internal_buffer.extend((0..frame_len).map(|_| 0)); self.internal_buffer_pos = 0; - } else { debug_assert_eq!(frame_len, 0); self.state = State::ReadingLength; @@ -149,29 +154,32 @@ impl Stream for LengthDelimitedFramedRead self.internal_buffer_pos = 0; return Ok(Async::Ready(Some(From::from(&[][..])))); } - } else if self.internal_buffer_pos >= 2 { // Length prefix is too long. See module doc for info about max frame len. - return Err(IoError::new(IoErrorKind::InvalidData, "frame length too long")); - + return Err(IoError::new( + IoErrorKind::InvalidData, + "frame length too long", + )); } else { // Prepare for next read. self.internal_buffer.push(0); } - }, + } State::ReadingData { frame_len } => { - match self.inner.read(&mut self.internal_buffer[self.internal_buffer_pos..]) { + match self.inner + .read(&mut self.internal_buffer[self.internal_buffer_pos..]) + { Ok(0) => { return Err(IoError::new(IoErrorKind::BrokenPipe, "unexpected eof")); - }, + } Ok(n) => self.internal_buffer_pos += n, Err(ref err) if err.kind() == IoErrorKind::WouldBlock => { return Ok(Async::NotReady); - }, + } Err(err) => { return Err(err); - }, + } }; if self.internal_buffer_pos >= frame_len as usize { @@ -183,14 +191,15 @@ impl Stream for LengthDelimitedFramedRead self.internal_buffer_pos = 0; return Ok(Async::Ready(Some(out_data))); } - }, + } } } } } impl Sink for LengthDelimitedFramedRead - where S: Sink +where + S: Sink, { type SinkItem = S::SinkItem; type SinkError = S::SinkError; @@ -250,25 +259,34 @@ mod tests { fn two_bytes_long_packet() { let len = 5000u16; assert!(len < (1 << 15)); - let frame = (0 .. len).map(|n| (n & 0xff) as u8).collect::>(); + let frame = (0..len).map(|n| (n & 0xff) as u8).collect::>(); let mut data = vec![(len & 0x7f) as u8 | 0x80, (len >> 7) as u8]; data.extend(frame.clone().into_iter()); let framed = LengthDelimitedFramedRead::, _>::new(Cursor::new(data)); - let recved = framed.into_future().map(|(m, _)| m).map_err(|_| ()).wait().unwrap(); + let recved = framed + .into_future() + .map(|(m, _)| m) + .map_err(|_| ()) + .wait() + .unwrap(); assert_eq!(recved.unwrap(), frame); } #[test] fn packet_len_too_long() { let mut data = vec![0x81, 0x81, 0x1]; - data.extend((0 .. 16513).map(|_| 0)); + data.extend((0..16513).map(|_| 0)); let framed = LengthDelimitedFramedRead::, _>::new(Cursor::new(data)); - let recved = framed.into_future().map(|(m, _)| m).map_err(|(err, _)| err).wait(); + let recved = framed + .into_future() + .map(|(m, _)| m) + .map_err(|(err, _)| err) + .wait(); match recved { Err(io_err) => assert_eq!(io_err.kind(), ErrorKind::InvalidData), - _ => panic!() + _ => panic!(), } } @@ -278,7 +296,16 @@ mod tests { let framed = LengthDelimitedFramedRead::, _>::new(Cursor::new(data)); let recved = framed.collect().wait().unwrap(); - assert_eq!(recved, vec![vec![], vec![], vec![9, 8, 7, 6, 5, 4], vec![], vec![9, 8, 7]]); + assert_eq!( + recved, + vec![ + vec![], + vec![], + vec![9, 8, 7, 6, 5, 4], + vec![], + vec![9, 8, 7], + ] + ); } #[test] @@ -289,7 +316,7 @@ mod tests { let recved = framed.collect().wait(); match recved { Err(io_err) => assert_eq!(io_err.kind(), ErrorKind::BrokenPipe), - _ => panic!() + _ => panic!(), } } @@ -301,7 +328,7 @@ mod tests { let recved = framed.collect().wait(); match recved { Err(io_err) => assert_eq!(io_err.kind(), ErrorKind::BrokenPipe), - _ => panic!() + _ => panic!(), } } @@ -313,7 +340,7 @@ mod tests { let recved = framed.collect().wait(); match recved { Err(io_err) => assert_eq!(io_err.kind(), ErrorKind::BrokenPipe), - _ => panic!() + _ => panic!(), } } } diff --git a/multistream-select/src/lib.rs b/multistream-select/src/lib.rs index c9675e6c..2839b190 100644 --- a/multistream-select/src/lib.rs +++ b/multistream-select/src/lib.rs @@ -1,21 +1,21 @@ // Copyright 2017 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. // TODO: use this once stable ; for now we just copy-paste the content of the README.md @@ -39,11 +39,11 @@ //! The dialer has two options available: either request the list of protocols that the listener //! supports, or suggest a protocol. If a protocol is suggested, the listener can either accept (by //! answering with the same protocol name) or refuse the choice (by answering "not available"). -//! +//! //! ## Examples -//! +//! //! For a dialer: -//! +//! //! ```no_run //! extern crate bytes; //! extern crate futures; @@ -79,7 +79,7 @@ //! ``` //! //! For a listener: -//! +//! //! ```no_run //! extern crate bytes; //! extern crate futures; diff --git a/multistream-select/src/listener_select.rs b/multistream-select/src/listener_select.rs index c258caac..f7ce99b7 100644 --- a/multistream-select/src/listener_select.rs +++ b/multistream-select/src/listener_select.rs @@ -1,21 +1,21 @@ // Copyright 2017 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. //! Contains the `listener_select_proto` code, which allows selecting a protocol thanks to @@ -47,56 +47,60 @@ use tokio_io::{AsyncRead, AsyncWrite}; /// socket now uses this protocol. // TODO: remove the Box once -> impl Trait lands pub fn listener_select_proto<'a, R, I, M, P>( - inner: R, - protocols: I, + inner: R, + protocols: I, ) -> Box + 'a> - where R: AsyncRead + AsyncWrite + 'a, - I: Iterator + Clone + 'a, - M: FnMut(&Bytes, &Bytes) -> bool + 'a, - P: 'a +where + R: AsyncRead + AsyncWrite + 'a, + I: Iterator + Clone + 'a, + M: FnMut(&Bytes, &Bytes) -> bool + 'a, + P: 'a, { - let future = Listener::new(inner).from_err().and_then(move |listener| { + let future = Listener::new(inner).from_err().and_then(move |listener| { + loop_fn(listener, move |listener| { + let protocols = protocols.clone(); - loop_fn(listener, move |listener| { - let protocols = protocols.clone(); + listener + .into_future() + .map_err(|(e, _)| e.into()) + .and_then(move |(message, listener)| match message { + Some(DialerToListenerMessage::ProtocolsListRequest) => { + let msg = ListenerToDialerMessage::ProtocolsListResponse { + list: protocols.map(|(p, _, _)| p).collect(), + }; + let fut = listener + .send(msg) + .from_err() + .map(move |listener| (None, listener)); + Box::new(fut) as Box> + } + Some(DialerToListenerMessage::ProtocolRequest { name }) => { + let mut outcome = None; + let mut send_back = ListenerToDialerMessage::NotAvailable; + for (supported, mut matches, value) in protocols { + if matches(&name, &supported) { + send_back = + ListenerToDialerMessage::ProtocolAck { name: name.clone() }; + outcome = Some(value); + break; + } + } - listener.into_future() - .map_err(|(e, _)| e.into()) - .and_then(move |(message, listener)| match message { - Some(DialerToListenerMessage::ProtocolsListRequest) => { - let msg = ListenerToDialerMessage::ProtocolsListResponse { - list: protocols.map(|(p, _, _)| p).collect(), - }; - let fut = listener.send(msg).from_err().map(move |listener| (None, listener)); - Box::new(fut) as Box> - } - Some(DialerToListenerMessage::ProtocolRequest { name }) => { - let mut outcome = None; - let mut send_back = ListenerToDialerMessage::NotAvailable; - for (supported, mut matches, value) in protocols { - if matches(&name, &supported) { - send_back = ListenerToDialerMessage::ProtocolAck { name: name.clone() }; - outcome = Some(value); - break; - } - } + let fut = listener + .send(send_back) + .from_err() + .map(move |listener| (outcome, listener)); + Box::new(fut) as Box> + } + None => Box::new(err(ProtocolChoiceError::NoProtocolFound)) as Box<_>, + }) + .map(|(outcome, listener): (_, Listener)| match outcome { + Some(outcome) => Loop::Break((outcome, listener.into_inner())), + None => Loop::Continue(listener), + }) + }) + }); - let fut = listener.send(send_back) - .from_err() - .map(move |listener| (outcome, listener)); - Box::new(fut) as Box> - } - None => { - Box::new(err(ProtocolChoiceError::NoProtocolFound)) as Box<_> - } - }) - .map(|(outcome, listener): (_, Listener)| match outcome { - Some(outcome) => Loop::Break((outcome, listener.into_inner())), - None => Loop::Continue(listener), - }) - }) - }); - - // The "Rust doesn't have impl Trait yet" tax. - Box::new(future) + // The "Rust doesn't have impl Trait yet" tax. + Box::new(future) } diff --git a/multistream-select/src/protocol/dialer.rs b/multistream-select/src/protocol/dialer.rs index 917882b7..163530f8 100644 --- a/multistream-select/src/protocol/dialer.rs +++ b/multistream-select/src/protocol/dialer.rs @@ -1,21 +1,21 @@ // Copyright 2017 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. //! Contains the `Dialer` wrapper, which allows raw communications with a listener. @@ -27,7 +27,7 @@ use protocol::DialerToListenerMessage; use protocol::ListenerToDialerMessage; use protocol::MULTISTREAM_PROTOCOL_WITH_LF; use protocol::MultistreamSelectError; -use std::io::{Cursor, Read, BufRead}; +use std::io::{BufRead, Cursor, Read}; use tokio_io::{AsyncRead, AsyncWrite}; use tokio_io::codec::length_delimited::Builder as LengthDelimitedBuilder; use tokio_io::codec::length_delimited::FramedWrite as LengthDelimitedFramedWrite; @@ -36,181 +36,192 @@ use varint; /// Wraps around a `AsyncRead+AsyncWrite`. Assumes that we're on the dialer's side. Produces and /// accepts messages. pub struct Dialer { - inner: LengthDelimitedFramedRead>, - handshake_finished: bool, + inner: LengthDelimitedFramedRead>, + handshake_finished: bool, } impl Dialer - where R: AsyncRead + AsyncWrite +where + R: AsyncRead + AsyncWrite, { - /// Takes ownership of a socket and starts the handshake. If the handshake succeeds, the - /// future returns a `Dialer`. - pub fn new<'a>(inner: R) -> Box, Error = MultistreamSelectError> + 'a> - where R: 'a - { - let write = LengthDelimitedBuilder::new().length_field_length(1).new_write(inner); - let inner = LengthDelimitedFramedRead::new(write); + /// Takes ownership of a socket and starts the handshake. If the handshake succeeds, the + /// future returns a `Dialer`. + pub fn new<'a>(inner: R) -> Box, Error = MultistreamSelectError> + 'a> + where + R: 'a, + { + let write = LengthDelimitedBuilder::new() + .length_field_length(1) + .new_write(inner); + let inner = LengthDelimitedFramedRead::new(write); - let future = - inner.send(BytesMut::from(MULTISTREAM_PROTOCOL_WITH_LF)).from_err().map(|inner| { - Dialer { - inner: inner, - handshake_finished: false, - } - }); - Box::new(future) - } + let future = inner + .send(BytesMut::from(MULTISTREAM_PROTOCOL_WITH_LF)) + .from_err() + .map(|inner| Dialer { + inner: inner, + handshake_finished: false, + }); + Box::new(future) + } - /// Grants back the socket. Typically used after a `ProtocolAck` has been received. - #[inline] - pub fn into_inner(self) -> R { - self.inner.into_inner().into_inner() - } + /// Grants back the socket. Typically used after a `ProtocolAck` has been received. + #[inline] + pub fn into_inner(self) -> R { + self.inner.into_inner().into_inner() + } } impl Sink for Dialer - where R: AsyncRead + AsyncWrite +where + R: AsyncRead + AsyncWrite, { - type SinkItem = DialerToListenerMessage; - type SinkError = MultistreamSelectError; + type SinkItem = DialerToListenerMessage; + type SinkError = MultistreamSelectError; - fn start_send(&mut self, item: Self::SinkItem) -> StartSend { - match item { - DialerToListenerMessage::ProtocolRequest { name } => { - if !name.starts_with(b"/") { - return Err(MultistreamSelectError::WrongProtocolName); - } - let mut protocol = BytesMut::from(name); - protocol.extend_from_slice(&[b'\n']); - match self.inner.start_send(protocol) { - Ok(AsyncSink::Ready) => Ok(AsyncSink::Ready), - Ok(AsyncSink::NotReady(mut protocol)) => { - let protocol_len = protocol.len(); - protocol.truncate(protocol_len - 1); - let protocol = protocol.freeze(); - Ok(AsyncSink::NotReady( - DialerToListenerMessage::ProtocolRequest { name: protocol }, - )) - } - Err(err) => Err(err.into()), - } - } + fn start_send(&mut self, item: Self::SinkItem) -> StartSend { + match item { + DialerToListenerMessage::ProtocolRequest { name } => { + if !name.starts_with(b"/") { + return Err(MultistreamSelectError::WrongProtocolName); + } + let mut protocol = BytesMut::from(name); + protocol.extend_from_slice(&[b'\n']); + match self.inner.start_send(protocol) { + Ok(AsyncSink::Ready) => Ok(AsyncSink::Ready), + Ok(AsyncSink::NotReady(mut protocol)) => { + let protocol_len = protocol.len(); + protocol.truncate(protocol_len - 1); + let protocol = protocol.freeze(); + Ok(AsyncSink::NotReady( + DialerToListenerMessage::ProtocolRequest { name: protocol }, + )) + } + Err(err) => Err(err.into()), + } + } - DialerToListenerMessage::ProtocolsListRequest => { - match self.inner.start_send(BytesMut::from(&b"ls\n"[..])) { - Ok(AsyncSink::Ready) => Ok(AsyncSink::Ready), - Ok(AsyncSink::NotReady(_)) => { - Ok(AsyncSink::NotReady(DialerToListenerMessage::ProtocolsListRequest)) - } - Err(err) => Err(err.into()), - } - } - } - } + DialerToListenerMessage::ProtocolsListRequest => { + match self.inner.start_send(BytesMut::from(&b"ls\n"[..])) { + Ok(AsyncSink::Ready) => Ok(AsyncSink::Ready), + Ok(AsyncSink::NotReady(_)) => Ok(AsyncSink::NotReady( + DialerToListenerMessage::ProtocolsListRequest, + )), + Err(err) => Err(err.into()), + } + } + } + } - #[inline] - fn poll_complete(&mut self) -> Poll<(), Self::SinkError> { - Ok(self.inner.poll_complete()?) - } + #[inline] + fn poll_complete(&mut self) -> Poll<(), Self::SinkError> { + Ok(self.inner.poll_complete()?) + } } impl Stream for Dialer - where R: AsyncRead + AsyncWrite +where + R: AsyncRead + AsyncWrite, { - type Item = ListenerToDialerMessage; - type Error = MultistreamSelectError; + type Item = ListenerToDialerMessage; + type Error = MultistreamSelectError; - fn poll(&mut self) -> Poll, Self::Error> { - loop { - let mut frame = match self.inner.poll() { - Ok(Async::Ready(Some(frame))) => frame, - Ok(Async::Ready(None)) => return Ok(Async::Ready(None)), - Ok(Async::NotReady) => return Ok(Async::NotReady), - Err(err) => return Err(err.into()), - }; + fn poll(&mut self) -> Poll, Self::Error> { + loop { + let mut frame = match self.inner.poll() { + Ok(Async::Ready(Some(frame))) => frame, + Ok(Async::Ready(None)) => return Ok(Async::Ready(None)), + Ok(Async::NotReady) => return Ok(Async::NotReady), + Err(err) => return Err(err.into()), + }; - if !self.handshake_finished { - if frame == MULTISTREAM_PROTOCOL_WITH_LF { - self.handshake_finished = true; - continue; - } else { - return Err(MultistreamSelectError::FailedHandshake); - } - } + if !self.handshake_finished { + if frame == MULTISTREAM_PROTOCOL_WITH_LF { + self.handshake_finished = true; + continue; + } else { + return Err(MultistreamSelectError::FailedHandshake); + } + } - if frame.get(0) == Some(&b'/') && frame.last() == Some(&b'\n') { - let frame_len = frame.len(); - let protocol = frame.split_to(frame_len - 1); - return Ok( - Async::Ready(Some(ListenerToDialerMessage::ProtocolAck { name: protocol })), - ); + if frame.get(0) == Some(&b'/') && frame.last() == Some(&b'\n') { + let frame_len = frame.len(); + let protocol = frame.split_to(frame_len - 1); + return Ok(Async::Ready(Some(ListenerToDialerMessage::ProtocolAck { + name: protocol, + }))); + } else if frame == &b"na\n"[..] { + return Ok(Async::Ready(Some(ListenerToDialerMessage::NotAvailable))); + } else { + // A varint number of protocols + let mut reader = Cursor::new(frame); + let num_protocols: usize = varint::decode(reader.by_ref())?; - } else if frame == &b"na\n"[..] { - return Ok(Async::Ready(Some(ListenerToDialerMessage::NotAvailable))); + let mut iter = BufRead::split(reader, b'\r'); + if !iter.next() + .ok_or(MultistreamSelectError::UnknownMessage)?? + .is_empty() + { + return Err(MultistreamSelectError::UnknownMessage); + } - } else { - // A varint number of protocols - let mut reader = Cursor::new(frame); - let num_protocols: usize = varint::decode(reader.by_ref())?; + let mut out = Vec::with_capacity(num_protocols); + for proto in iter.by_ref().take(num_protocols) { + let mut proto = proto?; + let poped = proto.pop(); // Pop the `\n` + if poped != Some(b'\n') { + return Err(MultistreamSelectError::UnknownMessage); + } + out.push(Bytes::from(proto)); + } - let mut iter = BufRead::split(reader, b'\r'); - if !iter.next().ok_or(MultistreamSelectError::UnknownMessage)??.is_empty() { - return Err(MultistreamSelectError::UnknownMessage); - } + // Making sure that the number of protocols was correct. + if iter.next().is_some() || out.len() != num_protocols { + return Err(MultistreamSelectError::UnknownMessage); + } - let mut out = Vec::with_capacity(num_protocols); - for proto in iter.by_ref().take(num_protocols) { - let mut proto = proto?; - let poped = proto.pop(); // Pop the `\n` - if poped != Some(b'\n') { - return Err(MultistreamSelectError::UnknownMessage); - } - out.push(Bytes::from(proto)); - } - - // Making sure that the number of protocols was correct. - if iter.next().is_some() || out.len() != num_protocols { - return Err(MultistreamSelectError::UnknownMessage); - } - - return Ok(Async::Ready(Some(ListenerToDialerMessage::ProtocolsListResponse { - list: out - }))); - } - } - } + return Ok(Async::Ready(Some( + ListenerToDialerMessage::ProtocolsListResponse { list: out }, + ))); + } + } + } } #[cfg(test)] mod tests { - extern crate tokio_core; - use bytes::Bytes; - use futures::{Sink, Stream}; - use futures::Future; - use protocol::{Dialer, DialerToListenerMessage, MultistreamSelectError}; - use self::tokio_core::net::{TcpListener, TcpStream}; - use self::tokio_core::reactor::Core; + extern crate tokio_core; + use bytes::Bytes; + use futures::{Sink, Stream}; + use futures::Future; + use protocol::{Dialer, DialerToListenerMessage, MultistreamSelectError}; + use self::tokio_core::net::{TcpListener, TcpStream}; + use self::tokio_core::reactor::Core; - #[test] - fn wrong_proto_name() { - let mut core = Core::new().unwrap(); + #[test] + fn wrong_proto_name() { + let mut core = Core::new().unwrap(); - let listener = TcpListener::bind(&"127.0.0.1:0".parse().unwrap(), &core.handle()).unwrap(); - let listener_addr = listener.local_addr().unwrap(); + let listener = TcpListener::bind(&"127.0.0.1:0".parse().unwrap(), &core.handle()).unwrap(); + let listener_addr = listener.local_addr().unwrap(); - let server = listener.incoming().into_future().map(|_| ()).map_err(|(e, _)| e.into()); + let server = listener + .incoming() + .into_future() + .map(|_| ()) + .map_err(|(e, _)| e.into()); - let client = TcpStream::connect(&listener_addr, &core.handle()) - .from_err() - .and_then(move |stream| Dialer::new(stream)) - .and_then(move |dialer| { - let p = Bytes::from("invalid_name"); - dialer.send(DialerToListenerMessage::ProtocolRequest { name: p }) - }); + let client = TcpStream::connect(&listener_addr, &core.handle()) + .from_err() + .and_then(move |stream| Dialer::new(stream)) + .and_then(move |dialer| { + let p = Bytes::from("invalid_name"); + dialer.send(DialerToListenerMessage::ProtocolRequest { name: p }) + }); - match core.run(server.join(client)) { - Err(MultistreamSelectError::WrongProtocolName) => (), - _ => panic!(), - } - } + match core.run(server.join(client)) { + Err(MultistreamSelectError::WrongProtocolName) => (), + _ => panic!(), + } + } } diff --git a/multistream-select/src/protocol/error.rs b/multistream-select/src/protocol/error.rs index 431c0e3b..24f51f5a 100644 --- a/multistream-select/src/protocol/error.rs +++ b/multistream-select/src/protocol/error.rs @@ -1,21 +1,21 @@ // Copyright 2017 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. //! Contains the error structs for the low-level protocol handling. @@ -28,72 +28,66 @@ use varint; /// Error at the multistream-select layer of communication. #[derive(Debug)] pub enum MultistreamSelectError { - /// I/O error. - IoError(io::Error), + /// I/O error. + IoError(io::Error), - /// The remote doesn't use the same multistream-select protocol as we do. - FailedHandshake, + /// The remote doesn't use the same multistream-select protocol as we do. + FailedHandshake, - /// Received an unknown message from the remote. - UnknownMessage, + /// Received an unknown message from the remote. + UnknownMessage, - /// Protocol names must always start with `/`, otherwise this error is returned. - WrongProtocolName, + /// Protocol names must always start with `/`, otherwise this error is returned. + WrongProtocolName, - /// Failure to parse variable-length integer. - // TODO: we don't include the actual error, because that would remove Send from the enum - VarintParseError(String), + /// Failure to parse variable-length integer. + // TODO: we don't include the actual error, because that would remove Send from the enum + VarintParseError(String), } impl From for MultistreamSelectError { - #[inline] - fn from(err: io::Error) -> MultistreamSelectError { - MultistreamSelectError::IoError(err) - } + #[inline] + fn from(err: io::Error) -> MultistreamSelectError { + MultistreamSelectError::IoError(err) + } } impl From for MultistreamSelectError { - #[inline] - fn from(err: varint::Error) -> MultistreamSelectError { - MultistreamSelectError::VarintParseError(err.to_string()) - } + #[inline] + fn from(err: varint::Error) -> MultistreamSelectError { + MultistreamSelectError::VarintParseError(err.to_string()) + } } impl error::Error for MultistreamSelectError { - #[inline] - fn description(&self) -> &str { - match *self { - MultistreamSelectError::IoError(_) => { - "I/O error" - }, - MultistreamSelectError::FailedHandshake => { - "the remote doesn't use the same multistream-select protocol as we do" - }, - MultistreamSelectError::UnknownMessage => { - "received an unknown message from the remote" - }, - MultistreamSelectError::WrongProtocolName => { - "protocol names must always start with `/`, otherwise this error is returned" - }, - MultistreamSelectError::VarintParseError(_) => { - "failure to parse variable-length integer" - }, - } - } + #[inline] + fn description(&self) -> &str { + match *self { + MultistreamSelectError::IoError(_) => "I/O error", + MultistreamSelectError::FailedHandshake => { + "the remote doesn't use the same multistream-select protocol as we do" + } + MultistreamSelectError::UnknownMessage => "received an unknown message from the remote", + MultistreamSelectError::WrongProtocolName => { + "protocol names must always start with `/`, otherwise this error is returned" + } + MultistreamSelectError::VarintParseError(_) => { + "failure to parse variable-length integer" + } + } + } - fn cause(&self) -> Option<&error::Error> { - match *self { - MultistreamSelectError::IoError(ref err) => { - Some(err) - } - _ => None, - } - } + fn cause(&self) -> Option<&error::Error> { + match *self { + MultistreamSelectError::IoError(ref err) => Some(err), + _ => None, + } + } } impl fmt::Display for MultistreamSelectError { - #[inline] - fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write!(fmt, "{}", error::Error::description(self)) - } + #[inline] + fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + write!(fmt, "{}", error::Error::description(self)) + } } diff --git a/multistream-select/src/protocol/listener.rs b/multistream-select/src/protocol/listener.rs index 89a0c501..f73b6fd1 100644 --- a/multistream-select/src/protocol/listener.rs +++ b/multistream-select/src/protocol/listener.rs @@ -1,21 +1,21 @@ // Copyright 2017 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. //! Contains the `Listener` wrapper, which allows raw communications with a dialer. @@ -35,176 +35,186 @@ use varint; /// Wraps around a `AsyncRead+AsyncWrite`. Assumes that we're on the listener's side. Produces and /// accepts messages. pub struct Listener { - inner: LengthDelimitedFramedRead>, + inner: LengthDelimitedFramedRead>, } impl Listener - where R: AsyncRead + AsyncWrite +where + R: AsyncRead + AsyncWrite, { - /// Takes ownership of a socket and starts the handshake. If the handshake succeeds, the - /// future returns a `Listener`. - pub fn new<'a>(inner: R) -> Box, Error = MultistreamSelectError> + 'a> - where R: 'a - { - let write = LengthDelimitedBuilder::new().length_field_length(1).new_write(inner); - let inner = LengthDelimitedFramedRead::::new(write); + /// Takes ownership of a socket and starts the handshake. If the handshake succeeds, the + /// future returns a `Listener`. + pub fn new<'a>(inner: R) -> Box, Error = MultistreamSelectError> + 'a> + where + R: 'a, + { + let write = LengthDelimitedBuilder::new() + .length_field_length(1) + .new_write(inner); + let inner = LengthDelimitedFramedRead::::new(write); - let future = inner.into_future() - .map_err(|(e, _)| e.into()) - .and_then(|(msg, rest)| { - if msg.as_ref().map(|b| &b[..]) != Some(MULTISTREAM_PROTOCOL_WITH_LF) { - return Err(MultistreamSelectError::FailedHandshake); - } - Ok(rest) - }) - .and_then(|socket| { - socket.send(BytesMut::from(MULTISTREAM_PROTOCOL_WITH_LF)).from_err() - }) - .map(|inner| Listener { inner: inner }); + let future = inner + .into_future() + .map_err(|(e, _)| e.into()) + .and_then(|(msg, rest)| { + if msg.as_ref().map(|b| &b[..]) != Some(MULTISTREAM_PROTOCOL_WITH_LF) { + return Err(MultistreamSelectError::FailedHandshake); + } + Ok(rest) + }) + .and_then(|socket| { + socket + .send(BytesMut::from(MULTISTREAM_PROTOCOL_WITH_LF)) + .from_err() + }) + .map(|inner| Listener { inner: inner }); - Box::new(future) - } + Box::new(future) + } - /// Grants back the socket. Typically used after a `ProtocolRequest` has been received and a - /// `ProtocolAck` has been sent back. - #[inline] - pub fn into_inner(self) -> R { - self.inner.into_inner().into_inner() - } + /// Grants back the socket. Typically used after a `ProtocolRequest` has been received and a + /// `ProtocolAck` has been sent back. + #[inline] + pub fn into_inner(self) -> R { + self.inner.into_inner().into_inner() + } } impl Sink for Listener - where R: AsyncRead + AsyncWrite +where + R: AsyncRead + AsyncWrite, { - type SinkItem = ListenerToDialerMessage; - type SinkError = MultistreamSelectError; + type SinkItem = ListenerToDialerMessage; + type SinkError = MultistreamSelectError; - #[inline] - fn start_send(&mut self, item: Self::SinkItem) -> StartSend { - match item { - ListenerToDialerMessage::ProtocolAck { name } => { - if !name.starts_with(b"/") { - return Err(MultistreamSelectError::WrongProtocolName); - } - let mut protocol = BytesMut::from(name); - protocol.extend_from_slice(&[b'\n']); - match self.inner.start_send(protocol) { - Ok(AsyncSink::Ready) => Ok(AsyncSink::Ready), - Ok(AsyncSink::NotReady(mut protocol)) => { - let protocol_len = protocol.len(); - protocol.truncate(protocol_len - 1); - let protocol = protocol.freeze(); - Ok( - AsyncSink::NotReady(ListenerToDialerMessage::ProtocolAck { name: protocol }), - ) - } - Err(err) => Err(err.into()), - } - } + #[inline] + fn start_send(&mut self, item: Self::SinkItem) -> StartSend { + match item { + ListenerToDialerMessage::ProtocolAck { name } => { + if !name.starts_with(b"/") { + return Err(MultistreamSelectError::WrongProtocolName); + } + let mut protocol = BytesMut::from(name); + protocol.extend_from_slice(&[b'\n']); + match self.inner.start_send(protocol) { + Ok(AsyncSink::Ready) => Ok(AsyncSink::Ready), + Ok(AsyncSink::NotReady(mut protocol)) => { + let protocol_len = protocol.len(); + protocol.truncate(protocol_len - 1); + let protocol = protocol.freeze(); + Ok(AsyncSink::NotReady(ListenerToDialerMessage::ProtocolAck { + name: protocol, + })) + } + Err(err) => Err(err.into()), + } + } - ListenerToDialerMessage::NotAvailable => { - match self.inner.start_send(BytesMut::from(&b"na\n"[..])) { - Ok(AsyncSink::Ready) => Ok(AsyncSink::Ready), - Ok(AsyncSink::NotReady(_)) => { - Ok(AsyncSink::NotReady(ListenerToDialerMessage::NotAvailable)) - } - Err(err) => Err(err.into()), - } - } + ListenerToDialerMessage::NotAvailable => { + match self.inner.start_send(BytesMut::from(&b"na\n"[..])) { + Ok(AsyncSink::Ready) => Ok(AsyncSink::Ready), + Ok(AsyncSink::NotReady(_)) => { + Ok(AsyncSink::NotReady(ListenerToDialerMessage::NotAvailable)) + } + Err(err) => Err(err.into()), + } + } - ListenerToDialerMessage::ProtocolsListResponse { list } => { - use std::iter; + ListenerToDialerMessage::ProtocolsListResponse { list } => { + use std::iter; - let mut out_msg = varint::encode(list.len()); - for elem in list.iter() { - out_msg.extend(iter::once(b'\r')); - out_msg.extend_from_slice(elem); - out_msg.extend(iter::once(b'\n')); - } + let mut out_msg = varint::encode(list.len()); + for elem in list.iter() { + out_msg.extend(iter::once(b'\r')); + out_msg.extend_from_slice(elem); + out_msg.extend(iter::once(b'\n')); + } - match self.inner.start_send(BytesMut::from(out_msg)) { - Ok(AsyncSink::Ready) => Ok(AsyncSink::Ready), - Ok(AsyncSink::NotReady(_)) => { - let m = ListenerToDialerMessage::ProtocolsListResponse { list }; - Ok(AsyncSink::NotReady(m)) - } - Err(err) => Err(err.into()), - } - } - } - } + match self.inner.start_send(BytesMut::from(out_msg)) { + Ok(AsyncSink::Ready) => Ok(AsyncSink::Ready), + Ok(AsyncSink::NotReady(_)) => { + let m = ListenerToDialerMessage::ProtocolsListResponse { list }; + Ok(AsyncSink::NotReady(m)) + } + Err(err) => Err(err.into()), + } + } + } + } - #[inline] - fn poll_complete(&mut self) -> Poll<(), Self::SinkError> { - Ok(self.inner.poll_complete()?) - } + #[inline] + fn poll_complete(&mut self) -> Poll<(), Self::SinkError> { + Ok(self.inner.poll_complete()?) + } } impl Stream for Listener - where R: AsyncRead + AsyncWrite +where + R: AsyncRead + AsyncWrite, { - type Item = DialerToListenerMessage; - type Error = MultistreamSelectError; + type Item = DialerToListenerMessage; + type Error = MultistreamSelectError; - fn poll(&mut self) -> Poll, Self::Error> { - loop { - let mut frame = match self.inner.poll() { - Ok(Async::Ready(Some(frame))) => frame, - Ok(Async::Ready(None)) => return Ok(Async::Ready(None)), - Ok(Async::NotReady) => return Ok(Async::NotReady), - Err(err) => return Err(err.into()), - }; + fn poll(&mut self) -> Poll, Self::Error> { + loop { + let mut frame = match self.inner.poll() { + Ok(Async::Ready(Some(frame))) => frame, + Ok(Async::Ready(None)) => return Ok(Async::Ready(None)), + Ok(Async::NotReady) => return Ok(Async::NotReady), + Err(err) => return Err(err.into()), + }; - if frame.get(0) == Some(&b'/') && frame.last() == Some(&b'\n') { - let frame_len = frame.len(); - let protocol = frame.split_to(frame_len - 1); - return Ok(Async::Ready( - Some(DialerToListenerMessage::ProtocolRequest { name: protocol }), - )); - - } else if frame == &b"ls\n"[..] { - return Ok(Async::Ready(Some(DialerToListenerMessage::ProtocolsListRequest))); - - } else { - return Err(MultistreamSelectError::UnknownMessage); - } - } - } + if frame.get(0) == Some(&b'/') && frame.last() == Some(&b'\n') { + let frame_len = frame.len(); + let protocol = frame.split_to(frame_len - 1); + return Ok(Async::Ready(Some( + DialerToListenerMessage::ProtocolRequest { name: protocol }, + ))); + } else if frame == &b"ls\n"[..] { + return Ok(Async::Ready(Some( + DialerToListenerMessage::ProtocolsListRequest, + ))); + } else { + return Err(MultistreamSelectError::UnknownMessage); + } + } + } } #[cfg(test)] mod tests { - extern crate tokio_core; - use bytes::Bytes; - use futures::{Sink, Stream}; - use futures::Future; - use protocol::{Dialer, Listener, ListenerToDialerMessage, MultistreamSelectError}; - use self::tokio_core::net::{TcpListener, TcpStream}; - use self::tokio_core::reactor::Core; + extern crate tokio_core; + use bytes::Bytes; + use futures::{Sink, Stream}; + use futures::Future; + use protocol::{Dialer, Listener, ListenerToDialerMessage, MultistreamSelectError}; + use self::tokio_core::net::{TcpListener, TcpStream}; + use self::tokio_core::reactor::Core; - #[test] - fn wrong_proto_name() { - let mut core = Core::new().unwrap(); + #[test] + fn wrong_proto_name() { + let mut core = Core::new().unwrap(); - let listener = TcpListener::bind(&"127.0.0.1:0".parse().unwrap(), &core.handle()).unwrap(); - let listener_addr = listener.local_addr().unwrap(); + let listener = TcpListener::bind(&"127.0.0.1:0".parse().unwrap(), &core.handle()).unwrap(); + let listener_addr = listener.local_addr().unwrap(); - let server = listener.incoming() - .into_future() - .map_err(|(e, _)| e.into()) - .and_then(move |(connec, _)| Listener::new(connec.unwrap().0)) - .and_then(|listener| { - let proto_name = Bytes::from("invalid-proto"); - listener.send(ListenerToDialerMessage::ProtocolAck { name: proto_name }) - }); + let server = listener + .incoming() + .into_future() + .map_err(|(e, _)| e.into()) + .and_then(move |(connec, _)| Listener::new(connec.unwrap().0)) + .and_then(|listener| { + let proto_name = Bytes::from("invalid-proto"); + listener.send(ListenerToDialerMessage::ProtocolAck { name: proto_name }) + }); - let client = TcpStream::connect(&listener_addr, &core.handle()) - .from_err() - .and_then(move |stream| Dialer::new(stream)); + let client = TcpStream::connect(&listener_addr, &core.handle()) + .from_err() + .and_then(move |stream| Dialer::new(stream)); - match core.run(server.join(client)) { - Err(MultistreamSelectError::WrongProtocolName) => (), - _ => panic!(), - } - } + match core.run(server.join(client)) { + Err(MultistreamSelectError::WrongProtocolName) => (), + _ => panic!(), + } + } } diff --git a/multistream-select/src/protocol/mod.rs b/multistream-select/src/protocol/mod.rs index 3f0bd654..235a50a0 100644 --- a/multistream-select/src/protocol/mod.rs +++ b/multistream-select/src/protocol/mod.rs @@ -1,21 +1,21 @@ // Copyright 2017 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. //! Contains lower-level structs to handle the multistream protocol. @@ -35,33 +35,33 @@ pub use self::listener::Listener; /// Message sent from the dialer to the listener. #[derive(Debug, Clone, PartialEq, Eq)] pub enum DialerToListenerMessage { - /// The dialer wants us to use a protocol. - /// - /// If this is accepted (by receiving back a `ProtocolAck`), then we immediately start - /// communicating in the new protocol. - ProtocolRequest { - /// Name of the protocol. - name: Bytes, - }, + /// The dialer wants us to use a protocol. + /// + /// If this is accepted (by receiving back a `ProtocolAck`), then we immediately start + /// communicating in the new protocol. + ProtocolRequest { + /// Name of the protocol. + name: Bytes, + }, - /// The dialer requested the list of protocols that the listener supports. - ProtocolsListRequest, + /// The dialer requested the list of protocols that the listener supports. + ProtocolsListRequest, } /// Message sent from the listener to the dialer. #[derive(Debug, Clone, PartialEq, Eq)] pub enum ListenerToDialerMessage { - /// The protocol requested by the dialer is accepted. The socket immediately starts using the - /// new protocol. - ProtocolAck { name: Bytes }, + /// The protocol requested by the dialer is accepted. The socket immediately starts using the + /// new protocol. + ProtocolAck { name: Bytes }, - /// The protocol requested by the dialer is not supported or available. - NotAvailable, + /// The protocol requested by the dialer is not supported or available. + NotAvailable, - /// Response to the request for the list of protocols. - ProtocolsListResponse { - /// The list of protocols. - // TODO: use some sort of iterator - list: Vec, - }, + /// Response to the request for the list of protocols. + ProtocolsListResponse { + /// The list of protocols. + // TODO: use some sort of iterator + list: Vec, + }, } diff --git a/multistream-select/src/tests.rs b/multistream-select/src/tests.rs index 7871520d..bf479cd1 100644 --- a/multistream-select/src/tests.rs +++ b/multistream-select/src/tests.rs @@ -1,21 +1,21 @@ // Copyright 2017 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. //! Contains the unit tests of the library. @@ -24,190 +24,192 @@ extern crate tokio_core; -use {listener_select_proto, dialer_select_proto}; +use {dialer_select_proto, listener_select_proto}; use ProtocolChoiceError; use bytes::Bytes; use dialer_select::{dialer_select_proto_parallel, dialer_select_proto_serial}; use futures::{Sink, Stream}; use futures::Future; -use protocol::{Dialer, Listener, DialerToListenerMessage, ListenerToDialerMessage}; +use protocol::{Dialer, DialerToListenerMessage, Listener, ListenerToDialerMessage}; use self::tokio_core::net::TcpListener; use self::tokio_core::net::TcpStream; use self::tokio_core::reactor::Core; #[test] fn negotiate_with_self_succeeds() { - let mut core = Core::new().unwrap(); + let mut core = Core::new().unwrap(); - let listener = TcpListener::bind(&"127.0.0.1:0".parse().unwrap(), &core.handle()).unwrap(); - let listener_addr = listener.local_addr().unwrap(); + let listener = TcpListener::bind(&"127.0.0.1:0".parse().unwrap(), &core.handle()).unwrap(); + let listener_addr = listener.local_addr().unwrap(); - let server = listener.incoming() - .into_future() - .map_err(|(e, _)| e.into()) - .and_then(move |(connec, _)| Listener::new(connec.unwrap().0)) - .and_then(|l| l.into_future().map_err(|(e, _)| e)) - .and_then(|(msg, rest)| { - let proto = match msg { - Some(DialerToListenerMessage::ProtocolRequest { name }) => name, - _ => panic!(), - }; - rest.send(ListenerToDialerMessage::ProtocolAck { name: proto }) - }); + let server = listener + .incoming() + .into_future() + .map_err(|(e, _)| e.into()) + .and_then(move |(connec, _)| Listener::new(connec.unwrap().0)) + .and_then(|l| l.into_future().map_err(|(e, _)| e)) + .and_then(|(msg, rest)| { + let proto = match msg { + Some(DialerToListenerMessage::ProtocolRequest { name }) => name, + _ => panic!(), + }; + rest.send(ListenerToDialerMessage::ProtocolAck { name: proto }) + }); - let client = TcpStream::connect(&listener_addr, &core.handle()) - .from_err() - .and_then(move |stream| Dialer::new(stream)) - .and_then(move |dialer| { - let p = Bytes::from("/hello/1.0.0"); - dialer.send(DialerToListenerMessage::ProtocolRequest { name: p }) - }) - .and_then(move |dialer| dialer.into_future().map_err(|(e, _)| e)) - .and_then(move |(msg, _)| { - let proto = match msg { - Some(ListenerToDialerMessage::ProtocolAck { name }) => name, - _ => panic!(), - }; - assert_eq!(proto, "/hello/1.0.0"); - Ok(()) - }); + let client = TcpStream::connect(&listener_addr, &core.handle()) + .from_err() + .and_then(move |stream| Dialer::new(stream)) + .and_then(move |dialer| { + let p = Bytes::from("/hello/1.0.0"); + dialer.send(DialerToListenerMessage::ProtocolRequest { name: p }) + }) + .and_then(move |dialer| dialer.into_future().map_err(|(e, _)| e)) + .and_then(move |(msg, _)| { + let proto = match msg { + Some(ListenerToDialerMessage::ProtocolAck { name }) => name, + _ => panic!(), + }; + assert_eq!(proto, "/hello/1.0.0"); + Ok(()) + }); - core.run(server.join(client)).unwrap(); + core.run(server.join(client)).unwrap(); } #[test] fn select_proto_basic() { - let mut core = Core::new().unwrap(); + let mut core = Core::new().unwrap(); - let listener = TcpListener::bind(&"127.0.0.1:0".parse().unwrap(), &core.handle()).unwrap(); - let listener_addr = listener.local_addr().unwrap(); + let listener = TcpListener::bind(&"127.0.0.1:0".parse().unwrap(), &core.handle()).unwrap(); + let listener_addr = listener.local_addr().unwrap(); - let server = listener.incoming() - .into_future() - .map(|s| s.0.unwrap().0) - .map_err(|(e, _)| e.into()) - .and_then(move |connec| { - let protos = vec![ - (Bytes::from("/proto1"), ::eq, 0), - (Bytes::from("/proto2"), ::eq, 1), - ] - .into_iter(); - listener_select_proto(connec, protos).map(|r| r.0) - }); + let server = listener + .incoming() + .into_future() + .map(|s| s.0.unwrap().0) + .map_err(|(e, _)| e.into()) + .and_then(move |connec| { + let protos = vec![ + (Bytes::from("/proto1"), ::eq, 0), + (Bytes::from("/proto2"), ::eq, 1), + ].into_iter(); + listener_select_proto(connec, protos).map(|r| r.0) + }); - let client = - TcpStream::connect(&listener_addr, &core.handle()).from_err().and_then(move |connec| { - let protos = vec![ - (Bytes::from("/proto3"), ::eq, 2), - (Bytes::from("/proto2"), ::eq, 3), - ] - .into_iter(); - dialer_select_proto(connec, protos).map(|r| r.0) - }); + let client = TcpStream::connect(&listener_addr, &core.handle()) + .from_err() + .and_then(move |connec| { + let protos = vec![ + (Bytes::from("/proto3"), ::eq, 2), + (Bytes::from("/proto2"), ::eq, 3), + ].into_iter(); + dialer_select_proto(connec, protos).map(|r| r.0) + }); - let (dialer_chosen, listener_chosen) = core.run(client.join(server)).unwrap(); - assert_eq!(dialer_chosen, 3); - assert_eq!(listener_chosen, 1); + let (dialer_chosen, listener_chosen) = core.run(client.join(server)).unwrap(); + assert_eq!(dialer_chosen, 3); + assert_eq!(listener_chosen, 1); } #[test] fn no_protocol_found() { - let mut core = Core::new().unwrap(); + let mut core = Core::new().unwrap(); - let listener = TcpListener::bind(&"127.0.0.1:0".parse().unwrap(), &core.handle()).unwrap(); - let listener_addr = listener.local_addr().unwrap(); + let listener = TcpListener::bind(&"127.0.0.1:0".parse().unwrap(), &core.handle()).unwrap(); + let listener_addr = listener.local_addr().unwrap(); - let server = listener.incoming() - .into_future() - .map(|s| s.0.unwrap().0) - .map_err(|(e, _)| e.into()) - .and_then(move |connec| { - let protos = vec![ - (Bytes::from("/proto1"), ::eq, 1), - (Bytes::from("/proto2"), ::eq, 2), - ] - .into_iter(); - listener_select_proto(connec, protos).map(|r| r.0) - }); + let server = listener + .incoming() + .into_future() + .map(|s| s.0.unwrap().0) + .map_err(|(e, _)| e.into()) + .and_then(move |connec| { + let protos = vec![ + (Bytes::from("/proto1"), ::eq, 1), + (Bytes::from("/proto2"), ::eq, 2), + ].into_iter(); + listener_select_proto(connec, protos).map(|r| r.0) + }); - let client = - TcpStream::connect(&listener_addr, &core.handle()).from_err().and_then(move |connec| { - let protos = vec![ - (Bytes::from("/proto3"), ::eq, 3), - (Bytes::from("/proto4"), ::eq, 4), - ] - .into_iter(); - dialer_select_proto(connec, protos).map(|r| r.0) - }); + let client = TcpStream::connect(&listener_addr, &core.handle()) + .from_err() + .and_then(move |connec| { + let protos = vec![ + (Bytes::from("/proto3"), ::eq, 3), + (Bytes::from("/proto4"), ::eq, 4), + ].into_iter(); + dialer_select_proto(connec, protos).map(|r| r.0) + }); - match core.run(client.join(server)) { - Err(ProtocolChoiceError::NoProtocolFound) => (), - _ => panic!(), - } + match core.run(client.join(server)) { + Err(ProtocolChoiceError::NoProtocolFound) => (), + _ => panic!(), + } } #[test] fn select_proto_parallel() { - let mut core = Core::new().unwrap(); + let mut core = Core::new().unwrap(); - let listener = TcpListener::bind(&"127.0.0.1:0".parse().unwrap(), &core.handle()).unwrap(); - let listener_addr = listener.local_addr().unwrap(); + let listener = TcpListener::bind(&"127.0.0.1:0".parse().unwrap(), &core.handle()).unwrap(); + let listener_addr = listener.local_addr().unwrap(); - let server = listener.incoming() - .into_future() - .map(|s| s.0.unwrap().0) - .map_err(|(e, _)| e.into()) - .and_then(move |connec| { - let protos = vec![ - (Bytes::from("/proto1"), ::eq, 0), - (Bytes::from("/proto2"), ::eq, 1), - ] - .into_iter(); - listener_select_proto(connec, protos).map(|r| r.0) - }); + let server = listener + .incoming() + .into_future() + .map(|s| s.0.unwrap().0) + .map_err(|(e, _)| e.into()) + .and_then(move |connec| { + let protos = vec![ + (Bytes::from("/proto1"), ::eq, 0), + (Bytes::from("/proto2"), ::eq, 1), + ].into_iter(); + listener_select_proto(connec, protos).map(|r| r.0) + }); - let client = - TcpStream::connect(&listener_addr, &core.handle()).from_err().and_then(move |connec| { - let protos = vec![ - (Bytes::from("/proto3"), ::eq, 2), - (Bytes::from("/proto2"), ::eq, 3), - ] - .into_iter(); - dialer_select_proto_parallel(connec, protos).map(|r| r.0) - }); + let client = TcpStream::connect(&listener_addr, &core.handle()) + .from_err() + .and_then(move |connec| { + let protos = vec![ + (Bytes::from("/proto3"), ::eq, 2), + (Bytes::from("/proto2"), ::eq, 3), + ].into_iter(); + dialer_select_proto_parallel(connec, protos).map(|r| r.0) + }); - let (dialer_chosen, listener_chosen) = core.run(client.join(server)).unwrap(); - assert_eq!(dialer_chosen, 3); - assert_eq!(listener_chosen, 1); + let (dialer_chosen, listener_chosen) = core.run(client.join(server)).unwrap(); + assert_eq!(dialer_chosen, 3); + assert_eq!(listener_chosen, 1); } #[test] fn select_proto_serial() { - let mut core = Core::new().unwrap(); + let mut core = Core::new().unwrap(); - let listener = TcpListener::bind(&"127.0.0.1:0".parse().unwrap(), &core.handle()).unwrap(); - let listener_addr = listener.local_addr().unwrap(); + let listener = TcpListener::bind(&"127.0.0.1:0".parse().unwrap(), &core.handle()).unwrap(); + let listener_addr = listener.local_addr().unwrap(); - let server = listener.incoming() - .into_future() - .map(|s| s.0.unwrap().0) - .map_err(|(e, _)| e.into()) - .and_then(move |connec| { - let protos = vec![ - (Bytes::from("/proto1"), ::eq, 0), - (Bytes::from("/proto2"), ::eq, 1), - ] - .into_iter(); - listener_select_proto(connec, protos).map(|r| r.0) - }); + let server = listener + .incoming() + .into_future() + .map(|s| s.0.unwrap().0) + .map_err(|(e, _)| e.into()) + .and_then(move |connec| { + let protos = vec![ + (Bytes::from("/proto1"), ::eq, 0), + (Bytes::from("/proto2"), ::eq, 1), + ].into_iter(); + listener_select_proto(connec, protos).map(|r| r.0) + }); - let client = - TcpStream::connect(&listener_addr, &core.handle()).from_err().and_then(move |connec| { - let protos = vec![(Bytes::from("/proto3"), 2), (Bytes::from("/proto2"), 3)].into_iter(); - dialer_select_proto_serial(connec, protos).map(|r| r.0) - }); + let client = TcpStream::connect(&listener_addr, &core.handle()) + .from_err() + .and_then(move |connec| { + let protos = vec![(Bytes::from("/proto3"), 2), (Bytes::from("/proto2"), 3)].into_iter(); + dialer_select_proto_serial(connec, protos).map(|r| r.0) + }); - let (dialer_chosen, listener_chosen) = core.run(client.join(server)).unwrap(); - assert_eq!(dialer_chosen, 3); - assert_eq!(listener_chosen, 1); + let (dialer_chosen, listener_chosen) = core.run(client.join(server)).unwrap(); + assert_eq!(dialer_chosen, 3); + assert_eq!(listener_chosen, 1); } diff --git a/rust-multiaddr/src/errors.rs b/rust-multiaddr/src/errors.rs index b7dd5c73..6f6bdef0 100644 --- a/rust-multiaddr/src/errors.rs +++ b/rust-multiaddr/src/errors.rs @@ -1,4 +1,4 @@ -use std::{net, fmt, error, io, num, string}; +use std::{error, fmt, io, net, num, string}; use cid; use byteorder; @@ -35,7 +35,7 @@ impl error::Error for Error { fn cause(&self) -> Option<&error::Error> { match *self { Error::ParsingError(ref err) => Some(&**err), - _ => None + _ => None, } } } diff --git a/rust-multiaddr/src/lib.rs b/rust-multiaddr/src/lib.rs index 836be8db..fa329199 100644 --- a/rust-multiaddr/src/lib.rs +++ b/rust-multiaddr/src/lib.rs @@ -9,12 +9,12 @@ extern crate integer_encoding; mod protocol; mod errors; -pub use errors::{Result, Error}; -pub use protocol::{ProtocolId, ProtocolArgSize, AddrComponent}; +pub use errors::{Error, Result}; +pub use protocol::{AddrComponent, ProtocolArgSize, ProtocolId}; use std::fmt; use std::iter::FromIterator; -use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6, IpAddr, Ipv4Addr, Ipv6Addr}; +use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; use std::str::FromStr; /// Representation of a Multiaddr. @@ -135,7 +135,9 @@ impl Multiaddr { /// #[inline] pub fn append(&mut self, component: AddrComponent) { - component.write_bytes(&mut self.bytes).expect("writing to a Vec never fails") + component + .write_bytes(&mut self.bytes) + .expect("writing to a Vec never fails") } /// Remove the outermost address. @@ -189,7 +191,9 @@ impl Multiaddr { } if !matches { - return Ok(Multiaddr { bytes: self.bytes.clone() }); + return Ok(Multiaddr { + bytes: self.bytes.clone(), + }); } let mut bytes = self.bytes.clone(); @@ -199,14 +203,14 @@ impl Multiaddr { } /// Returns the components of this multiaddress. - /// + /// /// ``` /// use std::net::Ipv4Addr; /// use multiaddr::AddrComponent; /// use multiaddr::Multiaddr; /// /// let address: Multiaddr = "/ip4/127.0.0.1/udt/sctp/5678".parse().unwrap(); - /// + /// /// let components = address.iter().collect::>(); /// assert_eq!(components[0], AddrComponent::IP4(Ipv4Addr::new(127, 0, 0, 1))); /// assert_eq!(components[1], AddrComponent::UDT); @@ -218,13 +222,13 @@ impl Multiaddr { Iter(&self.bytes) } - /// Pops the last `AddrComponent` of this multiaddr, or `None` if the multiaddr is empty. + /// Pops the last `AddrComponent` of this multiaddr, or `None` if the multiaddr is empty. /// ``` /// use multiaddr::AddrComponent; /// use multiaddr::Multiaddr; /// /// let address: Multiaddr = "/ip4/127.0.0.1/udt/sctp/5678".parse().unwrap(); - /// + /// /// assert_eq!(address.pop().unwrap(), AddrComponent::SCTP(5678)); /// assert_eq!(address.pop().unwrap(), AddrComponent::UDT); /// ``` @@ -241,7 +245,8 @@ impl Multiaddr { impl From for Multiaddr { fn from(addr: AddrComponent) -> Multiaddr { let mut out = Vec::new(); - addr.write_bytes(&mut out).expect("writing to a Vec never fails"); + addr.write_bytes(&mut out) + .expect("writing to a Vec never fails"); Multiaddr { bytes: out } } } @@ -258,11 +263,13 @@ impl<'a> IntoIterator for &'a Multiaddr { impl FromIterator for Multiaddr { fn from_iter(iter: T) -> Self - where T: IntoIterator + where + T: IntoIterator, { let mut bytes = Vec::new(); for cmp in iter { - cmp.write_bytes(&mut bytes).expect("writing to a Vec never fails"); + cmp.write_bytes(&mut bytes) + .expect("writing to a Vec never fails"); } Multiaddr { bytes: bytes } } @@ -285,15 +292,17 @@ impl FromStr for Multiaddr { let protocol: ProtocolId = part.parse()?; let addr_component = match protocol.size() { ProtocolArgSize::Fixed { bytes: 0 } => { - protocol.parse_data("")? // TODO: bad design - }, + protocol.parse_data("")? // TODO: bad design + } _ => { let data = parts.next().ok_or(Error::MissingAddress)?; protocol.parse_data(data)? - }, + } }; - addr_component.write_bytes(&mut bytes).expect("writing to a Vec never fails"); + addr_component + .write_bytes(&mut bytes) + .expect("writing to a Vec never fails"); } Ok(Multiaddr { bytes: bytes }) @@ -311,8 +320,8 @@ impl<'a> Iterator for Iter<'a> { return None; } - let (component, next_data) = AddrComponent::from_bytes(self.0) - .expect("multiaddr is known to be valid"); + let (component, next_data) = + AddrComponent::from_bytes(self.0).expect("multiaddr is known to be valid"); self.0 = next_data; Some(component) } diff --git a/rust-multiaddr/src/protocol.rs b/rust-multiaddr/src/protocol.rs index d562186b..fd8fbf58 100644 --- a/rust-multiaddr/src/protocol.rs +++ b/rust-multiaddr/src/protocol.rs @@ -1,12 +1,12 @@ use std::net::{Ipv4Addr, Ipv6Addr}; use std::str::FromStr; use std::convert::From; -use std::io::{Cursor, Write, Result as IoResult}; +use std::io::{Cursor, Result as IoResult, Write}; use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use cid::Cid; use integer_encoding::{VarInt, VarIntWriter}; -use {Result, Error}; +use {Error, Result}; ///! # ProtocolId ///! @@ -117,7 +117,6 @@ impl FromStr for ProtocolId { } } - impl ProtocolId { /// Convert a `u64` based code to a `ProtocolId`. /// @@ -232,12 +231,8 @@ impl ProtocolId { let addr = Ipv6Addr::from_str(a)?; Ok(AddrComponent::IP6(addr)) } - ProtocolId::DNS4 => { - Ok(AddrComponent::DNS4(a.to_owned())) - } - ProtocolId::DNS6 => { - Ok(AddrComponent::DNS6(a.to_owned())) - } + ProtocolId::DNS4 => Ok(AddrComponent::DNS4(a.to_owned())), + ProtocolId::DNS6 => Ok(AddrComponent::DNS6(a.to_owned())), ProtocolId::TCP => { let parsed: u16 = a.parse()?; Ok(AddrComponent::TCP(parsed)) @@ -262,12 +257,10 @@ impl ProtocolId { let bytes = Cid::from(a)?.to_bytes(); Ok(AddrComponent::IPFS(bytes)) } - ProtocolId::ONION => unimplemented!(), // TODO: + ProtocolId::ONION => unimplemented!(), // TODO: ProtocolId::QUIC => Ok(AddrComponent::QUIC), ProtocolId::UTP => Ok(AddrComponent::UTP), - ProtocolId::UNIX => { - Ok(AddrComponent::UNIX(a.to_owned())) - } + ProtocolId::UNIX => Ok(AddrComponent::UNIX(a.to_owned())), ProtocolId::UDT => Ok(AddrComponent::UDT), ProtocolId::HTTP => Ok(AddrComponent::HTTP), ProtocolId::HTTPS => Ok(AddrComponent::HTTPS), @@ -342,17 +335,15 @@ impl AddrComponent { /// Builds an `AddrComponent` from an array that starts with a bytes representation. On /// success, also returns the rest of the slice. pub fn from_bytes(input: &[u8]) -> Result<(AddrComponent, &[u8])> { - let (proto_num, proto_id_len) = u64::decode_var(input); // TODO: will panic if ID too large + let (proto_num, proto_id_len) = u64::decode_var(input); // TODO: will panic if ID too large let protocol_id = ProtocolId::from(proto_num)?; let (data_offset, data_size) = match protocol_id.size() { - ProtocolArgSize::Fixed { bytes } => { - (0, bytes) - }, + ProtocolArgSize::Fixed { bytes } => (0, bytes), ProtocolArgSize::Variable => { - let (data_size, varint_len) = u64::decode_var(&input[proto_id_len..]); // TODO: will panic if ID too large + let (data_size, varint_len) = u64::decode_var(&input[proto_id_len..]); // TODO: will panic if ID too large (varint_len, data_size as usize) - }, + } }; let (data, rest) = input[proto_id_len..][data_offset..].split_at(data_size); @@ -360,7 +351,7 @@ impl AddrComponent { let addr_component = match protocol_id { ProtocolId::IP4 => { AddrComponent::IP4(Ipv4Addr::new(data[0], data[1], data[2], data[3])) - }, + } ProtocolId::IP6 => { let mut rdr = Cursor::new(data); let mut seg = vec![]; @@ -369,22 +360,20 @@ impl AddrComponent { seg.push(rdr.read_u16::()?); } - let addr = Ipv6Addr::new(seg[0], - seg[1], - seg[2], - seg[3], - seg[4], - seg[5], - seg[6], - seg[7]); + let addr = Ipv6Addr::new( + seg[0], + seg[1], + seg[2], + seg[3], + seg[4], + seg[5], + seg[6], + seg[7], + ); AddrComponent::IP6(addr) } - ProtocolId::DNS4 => { - AddrComponent::DNS4(String::from_utf8(data.to_owned())?) - } - ProtocolId::DNS6 => { - AddrComponent::DNS6(String::from_utf8(data.to_owned())?) - } + ProtocolId::DNS4 => AddrComponent::DNS4(String::from_utf8(data.to_owned())?), + ProtocolId::DNS6 => AddrComponent::DNS6(String::from_utf8(data.to_owned())?), ProtocolId::TCP => { let mut rdr = Cursor::new(data); let num = rdr.read_u16::()?; @@ -405,9 +394,7 @@ impl AddrComponent { let num = rdr.read_u16::()?; AddrComponent::SCTP(num) } - ProtocolId::UNIX => { - AddrComponent::UNIX(String::from_utf8(data.to_owned())?) - } + ProtocolId::UNIX => AddrComponent::UNIX(String::from_utf8(data.to_owned())?), ProtocolId::P2P => { let bytes = Cid::from(data)?.to_bytes(); AddrComponent::P2P(bytes) @@ -416,7 +403,7 @@ impl AddrComponent { let bytes = Cid::from(data)?.to_bytes(); AddrComponent::IPFS(bytes) } - ProtocolId::ONION => unimplemented!(), // TODO: + ProtocolId::ONION => unimplemented!(), // TODO: ProtocolId::QUIC => AddrComponent::QUIC, ProtocolId::UTP => AddrComponent::UTP, ProtocolId::UDT => AddrComponent::UDT, @@ -441,13 +428,13 @@ impl AddrComponent { AddrComponent::IP4(addr) => { out.write_all(&addr.octets())?; } - AddrComponent::IP6(addr) => { - for &segment in &addr.segments() { - out.write_u16::(segment)?; - } - } - AddrComponent::TCP(port) | AddrComponent::UDP(port) | AddrComponent::DCCP(port) | - AddrComponent::SCTP(port) => { + AddrComponent::IP6(addr) => for &segment in &addr.segments() { + out.write_u16::(segment)?; + }, + AddrComponent::TCP(port) + | AddrComponent::UDP(port) + | AddrComponent::DCCP(port) + | AddrComponent::SCTP(port) => { out.write_u16::(port)?; } AddrComponent::DNS4(s) | AddrComponent::DNS6(s) | AddrComponent::UNIX(s) => { @@ -460,19 +447,19 @@ impl AddrComponent { out.write_all(&bytes)?; } AddrComponent::ONION(_) => { - unimplemented!() // TODO: - }, - AddrComponent::QUIC | - AddrComponent::UTP | - AddrComponent::UDT | - AddrComponent::HTTP | - AddrComponent::HTTPS | - AddrComponent::WS | - AddrComponent::WSS | - AddrComponent::Libp2pWebsocketStar | - AddrComponent::Libp2pWebrtcStar | - AddrComponent::Libp2pWebrtcDirect | - AddrComponent::P2pCircuit => {} + unimplemented!() // TODO: + } + AddrComponent::QUIC + | AddrComponent::UTP + | AddrComponent::UDT + | AddrComponent::HTTP + | AddrComponent::HTTPS + | AddrComponent::WS + | AddrComponent::WSS + | AddrComponent::Libp2pWebsocketStar + | AddrComponent::Libp2pWebrtcStar + | AddrComponent::Libp2pWebrtcDirect + | AddrComponent::P2pCircuit => {} }; Ok(()) @@ -497,15 +484,15 @@ impl ToString for AddrComponent { // TODO: meh for cloning let c = Cid::from(bytes.clone()).expect("cid is known to be valid"); format!("/p2p/{}", c) - }, + } AddrComponent::IPFS(ref bytes) => { // TODO: meh for cloning let c = Cid::from(bytes.clone()).expect("cid is known to be valid"); format!("/ipfs/{}", c) - }, + } AddrComponent::HTTP => format!("/http"), AddrComponent::HTTPS => format!("/https"), - AddrComponent::ONION(_) => unimplemented!(),//format!("/onion"), // TODO: + AddrComponent::ONION(_) => unimplemented!(), //format!("/onion"), // TODO: AddrComponent::QUIC => format!("/quic"), AddrComponent::WS => format!("/ws"), AddrComponent::WSS => format!("/wss"), diff --git a/rust-multiaddr/tests/lib.rs b/rust-multiaddr/tests/lib.rs index 85bc8abe..9734e7a8 100644 --- a/rust-multiaddr/tests/lib.rs +++ b/rust-multiaddr/tests/lib.rs @@ -1,9 +1,9 @@ -extern crate multiaddr; extern crate data_encoding; +extern crate multiaddr; use data_encoding::hex; use multiaddr::*; -use std::net::{SocketAddrV4, SocketAddrV6, Ipv4Addr, Ipv6Addr}; +use std::net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6}; #[test] fn protocol_to_code() { @@ -15,11 +15,16 @@ fn protocol_to_name() { assert_eq!(ProtocolId::TCP.to_string(), "tcp"); } - fn assert_bytes(source: &str, target: &str, protocols: Vec) -> () { let address = source.parse::().unwrap(); assert_eq!(hex::encode(address.to_bytes().as_slice()), target); - assert_eq!(address.iter().map(|addr| addr.protocol_id()).collect::>(), protocols); + assert_eq!( + address + .iter() + .map(|addr| addr.protocol_id()) + .collect::>(), + protocols + ); } fn ma_valid(source: &str, target: &str, protocols: Vec) -> () { assert_bytes(source, target, protocols); @@ -45,9 +50,11 @@ fn construct_success() { ma_valid("/ip4/1.2.3.4", "0401020304", vec![IP4]); ma_valid("/ip4/0.0.0.0", "0400000000", vec![IP4]); ma_valid("/ip6/::1", "2900000000000000000000000000000001", vec![IP6]); - ma_valid("/ip6/2601:9:4f81:9700:803e:ca65:66e8:c21", - "29260100094F819700803ECA6566E80C21", - vec![IP6]); + ma_valid( + "/ip6/2601:9:4f81:9700:803e:ca65:66e8:c21", + "29260100094F819700803ECA6566E80C21", + vec![IP6], + ); ma_valid("/udp/0", "110000", vec![UDP]); ma_valid("/tcp/0", "060000", vec![TCP]); ma_valid("/sctp/0", "84010000", vec![SCTP]); @@ -56,116 +63,156 @@ fn construct_success() { ma_valid("/sctp/1234", "840104D2", vec![SCTP]); ma_valid("/udp/65535", "11FFFF", vec![UDP]); ma_valid("/tcp/65535", "06FFFF", vec![TCP]); - ma_valid("/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC", - "A503221220D52EBB89D85B02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C0B", - vec![IPFS]); + ma_valid( + "/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC", + "A503221220D52EBB89D85B02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C0B", + vec![IPFS], + ); ma_valid("/udp/1234/sctp/1234", "1104D2840104D2", vec![UDP, SCTP]); ma_valid("/udp/1234/udt", "1104D2AD02", vec![UDP, UDT]); ma_valid("/udp/1234/utp", "1104D2AE02", vec![UDP, UTP]); ma_valid("/tcp/1234/http", "0604D2E003", vec![TCP, HTTP]); ma_valid("/tcp/1234/https", "0604D2BB03", vec![TCP, HTTPS]); - ma_valid("/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234", - "A503221220D52EBB89D85B02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C0B0604D2", - vec![IPFS, TCP]); - ma_valid("/ip4/127.0.0.1/udp/1234", - "047F0000011104D2", - vec![IP4, UDP]); + ma_valid( + "/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234", + "A503221220D52EBB89D85B02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C0B0604D2", + vec![IPFS, TCP], + ); + ma_valid( + "/ip4/127.0.0.1/udp/1234", + "047F0000011104D2", + vec![IP4, UDP], + ); ma_valid("/ip4/127.0.0.1/udp/0", "047F000001110000", vec![IP4, UDP]); - ma_valid("/ip4/127.0.0.1/tcp/1234", - "047F0000010604D2", - vec![IP4, TCP]); - ma_valid("/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC", - "047F000001A503221220D52EBB89D85B02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C0B", - vec![IP4, IPFS]); - ma_valid("/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234", - "047F000001A503221220D52EBB89D85B02A284948203A\ -62FF28389C57C9F42BEEC4EC20DB76A68911C0B0604D2", - vec![IP4, IPFS, TCP]); + ma_valid( + "/ip4/127.0.0.1/tcp/1234", + "047F0000010604D2", + vec![IP4, TCP], + ); + ma_valid( + "/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC", + "047F000001A503221220D52EBB89D85B02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C0B", + vec![IP4, IPFS], + ); + ma_valid( + "/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234", + "047F000001A503221220D52EBB89D85B02A284948203A\ + 62FF28389C57C9F42BEEC4EC20DB76A68911C0B0604D2", + vec![IP4, IPFS, TCP], + ); // /unix/a/b/c/d/e, // /unix/stdio, // /ip4/1.2.3.4/tcp/80/unix/a/b/c/d/e/f, // /ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234/unix/stdio - ma_valid("/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:\ - 7095/tcp/8000/ws/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC", - "29200108A07AC542013AC986FFFE317095061F40DD03A5\ -03221220D52EBB89D85B02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C0B", - vec![IP6, TCP, WS, IPFS]); - ma_valid("/p2p-webrtc-star/ip4/127.0.0.\ - 1/tcp/9090/ws/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC", - "9302047F000001062382DD03A503221220D52EBB89D85B\ -02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C0B", - vec![Libp2pWebrtcStar, IP4, TCP, WS, IPFS]); - ma_valid("/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:\ - 7095/tcp/8000/wss/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC", - "29200108A07AC542013AC986FFFE317095061F40DE03A503221220D52EBB8\ -9D85B02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C0B", - vec![IP6, TCP, WSS, IPFS]); - ma_valid("/ip4/127.0.0.1/tcp/9090/p2p-circuit/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC", - "047F000001062382A202A503221220D52EBB89D85B\ -02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C0B", - vec![IP4, TCP, P2pCircuit, IPFS]); + ma_valid( + "/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:\ + 7095/tcp/8000/ws/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC", + "29200108A07AC542013AC986FFFE317095061F40DD03A5\ + 03221220D52EBB89D85B02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C0B", + vec![IP6, TCP, WS, IPFS], + ); + ma_valid( + "/p2p-webrtc-star/ip4/127.0.0.\ + 1/tcp/9090/ws/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC", + "9302047F000001062382DD03A503221220D52EBB89D85B\ + 02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C0B", + vec![Libp2pWebrtcStar, IP4, TCP, WS, IPFS], + ); + ma_valid( + "/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:\ + 7095/tcp/8000/wss/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC", + "29200108A07AC542013AC986FFFE317095061F40DE03A503221220D52EBB8\ + 9D85B02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C0B", + vec![IP6, TCP, WSS, IPFS], + ); + ma_valid( + "/ip4/127.0.0.1/tcp/9090/p2p-circuit/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC", + "047F000001062382A202A503221220D52EBB89D85B\ + 02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C0B", + vec![IP4, TCP, P2pCircuit, IPFS], + ); } #[test] fn construct_fail() { - let addresses = ["/ip4", - "/ip4/::1", - "/ip4/fdpsofodsajfdoisa", - "/ip6", - "/udp", - "/tcp", - "/sctp", - "/udp/65536", - "/tcp/65536", - // "/onion/9imaq4ygg2iegci7:80", - // "/onion/aaimaq4ygg2iegci7:80", - // "/onion/timaq4ygg2iegci7:0", - // "/onion/timaq4ygg2iegci7:-1", - // "/onion/timaq4ygg2iegci7", - // "/onion/timaq4ygg2iegci@:666", - "/udp/1234/sctp", - "/udp/1234/udt/1234", - "/udp/1234/utp/1234", - "/ip4/127.0.0.1/udp/jfodsajfidosajfoidsa", - "/ip4/127.0.0.1/udp", - "/ip4/127.0.0.1/tcp/jfodsajfidosajfoidsa", - "/ip4/127.0.0.1/tcp", - "/ip4/127.0.0.1/ipfs", - "/ip4/127.0.0.1/ipfs/tcp", - "/p2p-circuit/50"]; + let addresses = [ + "/ip4", + "/ip4/::1", + "/ip4/fdpsofodsajfdoisa", + "/ip6", + "/udp", + "/tcp", + "/sctp", + "/udp/65536", + "/tcp/65536", + // "/onion/9imaq4ygg2iegci7:80", + // "/onion/aaimaq4ygg2iegci7:80", + // "/onion/timaq4ygg2iegci7:0", + // "/onion/timaq4ygg2iegci7:-1", + // "/onion/timaq4ygg2iegci7", + // "/onion/timaq4ygg2iegci@:666", + "/udp/1234/sctp", + "/udp/1234/udt/1234", + "/udp/1234/utp/1234", + "/ip4/127.0.0.1/udp/jfodsajfidosajfoidsa", + "/ip4/127.0.0.1/udp", + "/ip4/127.0.0.1/tcp/jfodsajfidosajfoidsa", + "/ip4/127.0.0.1/tcp", + "/ip4/127.0.0.1/ipfs", + "/ip4/127.0.0.1/ipfs/tcp", + "/p2p-circuit/50", + ]; for address in &addresses { assert!(address.parse::().is_err(), address.to_string()); } } - #[test] fn to_multiaddr() { - assert_eq!(Ipv4Addr::new(127, 0, 0, 1).to_multiaddr().unwrap(), - "/ip4/127.0.0.1".parse::().unwrap()); - assert_eq!(Ipv6Addr::new(0x2601, 0x9, 0x4f81, 0x9700, 0x803e, 0xca65, 0x66e8, 0xc21) - .to_multiaddr() - .unwrap(), - "/ip6/2601:9:4f81:9700:803e:ca65:66e8:c21".parse::().unwrap()); - assert_eq!("/ip4/127.0.0.1/tcp/1234".to_string().to_multiaddr().unwrap(), - "/ip4/127.0.0.1/tcp/1234".parse::().unwrap()); - assert_eq!("/ip6/2601:9:4f81:9700:803e:ca65:66e8:c21".to_multiaddr().unwrap(), - "/ip6/2601:9:4f81:9700:803e:ca65:66e8:c21".parse::().unwrap()); - assert_eq!(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 1234).to_multiaddr().unwrap(), - "/ip4/127.0.0.1/tcp/1234".parse::().unwrap()); - assert_eq!(SocketAddrV6::new(Ipv6Addr::new(0x2601, - 0x9, - 0x4f81, - 0x9700, - 0x803e, - 0xca65, - 0x66e8, - 0xc21), - 1234, - 0, - 0) - .to_multiaddr() - .unwrap(), - "/ip6/2601:9:4f81:9700:803e:ca65:66e8:c21/tcp/1234".parse::().unwrap()); + assert_eq!( + Ipv4Addr::new(127, 0, 0, 1).to_multiaddr().unwrap(), + "/ip4/127.0.0.1".parse::().unwrap() + ); + assert_eq!( + Ipv6Addr::new(0x2601, 0x9, 0x4f81, 0x9700, 0x803e, 0xca65, 0x66e8, 0xc21) + .to_multiaddr() + .unwrap(), + "/ip6/2601:9:4f81:9700:803e:ca65:66e8:c21" + .parse::() + .unwrap() + ); + assert_eq!( + "/ip4/127.0.0.1/tcp/1234" + .to_string() + .to_multiaddr() + .unwrap(), + "/ip4/127.0.0.1/tcp/1234".parse::().unwrap() + ); + assert_eq!( + "/ip6/2601:9:4f81:9700:803e:ca65:66e8:c21" + .to_multiaddr() + .unwrap(), + "/ip6/2601:9:4f81:9700:803e:ca65:66e8:c21" + .parse::() + .unwrap() + ); + assert_eq!( + SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 1234) + .to_multiaddr() + .unwrap(), + "/ip4/127.0.0.1/tcp/1234".parse::().unwrap() + ); + assert_eq!( + SocketAddrV6::new( + Ipv6Addr::new(0x2601, 0x9, 0x4f81, 0x9700, 0x803e, 0xca65, 0x66e8, 0xc21), + 1234, + 0, + 0 + ).to_multiaddr() + .unwrap(), + "/ip6/2601:9:4f81:9700:803e:ca65:66e8:c21/tcp/1234" + .parse::() + .unwrap() + ); } diff --git a/rustfmt.toml b/rustfmt.toml deleted file mode 100644 index 9b79c8f1..00000000 --- a/rustfmt.toml +++ /dev/null @@ -1,17 +0,0 @@ -verbose=false -max_width=100 -comment_width=100 -tab_spaces=4 -fn_call_width=100 -struct_lit_width=32 -fn_call_style="Visual" -single_line_if_else_max_width=100 -trailing_comma="Vertical" -chain_indent="Visual" -chain_one_line_max=100 -reorder_imports=true -format_strings=false -hard_tabs=true -wrap_match_arms=false -error_on_line_overflow=false -where_style="Legacy" diff --git a/rw-stream-sink/src/lib.rs b/rw-stream-sink/src/lib.rs index b9de4e5f..9fe0779b 100644 --- a/rw-stream-sink/src/lib.rs +++ b/rw-stream-sink/src/lib.rs @@ -1,21 +1,21 @@ // Copyright 2017 Parity Technologies (UK) Ltd. // -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. // TODO: use this once stable ; for now we just copy-paste the content of the README.md @@ -39,16 +39,24 @@ use std::io::Error as IoError; use std::io::ErrorKind as IoErrorKind; use std::io::{Read, Write}; use bytes::{Buf, IntoBuf}; -use futures::{Async, AsyncSink, Poll, Stream, Sink}; +use futures::{Async, AsyncSink, Poll, Sink, Stream}; use tokio_io::{AsyncRead, AsyncWrite}; /// Wraps around a `Stream + Sink` whose items are buffers. Implements `AsyncRead` and `AsyncWrite`. -pub struct RwStreamSink where S: Stream, S::Item: IntoBuf { +pub struct RwStreamSink +where + S: Stream, + S::Item: IntoBuf, +{ inner: S, current_item: Option<::Buf>, } -impl RwStreamSink where S: Stream, S::Item: IntoBuf { +impl RwStreamSink +where + S: Stream, + S::Item: IntoBuf, +{ /// Wraps around `inner`. #[inline] pub fn new(inner: S) -> RwStreamSink { @@ -60,8 +68,9 @@ impl RwStreamSink where S: Stream, S::Item: IntoBuf { } impl Read for RwStreamSink - where S: Stream, - S::Item: IntoBuf, +where + S: Stream, + S::Item: IntoBuf, { fn read(&mut self, buf: &mut [u8]) -> Result { let mut written = 0; @@ -82,14 +91,14 @@ impl Read for RwStreamSink } else { return Ok(written); } - }, + } Err(err) => { if written == 0 { return Err(err); } else { return Ok(written); } - }, + } }; } @@ -103,22 +112,27 @@ impl Read for RwStreamSink return Ok(written); } - current_item.by_ref().take(to_copy).copy_to_slice(&mut buf[written..(written+to_copy)]); + current_item + .by_ref() + .take(to_copy) + .copy_to_slice(&mut buf[written..(written + to_copy)]); written += to_copy; } } } impl AsyncRead for RwStreamSink - where S: Stream, - S::Item: IntoBuf +where + S: Stream, + S::Item: IntoBuf, { } impl Write for RwStreamSink - where S: Stream + Sink, - S::SinkItem: for<'r> From<&'r [u8]>, - S::Item: IntoBuf +where + S: Stream + Sink, + S::SinkItem: for<'r> From<&'r [u8]>, + S::Item: IntoBuf, { #[inline] fn write(&mut self, buf: &[u8]) -> Result { @@ -137,9 +151,10 @@ impl Write for RwStreamSink } impl AsyncWrite for RwStreamSink - where S: Stream + Sink, - S::SinkItem: for<'r> From<&'r [u8]>, - S::Item: IntoBuf +where + S: Stream + Sink, + S::SinkItem: for<'r> From<&'r [u8]>, + S::Item: IntoBuf, { #[inline] fn shutdown(&mut self) -> Poll<(), IoError> { @@ -150,24 +165,33 @@ impl AsyncWrite for RwStreamSink #[cfg(test)] mod tests { use bytes::Bytes; - use futures::{Sink, Stream, Future, Poll, StartSend}; + use futures::{Future, Poll, Sink, StartSend, Stream}; use futures::sync::mpsc::channel; use std::io::Read; use RwStreamSink; // This struct merges a stream and a sink and is quite useful for tests. struct Wrapper(St, Si); - impl Stream for Wrapper where St: Stream { + impl Stream for Wrapper + where + St: Stream, + { type Item = St::Item; type Error = St::Error; fn poll(&mut self) -> Poll, Self::Error> { self.0.poll() } } - impl Sink for Wrapper where Si: Sink { + impl Sink for Wrapper + where + Si: Sink, + { type SinkItem = Si::SinkItem; type SinkError = Si::SinkError; - fn start_send(&mut self, item: Self::SinkItem) -> StartSend { + fn start_send( + &mut self, + item: Self::SinkItem, + ) -> StartSend { self.1.start_send(item) } fn poll_complete(&mut self) -> Poll<(), Self::SinkError> { @@ -185,7 +209,8 @@ mod tests { tx2.send(Bytes::from("hel")) .and_then(|tx| tx.send(Bytes::from("lo wor"))) .and_then(|tx| tx.send(Bytes::from("ld"))) - .wait().unwrap(); + .wait() + .unwrap(); let mut data1 = [0u8; 5]; assert_eq!(wrapper.read(&mut data1).unwrap(), 5); diff --git a/varint-rs/src/lib.rs b/varint-rs/src/lib.rs index 2166930a..216b1aee 100644 --- a/varint-rs/src/lib.rs +++ b/varint-rs/src/lib.rs @@ -23,20 +23,20 @@ //! Encoding and decoding state machines for protobuf varints // TODO: Non-allocating `BigUint`? +extern crate bytes; +#[macro_use] +extern crate error_chain; +extern crate futures; extern crate num_bigint; extern crate num_traits; extern crate tokio_io; -extern crate bytes; -extern crate futures; -#[macro_use] -extern crate error_chain; use bytes::{BufMut, Bytes, BytesMut, IntoBuf}; -use futures::{Poll, Async}; +use futures::{Async, Poll}; use num_bigint::BigUint; use num_traits::ToPrimitive; use tokio_io::{AsyncRead, AsyncWrite}; -use tokio_io::codec::{Encoder, Decoder}; +use tokio_io::codec::{Decoder, Encoder}; use std::io; use std::io::prelude::*; use std::marker::PhantomData; @@ -143,7 +143,10 @@ macro_rules! impl_decoderstate { ($t:ty, $make_fn:expr, $shift_fn:expr) => { impl DecoderHelper for $t { #[inline] - fn decode_one(decoder: &mut DecoderState, byte: u8) -> ::errors::Result> { + fn decode_one( + decoder: &mut DecoderState, + byte: u8, + ) -> ::errors::Result> { let res = decoder.accumulator.take().and_then(|accumulator| { let out = accumulator | match $shift_fn( $make_fn(byte & 0x7F), @@ -439,16 +442,14 @@ impl Decoder for VarintCodec { self.inner = VarintCodecInner::WaitingForData(len); return Ok(None); } - }, - VarintCodecInner::WaitingForLen(mut decoder) => { - match decoder.decode(src)? { - None => { - self.inner = VarintCodecInner::WaitingForLen(decoder); - return Ok(None); - }, - Some(len) => { - self.inner = VarintCodecInner::WaitingForData(len); - }, + } + VarintCodecInner::WaitingForLen(mut decoder) => match decoder.decode(src)? { + None => { + self.inner = VarintCodecInner::WaitingForLen(decoder); + return Ok(None); + } + Some(len) => { + self.inner = VarintCodecInner::WaitingForData(len); } }, VarintCodecInner::Poisoned => panic!("varint codec was poisoned"), @@ -458,7 +459,8 @@ impl Decoder for VarintCodec { } impl Encoder for VarintCodec - where D: IntoBuf + AsRef<[u8]>, +where + D: IntoBuf + AsRef<[u8]>, { type Item = D; type Error = io::Error; @@ -507,7 +509,7 @@ pub fn encode(input: T) -> Bytes { #[cfg(test)] mod tests { - use super::{decode, VarintDecoder, EncoderState}; + use super::{decode, EncoderState, VarintDecoder}; use tokio_io::codec::FramedRead; use num_bigint::BigUint; use futures::{Future, Stream};