diff --git a/src/ext.rs b/src/ext.rs index 4373569..5734df0 100644 --- a/src/ext.rs +++ b/src/ext.rs @@ -214,4 +214,5 @@ pub mod bytes } } -pub mod slice; +mod slice; +pub use slice::*; diff --git a/src/stream.rs b/src/stream.rs index aa10026..ebedbd2 100644 --- a/src/stream.rs +++ b/src/stream.rs @@ -20,6 +20,13 @@ pub trait AsyncStream: AsyncRead + AsyncWrite{} impl AsyncStream for T{} /// Inner rsa data for encrypted stream read+write halves +/// +/// # Exchange / mutation +/// For split streams, this becomes immutable. If exchange has not been performed by the combined stream before splitting, then it is impossible for the split Read and Write halves to form EncryptedRead and EncryptedWrite instances on top of themselves. +/// The stream must be re-joined, exchanged, and then split again in this case. +/// Therefore exchange should happen before the original stream is split at all. +/// +/// Only the combined stream can mutate this structure. The halves hold it behind an immutable shared reference. struct EncryptedStreamMeta { us: RsaPrivateKey, @@ -31,7 +38,11 @@ struct EncryptedStreamMeta pub struct WriteHalf where S: AsyncWrite { - meta: Arc, + /// Shared reference to the RSA data of the backing stream, held by both Write and Read halves. + /// + /// # Immutability of this metadata + /// Exchange can only happen on the combined Read+Write stream, so we don't need ayn mutability of `meta` here. Mutating `meta` happens only when it's owned by the combined stream (not in an `Arc`, which is only used to share it between the Read and Write half). + meta: Arc, #[pin] backing_write: S,//Box>, } @@ -40,8 +51,36 @@ where S: AsyncWrite pub struct EncryptedWriteHalf<'a, S> where S: AsyncWrite, { + /// Used to transform input `buf` into `self.crypt_buffer` before polling a write to `backing_write` with the newly filled `self.crypt_buffer`. + /// See below 2 fields. cipher: Crypter, - // Buffer for when `backing.poll_write()` returns `Pending`. + + /// Slice pointer of the input `buf` that corresponds to the transformed data in `crypt_buf`. + /// Used to check if a `Pending` write was cancelled, by comparing if the input `buf` slice of this next write is different from the last one (which's data is stored in this field after the poll becomes `Pending`.) + /// + /// # Usage + /// Before checking is `crypt_buffer` is empty and that we should re-poll the backing stream with it, we check the input `buf` against this value. + /// If they differ, then the `Pending` result from the last poll was discarded, and we clear the `crypt_buffer` and re-encrypt the new `buf` into it. + /// + /// After a `Pending` write to `backing_write`, a `SliceMeta` from the input `buf` is written to this field. + /// If it was *not* a `Pending` poll result, then this field is re-set to `Default` (an invalid `null` value). + /// + /// This compares **pointer** and **length** identity of the slice. (See `SliceMeta` for more information.) + /// Which is a faster method of determining if the buffer has changed than applying `Hash` to the whole buffer each time `poll_write` is called just to compare. + /// + /// # Initialised + /// Initialised as `Default` (`null`). + /// Will be `null` if `crypt_buffer` is empty (i.e. a non-`Pending` poll result). + crypt_buf_ptr: SliceMeta, + /// Buffer written to when encrypting the input `buf`. + /// + /// It is cleared after a `Ready` `poll_write()` on `backing_write`. + /// On a `Pending` write, this buffer is resized to only fit the transformed data written to it, and left as it is until the next call to `poll_write`. + /// + /// If the poll was not discarded (see above field), on the next call to this instance's `poll_write` we just immediatly re-poll `backing_write` with this buffer. + /// If it was disarded. We re-set this buffer and transform the new input `buf` into it as if the previous poll returned `Ready`. + /// + /// This exists so we don't have to transform the entire `buf` on every poll. We can just transform it once and then wait until it is `Ready` before discarding the data (`.empty()`) and allowing new data to fill it on the next, fresh `poll_write`. crypt_buffer: Vec, backing: &'a mut WriteHalf,