Message order flip

This commit is contained in:
Gregor Reitzenstein 2020-05-14 23:19:26 +02:00
parent dfdeaaefa6
commit 0c5dda057e
2 changed files with 73 additions and 27 deletions

View File

@ -0,0 +1,42 @@
# Stream initiation
In a session there are two parties: The initiating entity and the receiving
entity. This terminology does not refer to information flow but rather to the
side opening a connection respectively the one listening for connection
attempts.
In the currently envisioned use-case the initiating entity is a) a client
(i.e. interactive or batch/automated program) trying to interact in some way or
other with a server b) a server trying to exchange / request information
with/from another server (i.e. federating). The receiving entity however is
already a server.
Additionally the amount and type of clients is likely to be more diverse and
less up to date than the servers.
Conclusions I draw from this:
- Clients are more likely to implement an outdated version of the communication
protocol.
- The place for backwards-compatability should be the servers.
- Thus the client (initiating entity) should send the expected API version
first, the server then using that as a basis to decide with which API
version to answer.
# Stream negotiation
Since the receiving entity for a connection is responsible for the machines it
controls it imposes conditions for connecting either as client or as federating
server. At least every initiating entity is required to authenticate itself to
the receiving entity before attempting further actions or requesting
information. But a receiving entity can require other features, such as
transport layer encryption.
To this end a receiving entity informs the initiating entity about features that
it requires from the initiating entity before taking any further action and
features that are voluntary to negotiate but may improve qualities of the stream
(such as message compression)
A varying set of conditions implies negotiation needs to take place. Since
features potentially require a strict order (e.g. Encryption before
Authentication) negotiation has to be a multi-stage process. Further
restrictions are imposed because some features may only be offered after others
have been established (e.g. SASL authentication only becoming available after
encryption, EXTERNAL mechanism only being available to local sockets or
connections providing a certificate)

View File

@ -15,38 +15,42 @@ pub async fn handle_connection(log: Logger, mut stream: TcpStream) -> Result<()>
let program = "Difluoroborane-0.1.0";
let version = (0u32,1u32);
let mut message = capnp::message::Builder::new_default();
let greet_outer = message.init_root::<gen::message::Builder>();
let mut greeting = greet_outer.init_greet();
greeting.set_host(host);
greeting.set_program(program);
greeting.set_major(version.0);
greeting.set_minor(version.1);
capnp_futures::serialize::write_message(&mut stream, message).await?;
{
let receive_options = capnp::message::ReaderOptions::default();
let message = capnp_futures::serialize::read_message(&mut stream, receive_options).await.unwrap().unwrap();
let m = message.get_root::<gen::message::Reader>().unwrap();
stream.flush().await?;
let receive_options = capnp::message::ReaderOptions::default();
let message = capnp_futures::serialize::read_message(&mut stream, receive_options).await.unwrap().unwrap();
let body: capnp::any_pointer::Reader = message.get_root().unwrap();
let m = body.get_as::<gen::message::Reader>().unwrap();
if m.has_greet() {
match m.which() {
Ok(gen::message::Which::Greet(Ok(r))) => {
println!("Host {} with program {} is saying hello. They speak API version {}.{}.",
r.get_host().unwrap(),
r.get_program().unwrap(),
r.get_major(),
r.get_minor())
},
_ => {
// We *JUST* checked that it's a greeting. This can not happen
unreachable!()
if m.has_greet() {
match m.which() {
Ok(gen::message::Which::Greet(Ok(r))) => {
println!("Host {} with program {} is saying hello. They speak API version {}.{}.",
r.get_host().unwrap(),
r.get_program().unwrap(),
r.get_major(),
r.get_minor())
},
_ => {
// We *JUST* checked that it's a greeting. This can not happen
unreachable!()
}
}
}
}
{
let mut message = capnp::message::Builder::new_default();
let greet_outer = message.init_root::<gen::message::Builder>();
let mut greeting = greet_outer.init_greet();
greeting.set_host(host);
greeting.set_program(program);
greeting.set_major(version.0);
greeting.set_minor(version.1);
capnp_futures::serialize::write_message(&mut stream, message).await?;
}
stream.flush().await?;
Ok(())
}