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
// 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 connect;
pub mod encrypted;
pub mod unencrypted;
#[cfg(feature = "zmq")]
pub mod zeromq;

use std::io::ErrorKind;

#[cfg(feature = "zmq")]
pub use zeromq::{ZmqConnectionType, ZmqSocketType};

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(zeromq::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 Noise_XK length header
    NoNoiseHeader,

    /// 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 DuplexConnection {
    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 if a tcp connection is used.
    ///
    /// # 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`] and a tcp connection is used
    // 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.
    ///
    /// # 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
    ///
    /// # 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")
    }
}