Oregami
Repositories/oxedyne/fe2o3

oxedyne/fe2o3/fe2o3_shield/src/srv/msg/app.rs

4.8 KiB, 19 runs

created by r1870400018:20664, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1//! The application payload command: opaque bytes a library user carries over
2//! the SHIELD wire.
3//!
4//! Everything else the protocol sends is the protocol's own business -- the
5//! handshake stages, and eventually the session they establish. This is the
6//! one message type that carries something SHIELD does not read: a caller's
7//! bytes, chunked, proof-of-worked, signed and reassembled exactly as any
8//! other message is, and handed back whole at the other end.
9//!
10//! An exchange is a request and at most one reply, correlated by the message
11//! identifier in the packet header rather than by a second connection. That is
12//! not a stylistic choice: a peer behind a household router can send a
13//! datagram and hear the answer on the socket it sent from, and cannot be sent
14//! one out of the blue. A reply that needed its own path is a reply half the
15//! network never receives.
16//!
17//! What this does *not* do is establish a session or encrypt anything. The
18//! packet signature says the packet was signed by the key travelling with it,
19//! and nothing more; whatever identity the payload has is the caller's to put
20//! inside it and check at the other end.
21
22use crate::srv::{
23 constant,
24 msg::{
25 core::{
26 IdentifiedMessage,
27 IdTypes,
28 MsgFmt,
29 MsgIds,
30 MsgPow,
31 MsgType,
32 },
33 encode::ShieldCommand,
34 },
35};
36
37use oxedyne_fe2o3_core::{
38 prelude::*,
39 byte::IntoBytes,
40 mem::Extract,
41};
42use oxedyne_fe2o3_jdat::prelude::*;
43use oxedyne_fe2o3_syntax::msg::{
44 Msg,
45 MsgCmd,
46};
47
48
49#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
50pub enum AppMsgKind {
51 #[default]
52 Request,
53 Reply,
54}
55
56impl AppMsgKind {
57 pub fn typ(&self) -> MsgType {
58 match self {
59 Self::Request => constant::MSG_TYPE_APP_REQUEST,
60 Self::Reply => constant::MSG_TYPE_APP_REPLY,
61 }
62 }
63
64 pub fn name(&self) -> &'static str {
65 match self {
66 Self::Request => constant::MSG_CMD_APP_REQUEST,
67 Self::Reply => constant::MSG_CMD_APP_REPLY,
68 }
69 }
70
71 pub fn from_msg_type(typ: MsgType) -> Option<Self> {
72 match typ {
73 constant::MSG_TYPE_APP_REQUEST => Some(Self::Request),
74 constant::MSG_TYPE_APP_REPLY => Some(Self::Reply),
75 _ => None,
76 }
77 }
78
79 pub fn from_cmd_name(name: &str) -> Option<Self> {
80 match name {
81 constant::MSG_CMD_APP_REQUEST => Some(Self::Request),
82 constant::MSG_CMD_APP_REPLY => Some(Self::Reply),
83 _ => None,
84 }
85 }
86}
87
88#[derive(Clone, Debug, Default)]
89pub struct AppMsg<
90 const ML: usize,
91 const SL: usize,
92 const UL: usize,
93 ID: IdTypes<ML, SL, UL>,
94> {
95 pub fmt: MsgFmt,
96 pub pow: MsgPow,
97 pub mid: MsgIds<SL, UL, ID::S, ID::U>,
98 // Command-specific
99 pub kind: AppMsgKind,
100 pub payload: Vec<u8>,
101}
102
103impl<
104 const ML: usize,
105 const SL: usize,
106 const UL: usize,
107 ID: IdTypes<ML, SL, UL>,
108>
109 IntoBytes for AppMsg<ML, SL, UL, ID>
110{
111 fn into_bytes(self, buf: Vec<u8>) -> Outcome<Vec<u8>> {
112 res!(self.construct()).into_bytes(buf)
113 }
114}
115
116impl<
117 const ML: usize,
118 const SL: usize,
119 const UL: usize,
120 ID: IdTypes<ML, SL, UL>,
121>
122 IdentifiedMessage for AppMsg<ML, SL, UL, ID>
123{
124 fn typ(&self) -> MsgType { self.kind.typ() }
125 fn name(&self) -> &'static str { self.kind.name() }
126}
127
128impl<
129 const ML: usize,
130 const SL: usize,
131 const UL: usize,
132 ID: IdTypes<ML, SL, UL>,
133>
134 ShieldCommand<ML, SL, UL, ID> for AppMsg<ML, SL, UL, ID>
135{
136 fn fmt(&self) -> &MsgFmt { &self.fmt }
137 fn pow(&self) -> &MsgPow { &self.pow }
138 fn mid(&self) -> &MsgIds<SL, UL, ID::S, ID::U> { &self.mid }
139
140 fn inc_sigpk(&self) -> bool { true }
141
142 fn pad_last(&self) -> bool { false }
143
144 fn construct(self) -> Outcome<Msg> {
145 let name = self.name();
146 let mut msg = Msg::new(self.syntax().clone()); // cloning ref
147 msg.set_encoding(*self.encoding());
148 if let Some(sid) = self.sid_opt() {
149 msg = res!(msg.add_arg_val("-s", Some(res!(sid.to_dat()))));
150 }
151 msg = res!(msg.add_arg_val("-zb", Some(dat!(self.pow_zbits()))));
152 let mut mcmd = res!(msg.new_cmd(name));
153 mcmd = res!(mcmd.add_arg_val("-p", Some(Dat::BU64(self.payload))));
154 msg = res!(msg.add_cmd(mcmd));
155 res!(msg.validate());
156 Ok(msg)
157 }
158
159 fn deconstruct(&mut self, mcmd: &mut MsgCmd) -> Outcome<()> {
160 self.payload = match mcmd.get_arg_vals_mut("-p") {
161 Some(vals) => try_extract_dat!(vals[0].extract(), BU64),
162 None => return Err(err!(
163 "An application message carries no payload argument (-p).";
164 Invalid, Input, Missing)),
165 };
166 Ok(())
167 }
168}
169
170#[derive(Clone, Debug)]
171pub enum Answer {
172 Nothing,
173 Reply(Vec<u8>),
174}