1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
// LNP/BP Core Library implementing LNPBP specifications & standards
// Written in 2020 by
// Dr. Maxim Orlovsky <orlovsky@pandoracore.com>
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the MIT License
// along with this software.
// If not, see <https://opensource.org/licenses/MIT>.
//! LNP transport level works with framed messages of defined size. This
//! messages can be put into different underlying transport protocols, including
//! streaming protocols (like TCP), or overlaid over application-level
//! protocols like HTTP, Websockets, SMTP (for high-latency communication
//! networks). Current mod implements such overlays and provides TCP with
//! the required framing functionality (this variant is called FTCP). It also
//! integrates with ZMQ such that the upper level can abstract for a particular
//! transport protocol used.
pub mod brontide;
pub mod ftcp;
pub mod generic;
pub mod socket_addr;
pub mod websocket;
#[cfg(feature = "zmq")]
pub mod zmqsocket;
use std::io::ErrorKind;
pub use socket_addr::{FramingProtocol, LocalSocketAddr, RemoteSocketAddr};
#[cfg(feature = "zmq")]
pub use zmqsocket::{ZmqSocketAddr, ZmqType, ZMQ_CONTEXT};
use crate::session::HandshakeError;
/// Maximum size of the transport frame; chosen in compliance with LN specs
pub const MAX_FRAME_SIZE: usize =
FRAME_PREFIX_SIZE + MAX_FRAME_PAYLOAD_SIZE + FRAME_SUFFIX_SIZE;
/// Size of the frame prefix which is not included into payload size, consisting
/// of the 2-bytes message size data and 16-byte MAC of the payload length
pub const FRAME_PREFIX_SIZE: usize = 2 + 16;
/// Size of the frame suffix represented by a 16-byte MAC of the frame payload
pub const FRAME_SUFFIX_SIZE: usize = 16;
/// Maximum size of the frame payload which may be expressed by two bytes
pub const MAX_FRAME_PAYLOAD_SIZE: usize = 0xFFFF;
/// Transport protocol-level errors
#[derive(Clone, PartialEq, Eq, Hash, Debug, Display, Error, From)]
#[display(doc_comments)]
pub enum Error {
/// I/O socket error, generated by underlying socket implementation
/// (POSIX or TCP). Error type is {_0:?}
#[from]
SocketIo(std::io::ErrorKind),
/// ZMQ socket error, type {0}
#[cfg(feature = "zmq")]
Zmq(zmqsocket::Error),
/// service is offline or not responding
ServiceOffline,
/// the function requires that the connecting socket must be present on the
/// the same machine, i.e. it should be a raw POSIX socket or IPC & Inproc
/// ZMQ socket
RequiresLocalSocket,
/// the provided frame size ({0}) exceeds frame size limit of
/// MAX_FRAME_SIZE bytes
OversizedFrame(usize),
/// frame size {0} is less than minimal (34 bytes)
FrameTooSmall(usize),
/// frame structure broken: {0}
FrameBroken(&'static str),
/// read length {actual} is not equal to the expected length {expected}
InvalidLength { expected: u16, actual: u16 },
/// message does not contain Brontide length header
NoBrontideHeader,
/// connections over Tor protocol are not yet supported
TorNotSupportedYet,
/// read or write attempt exceeded socket timeout
TimedOut,
/// failed Noise_XK handshake due to {0}
#[from]
Handshake(HandshakeError),
/// use of {0} API requires compilatino with `keygen` feature enabled
KeygenFeatureRequired(&'static str),
}
impl From<std::io::Error> for Error {
fn from(err: std::io::Error) -> Error {
match err.kind() {
ErrorKind::WouldBlock | ErrorKind::TimedOut => Error::TimedOut,
kind => Error::SocketIo(kind),
}
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct RoutedFrame {
/// Previous hop where we received message from during the routing
pub hop: Vec<u8>,
/// Originator of the message
pub src: Vec<u8>,
/// Destination of the message
pub dst: Vec<u8>,
/// Message itself
pub msg: Vec<u8>,
}
/// Marker trait for types that can provide a concrete implementation for both
/// frame parser implementing [`RecvFrame`] and frame composer implementing
/// [`SendFrame`]. These types must also implement [`amplify::Bipolar`], i.e.
/// they must be splittable into the receiving and sending half-types.
pub trait Duplex {
fn as_receiver(&mut self) -> &mut dyn RecvFrame;
fn as_sender(&mut self) -> &mut dyn SendFrame;
fn split(self) -> (Box<dyn RecvFrame + Send>, Box<dyn SendFrame + Send>);
}
/// Frame receiving type which is able to parse raw data (streamed or framed by
/// an underlying overlaid protocol such as ZMQ, HTTP, Websocket).
pub trait RecvFrame {
/// Receive a single frame of data structured as a byte string. The frame
/// contains LNP framing prefix, which is used by upstream session-level
/// protocols.
///
/// # Errors
/// Returns only [`Error::SocketIo`] if the overlaid protocol errors with
/// I/O error type
fn recv_frame(&mut self) -> Result<Vec<u8>, Error>;
/// Try to receive `len` number of bytes and pack them as a frame.
/// The actual amount of bytes received may differ for some protocols,
/// like ZMQ, so the function should be used with caution!
///
/// # Errors
/// Returns only [`Error::SocketIo`] if the overlaid protocol errors with
/// I/O error type
fn recv_raw(&mut self, len: usize) -> Result<Vec<u8>, Error>;
/// Receive frame like with [`RecvFrame::recv_frame`], but only originating
/// from the specified remote address.
///
/// # Returns
/// Tuple, consisting of two byte strings:
/// * Received frame
/// * Source of the frame (i.e. some id of the remote node that sent this
/// frame). The id is specific for the underlying overlaid protocol.
///
/// # Errors
/// Returns only [`Error::SocketIo`] if the overlaid protocol errors with
/// I/O error type
///
/// # Panics
/// Default implementation panics, since most of the framing protocols do
/// not support multipeer sockets and [`RecvFrame::recv_frame`] must be
/// used instead (currently only ZMQ-based connections support this
/// operation)
fn recv_routed(&mut self) -> Result<RoutedFrame, Error> {
// We panic here because this is a program architecture design
// error and developer must be notified about it; the program using
// this pattern can't work
panic!("Multipeer sockets are not possible with the chosen transport")
}
}
/// Frame sending type which is able to compose frame with a given raw data and
/// send it via an underlying overlaid protocol such as ZMQ, HTTP, Websocket.
pub trait SendFrame {
/// Sends a single frame of data structured as a byte string. The frame must
/// already contain LNP framing prefix with size data. The function must
/// check that the provided data frame length is below the limit defined
/// with [`MAX_FRAME_SIZE`] constant.
///
/// # Returns
/// In case of success, number of bytes send (NB: this is larger than the
/// message payload size and is equal to the size of the provided `frame`
/// argument)
///
/// # Errors
/// * [`Error::SocketIo`] if the overlaid protocol errors with I/O error
/// type
/// * [`Error::OversizedFrame`] if the provided data length exceeds
/// [`MAX_FRAME_SIZE`]
// We can't use `impl AsRev<[u8]>` here since with it the trait can't be
// made into an object
fn send_frame(&mut self, frame: &[u8]) -> Result<usize, Error>;
/// Sends a single frame of data structured as a byte string. The frame must
/// already contain LNP framing prefix with size data.
///
/// NB: Unlike [`SendFrame::send_frame`], this function **does not** check
/// that the provided data frame length is below the limit defined with
/// [`MAX_FRAME_SIZE`] constant.
///
/// # Returns
/// In case of success, number of bytes send (NB: this is larger than the
/// message payload size and is equal to the size of the provided
/// `raw_frame` argument)
///
/// # Errors
/// * [`Error::SocketIo`] if the overlaid protocol errors with I/O error
/// type
fn send_raw(&mut self, raw_frame: &[u8]) -> Result<usize, Error>;
/// Sends a single frame of data structured as a byte string to a specific
/// receiver with `remote_id`. Function works like [`RecvFrame::recv_frame`]
/// and is used for the underlying protocols supporting multipeer
/// connectivity. The frame must already contain LNP framing prefix with
/// size data. The function must check that the provided data frame
/// length is below the limit defined with [`MAX_FRAME_SIZE`] constant.
///
/// # Returns
/// In case of success, number of bytes send (NB: this is larger than the
/// message payload size and is equal to the size of the provided `frame`
/// argument)
///
/// # Errors
/// * [`Error::SocketIo`] if the overlaid protocol errors with I/O error
/// type
/// * [`Error::OversizedFrame`] if the provided data length exceeds
/// [`MAX_FRAME_SIZE`]
///
/// # Panics
/// Default implementation panics, since the most of framing protocols do
/// not support multipeer sockets and [`SendFrame::send_frame`] must be
/// used instead (currently only ZMQ-based connections support this
/// operation)
#[allow(dead_code)]
fn send_routed(
&mut self,
_source: &[u8],
_route: &[u8],
_address: &[u8],
_data: &[u8],
) -> Result<usize, Error> {
// We panic here because this is a program architecture design
// error and developer must be notified about it; the program using
// this pattern can't work
panic!("Multipeer sockets are not possible with the chosen transport")
}
}
/// Async version of [`RecvFrame`] trait
#[cfg(feature = "async")]
#[async_trait]
pub trait AsyncRecvFrame {
/// Async version of [`RecvFrame::recv_frame`]; pls refer to it for the
/// function documentation
async fn async_recv_frame(&mut self) -> Result<Vec<u8>, Error>;
/// Async version of [`RecvFrame::recv_raw`]; pls refer to it for the
/// function documentation
async fn async_recv_raw(&mut self, len: usize) -> Result<Vec<u8>, Error>;
/// Async version of [`RecvFrame::recv_from`]; pls refer to it for the
/// function documentation
async fn async_recv_from(&mut self) -> Result<(Vec<u8>, Vec<u8>), Error> {
// We panic here because this is a program architecture design
// error and developer must be notified about it; the program using
// this pattern can't work
panic!("Multipeer sockets are not possible with the chosen transport")
}
}
/// Async version of [`SendFrame`] trait
#[cfg(feature = "async")]
#[async_trait]
pub trait AsyncSendFrame {
/// Async version of [`SendFrame::send_frame`]; pls refer to it for the
/// function documentation
async fn async_send_frame(&mut self, frame: &[u8]) -> Result<usize, Error>;
/// Async version of [`RecvFrame::send_raw`]; pls refer to it for the
/// function documentation
async fn async_send_raw(
&mut self,
raw_frame: &[u8],
) -> Result<usize, Error>;
/// Async version of [`RecvFrame::send_to`]; pls refer to it for the
/// function documentation
async fn async_send_to(
&mut self,
remote_id: &[u8],
frame: &[u8],
) -> Result<usize, Error> {
// We panic here because this is a program architecture design
// error and developer must be notified about it; the program using
// this pattern can't work
panic!("Multipeer sockets are not possible with the chosen transport")
}
}