Skip to main content

pallas_network/
multiplexer.rs

1//! A multiplexer of several mini-protocols through a single bearer
2
3use std::collections::HashMap;
4
5use byteorder::{ByteOrder, NetworkEndian};
6use pallas_codec::{Fragment, minicbor};
7use thiserror::Error;
8use tokio::io::{AsyncReadExt, AsyncWriteExt};
9use tokio::task::JoinHandle;
10use tokio::time::Instant;
11use tokio::{select, sync::mpsc::error::SendError};
12use tracing::{debug, error, trace, warn};
13
14type IOResult<T> = tokio::io::Result<T>;
15
16use tokio::net as tcp;
17
18#[cfg(unix)]
19use tokio::net as unix;
20
21#[cfg(windows)]
22use tokio::net::windows::named_pipe::NamedPipeClient;
23
24#[cfg(windows)]
25use tokio::io::{ReadHalf, WriteHalf};
26
27const HEADER_LEN: usize = 8;
28
29/// Wall-clock microseconds since the multiplexer started, used to stamp segments.
30pub type Timestamp = u32;
31
32/// Raw bytes of a single segment payload.
33pub type Payload = Vec<u8>;
34
35/// Mini-protocol channel identifier (16-bit).
36pub type Protocol = u16;
37
38/// 8-byte segment header that prefixes every multiplexed payload.
39#[derive(Debug)]
40pub struct Header {
41    /// Mini-protocol channel that owns the segment.
42    pub protocol: Protocol,
43    /// Wall-clock microseconds since the multiplexer started.
44    pub timestamp: Timestamp,
45    /// Length in bytes of the payload that follows this header.
46    pub payload_len: u16,
47}
48
49impl From<&[u8]> for Header {
50    fn from(value: &[u8]) -> Self {
51        let timestamp = NetworkEndian::read_u32(&value[0..4]);
52        let protocol = NetworkEndian::read_u16(&value[4..6]);
53        let payload_len = NetworkEndian::read_u16(&value[6..8]);
54
55        Self {
56            timestamp,
57            protocol,
58            payload_len,
59        }
60    }
61}
62
63impl From<Header> for [u8; 8] {
64    fn from(value: Header) -> Self {
65        let mut out = [0u8; 8];
66        NetworkEndian::write_u32(&mut out[0..4], value.timestamp);
67        NetworkEndian::write_u16(&mut out[4..6], value.protocol);
68        NetworkEndian::write_u16(&mut out[6..8], value.payload_len);
69
70        out
71    }
72}
73
74/// A single segment: header plus its raw payload bytes.
75pub struct Segment {
76    /// Segment header (protocol, timestamp, length).
77    pub header: Header,
78    /// Raw payload bytes.
79    pub payload: Payload,
80}
81
82/// Underlying transport carrying multiplexed segments.
83pub enum Bearer {
84    /// TCP socket (node-to-node).
85    Tcp(tcp::TcpStream),
86
87    /// Unix domain socket (node-to-client on Unix).
88    #[cfg(unix)]
89    Unix(unix::UnixStream),
90
91    /// Windows named pipe (node-to-client on Windows).
92    #[cfg(windows)]
93    NamedPipe(NamedPipeClient),
94}
95
96impl Bearer {
97    fn configure_tcp(stream: &tcp::TcpStream) -> IOResult<()> {
98        let sock_ref = socket2::SockRef::from(&stream);
99        let mut tcp_keepalive = socket2::TcpKeepalive::new();
100        tcp_keepalive = tcp_keepalive.with_time(tokio::time::Duration::from_secs(20));
101        tcp_keepalive = tcp_keepalive.with_interval(tokio::time::Duration::from_secs(20));
102        sock_ref.set_tcp_keepalive(&tcp_keepalive)?;
103        sock_ref.set_tcp_nodelay(true)?;
104        sock_ref.set_linger(Some(std::time::Duration::from_secs(0)))?;
105
106        Ok(())
107    }
108
109    /// Connect a TCP bearer to `addr`, applying the default keep-alive and
110    /// no-delay socket settings.
111    pub async fn connect_tcp(addr: impl tcp::ToSocketAddrs) -> Result<Self, tokio::io::Error> {
112        let stream = tcp::TcpStream::connect(addr).await?;
113        Self::configure_tcp(&stream)?;
114        Ok(Self::Tcp(stream))
115    }
116
117    /// Same as [`Self::connect_tcp`] but aborts with `TimedOut` after `timeout`.
118    pub async fn connect_tcp_timeout(
119        addr: impl tcp::ToSocketAddrs,
120        timeout: std::time::Duration,
121    ) -> IOResult<Self> {
122        select! {
123            result = Self::connect_tcp(addr) => result,
124            _ = tokio::time::sleep(timeout) => Err(tokio::io::Error::new(tokio::io::ErrorKind::TimedOut, "connect timeout")),
125        }
126    }
127
128    /// Accept the next TCP connection from `listener` as a bearer.
129    pub async fn accept_tcp(listener: &tcp::TcpListener) -> IOResult<(Self, std::net::SocketAddr)> {
130        let (stream, addr) = listener.accept().await?;
131        Self::configure_tcp(&stream)?;
132        Ok((Self::Tcp(stream), addr))
133    }
134
135    /// Connect a Unix-domain bearer to `path`.
136    #[cfg(unix)]
137    pub async fn connect_unix(path: impl AsRef<std::path::Path>) -> IOResult<Self> {
138        let stream = unix::UnixStream::connect(path).await?;
139        Ok(Self::Unix(stream))
140    }
141
142    /// Accept the next Unix-domain connection from `listener` as a bearer.
143    #[cfg(unix)]
144    pub async fn accept_unix(
145        listener: &unix::UnixListener,
146    ) -> IOResult<(Self, unix::unix::SocketAddr)> {
147        let (stream, addr) = listener.accept().await?;
148        Ok((Self::Unix(stream), addr))
149    }
150
151    /// Connect to a Windows named pipe as a bearer.
152    #[cfg(windows)]
153    pub fn connect_named_pipe(pipe_name: impl AsRef<std::ffi::OsStr>) -> IOResult<Self> {
154        let client = tokio::net::windows::named_pipe::ClientOptions::new().open(&pipe_name)?;
155        Ok(Self::NamedPipe(client))
156    }
157
158    /// Split the bearer into independent read and write halves.
159    pub fn into_split(self) -> (BearerReadHalf, BearerWriteHalf) {
160        match self {
161            Bearer::Tcp(x) => {
162                let (r, w) = x.into_split();
163                (BearerReadHalf::Tcp(r), BearerWriteHalf::Tcp(w))
164            }
165
166            #[cfg(unix)]
167            Bearer::Unix(x) => {
168                let (r, w) = x.into_split();
169                (BearerReadHalf::Unix(r), BearerWriteHalf::Unix(w))
170            }
171
172            #[cfg(windows)]
173            Bearer::NamedPipe(x) => {
174                let (read, write) = tokio::io::split(x);
175                let reader = BearerReadHalf::NamedPipe(read);
176                let writer = BearerWriteHalf::NamedPipe(write);
177
178                (reader, writer)
179            }
180        }
181    }
182}
183
184/// Read half of a split [`Bearer`].
185pub enum BearerReadHalf {
186    /// TCP read half.
187    Tcp(tcp::tcp::OwnedReadHalf),
188
189    /// Unix-domain read half.
190    #[cfg(unix)]
191    Unix(unix::unix::OwnedReadHalf),
192
193    /// Named-pipe read half (Windows).
194    #[cfg(windows)]
195    NamedPipe(ReadHalf<NamedPipeClient>),
196}
197
198impl BearerReadHalf {
199    async fn read_exact(&mut self, buf: &mut [u8]) -> IOResult<usize> {
200        match self {
201            BearerReadHalf::Tcp(x) => x.read_exact(buf).await,
202
203            #[cfg(unix)]
204            BearerReadHalf::Unix(x) => x.read_exact(buf).await,
205
206            #[cfg(windows)]
207            BearerReadHalf::NamedPipe(x) => x.read_exact(buf).await,
208        }
209    }
210}
211
212/// Write half of a split [`Bearer`].
213pub enum BearerWriteHalf {
214    /// TCP write half.
215    Tcp(tcp::tcp::OwnedWriteHalf),
216
217    /// Unix-domain write half.
218    #[cfg(unix)]
219    Unix(unix::unix::OwnedWriteHalf),
220
221    /// Named-pipe write half (Windows).
222    #[cfg(windows)]
223    NamedPipe(WriteHalf<NamedPipeClient>),
224}
225
226impl BearerWriteHalf {
227    async fn write_all(&mut self, buf: &[u8]) -> IOResult<()> {
228        match self {
229            Self::Tcp(x) => x.write_all(buf).await,
230
231            #[cfg(unix)]
232            Self::Unix(x) => x.write_all(buf).await,
233
234            #[cfg(windows)]
235            Self::NamedPipe(x) => x.write_all(buf).await,
236        }
237    }
238
239    async fn flush(&mut self) -> IOResult<()> {
240        match self {
241            Self::Tcp(x) => x.flush().await,
242
243            #[cfg(unix)]
244            Self::Unix(x) => x.flush().await,
245
246            #[cfg(windows)]
247            Self::NamedPipe(x) => x.flush().await,
248        }
249    }
250}
251
252/// Errors produced by the multiplexer and its agent channels.
253#[derive(Debug, Error)]
254pub enum Error {
255    /// The bearer returned EOF before a segment could be fully read.
256    #[error("no data available in bearer to complete segment")]
257    EmptyBearer,
258
259    /// Underlying bearer I/O error.
260    #[error("bearer I/O error")]
261    BearerIo(tokio::io::Error),
262
263    /// Failed to decode a message off the wire.
264    #[error("failure to encode channel message")]
265    Decoding(String),
266
267    /// Failed to encode a message for the wire.
268    #[error("failure to decode channel message")]
269    Encoding(String),
270
271    /// Agent could not push an outbound chunk to the muxer for `Protocol`.
272    #[error("agent failed to enqueue chunk for protocol {0}")]
273    AgentEnqueue(Protocol, Payload),
274
275    /// Agent could not pull an inbound chunk from the demuxer.
276    #[error("agent failed to dequeue chunk")]
277    AgentDequeue,
278
279    /// Demuxer could not deliver an inbound chunk to the subscribed agent.
280    #[error("plexer failed to dumux chunk for protocol {0}")]
281    PlexerDemux(Protocol, Payload),
282
283    /// Muxer could not write a chunk to the bearer.
284    #[error("plexer failed to mux chunk")]
285    PlexerMux,
286
287    /// Aborting the spawned muxer / demuxer tasks failed.
288    #[error("failure to abort the plexer threads")]
289    AbortFailure,
290}
291
292type EgressChannel = tokio::sync::mpsc::Sender<Payload>;
293type Egress = HashMap<Protocol, EgressChannel>;
294
295const EGRESS_MSG_QUEUE_BUFFER: usize = 100;
296
297/// Reads segments off the bearer and dispatches them to subscribed agents.
298pub struct Demuxer(BearerReadHalf, Egress);
299
300impl Demuxer {
301    /// Build a demuxer over the read half of a bearer.
302    pub fn new(bearer: BearerReadHalf) -> Self {
303        let egress = HashMap::new();
304        Self(bearer, egress)
305    }
306
307    /// Read the next segment off the bearer and return its `(protocol, payload)`.
308    pub async fn read_segment(&mut self) -> Result<(Protocol, Payload), Error> {
309        trace!("waiting for segment header");
310        let mut buf = vec![0u8; HEADER_LEN];
311        self.0.read_exact(&mut buf).await.map_err(Error::BearerIo)?;
312        let header = Header::from(buf.as_slice());
313
314        trace!("waiting for full segment");
315        let segment_size = header.payload_len as usize;
316        let mut buf = vec![0u8; segment_size];
317        self.0.read_exact(&mut buf).await.map_err(Error::BearerIo)?;
318
319        Ok((header.protocol, buf))
320    }
321
322    async fn demux(&mut self, protocol: Protocol, payload: Payload) -> Result<(), Error> {
323        let channel = self.1.get(&protocol);
324
325        if let Some(sender) = channel {
326            sender
327                .send(payload)
328                .await
329                .map_err(|err| Error::PlexerDemux(protocol, err.0))?;
330        } else {
331            warn!(protocol, "message for unregistered protocol");
332        }
333
334        Ok(())
335    }
336
337    /// Register an agent's interest in a protocol channel and return the
338    /// receiver it will pull inbound payloads from.
339    pub fn subscribe(&mut self, protocol: Protocol) -> tokio::sync::mpsc::Receiver<Payload> {
340        let (sender, recv) = tokio::sync::mpsc::channel(EGRESS_MSG_QUEUE_BUFFER);
341
342        // keep track of the sender
343        self.1.insert(protocol, sender);
344
345        // return the receiver for the agent
346        recv
347    }
348
349    /// Read one segment and dispatch it. Returns `Ok` after a single iteration.
350    pub async fn tick(&mut self) -> Result<(), Error> {
351        let (protocol, payload) = self.read_segment().await?;
352        trace!(protocol, "demux happening");
353        self.demux(protocol, payload).await
354    }
355
356    /// Run the demux loop until an error occurs.
357    pub async fn run(&mut self) -> Result<(), Error> {
358        loop {
359            if let Err(err) = self.tick().await {
360                break Err(err);
361            }
362        }
363    }
364}
365
366type Ingress = (
367    tokio::sync::mpsc::Sender<(Protocol, Payload)>,
368    tokio::sync::mpsc::Receiver<(Protocol, Payload)>,
369);
370
371type Clock = Instant;
372
373const INGRESS_MSG_QUEUE_BUFFER: usize = 100;
374
375/// Collects payloads from all agents and writes them to the bearer as segments.
376pub struct Muxer(BearerWriteHalf, Clock, Ingress);
377
378impl Muxer {
379    /// Build a muxer over the write half of a bearer.
380    pub fn new(bearer: BearerWriteHalf) -> Self {
381        let ingress = tokio::sync::mpsc::channel(INGRESS_MSG_QUEUE_BUFFER);
382        let clock = Instant::now();
383        Self(bearer, clock, ingress)
384    }
385
386    async fn write_segment(&mut self, protocol: u16, payload: &[u8]) -> Result<(), std::io::Error> {
387        let header = Header {
388            protocol,
389            timestamp: self.1.elapsed().as_micros() as u32,
390            payload_len: payload.len() as u16,
391        };
392
393        let buf: [u8; 8] = header.into();
394        self.0.write_all(&buf).await?;
395        self.0.write_all(payload).await?;
396
397        self.0.flush().await?;
398
399        Ok(())
400    }
401
402    /// Write a single `(protocol, payload)` pair to the bearer as one segment.
403    pub async fn mux(&mut self, msg: (Protocol, Payload)) -> Result<(), Error> {
404        self.write_segment(msg.0, &msg.1)
405            .await
406            .map_err(|_| Error::PlexerMux)?;
407
408        if tracing::event_enabled!(tracing::Level::TRACE) {
409            trace!(
410                protocol = msg.0,
411                data = hex::encode(&msg.1),
412                "write to bearer"
413            );
414        }
415
416        Ok(())
417    }
418
419    /// Clone the ingress sender so an agent can push outbound payloads here.
420    pub fn clone_sender(&self) -> tokio::sync::mpsc::Sender<(Protocol, Payload)> {
421        self.2.0.clone()
422    }
423
424    /// Take one queued message and write it as a segment.
425    pub async fn tick(&mut self) -> Result<(), Error> {
426        let msg = self.2.1.recv().await;
427
428        if let Some(x) = msg {
429            trace!(protocol = x.0, "mux happening");
430            self.mux(x).await?
431        }
432
433        Ok(())
434    }
435
436    /// Run the mux loop until an error occurs.
437    pub async fn run(&mut self) -> Result<(), Error> {
438        loop {
439            if let Err(err) = self.tick().await {
440                break Err(err);
441            }
442        }
443    }
444}
445
446type ToPlexerPort = tokio::sync::mpsc::Sender<(Protocol, Payload)>;
447type FromPlexerPort = tokio::sync::mpsc::Receiver<Payload>;
448
449/// Bidirectional channel exposed to a mini-protocol agent: send raw chunks out
450/// through the muxer and receive inbound chunks from the demuxer.
451pub struct AgentChannel {
452    protocol: Protocol,
453    to_plexer: ToPlexerPort,
454    from_plexer: FromPlexerPort,
455}
456
457impl AgentChannel {
458    fn for_client(
459        protocol: Protocol,
460        to_plexer: ToPlexerPort,
461        from_plexer: FromPlexerPort,
462    ) -> Self {
463        Self {
464            protocol,
465            from_plexer,
466            to_plexer,
467        }
468    }
469
470    fn for_server(
471        protocol: Protocol,
472        to_plexer: ToPlexerPort,
473        from_plexer: FromPlexerPort,
474    ) -> Self {
475        Self {
476            protocol,
477            from_plexer,
478            to_plexer,
479        }
480    }
481
482    /// Push an outbound chunk to the muxer for this protocol.
483    pub async fn enqueue_chunk(&mut self, chunk: Payload) -> Result<(), Error> {
484        self.to_plexer
485            .send((self.protocol, chunk))
486            .await
487            .map_err(|SendError((protocol, payload))| Error::AgentEnqueue(protocol, payload))
488    }
489
490    /// Pull the next inbound chunk for this protocol from the demuxer.
491    pub async fn dequeue_chunk(&mut self) -> Result<Payload, Error> {
492        self.from_plexer.recv().await.ok_or(Error::AgentDequeue)
493    }
494}
495
496/// Handle to the spawned muxer and demuxer tasks of a running [`Plexer`].
497pub struct RunningPlexer {
498    demuxer: JoinHandle<Result<(), Error>>,
499    muxer: JoinHandle<Result<(), Error>>,
500}
501
502impl RunningPlexer {
503    /// Abort the muxer and demuxer tasks.
504    pub async fn abort(self) {
505        self.demuxer.abort();
506        self.muxer.abort();
507    }
508}
509
510/// Pairs a [`Demuxer`] and a [`Muxer`] sharing a single bearer.
511pub struct Plexer {
512    demuxer: Demuxer,
513    muxer: Muxer,
514}
515
516impl Plexer {
517    /// Build a plexer over the given bearer.
518    pub fn new(bearer: Bearer) -> Self {
519        let (r, w) = bearer.into_split();
520
521        Self {
522            demuxer: Demuxer::new(r),
523            muxer: Muxer::new(w),
524        }
525    }
526
527    /// Open a client-side agent channel on the given protocol id.
528    pub fn subscribe_client(&mut self, protocol: Protocol) -> AgentChannel {
529        let to_plexer = self.muxer.clone_sender();
530        let from_plexer = self.demuxer.subscribe(protocol ^ 0x8000);
531        AgentChannel::for_client(protocol, to_plexer, from_plexer)
532    }
533
534    /// Open a server-side agent channel on the given protocol id.
535    pub fn subscribe_server(&mut self, protocol: Protocol) -> AgentChannel {
536        let to_plexer = self.muxer.clone_sender();
537        let from_plexer = self.demuxer.subscribe(protocol);
538        AgentChannel::for_server(protocol ^ 0x8000, to_plexer, from_plexer)
539    }
540
541    /// Spawn the muxer and demuxer loops on the current Tokio runtime and
542    /// return a handle for aborting them.
543    pub fn spawn(self) -> RunningPlexer {
544        let mut demuxer = self.demuxer;
545        let mut muxer = self.muxer;
546
547        let demuxer = tokio::spawn(async move { demuxer.run().await });
548        let muxer = tokio::spawn(async move { muxer.run().await });
549
550        RunningPlexer { demuxer, muxer }
551    }
552}
553
554/// Protocol value that defines max segment length
555pub const MAX_SEGMENT_PAYLOAD_LENGTH: usize = 65535;
556
557fn try_decode_message<M>(buffer: &mut Vec<u8>) -> Result<Option<M>, Error>
558where
559    M: Fragment,
560{
561    let mut decoder = minicbor::Decoder::new(buffer);
562    let maybe_msg = decoder.decode();
563
564    match maybe_msg {
565        Ok(msg) => {
566            let pos = decoder.position();
567            buffer.drain(0..pos);
568            Ok(Some(msg))
569        }
570        Err(err) if err.is_end_of_input() => Ok(None),
571        Err(err) => {
572            error!(?err);
573            trace!("{}", hex::encode(buffer));
574            Err(Error::Decoding(err.to_string()))
575        }
576    }
577}
578
579/// A channel abstraction to hide the complexity of partial payloads
580pub struct ChannelBuffer {
581    channel: AgentChannel,
582    temp: Vec<u8>,
583}
584
585impl ChannelBuffer {
586    /// Wrap a raw [`AgentChannel`] in a message-aware buffer.
587    pub fn new(channel: AgentChannel) -> Self {
588        Self {
589            channel,
590            temp: Vec::new(),
591        }
592    }
593
594    /// Enqueues a msg as a sequence payload chunks
595    pub async fn send_msg_chunks<M>(&mut self, msg: &M) -> Result<(), Error>
596    where
597        M: Fragment,
598    {
599        let mut payload = Vec::new();
600        minicbor::encode(msg, &mut payload).map_err(|err| Error::Encoding(err.to_string()))?;
601
602        let chunks = payload.chunks(MAX_SEGMENT_PAYLOAD_LENGTH);
603
604        for chunk in chunks {
605            self.channel.enqueue_chunk(Vec::from(chunk)).await?;
606        }
607
608        Ok(())
609    }
610
611    /// Reads from the channel until a complete message is found
612    pub async fn recv_full_msg<M>(&mut self) -> Result<M, Error>
613    where
614        M: Fragment,
615    {
616        trace!(len = self.temp.len(), "waiting for full message");
617
618        if !self.temp.is_empty() {
619            trace!("buffer has data from previous payload");
620
621            if let Some(msg) = try_decode_message::<M>(&mut self.temp)? {
622                debug!("decoding done");
623                return Ok(msg);
624            }
625        }
626
627        loop {
628            let chunk = self.channel.dequeue_chunk().await?;
629            self.temp.extend(chunk);
630
631            if let Some(msg) = try_decode_message::<M>(&mut self.temp)? {
632                debug!("decoding done");
633                return Ok(msg);
634            }
635
636            trace!("not enough data");
637        }
638    }
639
640    /// Discard the buffer and return the underlying raw channel.
641    pub fn unwrap(self) -> AgentChannel {
642        self.channel
643    }
644}
645
646impl From<AgentChannel> for ChannelBuffer {
647    fn from(channel: AgentChannel) -> Self {
648        ChannelBuffer::new(channel)
649    }
650}
651
652#[cfg(test)]
653mod tests {
654    use super::*;
655    use pallas_codec::minicbor;
656
657    #[tokio::test]
658    async fn multiple_messages_in_same_payload() {
659        let mut input = Vec::new();
660        let in_part1 = (1u8, 2u8, 3u8);
661        let in_part2 = (6u8, 5u8, 4u8);
662
663        minicbor::encode(in_part1, &mut input).unwrap();
664        minicbor::encode(in_part2, &mut input).unwrap();
665
666        let (to_plexer, _) = tokio::sync::mpsc::channel(100);
667        let (into_plexer, from_plexer) = tokio::sync::mpsc::channel(100);
668
669        let channel = AgentChannel::for_client(0, to_plexer, from_plexer);
670
671        into_plexer.send(input).await.unwrap();
672
673        let mut buf = ChannelBuffer::new(channel);
674
675        let out_part1 = buf.recv_full_msg::<(u8, u8, u8)>().await.unwrap();
676        let out_part2 = buf.recv_full_msg::<(u8, u8, u8)>().await.unwrap();
677
678        assert_eq!(in_part1, out_part1);
679        assert_eq!(in_part2, out_part2);
680    }
681
682    #[tokio::test]
683    async fn fragmented_message_in_multiple_payloads() {
684        let mut input = Vec::new();
685        let msg = (11u8, 12u8, 13u8, 14u8, 15u8, 16u8, 17u8);
686        minicbor::encode(msg, &mut input).unwrap();
687
688        let (to_plexer, _) = tokio::sync::mpsc::channel(100);
689        let (into_plexer, from_plexer) = tokio::sync::mpsc::channel(100);
690
691        let channel = AgentChannel::for_client(0, to_plexer, from_plexer);
692
693        while !input.is_empty() {
694            let chunk = Vec::from(input.drain(0..2).as_slice());
695            into_plexer.send(chunk).await.unwrap();
696        }
697
698        let mut buf = ChannelBuffer::new(channel);
699
700        let out_msg = buf
701            .recv_full_msg::<(u8, u8, u8, u8, u8, u8, u8)>()
702            .await
703            .unwrap();
704
705        assert_eq!(msg, out_msg);
706    }
707}