mirror of
https://gitlab.com/fabinfra/fabaccess/bffh.git
synced 2024-11-11 01:53:23 +01:00
Message order flip
This commit is contained in:
parent
dfdeaaefa6
commit
0c5dda057e
42
draft-fabaccess-protocol.md
Normal file
42
draft-fabaccess-protocol.md
Normal 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)
|
@ -15,38 +15,42 @@ pub async fn handle_connection(log: Logger, mut stream: TcpStream) -> Result<()>
|
|||||||
let program = "Difluoroborane-0.1.0";
|
let program = "Difluoroborane-0.1.0";
|
||||||
let version = (0u32,1u32);
|
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?;
|
if m.has_greet() {
|
||||||
|
match m.which() {
|
||||||
let receive_options = capnp::message::ReaderOptions::default();
|
Ok(gen::message::Which::Greet(Ok(r))) => {
|
||||||
let message = capnp_futures::serialize::read_message(&mut stream, receive_options).await.unwrap().unwrap();
|
println!("Host {} with program {} is saying hello. They speak API version {}.{}.",
|
||||||
let body: capnp::any_pointer::Reader = message.get_root().unwrap();
|
r.get_host().unwrap(),
|
||||||
let m = body.get_as::<gen::message::Reader>().unwrap();
|
r.get_program().unwrap(),
|
||||||
|
r.get_major(),
|
||||||
if m.has_greet() {
|
r.get_minor())
|
||||||
match m.which() {
|
},
|
||||||
Ok(gen::message::Which::Greet(Ok(r))) => {
|
_ => {
|
||||||
println!("Host {} with program {} is saying hello. They speak API version {}.{}.",
|
// We *JUST* checked that it's a greeting. This can not happen
|
||||||
r.get_host().unwrap(),
|
unreachable!()
|
||||||
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user