mirror of
https://github.com/fluencelabs/rust-libp2p
synced 2025-06-29 17:51:35 +00:00
Configurable multistream-select protocol. Add V1Lazy variant. (#1245)
Make the multistream-select protocol (version) configurable on transport upgrades as well as for individual substreams. Add a "lazy" variant of multistream-select 1.0 that delays sending of negotiation protocol frames as much as possible but is only safe to use under additional assumptions that go beyond what is required by the multistream-select v1 specification.
This commit is contained in:
@ -22,7 +22,7 @@
|
||||
|
||||
#![cfg(test)]
|
||||
|
||||
use crate::NegotiationError;
|
||||
use crate::{Version, NegotiationError};
|
||||
use crate::dialer_select::{dialer_select_proto_parallel, dialer_select_proto_serial};
|
||||
use crate::{dialer_select_proto, listener_select_proto};
|
||||
use futures::prelude::*;
|
||||
@ -32,137 +32,157 @@ use tokio_io::io as nio;
|
||||
|
||||
#[test]
|
||||
fn select_proto_basic() {
|
||||
let listener = TcpListener::bind(&"127.0.0.1:0".parse().unwrap()).unwrap();
|
||||
let listener_addr = listener.local_addr().unwrap();
|
||||
fn run(version: Version) {
|
||||
let listener = TcpListener::bind(&"127.0.0.1:0".parse().unwrap()).unwrap();
|
||||
let listener_addr = listener.local_addr().unwrap();
|
||||
|
||||
let server = listener
|
||||
.incoming()
|
||||
.into_future()
|
||||
.map(|s| s.0.unwrap())
|
||||
.map_err(|(e, _)| e.into())
|
||||
.and_then(move |connec| {
|
||||
let protos = vec![b"/proto1", b"/proto2"];
|
||||
listener_select_proto(connec, protos)
|
||||
})
|
||||
.and_then(|(proto, io)| {
|
||||
nio::write_all(io, b"pong").from_err().map(move |_| proto)
|
||||
});
|
||||
|
||||
let client = TcpStream::connect(&listener_addr)
|
||||
.from_err()
|
||||
.and_then(move |connec| {
|
||||
let protos = vec![b"/proto3", b"/proto2"];
|
||||
dialer_select_proto(connec, protos)
|
||||
})
|
||||
.and_then(|(proto, io)| {
|
||||
nio::write_all(io, b"ping").from_err().map(move |(io, _)| (proto, io))
|
||||
})
|
||||
.and_then(|(proto, io)| {
|
||||
nio::read_exact(io, [0; 4]).from_err().map(move |(_, msg)| {
|
||||
assert_eq!(&msg, b"pong");
|
||||
proto
|
||||
let server = listener
|
||||
.incoming()
|
||||
.into_future()
|
||||
.map(|s| s.0.unwrap())
|
||||
.map_err(|(e, _)| e.into())
|
||||
.and_then(move |connec| {
|
||||
let protos = vec![b"/proto1", b"/proto2"];
|
||||
listener_select_proto(connec, protos)
|
||||
})
|
||||
});
|
||||
.and_then(|(proto, io)| {
|
||||
nio::write_all(io, b"pong").from_err().map(move |_| proto)
|
||||
});
|
||||
|
||||
let mut rt = Runtime::new().unwrap();
|
||||
let (dialer_chosen, listener_chosen) =
|
||||
rt.block_on(client.join(server)).unwrap();
|
||||
let client = TcpStream::connect(&listener_addr)
|
||||
.from_err()
|
||||
.and_then(move |connec| {
|
||||
let protos = vec![b"/proto3", b"/proto2"];
|
||||
dialer_select_proto(connec, protos, version)
|
||||
})
|
||||
.and_then(|(proto, io)| {
|
||||
nio::write_all(io, b"ping").from_err().map(move |(io, _)| (proto, io))
|
||||
})
|
||||
.and_then(|(proto, io)| {
|
||||
nio::read_exact(io, [0; 4]).from_err().map(move |(_, msg)| {
|
||||
assert_eq!(&msg, b"pong");
|
||||
proto
|
||||
})
|
||||
});
|
||||
|
||||
assert_eq!(dialer_chosen, b"/proto2");
|
||||
assert_eq!(listener_chosen, b"/proto2");
|
||||
let mut rt = Runtime::new().unwrap();
|
||||
let (dialer_chosen, listener_chosen) =
|
||||
rt.block_on(client.join(server)).unwrap();
|
||||
|
||||
assert_eq!(dialer_chosen, b"/proto2");
|
||||
assert_eq!(listener_chosen, b"/proto2");
|
||||
}
|
||||
|
||||
run(Version::V1);
|
||||
run(Version::V1Lazy);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_protocol_found() {
|
||||
let listener = TcpListener::bind(&"127.0.0.1:0".parse().unwrap()).unwrap();
|
||||
let listener_addr = listener.local_addr().unwrap();
|
||||
fn run(version: Version) {
|
||||
let listener = TcpListener::bind(&"127.0.0.1:0".parse().unwrap()).unwrap();
|
||||
let listener_addr = listener.local_addr().unwrap();
|
||||
|
||||
let server = listener
|
||||
.incoming()
|
||||
.into_future()
|
||||
.map(|s| s.0.unwrap())
|
||||
.map_err(|(e, _)| e.into())
|
||||
.and_then(move |connec| {
|
||||
let protos = vec![b"/proto1", b"/proto2"];
|
||||
listener_select_proto(connec, protos)
|
||||
})
|
||||
.and_then(|(proto, io)| io.complete().map(move |_| proto));
|
||||
let server = listener
|
||||
.incoming()
|
||||
.into_future()
|
||||
.map(|s| s.0.unwrap())
|
||||
.map_err(|(e, _)| e.into())
|
||||
.and_then(move |connec| {
|
||||
let protos = vec![b"/proto1", b"/proto2"];
|
||||
listener_select_proto(connec, protos)
|
||||
})
|
||||
.and_then(|(proto, io)| io.complete().map(move |_| proto));
|
||||
|
||||
let client = TcpStream::connect(&listener_addr)
|
||||
.from_err()
|
||||
.and_then(move |connec| {
|
||||
let protos = vec![b"/proto3", b"/proto4"];
|
||||
dialer_select_proto(connec, protos)
|
||||
})
|
||||
.and_then(|(proto, io)| io.complete().map(move |_| proto));
|
||||
let client = TcpStream::connect(&listener_addr)
|
||||
.from_err()
|
||||
.and_then(move |connec| {
|
||||
let protos = vec![b"/proto3", b"/proto4"];
|
||||
dialer_select_proto(connec, protos, version)
|
||||
})
|
||||
.and_then(|(proto, io)| io.complete().map(move |_| proto));
|
||||
|
||||
let mut rt = Runtime::new().unwrap();
|
||||
match rt.block_on(client.join(server)) {
|
||||
Err(NegotiationError::Failed) => (),
|
||||
e => panic!("{:?}", e),
|
||||
let mut rt = Runtime::new().unwrap();
|
||||
match rt.block_on(client.join(server)) {
|
||||
Err(NegotiationError::Failed) => (),
|
||||
e => panic!("{:?}", e),
|
||||
}
|
||||
}
|
||||
|
||||
run(Version::V1);
|
||||
run(Version::V1Lazy);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn select_proto_parallel() {
|
||||
let listener = TcpListener::bind(&"127.0.0.1:0".parse().unwrap()).unwrap();
|
||||
let listener_addr = listener.local_addr().unwrap();
|
||||
fn run(version: Version) {
|
||||
let listener = TcpListener::bind(&"127.0.0.1:0".parse().unwrap()).unwrap();
|
||||
let listener_addr = listener.local_addr().unwrap();
|
||||
|
||||
let server = listener
|
||||
.incoming()
|
||||
.into_future()
|
||||
.map(|s| s.0.unwrap())
|
||||
.map_err(|(e, _)| e.into())
|
||||
.and_then(move |connec| {
|
||||
let protos = vec![b"/proto1", b"/proto2"];
|
||||
listener_select_proto(connec, protos)
|
||||
})
|
||||
.and_then(|(proto, io)| io.complete().map(move |_| proto));
|
||||
let server = listener
|
||||
.incoming()
|
||||
.into_future()
|
||||
.map(|s| s.0.unwrap())
|
||||
.map_err(|(e, _)| e.into())
|
||||
.and_then(move |connec| {
|
||||
let protos = vec![b"/proto1", b"/proto2"];
|
||||
listener_select_proto(connec, protos)
|
||||
})
|
||||
.and_then(|(proto, io)| io.complete().map(move |_| proto));
|
||||
|
||||
let client = TcpStream::connect(&listener_addr)
|
||||
.from_err()
|
||||
.and_then(move |connec| {
|
||||
let protos = vec![b"/proto3", b"/proto2"];
|
||||
dialer_select_proto_parallel(connec, protos.into_iter())
|
||||
})
|
||||
.and_then(|(proto, io)| io.complete().map(move |_| proto));
|
||||
let client = TcpStream::connect(&listener_addr)
|
||||
.from_err()
|
||||
.and_then(move |connec| {
|
||||
let protos = vec![b"/proto3", b"/proto2"];
|
||||
dialer_select_proto_parallel(connec, protos.into_iter(), version)
|
||||
})
|
||||
.and_then(|(proto, io)| io.complete().map(move |_| proto));
|
||||
|
||||
let mut rt = Runtime::new().unwrap();
|
||||
let (dialer_chosen, listener_chosen) =
|
||||
rt.block_on(client.join(server)).unwrap();
|
||||
let mut rt = Runtime::new().unwrap();
|
||||
let (dialer_chosen, listener_chosen) =
|
||||
rt.block_on(client.join(server)).unwrap();
|
||||
|
||||
assert_eq!(dialer_chosen, b"/proto2");
|
||||
assert_eq!(listener_chosen, b"/proto2");
|
||||
assert_eq!(dialer_chosen, b"/proto2");
|
||||
assert_eq!(listener_chosen, b"/proto2");
|
||||
}
|
||||
|
||||
run(Version::V1);
|
||||
run(Version::V1Lazy);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn select_proto_serial() {
|
||||
let listener = TcpListener::bind(&"127.0.0.1:0".parse().unwrap()).unwrap();
|
||||
let listener_addr = listener.local_addr().unwrap();
|
||||
fn run(version: Version) {
|
||||
let listener = TcpListener::bind(&"127.0.0.1:0".parse().unwrap()).unwrap();
|
||||
let listener_addr = listener.local_addr().unwrap();
|
||||
|
||||
let server = listener
|
||||
.incoming()
|
||||
.into_future()
|
||||
.map(|s| s.0.unwrap())
|
||||
.map_err(|(e, _)| e.into())
|
||||
.and_then(move |connec| {
|
||||
let protos = vec![b"/proto1", b"/proto2"];
|
||||
listener_select_proto(connec, protos)
|
||||
})
|
||||
.and_then(|(proto, io)| io.complete().map(move |_| proto));
|
||||
let server = listener
|
||||
.incoming()
|
||||
.into_future()
|
||||
.map(|s| s.0.unwrap())
|
||||
.map_err(|(e, _)| e.into())
|
||||
.and_then(move |connec| {
|
||||
let protos = vec![b"/proto1", b"/proto2"];
|
||||
listener_select_proto(connec, protos)
|
||||
})
|
||||
.and_then(|(proto, io)| io.complete().map(move |_| proto));
|
||||
|
||||
let client = TcpStream::connect(&listener_addr)
|
||||
.from_err()
|
||||
.and_then(move |connec| {
|
||||
let protos = vec![b"/proto3", b"/proto2"];
|
||||
dialer_select_proto_serial(connec, protos.into_iter())
|
||||
})
|
||||
.and_then(|(proto, io)| io.complete().map(move |_| proto));
|
||||
let client = TcpStream::connect(&listener_addr)
|
||||
.from_err()
|
||||
.and_then(move |connec| {
|
||||
let protos = vec![b"/proto3", b"/proto2"];
|
||||
dialer_select_proto_serial(connec, protos.into_iter(), version)
|
||||
})
|
||||
.and_then(|(proto, io)| io.complete().map(move |_| proto));
|
||||
|
||||
let mut rt = Runtime::new().unwrap();
|
||||
let (dialer_chosen, listener_chosen) =
|
||||
rt.block_on(client.join(server)).unwrap();
|
||||
let mut rt = Runtime::new().unwrap();
|
||||
let (dialer_chosen, listener_chosen) =
|
||||
rt.block_on(client.join(server)).unwrap();
|
||||
|
||||
assert_eq!(dialer_chosen, b"/proto2");
|
||||
assert_eq!(listener_chosen, b"/proto2");
|
||||
assert_eq!(dialer_chosen, b"/proto2");
|
||||
assert_eq!(listener_chosen, b"/proto2");
|
||||
}
|
||||
|
||||
run(Version::V1);
|
||||
run(Version::V1Lazy);
|
||||
}
|
||||
|
Reference in New Issue
Block a user