carrier_pigeon/net.rs
1//! Networking things that are not specific to either transport.
2
3pub use crate::header::TcpHeader;
4use serde::{Deserialize, Serialize};
5use std::any::Any;
6use std::fmt::{Debug, Display, Formatter};
7use std::io;
8use std::io::Error;
9use std::ops::Deref;
10use std::time::Duration;
11
12/// The maximum safe message size that can be sent on udp,
13/// after taking off the possible overheads from the transport.
14///
15/// The data must be `MAX_SAFE_MESSAGE_SIZE` or less to be guaranteed to
16/// be deliverable on udp.
17/// [source](https://newbedev.com/what-is-the-largest-safe-udp-packet-size-on-the-internet/)
18pub const MAX_SAFE_MESSAGE_SIZE: usize = 504;
19
20/// An enum representing the 2 possible transports.
21///
22/// - TCP is reliable but slower.
23/// - UDP is unreliable but quicker.
24#[derive(Copy, Clone, Debug, Eq, PartialEq)]
25pub enum Transport {
26 TCP,
27 UDP,
28}
29
30/// The function used to deserialize a message.
31///
32/// fn(&[u8]) -> Result<Box<dyn Any + Send + Sync>, io::Error>
33pub type DeserFn = fn(&[u8]) -> Result<Box<dyn Any + Send + Sync>, io::Error>;
34/// The function used to serialize a message.
35///
36/// fn(&(dyn Any + Send + Sync)) -> Result<Vec<u8>, io::Error>
37pub type SerFn = fn(&(dyn Any + Send + Sync)) -> Result<Vec<u8>, io::Error>;
38
39#[derive(Debug)]
40/// An enum for the possible states of a connection.
41pub enum Status {
42 /// The connection is still live.
43 Connected,
44 /// The connection is closed because the peer disconnected by sending a disconnection message.
45 Disconnected(Box<dyn Any + Send + Sync>),
46 /// The connection is closed because we chose to close the connection.
47 Closed,
48 /// The connection was dropped without sending a disconnection message.
49 Dropped(Error),
50}
51
52impl Display for Status {
53 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
54 match self {
55 Self::Connected => write!(f, "Connected"),
56 Self::Disconnected(_) => write!(f, "Disconnected gracefully"),
57 Self::Closed => write!(f, "Closed"),
58 Self::Dropped(e) => write!(f, "Dropped with error {}", e),
59 }
60 }
61}
62
63impl Status {
64 /// Returns whether the status is [`Status::Connected`].
65 pub fn connected(&self) -> bool {
66 match self {
67 Status::Connected => true,
68 _ => false,
69 }
70 }
71
72 /// Turns this into an option with the disconnect message.
73 ///
74 /// ### Panics
75 /// Panics if the generic parameter `D` isn't the disconnect message type (the same `D` that
76 /// you passed into `MsgTable::build`).
77 pub fn disconnected<D: Any + Send + Sync>(&self) -> Option<&D> {
78 match self {
79 Status::Disconnected(d) => Some(d.downcast_ref().expect("The generic parameter `D` must be the disconnection message type (the same `D` that you passed into `MsgTable::build`).")),
80 _ => None,
81 }
82 }
83
84 /// Turns this into an option with the disconnect message.
85 pub fn disconnected_dyn(&self) -> Option<&Box<dyn Any + Send + Sync>> {
86 match self {
87 Status::Disconnected(d) => Some(d),
88 _ => None,
89 }
90 }
91
92 /// Turns this into an option with the drop error.
93 pub fn dropped(&self) -> Option<&Error> {
94 match self {
95 Status::Dropped(e) => Some(e),
96 _ => None,
97 }
98 }
99
100 /// Returns whether the status is [`Status::Closed`].
101 pub fn closed(&self) -> bool {
102 match self {
103 Status::Closed => true,
104 _ => false,
105 }
106 }
107}
108
109/// Message ID.
110pub type MId = usize;
111
112/// Connection ID.
113pub type CId = u32;
114
115/// A way to specify the valid [`CId`]s for an operation.
116#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
117pub enum CIdSpec {
118 /// Matches all [`CId`]s
119 All,
120 /// Matches no [`CId`]s.
121 None,
122 /// Matches all except the inner [`CId`]
123 Except(CId),
124 /// Matches only the inner [`CId`]
125 Only(CId),
126}
127
128impl CIdSpec {
129 /// Weather the given cid matches the pattern.
130 pub fn matches(&self, cid: CId) -> bool {
131 match self {
132 CIdSpec::All => true,
133 CIdSpec::None => false,
134 CIdSpec::Except(o) => cid != *o,
135 CIdSpec::Only(o) => cid == *o,
136 }
137 }
138
139 /// Checks if the `other` [`CIdSpec`] overlaps (shares at least on common [`CId`]).
140 pub fn overlaps(&self, other: CIdSpec) -> bool {
141 use CIdSpec::*;
142
143 match (*self, other) {
144 (None, _) => false,
145 (_, None) => false,
146 (All, _) => true,
147 (_, All) => true,
148
149 (Except(_), Except(_)) => true,
150 (Only(o1), Only(o2)) => o1 == o2,
151
152 (Only(only), Except(except)) => only != except,
153 (Except(except), Only(only)) => only != except,
154 }
155 }
156}
157
158/// Configuration for a client or server.
159///
160/// This needs to be defined before starting up the server.
161///
162/// Contains all configurable information about the server.
163#[derive(Copy, Clone, Eq, PartialEq, Debug, Serialize, Deserialize)]
164pub struct Config {
165 /// The timeout for handling new connections. The time to wait for a connection message
166 /// after establishing a tcp connection.
167 pub timeout: Duration,
168 /// The maximum number of connections that this can handle at the same time.
169 pub max_con_handle: usize,
170 /// The maximum message size in bytes. This is used for sizing the buffer for TCP and UDP.
171 /// Any attempts to send messages over this size will be discarded. Keep in mind, there is
172 /// still a soft limit for UDP messages (`MAX_SAFE_MSG_SIZE`)
173 pub max_msg_size: usize,
174}
175
176impl Config {
177 /// Creates a new Server configuration.
178 pub fn new(timeout: Duration, max_con_handle: usize, max_msg_size: usize) -> Self {
179 Config {
180 timeout,
181 max_con_handle,
182 max_msg_size,
183 }
184 }
185}
186
187impl Default for Config {
188 fn default() -> Self {
189 Config {
190 timeout: Duration::from_millis(5_000),
191 max_con_handle: 4,
192 max_msg_size: 2048,
193 }
194 }
195}
196
197/// An untyped network message containing the message content, along with the metadata associated.
198#[derive(Debug)]
199pub(crate) struct ErasedNetMsg {
200 /// The [`CId`] that the message was sent from.
201 pub(crate) cid: CId,
202 /// The timestamp that the message was sent in unix millis.
203 ///
204 /// This is always `Some` if the message was sent with UDP, and always `None` if sent with TCP.
205 pub(crate) time: Option<u32>,
206 /// The actual message.
207 pub(crate) msg: Box<dyn Any + Send + Sync>,
208}
209
210impl ErasedNetMsg {
211 /// Converts this to NetMsg, borrowed from this.
212 pub(crate) fn to_typed<T: Any + Send + Sync>(&self) -> Option<NetMsg<T>> {
213 let msg = self.msg.downcast_ref()?;
214 Some(NetMsg {
215 cid: self.cid,
216 time: self.time,
217 m: msg,
218 })
219 }
220}
221
222/// A network message containing the message content, along with the metadata associated.
223#[derive(Eq, PartialEq, Copy, Clone, Debug)]
224pub struct NetMsg<'n, T: Any + Send + Sync> {
225 /// The [`CId`] that the message was sent from.
226 pub cid: CId,
227 /// The timestamp that the message was sent in unix millis.
228 ///
229 /// This is always `Some` if the message was sent with UDP, and always `None` if sent with TCP.
230 pub time: Option<u32>,
231 /// The actual message.
232 ///
233 /// Borrowed from the client or server.
234 pub m: &'n T,
235}
236
237impl<'n, T: Any + Send + Sync> Deref for NetMsg<'n, T> {
238 type Target = T;
239
240 fn deref(&self) -> &Self::Target {
241 self.m
242 }
243}