3 Angajamente 28eaf91e10 ... 3066400930

Autor SHA1 Permisiunea de a trimite mesaje. Dacă este dezactivată, utilizatorul nu va putea trimite nici un fel de mesaj Data
  Matthew Carr 3066400930 Modified the PoC protocol contract and actor implementation. 2 ani în urmă
  Matthew Carr d54e2c55bf Added a new deploy script to upload the site to freja. 2 ani în urmă
  Matthew Carr 43f461f7a9 Renamed btmsg to bttp. 2 ani în urmă

+ 27 - 27
Cargo.lock

@@ -285,8 +285,8 @@ version = "0.1.0"
 dependencies = [
  "anyhow",
  "btlib",
- "btmsg",
  "btserde",
+ "bttp",
  "bytes",
  "fuse-backend-rs",
  "futures",
@@ -323,8 +323,8 @@ dependencies = [
  "btfproto",
  "btlib",
  "btlib-tests",
- "btmsg",
  "btserde",
+ "bttp",
  "ctor",
  "env_logger",
  "figment",
@@ -345,8 +345,8 @@ dependencies = [
  "btfproto",
  "btfproto-tests",
  "btlib",
- "btmsg",
  "btserde",
+ "bttp",
  "ctor",
  "env_logger",
  "figment",
@@ -411,29 +411,6 @@ dependencies = [
  "tempdir",
 ]
 
-[[package]]
-name = "btmsg"
-version = "0.1.0"
-dependencies = [
- "anyhow",
- "btlib",
- "btserde",
- "bytes",
- "chrono",
- "ctor",
- "env_logger",
- "futures",
- "lazy_static",
- "log",
- "quinn",
- "rustls",
- "serde",
- "tokio",
- "tokio-stream",
- "tokio-util",
- "zerocopy",
-]
-
 [[package]]
 name = "btprovision"
 version = "0.1.0"
@@ -455,8 +432,8 @@ dependencies = [
  "anyhow",
  "btlib",
  "btlib-tests",
- "btmsg",
  "btserde",
+ "bttp",
  "bytes",
  "ctor",
  "env_logger",
@@ -478,6 +455,29 @@ dependencies = [
  "serde-big-array",
 ]
 
+[[package]]
+name = "bttp"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "btlib",
+ "btserde",
+ "bytes",
+ "chrono",
+ "ctor",
+ "env_logger",
+ "futures",
+ "lazy_static",
+ "log",
+ "quinn",
+ "rustls",
+ "serde",
+ "tokio",
+ "tokio-stream",
+ "tokio-util",
+ "zerocopy",
+]
+
 [[package]]
 name = "bumpalo"
 version = "3.11.1"

+ 1 - 1
README.md

@@ -26,7 +26,7 @@ by the [tpm](./btlib/crypto/tpm/index.html) module.
 * [btrun](./btrun/index.html): Contains the actor runtime.
 * [btserde](./btserde/index.html): Defines the serde compact binary serialization format used to
 store data on disk and transmit over the network.
-* [btmsg](./btmsg/index.html): Defines the message passing interface.
+* [bttp](./bttp/index.html): Defines the message passing interface.
 * [btfproto](./btfproto/index.html): Defines the message protocol used to communicate with file
 servers.
 * [btfsd](./btfsd/index.html): Implements a file server daemon.

+ 1 - 1
crates/btfproto/Cargo.toml

@@ -13,7 +13,7 @@ default = ["client", "server", "local-fs"]
 
 [dependencies]
 btlib = { path = "../btlib" }
-btmsg = { path = "../btmsg" }
+bttp = { path = "../bttp" }
 serde = { version = "^1.0.136", features = ["derive"] }
 paste = "1.0.11"
 log = "0.4.17"

+ 1 - 1
crates/btfproto/src/client.rs

@@ -3,7 +3,7 @@
 use crate::{msg::*, server::FsProvider, Handle, Inode};
 
 use btlib::{bterr, crypto::ConcretePub, BlockPath, IssuedProcRec, Result};
-use btmsg::{DeserCallback, Transmitter};
+use bttp::{DeserCallback, Transmitter};
 
 use core::future::{ready, Future, Ready};
 use futures::FutureExt;

+ 8 - 8
crates/btfproto/src/msg.rs

@@ -5,7 +5,7 @@ use super::{Handle, Inode};
 use btlib::{
     bterr, crypto::ConcretePub, BlockMetaSecrets, DirEntry, DirEntryKind, Epoch, IssuedProcRec,
 };
-use btmsg::CallMsg;
+use bttp::CallMsg;
 use core::time::Duration;
 use paste::paste;
 use serde::{Deserialize, Serialize};
@@ -149,7 +149,7 @@ impl BitOr<libc::mode_t> for FileType {
 #[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
 #[repr(i32)]
 /// The generators for the group of [Flags].
-/// 
+///
 /// These are mostly values from libc, save for several custom values. Note that the presence of a
 /// flag in this enum does not guarantee it's supported.
 /// The standard libc `O_*` value which corresponds to each variant is given in the variant's
@@ -281,7 +281,7 @@ impl Flags {
     }
 
     /// Asserts that these flags allow a file to be read.
-    /// 
+    ///
     /// If the assertion fails then an [io::Error] with the errno [libc::EACCES] is returned.
     pub fn assert_readable(self) -> Result<(), io::Error> {
         if !self.readable() {
@@ -292,7 +292,7 @@ impl Flags {
     }
 
     /// Asserts that these flags allow a file to be written.
-    /// 
+    ///
     /// If the assertion fails then an [io::Error] with the errno [libc::EACCES] is returned.
     pub fn assert_writeable(self) -> Result<(), io::Error> {
         if !self.writeable() {
@@ -361,7 +361,7 @@ pub struct Attrs {
 
 #[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Hash)]
 /// A type for indicating which fields in [Attrs] have been set and which should be ignored.
-/// 
+///
 /// This method was chosen over using [Option] for greater efficiency on the wire.
 pub struct AttrsSet(u16);
 
@@ -431,7 +431,7 @@ impl BitOrAssign<Self> for AttrsSet {
 }
 
 /// A filesystem entry.
-/// 
+///
 /// This struct includes attributes of a file as well as cache control
 /// information for how long it may be cached.
 #[derive(Debug, Serialize, Deserialize)]
@@ -561,7 +561,7 @@ pub struct LinkReply {
 }
 
 /// A request to remove a name referring to an inode.
-/// 
+///
 /// If the inode becomes orphaned, it is removed from durable storage.
 #[derive(Serialize, Deserialize)]
 pub struct Unlink<'a> {
@@ -617,7 +617,7 @@ pub struct Close {
 }
 
 /// A request to forget about an inode which was previously referenced.
-/// 
+///
 /// This message must be sent
 /// so the server knows when it can free resources associated with the inode.
 /// If `N` [Entry] structs are sent in a reply to [Lookup] messages, then the caller must send one

+ 2 - 2
crates/btfproto/src/server.rs

@@ -1,13 +1,13 @@
 // SPDX-License-Identifier: AGPL-3.0-or-later
 //! Code for creating filesystem servers.
-//! 
+//!
 //! The [FsProvider] trait defines the interface that a filesystem server
 //! must implement.
 //! A new server can be created using the [new_fs_server] function.
 use crate::msg::{Read as ReadMsg, *};
 
 use btlib::{crypto::Creds, BlockPath, Result};
-use btmsg::{MsgCallback, MsgReceived, Receiver};
+use bttp::{MsgCallback, MsgReceived, Receiver};
 use core::future::Future;
 use std::{net::IpAddr, ops::Deref, sync::Arc};
 

+ 1 - 1
crates/btfsd/Cargo.toml

@@ -7,7 +7,7 @@ edition = "2021"
 
 [dependencies]
 btlib = { path = "../btlib" }
-btmsg = { path = "../btmsg" }
+bttp = { path = "../bttp" }
 btfproto = { path = "../btfproto" }
 btconfig = { path = "../btconfig" }
 btconsole = { path = "../btconsole" }

+ 1 - 1
crates/btfsd/autobuild.sh

@@ -1,4 +1,4 @@
 #!/usr/bin/env bash
 # Automatically builds btconsole and btconsole-client when files in their respective crates change.
 set -euo pipefail
-RUST_LOG=warn,btfsd=debug,btconsole=debug,btmsg=debug cargo watch -- sh -c 'cd ../btconsole-client && trunk build && cd - && cargo run'
+RUST_LOG=warn,btfsd=debug,btconsole=debug,bttp=debug cargo watch -- sh -c 'cd ../btconsole-client && trunk build && cd - && cargo run'

+ 3 - 3
crates/btfsd/src/main.rs

@@ -6,7 +6,7 @@ use btfproto::{
     server::{new_fs_server, FsProvider},
 };
 use btlib::{bterr, crypto::Creds, error::DisplayErr, log::BuilderExt, Result};
-use btmsg::Receiver;
+use bttp::Receiver;
 use figment::{providers::Serialized, Figment};
 use serde::{Deserialize, Serialize};
 use std::{net::IpAddr, path::PathBuf, sync::Arc};
@@ -95,8 +95,8 @@ mod tests {
         AuthzAttrs, BlockMetaSecrets, Epoch, IssuedProcRec, Principaled, ProcRec,
     };
     use btlib_tests::{CredStoreTestingExt, TpmCredStoreHarness};
-    use btmsg::BlockAddr;
     use btserde::from_slice;
+    use bttp::BlockAddr;
     use std::net::{IpAddr, Ipv4Addr};
     use std::{future::ready, net::Ipv6Addr, time::Duration};
     use swtpm_harness::SwtpmHarness;
@@ -896,7 +896,7 @@ mod tests {
         let node_creds = case.harness.cred_store().node_creds().unwrap();
         let bind_path = node_creds.writecap().unwrap().bind_path();
         let block_addr = Arc::new(BlockAddr::new(LOCALHOST, Arc::new(bind_path)));
-        let tx = btmsg::Transmitter::new(block_addr, Arc::new(user_creds))
+        let tx = bttp::Transmitter::new(block_addr, Arc::new(user_creds))
             .await
             .unwrap();
         let client = FsClient::new(tx);

+ 1 - 1
crates/btfuse/Cargo.toml

@@ -11,7 +11,7 @@ btlib = { path = "../btlib" }
 btserde = { path = "../btserde" }
 swtpm-harness = { path = "../swtpm-harness" }
 btfproto = { path = "../btfproto" }
-btmsg = { path = "../btmsg" }
+bttp = { path = "../bttp" }
 btconfig = { path = "../btconfig" }
 tokio = { version = "1.24.2", features = ["rt", "rt-multi-thread"] }
 fuse-backend-rs = { version = "0.9.6", features = ["async-io"] }

+ 3 - 3
crates/btfuse/src/main.rs

@@ -11,7 +11,7 @@ use btlib::{
     crypto::{Creds, CredsPriv},
     Result,
 };
-use btmsg::{BlockAddr, Transmitter};
+use bttp::{BlockAddr, Transmitter};
 use serde::{Deserialize, Serialize};
 use std::{
     fs::{self},
@@ -191,7 +191,7 @@ mod test {
         log::BuilderExt,
         Epoch, Principaled,
     };
-    use btmsg::Receiver;
+    use bttp::Receiver;
     use ctor::ctor;
     use std::{
         ffi::{OsStr, OsString},
@@ -858,7 +858,7 @@ mod config_tests {
 
     use btconfig::CredStoreConfig;
     use btlib::BlockPath;
-    use btmsg::BlockAddr;
+    use bttp::BlockAddr;
     use figment::Jail;
 
     #[test]

+ 3 - 3
crates/btlib/src/crypto.rs

@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: AGPL-3.0-or-later
 //! This module contains types providing the cryptographic primitives necessary to implement
 //! Blocktree.
-//! 
+//!
 //! The [openssl] create is used for all of these primitives,
 //! none of them are directly implemented in this module.
 //! Rather, the types here wrap the functionality provided by OpenSSL in a more convenient
@@ -56,7 +56,7 @@ use strum_macros::{Display, EnumDiscriminants, FromRepr};
 use zeroize::{ZeroizeOnDrop, Zeroizing};
 
 /// The encryption of some type `T`.
-/// 
+///
 /// This type is just e wrapper around a [Vec] of [u8] which remembers the type it was serialized
 /// and encrypted from.
 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)]
@@ -75,7 +75,7 @@ impl<T> Ciphertext<T> {
 }
 
 /// A signature over the serialization of a type `T`.
-/// 
+///
 /// This struct allows the signature over a serialization of `T` to be stored together with a
 /// signature over  it.
 pub struct Signed<T> {

+ 1 - 1
crates/btrun/Cargo.toml

@@ -7,7 +7,7 @@ edition = "2021"
 
 [dependencies]
 btlib = { path = "../btlib" }
-btmsg = { path = "../btmsg" }
+bttp = { path = "../bttp" }
 btserde = { path = "../btserde" }
 tokio = { version = "1.23.0", features = ["rt-multi-thread"] }
 futures = "0.3.25"

+ 130 - 127
crates/btrun/src/lib.rs

@@ -13,8 +13,8 @@ use std::{
 };
 
 use btlib::{bterr, crypto::Creds, error::StringError, BlockPath, Result};
-use btmsg::{DeserCallback, MsgCallback, Receiver, Replier, Transmitter};
 use btserde::{field_helpers::smart_ptr, from_slice, to_vec, write_to};
+use bttp::{DeserCallback, MsgCallback, Receiver, Replier, Transmitter};
 use serde::{de::DeserializeOwned, Deserialize, Serialize};
 use tokio::{
     sync::{mpsc, oneshot, Mutex, RwLock},
@@ -177,7 +177,7 @@ impl Runtime {
         let act_name = self.actor_name(act_id);
         let (tx, rx) = mpsc::channel::<Envelope<Msg>>(MAILBOX_LIMIT);
         // The deliverer closure is responsible for deserializing messages received over the wire
-        // and delivering them to the actor's mailbox and sending replies to call messages.
+        // and delivering them to the actor's mailbox, and sending replies to call messages.
         let deliverer = {
             let buffer = Arc::new(Mutex::new(Vec::<u8>::new()));
             let tx = tx.clone();
@@ -286,6 +286,19 @@ impl Display for RuntimeError {
 
 impl std::error::Error for RuntimeError {}
 
+#[allow(dead_code)]
+/// Represents the terminal state of an actor, where it stops processing messages and halts.
+struct End;
+
+#[allow(dead_code)]
+/// Delivered to an actor implementation when it starts up.
+pub struct Activate {
+    /// A reference to the `Runtime` which is running this actor.
+    rt: &'static Runtime,
+    /// The ID assigned to this actor.
+    act_id: Uuid,
+}
+
 /// Deserializes replies sent over the wire.
 struct ReplyCallback<T> {
     _phantom: PhantomData<T>,
@@ -385,7 +398,7 @@ impl RuntimeCallback {
 impl MsgCallback for RuntimeCallback {
     type Arg<'de> = WireMsg<'de>;
     type CallFut<'de> = impl 'de + Future<Output = Result<()>>;
-    fn call<'de>(&'de self, arg: btmsg::MsgReceived<Self::Arg<'de>>) -> Self::CallFut<'de> {
+    fn call<'de>(&'de self, arg: bttp::MsgReceived<Self::Arg<'de>>) -> Self::CallFut<'de> {
         async move {
             let (_, body, replier) = arg.into_parts();
             if body.to.path() == self.rt.path() {
@@ -466,6 +479,10 @@ pub trait CallMsg: Serialize + DeserializeOwned + Send + Sync {
 /// Trait for messages which expect exactly zero replies.
 pub trait SendMsg: CallMsg {}
 
+/// A type used to express when a reply is not expected for a message type.
+#[derive(Serialize, Deserialize)]
+enum NoReply {}
+
 /// The maximum number of messages which can be kept in an actor's mailbox.
 const MAILBOX_LIMIT: usize = 32;
 
@@ -477,11 +494,11 @@ struct WireMsg<'a> {
     payload: &'a [u8],
 }
 
-impl<'a> btmsg::CallMsg<'a> for WireMsg<'a> {
+impl<'a> bttp::CallMsg<'a> for WireMsg<'a> {
     type Reply<'r> = WireReply<'r>;
 }
 
-impl<'a> btmsg::SendMsg<'a> for WireMsg<'a> {}
+impl<'a> bttp::SendMsg<'a> for WireMsg<'a> {}
 
 #[derive(Serialize, Deserialize)]
 enum WireReply<'a> {
@@ -504,10 +521,8 @@ impl<'de> WireEnvelope<'de> {
     }
 }
 
-/// Wraps a message to indicate if it was sent with `call` or `send`.
-///
-/// If the message was sent with call, then this enum will contain a channel that can be used to
-/// reply to it.
+/// Wrapper around a message type `T` which indicates who the message is from and, if the message
+/// was dispatched with `call`, provides a channel to reply to it.
 pub struct Envelope<T: CallMsg> {
     from: ActorName,
     reply: Option<oneshot::Sender<T::Reply>>,
@@ -656,8 +671,8 @@ mod tests {
         log::BuilderExt,
     };
     use btlib_tests::TEST_STORE;
-    use btmsg::BlockAddr;
     use btserde::to_vec;
+    use bttp::BlockAddr;
     use ctor::ctor;
     use lazy_static::lazy_static;
     use std::{
@@ -788,37 +803,46 @@ mod tests {
         assert_eq!(0, LOCAL_RT.num_running().await);
     }
 
-    struct Activate {
-        rt: &'static Runtime,
-        act_id: Uuid,
-    }
+    // The following code is a proof-of-concept for what types should be generated for a
+    // simple ping-pong protocol:
+    //
+    // protocol! {
+    //     ClientInit?Activate -> SentPing, Listening!Ping
+    //     ServerInit?Activate -> Listening
+    //     Listening?Ping -> End, SentPing!Ping::Reply
+    //     SentPing?Ping::Reply -> End
+    // }
+    //
+    // In words, the protocol is described as follows.
+    // 1. The ClientInit state receives the Activate message. It returns the SentPing state and a
+    //    Ping message to be sent to the Listening state.
+    // 2. The ServerInit state receives the Activate message. It returns the Listening state.
+    // 3. When the Listening state receives the Ping message it returns the End state and a
+    //    Ping::Reply message to be sent to the SentPing state.
+    // 4. When the SentPing state receives the Ping::Reply message it returns the End state.
+    //
+    // The End state represents an end to the session described by the protocol. When an actor
+    // transitions to the End state its function returns.
+    // The generated actor implementation is the sender of the Activate message.
+    // When a state is expecting a Reply message, an error occurs if the message is not received
+    // in a timely manner.
 
     #[derive(Serialize, Deserialize)]
     struct Ping;
     impl CallMsg for Ping {
-        type Reply = ();
+        type Reply = PingReply;
     }
-    impl SendMsg for Ping {}
 
+    // I was tempted to name this "Pong", but the proc macro wouldn't think to do that.
     #[derive(Serialize, Deserialize)]
-    struct Pong;
-    impl CallMsg for Pong {
-        type Reply = ();
-    }
-    impl SendMsg for Pong {}
+    struct PingReply;
 
     trait ClientInit {
         type AfterActivate: SentPing;
-        type HandleActivateFut: Future<Output = Result<Self::AfterActivate>>;
+        type HandleActivateFut: Future<Output = Result<(Self::AfterActivate, Ping)>>;
         fn handle_activate(self, msg: Activate) -> Self::HandleActivateFut;
     }
 
-    trait SentPing {
-        type AfterPong: Returned;
-        type HandlePongFut: Future<Output = Result<Self::AfterPong>>;
-        fn handle_pong(self, msg: Envelope<Pong>) -> Self::HandlePongFut;
-    }
-
     trait ServerInit {
         type AfterActivate: Listening;
         type HandleActivateFut: Future<Output = Result<Self::AfterActivate>>;
@@ -826,109 +850,77 @@ mod tests {
     }
 
     trait Listening {
-        type AfterPing: Returned;
-        type HandlePingFut: Future<Output = Result<Self::AfterPing>>;
-        fn handle_ping(self, msg: Envelope<Ping>) -> Self::HandlePingFut;
+        type HandlePingFut: Future<Output = Result<(End, PingReply)>>;
+        fn handle_ping(self, msg: Ping) -> Self::HandlePingFut;
     }
 
-    trait Returned {}
-
-    struct ReturnedState;
-
-    impl Returned for ReturnedState {}
-
-    trait PingProtocol {
-        type Client: ClientInit;
-        type Server: ServerInit;
+    trait SentPing {
+        type HandleReplyFut: Future<Output = Result<End>>;
+        fn handle_reply(self, msg: PingReply) -> Self::HandleReplyFut;
     }
 
     #[derive(Serialize, Deserialize)]
     enum PingProtocolMsg {
         Ping(Ping),
-        Pong(Pong),
+        PingReply(PingReply),
     }
     impl CallMsg for PingProtocolMsg {
-        type Reply = ();
+        type Reply = PingProtocolMsg;
     }
     impl SendMsg for PingProtocolMsg {}
 
-    #[allow(dead_code)]
-    enum PingClientState {
-        Init(ClientInitState),
-        SentPing(ClientState),
-        Returned(ReturnedState),
-    }
-
-    #[allow(dead_code)]
-    enum PingServerState {
-        ServerInit(ServerInitState),
-        Listening(ServerState),
-        Returned(ReturnedState),
-    }
-
-    struct ClientInitState {
-        server_name: ActorName,
-    }
-
-    struct ClientState;
+    struct ClientInitState;
 
     impl ClientInit for ClientInitState {
         type AfterActivate = ClientState;
-        type HandleActivateFut = impl Future<Output = Result<Self::AfterActivate>>;
-        fn handle_activate(self, msg: Activate) -> Self::HandleActivateFut {
-            async move {
-                let from = msg.rt.actor_name(msg.act_id);
-                // TODO: This implementation should not know about PingProtocolMsg. It should be
-                // able to send Ping directly.
-                msg.rt
-                    .send(self.server_name, from, PingProtocolMsg::Ping(Ping))
-                    .await?;
-                Ok(ClientState)
-            }
+        type HandleActivateFut = impl Future<Output = Result<(Self::AfterActivate, Ping)>>;
+        fn handle_activate(self, _msg: Activate) -> Self::HandleActivateFut {
+            ready(Ok((ClientState, Ping)))
         }
     }
 
+    struct ClientState;
+
     impl SentPing for ClientState {
-        type AfterPong = ReturnedState;
-        type HandlePongFut = Ready<Result<Self::AfterPong>>;
-        fn handle_pong(self, _msg: Envelope<Pong>) -> Self::HandlePongFut {
-            ready(Ok(ReturnedState))
+        type HandleReplyFut = Ready<Result<End>>;
+        fn handle_reply(self, _msg: PingReply) -> Self::HandleReplyFut {
+            ready(Ok(End))
         }
     }
 
+    #[allow(dead_code)]
+    enum PingClientState {
+        Init(ClientInitState),
+        SentPing(ClientState),
+        End(End),
+    }
+
     struct ServerInitState;
 
-    struct ServerState {
-        rt: &'static Runtime,
-        act_id: Uuid,
-    }
+    struct ServerState;
 
     impl ServerInit for ServerInitState {
         type AfterActivate = ServerState;
         type HandleActivateFut = Ready<Result<Self::AfterActivate>>;
-        fn handle_activate(self, msg: Activate) -> Self::HandleActivateFut {
-            ready(Ok(ServerState {
-                rt: msg.rt,
-                act_id: msg.act_id,
-            }))
+        fn handle_activate(self, _msg: Activate) -> Self::HandleActivateFut {
+            ready(Ok(ServerState))
         }
     }
 
     impl Listening for ServerState {
-        type AfterPing = ReturnedState;
-        type HandlePingFut = impl Future<Output = Result<Self::AfterPing>>;
-        fn handle_ping(self, msg: Envelope<Ping>) -> Self::HandlePingFut {
-            async move {
-                let to = msg.from;
-                let from = self.rt.actor_name(self.act_id);
-                // TODO: This implementation should not know about PingProtocolMsg. It should be
-                // able to send Pong directly.
-                self.rt.send(to, from, PingProtocolMsg::Pong(Pong)).await?;
-                Ok(ReturnedState)
-            }
+        type HandlePingFut = impl Future<Output = Result<(End, PingReply)>>;
+        fn handle_ping(self, _msg: Ping) -> Self::HandlePingFut {
+            ready(Ok((End, PingReply)))
         }
     }
 
+    #[allow(dead_code)]
+    enum PingServerState {
+        ServerInit(ServerInitState),
+        Listening(ServerState),
+        End(End),
+    }
+
     async fn ping_server(
         counter: Arc<AtomicU8>,
         rt: &'static Runtime,
@@ -941,20 +933,22 @@ mod tests {
             PingServerState::Listening(state)
         };
         while let Some(envelope) = mailbox.recv().await {
-            let (msg, replier, from) = envelope.split();
+            let (msg, replier, _from) = envelope.split();
             match (state, msg) {
                 (PingServerState::Listening(listening_state), PingProtocolMsg::Ping(msg)) => {
-                    let envelope = Envelope::new(msg, replier, from);
-                    state = PingServerState::Returned(
-                        listening_state.handle_ping(envelope).await.unwrap(),
-                    );
+                    let (new_state, reply) = listening_state.handle_ping(msg).await.unwrap();
+                    state = PingServerState::End(new_state);
+                    if let Err(_) = replier.unwrap().send(PingProtocolMsg::PingReply(reply)) {
+                        panic!("Failed to send Ping reply.");
+                    }
                 }
-                _ => {
-                    log::error!("Ping protocol violation.");
-                    break;
+                (_prev_state, _) => {
+                    panic!("Ping protocol violation.");
+                    // A real implementation should assign the previous state and log the error.
+                    // state = prev_state;
                 }
             }
-            if let PingServerState::Returned(_) = state {
+            if let PingServerState::End(_) = state {
                 break;
             }
         }
@@ -965,30 +959,20 @@ mod tests {
         counter: Arc<AtomicU8>,
         server_name: ActorName,
         rt: &'static Runtime,
-        mut mailbox: mpsc::Receiver<Envelope<PingProtocolMsg>>,
+        _mailbox: mpsc::Receiver<Envelope<PingProtocolMsg>>,
         act_id: Uuid,
     ) {
-        let mut state = {
-            let init = ClientInitState { server_name };
-            let state = init.handle_activate(Activate { rt, act_id }).await.unwrap();
-            PingClientState::SentPing(state)
-        };
-        while let Some(envelope) = mailbox.recv().await {
-            let (msg, replier, from) = envelope.split();
-            match (state, msg) {
-                (PingClientState::SentPing(curr_state), PingProtocolMsg::Pong(msg)) => {
-                    let envelope = Envelope::new(msg, replier, from);
-                    state =
-                        PingClientState::Returned(curr_state.handle_pong(envelope).await.unwrap());
-                }
-                _ => {
-                    log::error!("Ping protocol violation.");
-                    break;
-                }
-            }
-            if let PingClientState::Returned(_) = state {
-                break;
-            }
+        let init = ClientInitState;
+        let (state, msg) = init.handle_activate(Activate { rt, act_id }).await.unwrap();
+        let from = rt.actor_name(act_id);
+        let reply = rt
+            .call(server_name, from, PingProtocolMsg::Ping(msg))
+            .await
+            .unwrap();
+        if let PingProtocolMsg::PingReply(msg) = reply {
+            state.handle_reply(msg).await.unwrap();
+        } else {
+            panic!("Incorrect message type sent in reply to Ping.");
         }
         counter.fetch_sub(1, Ordering::SeqCst);
     }
@@ -1017,10 +1001,29 @@ mod tests {
             while counter.load(Ordering::SeqCst) > 0 && Instant::now() < deadline {
                 tokio::time::sleep(Duration::from_millis(20)).await;
             }
+            // Check that both tasks finished successfully and we didn't just timeout.
+            assert_eq!(0, counter.load(Ordering::SeqCst));
 
             // TODO: Should actor which return be removed from the runtime automatically?
             RUNTIME.take(&server_name).await.unwrap();
             RUNTIME.take(&client_name).await.unwrap();
         });
     }
+
+    // Here's another protocol example. This is the Customer and Travel Agency protocol used as an
+    // example in the survey paper "Behavioral Types in Programming Languages."
+    //
+    // protocol! {
+    //     CustomerInit?Activate -> Choosing
+    //     AgencyInit?Activate -> Listening
+    //     Choosing?Choice -> Choosing, Listening!Query|Accept|Reject
+    //     Listening?Query -> Listening, Choosing!Query::Reply
+    //     Choosing?Query::Reply -> Choosing
+    //     Listening?Accept -> End, Choosing!Accept::Reply
+    //     Choosing?Accept::Reply -> End
+    //     Listening?Reject -> End, Choosing!Reject:Reply
+    //     Choosing?Reject::Reply -> End
+    // }
+    //
+    // The Choice message is from the runtime itself. It represents receiving input from a user.
 }

+ 1 - 1
crates/btmsg/Cargo.lock → crates/bttp/Cargo.lock

@@ -206,7 +206,7 @@ dependencies = [
 ]
 
 [[package]]
-name = "btmsg"
+name = "bttp"
 version = "0.1.0"
 dependencies = [
  "btlib",

+ 1 - 1
crates/btmsg/Cargo.toml → crates/bttp/Cargo.toml

@@ -1,5 +1,5 @@
 [package]
-name = "btmsg"
+name = "bttp"
 version = "0.1.0"
 edition = "2021"
 

+ 0 - 0
crates/btmsg/src/common.rs → crates/bttp/src/common.rs


+ 1 - 1
crates/btmsg/src/lib.rs → crates/bttp/src/lib.rs

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: AGPL-3.0-or-later
 //! This crate contains the implementation of the secure message transport `bttp`.
-//! 
+//!
 //! A `bttp` server is implemented by [Receiver] and a client by [Transmitter].
 #![feature(impl_trait_in_assoc_type)]
 

+ 0 - 0
crates/btmsg/src/receiver.rs → crates/bttp/src/receiver.rs


+ 0 - 0
crates/btmsg/src/serialization.rs → crates/bttp/src/serialization.rs


+ 0 - 0
crates/btmsg/src/tls.rs → crates/bttp/src/tls.rs


+ 0 - 0
crates/btmsg/src/transmitter.rs → crates/bttp/src/transmitter.rs


+ 1 - 1
crates/btmsg/tests/tests.rs → crates/bttp/tests/tests.rs

@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: AGPL-3.0-or-later
 #![feature(impl_trait_in_assoc_type)]
 
-use btmsg::*;
+use bttp::*;
 
 use btlib::{
     crypto::{ConcreteCreds, Creds, CredsPriv},

+ 1 - 1
website/content/en/_index.html

@@ -41,7 +41,7 @@ Information in the filesystem secured with confidentiality and integrity protect
 Key management is handled by the platform.
 {{% /blocks/feature %}}
 
-{{% blocks/feature icon="fa-solid fa-envelope" title="Message Passing" url="./rustdoc/btmsg/index.html" %}}
+{{% blocks/feature icon="fa-solid fa-envelope" title="Message Passing" url="./rustdoc/bttp/index.html" %}}
 Apps are implemented as message passing actors.
 Messages are addressed using filesystem paths.
 The platform uses mutual TLS authentication to ensure your messages are only seen by their intended

+ 12 - 0
website/deploy-linode.sh

@@ -0,0 +1,12 @@
+#!/bin/sh
+# Deploys the site using s3cmd.
+# Make sure 'website/public/' has been purged then updated  using 'docs/build-docs.sh'
+# before running this script.
+# If you don't purge 'website/public/', you may get unexpected results.
+# To display information about the website configuration on Linode run:
+# ```s3cmd ws-info s3://blocktree```
+# If you need to setup s3cmd checkout the documentation on Linode's website:
+# https://www.linode.com/docs/products/storage/object-storage/guides/s3cmd/
+# The guide for deploying a Hugo site is also useful:
+# https://www.linode.com/docs/guides/host-static-site-object-storage/
+s3cmd --no-mime-magic --acl-public --delete-removed --delete-after sync public/ s3://www.blocktree.systems

+ 3 - 11
website/deploy.sh

@@ -1,12 +1,4 @@
 #!/bin/sh
-# Deploys the site using s3cmd.
-# Make sure 'website/public/' has been purged then updated  using 'docs/build-docs.sh'
-# before running this script.
-# Note that you must purge 'website/public/' or you may get unexpected results.
-# To display information about the website configuration on Linode run:
-# ```s3cmd ws-info s3://blocktree```
-# If you need to setup s3cmd checkout the documentation on Linode's website:
-# https://www.linode.com/docs/products/storage/object-storage/guides/s3cmd/
-# The guide for deploying a Hugo site is also useful:
-# https://www.linode.com/docs/guides/host-static-site-object-storage/
-s3cmd --no-mime-magic --acl-public --delete-removed --delete-after sync public/ s3://www.blocktree.systems
+# Deploys the site to freja using rsync.
+echo Deploying to freja...
+rsync -rav --delete public/ freja:/srv/http/www.blocktree.systems/