Skip to main content

enclave_runner/stream_router/
mod.rs

1/* Copyright (c) Fortanix, Inc.
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7use std::cell::RefCell;
8use std::future::Future;
9use std::mem;
10use std::io::Result as IoResult;
11use std::pin::{pin, Pin};
12use std::task::{Context, Poll};
13
14use tokio::io::{AsyncReadExt, AsyncRead, AsyncWrite};
15
16mod os;
17pub use self::os::OsStreamRouter;
18
19pub trait AsyncStream: AsyncRead + AsyncWrite + 'static + Send + Sync {
20    fn poll_read_alloc(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<IoResult<Vec<u8>>> {
21        fn empty_buf() -> Vec<u8> {
22            Vec::with_capacity(8192)
23        }
24
25        thread_local! {
26            static BUF: RefCell<Vec<u8>> = RefCell::new(empty_buf());
27        }
28
29        BUF.with_borrow_mut(|buf| {
30            pin!(self.read_buf(buf)).poll(cx)
31                .map_ok(|len| match len {
32                    // read_buf() left buffer empty. Re-use allocation for next call
33                    0 => Vec::new(),
34                    // read_buf() put some data in the buffer. Return it and allocate a new one
35                    _ => mem::replace(buf, empty_buf()),
36                })
37        })
38    }
39}
40
41impl<S: AsyncRead + AsyncWrite + Sync + Send + 'static> AsyncStream for S {}
42
43pub trait AsyncListener: 'static + Send {
44    /// Serve an accept call by the enclave, for the bound listener `self`.
45    ///
46    /// The enclave may optionally request the local or peer addresses be 
47    /// returned in `local_addr` or `peer_addr`, respectively. If `local_addr` 
48    /// and/or `peer_addr` are not [`None`], they will point to an empty 
49    /// [`String`]. On success, user-space can fill in the strings as 
50    /// appropriate.
51    ///
52    /// The enclave must not make any security decisions based on the local 
53    /// address received.
54    fn poll_accept(
55        self: Pin<&mut Self>,
56        cx: &mut Context,
57        local_addr: Option<&mut String>,
58        peer_addr: Option<&mut String>,
59    ) -> Poll<tokio::io::Result<Box<dyn AsyncStream>>>;
60}
61
62pub trait StreamRouter {
63    /// Obtain a list of basic streams that are available to every enclave.
64    /// Enclaves access these streams by numeric index in a platform-dependent
65    /// way.
66    ///
67    /// Implementers must ensure that the streams returned by any call to this
68    /// function represent the same streams as those returned by any other call.
69    /// Synchronization must be taken care of by the implementation.
70    ///
71    /// Most enclaves expect that the first elements are those returned by an 
72    /// instance of [`OsStreamRouter`].
73    fn basic_streams(&self) -> Vec<Box<dyn AsyncStream>>;
74
75    /// Serve a connect call by the enclave. The runner should determine the 
76    /// service that the enclave is trying to connect to by looking at `addr`.
77    ///
78    /// Most enclaves expect that unrecognized `addr`s are forwarded to an 
79    /// instance of [`OsStreamRouter`].
80    ///
81    /// The enclave may optionally request the local or peer addresses be 
82    /// returned in `local_addr` or `peer_addr`, respectively. If `local_addr` 
83    /// and/or `peer_addr` are not [`None`], they will point to an empty 
84    /// [`String`]. On success, user-space can fill in the strings as 
85    /// appropriate.
86    ///
87    /// The enclave must not make any security decisions based on the local or 
88    /// peer address received.
89    fn connect_stream<'future>(
90        &'future self,
91        addr: &'future str,
92        local_addr: Option<&'future mut String>,
93        peer_addr: Option<&'future mut String>,
94    ) -> std::pin::Pin<Box<dyn Future<Output = IoResult<Box<dyn AsyncStream>>> + Send +'future>>;
95
96    /// Serve a bind call by the enclave. The runner should determine the 
97    /// service that the enclave is trying to bind to by looking at `addr`.
98    ///
99    /// Most enclaves expect that unrecognized `addr`s are forwarded to an 
100    /// instance of [`OsStreamRouter`].
101    ///
102    /// The enclave may optionally request the local address be returned in 
103    /// `local_addr`. If `local_addr` is not [`None`], it will point to an 
104    /// empty [`String`]. On success, user-space can fill in the string as 
105    /// appropriate.
106    ///
107    /// The enclave must not make any security decisions based on the local 
108    /// address received.
109    fn bind_stream<'future>(
110        &'future self,
111        addr: &'future str,
112        local_addr: Option<&'future mut String>,
113    ) -> std::pin::Pin<Box<dyn Future<Output = IoResult<Box<dyn AsyncListener>>> + Send + 'future>>;
114}