| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| |
| //! Ding-Sun RPC (dsrpc) for MesaTEE-SGX |
| //! |
| //! MesaTEE-SGX uses direct ECALL/OCALL interfaces on local, and |
| //! socket for remote. |
| |
| use serde::{de::DeserializeOwned, Serialize}; |
| use sgx_types::c_int; |
| use std::io::{self, Read, Write}; |
| use std::marker::PhantomData; |
| use std::net::TcpStream; |
| |
| use crate::rpc::{EnclaveService, RpcClient, RpcServer}; |
| #[cfg(not(feature = "mesalock_sgx"))] |
| use std::os::unix::io::FromRawFd; |
| |
| use crate::Result; |
| |
| // TODO: make the following comments into doc comments starting with `//!`. |
| // Sgx Socket RPC always depends on a socket which is always managed by fd. |
| // Before launching a Sgx Socket server, one should run a thread pool and |
| // properly run a "accept loop" like before. On accept, use `into_raw_fd` to |
| // pass the fd to the enclave. |
| // |
| // ``` |
| // println!("Running as server..."); |
| // let listener = TcpListener::bind("0.0.0.0:3443").unwrap(); |
| // match listener.accept() { |
| // Ok((socket, addr)) => { |
| // println!("new client from {:?}", addr); |
| // let mut retval = sgx_status_t::SGX_SUCCESS; |
| // let result = unsafe { |
| // run_server(enclave.geteid(), &mut retval, socket.into_raw_fd(), sign_type) |
| // }; |
| // match result { |
| // sgx_status_t::SGX_SUCCESS => { |
| // println!("ECALL success!"); |
| // }, |
| // _ => { |
| // println!("[-] ECALL Enclave Failed {}!", result.as_str()); |
| // return; |
| // } |
| // } |
| // } |
| // Err(e) => println!("couldn't get client: {:?}", e), |
| // } |
| //``` |
| // `into_raw_fd` consumes the stream. So socket would **not** be dropped on |
| // leaving its scope, and **not** triggers its dtor which closes the connection. |
| // In MesaTEE, the stream is re-constructed in an enclave by `from_raw_fd`. So |
| // the dtor is invoked when the in-enclave stream leaves its scope. Pairing |
| // the `into_raw_fd` and `from_raw_fd` is **required**. |
| pub struct PipeConfig { |
| fd: c_int, |
| } |
| |
| impl PipeConfig { |
| pub fn new(fd: c_int) -> Self { |
| PipeConfig { fd } |
| } |
| |
| pub fn get(&self) -> c_int { |
| self.fd |
| } |
| } |
| |
| pub type PipeClientConfig = PipeConfig; |
| |
| // Pipe stores the `TcpStream` created from the fd comes from Config. |
| pub struct Pipe<U, V, X> { |
| inner: TcpStream, |
| u: PhantomData<U>, |
| v: PhantomData<V>, |
| x: PhantomData<X>, |
| } |
| |
| impl<U, V, X> Read for Pipe<U, V, X> { |
| fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { |
| self.inner.read(buf) |
| } |
| } |
| |
| impl<U, V, X> Write for Pipe<U, V, X> { |
| fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
| self.inner.write(buf) |
| } |
| fn flush(&mut self) -> io::Result<()> { |
| self.inner.flush() |
| } |
| } |
| |
| impl<U, V, X> RpcServer<U, V, X> for Pipe<U, V, X> |
| where |
| U: DeserializeOwned + std::fmt::Debug, |
| V: Serialize + std::fmt::Debug, |
| X: EnclaveService<U, V>, |
| { |
| type Config = PipeConfig; |
| // type X = Box<EnclaveService<U, V>>; |
| // The `TcpStream::new()` function is different from Rust's design. |
| // The SGX version takes a fd as a input and return an `Option`. |
| fn start(config: &Self::Config) -> Result<Self> { |
| Ok(Pipe { |
| #[cfg(feature = "mesalock_sgx")] |
| inner: TcpStream::new(config.get())?, |
| #[cfg(not(feature = "mesalock_sgx"))] |
| inner: unsafe { TcpStream::from_raw_fd(config.get()) }, |
| u: PhantomData::<U>, |
| v: PhantomData::<V>, |
| x: PhantomData::<X>, |
| }) |
| } |
| |
| // Use default impplementation |
| // fn serve(&mut self, mut s: X) -> Result<()>; |
| } |
| |
| pub struct PipeClient<U, V> { |
| inner: TcpStream, |
| u: PhantomData<U>, |
| v: PhantomData<V>, |
| } |
| |
| impl<U, V> Read for PipeClient<U, V> { |
| fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { |
| self.inner.read(buf) |
| } |
| } |
| |
| impl<U, V> Write for PipeClient<U, V> { |
| fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
| self.inner.write(buf) |
| } |
| fn flush(&mut self) -> io::Result<()> { |
| self.inner.flush() |
| } |
| } |
| |
| impl<U, V> RpcClient<U, V> for PipeClient<U, V> |
| where |
| U: Serialize, |
| V: DeserializeOwned, |
| { |
| type Config = PipeClientConfig; |
| |
| fn open(config: Self::Config) -> Result<Self> { |
| Ok(PipeClient { |
| #[cfg(feature = "mesalock_sgx")] |
| inner: TcpStream::new(config.get())?, |
| #[cfg(not(feature = "mesalock_sgx"))] |
| inner: unsafe { TcpStream::from_raw_fd(config.get()) }, |
| u: PhantomData::<U>, |
| v: PhantomData::<V>, |
| }) |
| } |
| |
| // Use default implementation |
| // fn invoke(&mut self, input: U) -> Result<V>; |
| } |