| 
					
				 | 
			
			
				@@ -0,0 +1,212 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//! Code which enables sending messages between processes in the blocktree system. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+pub use private::*; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+mod private { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    use crate::{crypto::rand_array, BlockPath, Result, Writecap}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    use btserde::{read_from, write_to}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    use os_pipe::{PipeReader, PipeWriter}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    use serde::{Deserialize, Serialize}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    use std::io::{Read, Write}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    use zerocopy::FromBytes; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    #[derive(PartialEq, Eq, Serialize, Deserialize)] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    pub enum MsgError {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    #[derive(Serialize, Deserialize)] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    pub enum MsgBody { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Success, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Fail(MsgError), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Ping, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Hello(Writecap), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Read { offset: u64 }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Write { offset: u64, data: Vec<u8> }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Custom(Vec<u8>), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    #[derive(Serialize, Deserialize)] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    pub struct Msg { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        from: BlockPath, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        to: BlockPath, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        id: u128, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        body: MsgBody, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    impl Msg { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        pub fn from(&self) -> &BlockPath { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            &self.from 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        pub fn to(&self) -> &BlockPath { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            &self.to 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        pub fn id(&self) -> u128 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            self.id 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        pub fn body(&self) -> &MsgBody { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            &self.body 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    #[derive(Serialize, Deserialize)] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    pub enum VerMsg { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        V0(Msg), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    pub trait Sender: Send { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fn send(&mut self, msg: Msg) -> Result<()>; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fn path(&self) -> &BlockPath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// Generates and returns a new message ID. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fn gen_id(&mut self) -> Result<u128> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            const LEN: usize = std::mem::size_of::<u128>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let bytes = rand_array::<LEN>()?; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let option = u128::read_from(bytes.as_slice()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Safety: because LEN == size_of::<u128>(), read_from should have returned Some. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Ok(option.unwrap()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// This is a convenience method which creates a new message, addresses it to the given 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// path, sets it as from this sender's path, generates a new ID for it, puts the given 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// body inside of it, and dispatches it with the `send` method. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fn send_new(&mut self, to: BlockPath, body: MsgBody) -> Result<()> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let id = self.gen_id()?; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let msg = Msg { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                to, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                from: self.path().to_owned(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                id, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                body, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            self.send(msg) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    pub trait Receiver { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fn receive(&mut self) -> Result<Msg>; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fn path(&self) -> &BlockPath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    pub trait Channel { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        type Sender: Sender; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        type Receiver: Receiver; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fn new(path: BlockPath) -> Result<(Self::Sender, Self::Receiver)>; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    pub trait Router { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fn add_sender<S: Sender>(&mut self, sender: S) -> Result<()>; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fn send(&mut self, msg: Msg) -> Result<()>; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    trait TryClone<O> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fn try_clone(&self) -> Result<O>; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    impl TryClone<PipeWriter> for PipeWriter { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fn try_clone(&self) -> Result<PipeWriter> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Ok(PipeWriter::try_clone(&self)?) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    pub struct WriteSender<W> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        write: W, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        path: BlockPath, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    impl<W: Write + Send> Sender for WriteSender<W> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fn send(&mut self, msg: Msg) -> Result<()> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Ok(write_to(&msg, &mut self.write)?) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fn path(&self) -> &BlockPath { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            &self.path 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    impl<W: Write + TryClone<W>> TryClone<WriteSender<W>> for WriteSender<W> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fn try_clone(&self) -> Result<WriteSender<W>> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Ok(WriteSender { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                write: self.write.try_clone()?, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                path: self.path.clone(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    pub struct ReadReceiver<R> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        read: R, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        path: BlockPath, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    impl<R: Read> Receiver for ReadReceiver<R> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fn receive(&mut self) -> Result<Msg> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Ok(read_from(&mut self.read)?) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fn path(&self) -> &BlockPath { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            &self.path 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    pub enum PipeChannel {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    impl Channel for PipeChannel { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        type Sender = WriteSender<PipeWriter>; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        type Receiver = ReadReceiver<PipeReader>; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fn new(path: BlockPath) -> Result<(Self::Sender, Self::Receiver)> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let (read, write) = os_pipe::pipe()?; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let sender = WriteSender { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                path: path.clone(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                write, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let receiver = ReadReceiver { path, read }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Ok((sender, receiver)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#[cfg(test)] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+mod tests { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    use crate::test_helpers; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    use super::*; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    #[test] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fn ping_pong_via_pipes() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let ping_path = test_helpers::make_path(vec!["ping"]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let (mut ping_sender, mut ping_receiver) = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            PipeChannel::new(ping_path.clone()).expect("failed to create a ping channel"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let pong_path = test_helpers::make_path(vec!["pong"]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let (mut pong_sender, mut pong_receiver) = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            PipeChannel::new(pong_path.clone()).expect("failed to create a pong channel"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let pong = std::thread::spawn(move || loop { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let msg = pong_receiver.receive().expect("pong receive failed"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            assert_eq!(pong_receiver.path(), msg.to()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            match msg.body() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                MsgBody::Ping => ping_sender 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    .send_new(ping_path.clone(), MsgBody::Success) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    .expect("send to ping failed"), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                MsgBody::Success => return, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                _ => panic!("unexpected message received by pong"), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let mut iter = 5; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        while iter > 0 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            pong_sender 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .send_new(pong_path.clone(), MsgBody::Ping) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .expect("send to pong failed"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let msg = ping_receiver.receive().expect("ping receive failed"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            assert_eq!(ping_receiver.path(), msg.to()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            match msg.body() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                MsgBody::Success => iter -= 1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                _ => panic!("unexpected message received by ping"), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        pong_sender 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .send_new(pong_path.clone(), MsgBody::Success) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .expect("send success to pong failed"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        pong.join().expect("join failed"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 |