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}