|
4 | 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | 6 |
|
7 | | -extern crate aesm_client; |
8 | | -extern crate enclave_runner; |
9 | | -extern crate sgxs_loaders; |
10 | | -extern crate tokio; |
| 7 | +use std::future::Future; |
| 8 | +use std::io::Result as IoResult; |
| 9 | +use std::pin::Pin; |
| 10 | +use std::process::Stdio; |
| 11 | +use std::task::{Context, Poll}; |
| 12 | + |
| 13 | +use futures::FutureExt; |
| 14 | +use tokio::io::{AsyncRead, AsyncWrite}; |
| 15 | +use tokio::process::{ChildStdin, ChildStdout, Command}; |
11 | 16 |
|
12 | 17 | use aesm_client::AesmClient; |
13 | 18 | use enclave_runner::usercalls::{AsyncStream, UsercallExtension}; |
14 | 19 | use enclave_runner::EnclaveBuilder; |
15 | 20 | use sgxs_loaders::isgx::Device as IsgxDevice; |
16 | | -use tokio::io::{AsyncRead, AsyncWrite}; |
17 | | -use std::io::{Read, Result as IoResult, Write}; |
18 | | -use std::process::{Child, Command, Stdio}; |
19 | | -use tokio::sync::lock::Lock; |
20 | | -use tokio::prelude::Async; |
21 | 21 |
|
22 | 22 | /// This example demonstrates use of usercall extensions. |
23 | 23 | /// User call extension allow the enclave code to "connect" to an external service via a customized enclave runner. |
24 | 24 | /// Here we customize the runner to intercept calls to connect to an address "cat" which actually connects the enclave application to |
25 | 25 | /// stdin and stdout of `cat` process. |
26 | 26 | struct CatService { |
27 | | - c: Lock<Child>, |
| 27 | + stdin: ChildStdin, |
| 28 | + stdout: ChildStdout, |
28 | 29 | } |
29 | 30 |
|
30 | 31 | impl CatService { |
| 32 | + // SAFETY: `Self` doesn't implement `Drop` or `Unpin`, and isn't `repr(packed)` |
| 33 | + pin_utils::unsafe_pinned!(stdin: ChildStdin); |
| 34 | + pin_utils::unsafe_pinned!(stdout: ChildStdout); |
| 35 | + |
31 | 36 | fn new() -> Result<CatService, std::io::Error> { |
32 | 37 | Command::new("/bin/cat") |
33 | 38 | .stdout(Stdio::piped()) |
34 | 39 | .stdin(Stdio::piped()) |
35 | 40 | .spawn() |
36 | | - .map(|c| Lock::new(c)) |
37 | | - .map(|c| CatService { c }) |
38 | | - } |
39 | | -} |
40 | | - |
41 | | -macro_rules! poll_lock_wouldblock { |
42 | | - ($lock:expr) => { |
43 | | - match $lock.clone().poll_lock() { |
44 | | - Async::NotReady => Err(std::io::ErrorKind::WouldBlock.into()), |
45 | | - Async::Ready(ret) => IoResult::Ok(ret), |
46 | | - } |
| 41 | + .map(|mut c| CatService { |
| 42 | + stdin: c.stdin.take().unwrap(), |
| 43 | + stdout: c.stdout.take().unwrap(), |
| 44 | + }) |
47 | 45 | } |
48 | 46 | } |
49 | 47 |
|
50 | | -impl Read for CatService { |
51 | | - fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> { |
52 | | - poll_lock_wouldblock!(self.c)?.stdout.as_mut().unwrap().read(buf) |
| 48 | +impl AsyncRead for CatService { |
| 49 | + fn poll_read( |
| 50 | + self: Pin<&mut Self>, |
| 51 | + cx: &mut Context, |
| 52 | + buf: &mut [u8] |
| 53 | + ) -> Poll<IoResult<usize>> { |
| 54 | + self.stdout().poll_read(cx, buf) |
53 | 55 | } |
54 | 56 | } |
55 | 57 |
|
56 | | -impl Write for CatService { |
57 | | - fn write(&mut self, buf: &[u8]) -> IoResult<usize> { |
58 | | - poll_lock_wouldblock!(self.c)?.stdin.as_mut().unwrap().write(buf) |
| 58 | +impl AsyncWrite for CatService { |
| 59 | + fn poll_write( |
| 60 | + self: Pin<&mut Self>, |
| 61 | + cx: &mut Context, |
| 62 | + buf: &[u8] |
| 63 | + ) -> Poll<IoResult<usize>> { |
| 64 | + self.stdin().poll_write(cx, buf) |
59 | 65 | } |
60 | 66 |
|
61 | | - fn flush(&mut self) -> IoResult<()> { |
62 | | - poll_lock_wouldblock!(self.c)?.stdin.as_mut().unwrap().flush() |
| 67 | + fn poll_flush(self: Pin<&mut Self>, cx: &mut Context) -> Poll<IoResult<()>> { |
| 68 | + self.stdin().poll_flush(cx) |
63 | 69 | } |
64 | | -} |
65 | | - |
66 | | -impl AsyncRead for CatService { |
67 | | -} |
68 | 70 |
|
69 | | -impl AsyncWrite for CatService { |
70 | | - fn shutdown(&mut self) -> tokio::prelude::Poll<(), std::io::Error> { |
71 | | - Ok(().into()) |
| 71 | + fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context) -> Poll<IoResult<()>> { |
| 72 | + self.stdin().poll_shutdown(cx) |
72 | 73 | } |
73 | 74 | } |
74 | 75 |
|
75 | 76 | #[derive(Debug)] |
76 | 77 | struct ExternalService; |
77 | 78 | // Ignoring local_addr and peer_addr, as they are not relavent in the current context. |
78 | 79 | impl UsercallExtension for ExternalService { |
79 | | - fn connect_stream( |
80 | | - &self, |
81 | | - addr: &str, |
82 | | - _local_addr: Option<&mut String>, |
83 | | - _peer_addr: Option<&mut String>, |
84 | | - ) -> IoResult<Option<Box<dyn AsyncStream>>> { |
85 | | - // If the passed address is not "cat", we return none, whereby the passed address gets treated as |
86 | | - // an IP address which is the default behavior. |
87 | | - match &*addr { |
88 | | - "cat" => { |
89 | | - let stream = CatService::new()?; |
90 | | - Ok(Some(Box::new(stream))) |
| 80 | + fn connect_stream<'future>( |
| 81 | + &'future self, |
| 82 | + addr: &'future str, |
| 83 | + _local_addr: Option<&'future mut String>, |
| 84 | + _peer_addr: Option<&'future mut String>, |
| 85 | + ) -> std::pin::Pin<Box<dyn Future<Output = IoResult<Option<Box<dyn AsyncStream>>>> +'future>> { |
| 86 | + async move { |
| 87 | + // If the passed address is not "cat", we return none, whereby the passed address gets treated as |
| 88 | + // an IP address which is the default behavior. |
| 89 | + match &*addr { |
| 90 | + "cat" => { |
| 91 | + let stream = CatService::new()?; |
| 92 | + Ok(Some(Box::new(stream) as _)) |
| 93 | + } |
| 94 | + _ => Ok(None), |
91 | 95 | } |
92 | | - _ => Ok(None), |
93 | | - } |
| 96 | + }.boxed_local() |
94 | 97 | } |
95 | 98 | } |
96 | 99 |
|
|
0 commit comments