use super::msg::{Body, empty_body};
use amplify::Getters;
use caret::caret_int;
use derive_deftly::Deftly;
use rand::{CryptoRng, Rng, RngCore};
use tor_bytes::{EncodeResult, Error, Readable, Reader, Result, Writeable, Writer};
use tor_llcrypto::util::ct::CtByteArray;
use tor_memquota::derive_deftly_template_HasMemoryCost;
const CONFLUX_LINK_VERSION: u8 = 1;
const V1_LINK_NONCE_LEN: usize = 32;
macro_rules! impl_link_wrapper {
($wrapper:ty) => {
impl $wrapper {
pub fn version(&self) -> u8 {
self.0.version
}
pub fn payload(&self) -> &V1LinkPayload {
&self.0.payload
}
}
};
}
#[derive(Debug, Clone, Deftly)]
#[derive_deftly(HasMemoryCost)]
pub struct ConfluxLink(Link);
impl ConfluxLink {
pub fn new(payload: V1LinkPayload) -> Self {
let link = Link {
version: CONFLUX_LINK_VERSION,
payload,
};
Self(link)
}
}
impl_link_wrapper!(ConfluxLink);
impl Body for ConfluxLink {
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
Link::decode_from_reader(r).map(Self)
}
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
self.0.encode_onto(w)
}
}
#[derive(Debug, Clone, Deftly)]
#[derive_deftly(HasMemoryCost)]
pub struct ConfluxLinked(Link);
impl ConfluxLinked {
pub fn new(payload: V1LinkPayload) -> Self {
let link = Link {
version: CONFLUX_LINK_VERSION,
payload,
};
Self(link)
}
}
impl_link_wrapper!(ConfluxLinked);
impl Body for ConfluxLinked {
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
Link::decode_from_reader(r).map(Self)
}
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
self.0.encode_onto(w)
}
}
#[derive(Debug, Clone, Deftly)]
#[derive_deftly(HasMemoryCost)]
struct Link {
version: u8,
payload: V1LinkPayload,
}
#[derive(Debug, Clone, Copy, Deftly, PartialEq, Eq)]
#[derive_deftly(HasMemoryCost)]
pub struct V1Nonce(CtByteArray<V1_LINK_NONCE_LEN>);
impl V1Nonce {
pub fn new<R: RngCore + CryptoRng>(rng: &mut R) -> V1Nonce {
let mut nonce = [0_u8; V1_LINK_NONCE_LEN];
rng.fill(&mut nonce[..]);
Self(nonce.into())
}
}
impl Readable for V1Nonce {
fn take_from(r: &mut Reader<'_>) -> Result<Self> {
Ok(Self(Readable::take_from(r)?))
}
}
impl Writeable for V1Nonce {
fn write_onto<W: Writer + ?Sized>(&self, w: &mut W) -> EncodeResult<()> {
self.0.write_onto(w)
}
}
#[derive(Debug, Clone, Deftly, Getters)]
#[derive_deftly(HasMemoryCost)]
pub struct V1LinkPayload {
nonce: V1Nonce,
last_seqno_sent: u64,
last_seqno_recv: u64,
desired_ux: V1DesiredUx,
}
impl V1LinkPayload {
pub fn new(nonce: V1Nonce, desired_ux: V1DesiredUx) -> Self {
Self {
nonce,
last_seqno_sent: 0,
last_seqno_recv: 0,
desired_ux,
}
}
pub fn set_last_seqno_sent(&mut self, seqno: u64) {
self.last_seqno_sent = seqno;
}
pub fn set_last_seqno_recv(&mut self, seqno: u64) {
self.last_seqno_recv = seqno;
}
}
caret_int! {
#[derive(Deftly)]
#[derive_deftly(HasMemoryCost)]
pub struct V1DesiredUx(u8) {
NO_OPINION = 0x0,
MIN_LATENCY = 0x1,
LOW_MEM_LATENCY = 0x2,
HIGH_THROUGHPUT = 0x3,
LOW_MEM_THROUGHPUT = 0x4,
}
}
impl Body for Link {
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
let version = r.take_u8()?;
if version != CONFLUX_LINK_VERSION {
return Err(Error::InvalidMessage(
"Unrecognized CONFLUX_LINK/CONFLUX_LINKED version.".into(),
));
}
let payload = V1LinkPayload::decode_from_reader(r)?;
Ok(Self { version, payload })
}
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write(&self.version)?;
self.payload.encode_onto(w)?;
Ok(())
}
}
impl Body for V1LinkPayload {
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
let nonce = r.extract()?;
let last_seqno_sent = r.take_u64()?;
let last_seqno_recv = r.take_u64()?;
let desired_ux = r.take_u8()?.into();
Ok(V1LinkPayload {
nonce,
last_seqno_sent,
last_seqno_recv,
desired_ux,
})
}
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
let V1LinkPayload {
nonce,
last_seqno_sent,
last_seqno_recv,
desired_ux,
} = self;
w.write(&nonce)?;
w.write_u64(last_seqno_sent);
w.write_u64(last_seqno_recv);
w.write_u8(desired_ux.into());
Ok(())
}
}
#[derive(Clone, Debug, Deftly, Getters)]
#[derive_deftly(HasMemoryCost)]
pub struct ConfluxSwitch {
#[getter(as_copy)]
seqno: u32,
}
impl ConfluxSwitch {
pub fn new(seqno: u32) -> Self {
Self { seqno }
}
}
impl Body for ConfluxSwitch {
fn decode_from_reader(r: &mut Reader<'_>) -> Result<Self> {
let seqno = r.take_u32()?;
Ok(Self { seqno })
}
fn encode_onto<W: Writer + ?Sized>(self, w: &mut W) -> EncodeResult<()> {
w.write(&self.seqno)?;
Ok(())
}
}
empty_body! {
pub struct ConfluxLinkedAck {}
}