This is an automated email from the ASF dual-hosted git repository. yuanz pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/incubator-teaclave-trustzone-sdk.git
commit a7098204742df4b788d42bd7f062e278c8801a8c Author: ivila <[email protected]> AuthorDate: Fri Jan 17 12:43:44 2025 +0800 optee-utee: refactoring net module - introduce the Socket struct for performing socket operations within TEE. - introduce the SocketAdapter trait to support various implementations of the GP TEE Sockets API. - introduce a predefined optee module for TCP and UDP support in OP-TEE compatible TEE OS. Signed-off-by: ivila <[email protected]> Reviewed-by: Yuan Zhuang <[email protected]> Reviewed-by: Sumit Garg <[email protected]> --- optee-utee/src/lib.rs | 2 - optee-utee/src/net.rs | 361 ------------------------------------- optee-utee/src/net/error.rs | 62 +++++++ optee-utee/src/net/mod.rs | 30 +++ optee-utee/src/net/optee.rs | 202 +++++++++++++++++++++ optee-utee/src/net/optee_no_std.rs | 150 +++++++++++++++ optee-utee/src/net/optee_std.rs | 146 +++++++++++++++ optee-utee/src/net/socket.rs | 102 +++++++++++ 8 files changed, 692 insertions(+), 363 deletions(-) diff --git a/optee-utee/src/lib.rs b/optee-utee/src/lib.rs index 679339c..af65778 100644 --- a/optee-utee/src/lib.rs +++ b/optee-utee/src/lib.rs @@ -64,6 +64,4 @@ pub mod time; pub mod arithmetical; pub mod extension; pub mod uuid; - -#[cfg(target_os = "optee")] pub mod net; diff --git a/optee-utee/src/net.rs b/optee-utee/src/net.rs deleted file mode 100644 index ea859b5..0000000 --- a/optee-utee/src/net.rs +++ /dev/null @@ -1,361 +0,0 @@ -// 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. - -use optee_utee_sys as raw; -use std::io; -use std::io::ErrorKind; -use std::ptr; - -pub struct TcpStream { - pub handle: raw::TEE_iSocketHandle, -} - -impl TcpStream { - fn connect_with_ip_version( - address: &str, - port: u16, - ip_version: raw::TEE_ipSocket_ipVersion, - ) -> std::io::Result<Self> { - use std::ffi::CString; - unsafe { - let addr = match CString::new(address) { - Ok(addr) => addr, - Err(_) => return Err(io::Error::new(ErrorKind::Other, "Invalid address")), - }; - let mut handle: raw::TEE_iSocketHandle = ptr::null_mut(); - let mut protocol_error: u32 = 0; - let mut setup = raw::TEE_tcpSocket_Setup { - ipVersion: ip_version, - server_addr: addr.as_ptr() as _, - server_port: port, - }; - let ret = ((*raw::TEE_tcpSocket).open)( - &mut handle, - &mut setup as *mut raw::TEE_tcpSocket_Setup as _, - &mut protocol_error, - ); - match ret { - raw::TEE_SUCCESS => Ok(Self { handle }), - raw::TEE_ERROR_CANCEL => { - Err(io::Error::new(ErrorKind::Interrupted, "TEE_ERROR_CANCEL")) - } - raw::TEE_ERROR_OUT_OF_MEMORY => { - Err(io::Error::new(ErrorKind::Other, "TEE_ERROR_OUT_OF_MEMORY")) - } - raw::TEE_ERROR_BAD_PARAMETERS => { - Err(io::Error::new(ErrorKind::Other, "TEE_ERROR_BAD_PARAMETERS")) - } - raw::TEE_ISOCKET_ERROR_TIMEOUT => Err(io::Error::new( - ErrorKind::TimedOut, - "TEE_ISOCKET_ERROR_TIMEOUT", - )), - raw::TEE_ERROR_COMMUNICATION => Err(io::Error::new( - ErrorKind::ConnectionAborted, - "TEE_ERROR_COMMUNICATION", - )), - raw::TEE_ISOCKET_ERROR_PROTOCOL => Err(io::Error::new( - ErrorKind::Other, - "TEE_ISOCKET_ERROR_PROTOCOL", - )), - raw::TEE_ISOCKET_WARNING_PROTOCOL => Err(io::Error::new( - ErrorKind::Other, - format!("TEE_ISOCKET_WARNING_PROTOCOL: {}", protocol_error), - )), - _ => panic!("Unexpected return value"), - } - } - } - - pub fn connect_v4(address: &str, port: u16) -> std::io::Result<Self> { - Self::connect_with_ip_version(address, port, raw::TEE_ipSocket_ipVersion::TEE_IP_VERSION_4) - } - - pub fn connect_v6(address: &str, port: u16) -> std::io::Result<Self> { - Self::connect_with_ip_version(address, port, raw::TEE_ipSocket_ipVersion::TEE_IP_VERSION_4) - } - - pub fn connect(address: &str, port: u16) -> std::io::Result<Self> { - Self::connect_v4(address, port) - } -} - -impl Drop for TcpStream { - fn drop(&mut self) { - // Ignore any errors on close. - unsafe { - ((*raw::TEE_tcpSocket).close)(self.handle); - } - } -} - -impl std::io::Read for TcpStream { - fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> { - let mut length: u32 = buf.len() as _; - let ret = unsafe { - ((*raw::TEE_tcpSocket).recv)( - self.handle, - buf.as_mut_ptr() as _, - &mut length, - raw::TEE_TIMEOUT_INFINITE, - ) - }; - - match ret { - raw::TEE_SUCCESS => Ok(length as _), - raw::TEE_ERROR_CANCEL => { - Err(io::Error::new(ErrorKind::Interrupted, "TEE_ERROR_CANCEL")) - } - raw::TEE_ISOCKET_ERROR_TIMEOUT => Err(io::Error::new( - ErrorKind::TimedOut, - "TEE_ISOCKET_ERROR_TIMEOUT", - )), - raw::TEE_ERROR_COMMUNICATION => Err(io::Error::new( - ErrorKind::ConnectionAborted, - "TEE_ERROR_COMMUNICATION", - )), - raw::TEE_ISOCKET_ERROR_REMOTE_CLOSED => Err(io::Error::new( - ErrorKind::ConnectionAborted, - "TEE_ISOCKET_ERROR_REMOTE_CLOSED", - )), - raw::TEE_ISOCKET_ERROR_PROTOCOL => Err(io::Error::new( - ErrorKind::Other, - "TEE_ISOCKET_ERROR_PROTOCOL", - )), - raw::TEE_ISOCKET_WARNING_PROTOCOL => Err(io::Error::new( - ErrorKind::Other, - "TEE_ISOCKET_WARNING_PROTOCOL", - )), - _ => panic!("Unexpected return value"), - } - } -} - -impl std::io::Write for TcpStream { - fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> { - let mut length: u32 = buf.len() as _; - let ret = unsafe { - ((*raw::TEE_tcpSocket).send)( - self.handle, - buf.as_ptr() as *const u8 as _, - &mut length, - raw::TEE_TIMEOUT_INFINITE, - ) - }; - - match ret { - raw::TEE_SUCCESS => Ok(length as _), - raw::TEE_ERROR_CANCEL => { - Err(io::Error::new(ErrorKind::Interrupted, "TEE_ERROR_CANCEL")) - } - raw::TEE_ISOCKET_ERROR_TIMEOUT => Err(io::Error::new( - ErrorKind::TimedOut, - "TEE_ISOCKET_ERROR_TIMEOUT", - )), - raw::TEE_ISOCKET_ERROR_REMOTE_CLOSED => Err(io::Error::new( - ErrorKind::ConnectionAborted, - "TEE_ISOCKET_ERROR_REMOTE_CLOSED", - )), - raw::TEE_ISOCKET_ERROR_PROTOCOL => Err(io::Error::new( - ErrorKind::Other, - "TEE_ISOCKET_ERROR_PROTOCOL", - )), - raw::TEE_ISOCKET_WARNING_PROTOCOL => Err(io::Error::new( - ErrorKind::Other, - "TEE_ISOCKET_WARNING_PROTOCOL", - )), - raw::TEE_ISOCKET_ERROR_LARGE_BUFFER => Err(io::Error::new( - ErrorKind::Other, - "TEE_ISOCKET_ERROR_LARGE_BUFFER", - )), - _ => panic!("Unexpected return value"), - } - } - - fn flush(&mut self) -> std::io::Result<()> { - Ok(()) - } -} - -pub struct UdpSocket { - pub handle: raw::TEE_iSocketHandle, -} - -impl UdpSocket { - fn connect_with_ip_version( - address: &str, - port: u16, - ip_version: raw::TEE_ipSocket_ipVersion, - ) -> std::io::Result<Self> { - use std::ffi::CString; - unsafe { - let addr = match CString::new(address) { - Ok(addr) => addr, - Err(_) => return Err(io::Error::new(ErrorKind::Other, "Invalid address")), - }; - let mut handle: raw::TEE_iSocketHandle = ptr::null_mut(); - let mut protocol_error: u32 = 0; - let mut setup = raw::TEE_udpSocket_Setup { - ipVersion: ip_version, - server_addr: addr.as_ptr() as _, - server_port: port, - }; - let ret = ((*raw::TEE_udpSocket).open)( - &mut handle, - &mut setup as *mut raw::TEE_udpSocket_Setup as _, - &mut protocol_error, - ); - match ret { - raw::TEE_SUCCESS => Ok(Self { handle }), - raw::TEE_ERROR_CANCEL => { - Err(io::Error::new(ErrorKind::Interrupted, "TEE_ERROR_CANCEL")) - } - raw::TEE_ERROR_OUT_OF_MEMORY => { - Err(io::Error::new(ErrorKind::Other, "TEE_ERROR_OUT_OF_MEMORY")) - } - raw::TEE_ERROR_BAD_PARAMETERS => { - Err(io::Error::new(ErrorKind::Other, "TEE_ERROR_BAD_PARAMETERS")) - } - raw::TEE_ISOCKET_ERROR_TIMEOUT => Err(io::Error::new( - ErrorKind::TimedOut, - "TEE_ISOCKET_ERROR_TIMEOUT", - )), - raw::TEE_ERROR_COMMUNICATION => Err(io::Error::new( - ErrorKind::ConnectionAborted, - "TEE_ERROR_COMMUNICATION", - )), - raw::TEE_ISOCKET_ERROR_PROTOCOL => Err(io::Error::new( - ErrorKind::Other, - "TEE_ISOCKET_ERROR_PROTOCOL", - )), - raw::TEE_ISOCKET_WARNING_PROTOCOL => Err(io::Error::new( - ErrorKind::Other, - format!("TEE_ISOCKET_WARNING_PROTOCOL: {}", protocol_error), - )), - _ => panic!("Unexpected return value"), - } - } - } - - pub fn connect_v4(address: &str, port: u16) -> std::io::Result<Self> { - Self::connect_with_ip_version(address, port, raw::TEE_ipSocket_ipVersion::TEE_IP_VERSION_4) - } - - pub fn connect_v6(address: &str, port: u16) -> std::io::Result<Self> { - Self::connect_with_ip_version(address, port, raw::TEE_ipSocket_ipVersion::TEE_IP_VERSION_4) - } - - pub fn connect(address: &str, port: u16) -> std::io::Result<Self> { - Self::connect_v4(address, port) - } -} - -impl Drop for UdpSocket { - fn drop(&mut self) { - // Ignore any errors on close. - unsafe { - ((*raw::TEE_udpSocket).close)(self.handle); - } - } -} - -impl std::io::Read for UdpSocket { - fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> { - let mut length: u32 = buf.len() as _; - let ret = unsafe { - ((*raw::TEE_udpSocket).recv)( - self.handle, - buf.as_mut_ptr() as _, - &mut length, - raw::TEE_TIMEOUT_INFINITE, - ) - }; - - match ret { - raw::TEE_SUCCESS => Ok(length as _), - raw::TEE_ERROR_CANCEL => { - Err(io::Error::new(ErrorKind::Interrupted, "TEE_ERROR_CANCEL")) - } - raw::TEE_ISOCKET_ERROR_TIMEOUT => Err(io::Error::new( - ErrorKind::TimedOut, - "TEE_ISOCKET_ERROR_TIMEOUT", - )), - raw::TEE_ERROR_COMMUNICATION => Err(io::Error::new( - ErrorKind::ConnectionAborted, - "TEE_ERROR_COMMUNICATION", - )), - raw::TEE_ISOCKET_ERROR_REMOTE_CLOSED => Err(io::Error::new( - ErrorKind::ConnectionAborted, - "TEE_ISOCKET_ERROR_REMOTE_CLOSED", - )), - raw::TEE_ISOCKET_ERROR_PROTOCOL => Err(io::Error::new( - ErrorKind::Other, - "TEE_ISOCKET_ERROR_PROTOCOL", - )), - raw::TEE_ISOCKET_WARNING_PROTOCOL => Err(io::Error::new( - ErrorKind::Other, - "TEE_ISOCKET_WARNING_PROTOCOL", - )), - _ => panic!("Unexpected return value"), - } - } -} - -impl std::io::Write for UdpSocket { - fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> { - let mut length: u32 = buf.len() as _; - let ret = unsafe { - ((*raw::TEE_udpSocket).send)( - self.handle, - buf.as_ptr() as *const u8 as _, - &mut length, - raw::TEE_TIMEOUT_INFINITE, - ) - }; - - match ret { - raw::TEE_SUCCESS => Ok(length as _), - raw::TEE_ERROR_CANCEL => { - Err(io::Error::new(ErrorKind::Interrupted, "TEE_ERROR_CANCEL")) - } - raw::TEE_ISOCKET_ERROR_TIMEOUT => Err(io::Error::new( - ErrorKind::TimedOut, - "TEE_ISOCKET_ERROR_TIMEOUT", - )), - raw::TEE_ISOCKET_ERROR_REMOTE_CLOSED => Err(io::Error::new( - ErrorKind::ConnectionAborted, - "TEE_ISOCKET_ERROR_REMOTE_CLOSED", - )), - raw::TEE_ISOCKET_ERROR_PROTOCOL => Err(io::Error::new( - ErrorKind::Other, - "TEE_ISOCKET_ERROR_PROTOCOL", - )), - raw::TEE_ISOCKET_WARNING_PROTOCOL => Err(io::Error::new( - ErrorKind::Other, - "TEE_ISOCKET_WARNING_PROTOCOL", - )), - raw::TEE_ISOCKET_ERROR_LARGE_BUFFER => Err(io::Error::new( - ErrorKind::Other, - "TEE_ISOCKET_ERROR_LARGE_BUFFER", - )), - _ => panic!("Unexpected return value"), - } - } - - fn flush(&mut self) -> std::io::Result<()> { - Ok(()) - } -} diff --git a/optee-utee/src/net/error.rs b/optee-utee/src/net/error.rs new file mode 100644 index 0000000..b62ece2 --- /dev/null +++ b/optee-utee/src/net/error.rs @@ -0,0 +1,62 @@ +// 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. + +use optee_utee_sys as raw; + +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum SocketError { + ErrorProtocol(u32), + RemoteClosed, + Timeout, + OutOfResource, + WarningProtocol(u32), + LargeBuffer, + Hostname, + Tee(crate::ErrorKind), + Unknown(u32), +} + +impl SocketError { + pub fn from_raw_error(code: u32, protocol_error: u32) -> Self { + match code { + raw::TEE_ISOCKET_ERROR_PROTOCOL => Self::ErrorProtocol(protocol_error), + raw::TEE_ISOCKET_ERROR_REMOTE_CLOSED => Self::RemoteClosed, + raw::TEE_ISOCKET_ERROR_TIMEOUT => Self::Timeout, + raw::TEE_ISOCKET_ERROR_OUT_OF_RESOURCES => Self::OutOfResource, + raw::TEE_ISOCKET_ERROR_LARGE_BUFFER => Self::LargeBuffer, + raw::TEE_ISOCKET_WARNING_PROTOCOL => Self::WarningProtocol(protocol_error), + raw::TEE_ISOCKET_ERROR_HOSTNAME => Self::Hostname, + raw::TEE_ERROR_CANCEL + | raw::TEE_ERROR_COMMUNICATION + | raw::TEE_ERROR_OUT_OF_MEMORY + | raw::TEE_ERROR_BAD_PARAMETERS => Self::Tee(crate::Error::from_raw_error(code).kind()), + _ => Self::Unknown(code), + } + } +} + +impl core::fmt::Display for SocketError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:?}", self) + } +} + +impl From<crate::Error> for SocketError { + fn from(value: crate::Error) -> Self { + Self::Tee(value.kind()) + } +} diff --git a/optee-utee/src/net/mod.rs b/optee-utee/src/net/mod.rs new file mode 100644 index 0000000..045453d --- /dev/null +++ b/optee-utee/src/net/mod.rs @@ -0,0 +1,30 @@ +// 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. + +mod error; +mod optee; +mod socket; + +pub use error::SocketError; +pub use optee::{Setup, TcpAdapter, TcpStream, UdpAdapter, UdpSocket}; +pub use socket::{Socket, SocketAdapter}; + +#[cfg(target_os = "optee")] +mod optee_std; + +mod optee_no_std; +pub use optee_no_std::{StdCompatConnect, StdCompatRead, StdCompatWrite}; diff --git a/optee-utee/src/net/optee.rs b/optee-utee/src/net/optee.rs new file mode 100644 index 0000000..b198319 --- /dev/null +++ b/optee-utee/src/net/optee.rs @@ -0,0 +1,202 @@ +// 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. + +use alloc::ffi::CString; +use core::ptr; +use optee_utee_sys as raw; + +use super::{Socket, SocketAdapter, SocketError}; + +/// A setup parameter used for OP-TEE. +pub struct Setup { + addr: CString, + port: u16, + version: raw::TEE_ipSocket_ipVersion, +} + +impl Setup { + pub(crate) fn new( + addr: &str, + port: u16, + version: raw::TEE_ipSocket_ipVersion, + ) -> crate::Result<Self> { + Ok(Self { + addr: CString::new(addr).map_err(|_| crate::ErrorKind::BadParameters)?, + port, + version, + }) + } + /// Construct a new IPv4 target parameter using the address and port. It + /// will return `BadParameters` if the address contains a `\0` character in + /// the middle. + pub fn new_v4(addr: &str, port: u16) -> crate::Result<Self> { + Self::new(addr, port, raw::TEE_ipSocket_ipVersion::TEE_IP_VERSION_4) + } + /// Construct a new IPv6 target parameter using the address and port. It + /// will return `BadParameters` if the address contains a `\0` character in + /// the middle. + pub fn new_v6(addr: &str, port: u16) -> crate::Result<Self> { + Self::new(addr, port, raw::TEE_ipSocket_ipVersion::TEE_IP_VERSION_6) + } +} + +/// An adapter for TCP sockets in OP-TEE. Typically, it is not used directly, +/// but can be employed for wrapper operations, such as traffic control within +/// the TEE. +pub struct TcpAdapter(raw::TEE_iSocketHandle); +/// An adapter for UDP sockets in OP-TEE. Typically, it is not used directly, +/// but can be employed for wrapper operations, such as traffic control within +/// the TEE. +pub struct UdpAdapter(raw::TEE_iSocketHandle); +/// A TcpStream that is compatible with OP-TEE. +pub type TcpStream = Socket<TcpAdapter>; +/// A UdpSocket that is compatible with OP-TEE. +pub type UdpSocket = Socket<UdpAdapter>; + +fn handle_socket_operation_error(handle: raw::TEE_iSocketHandle, code: u32) -> SocketError { + match code { + raw::TEE_ISOCKET_ERROR_PROTOCOL => { + let protocol_error = unsafe { ((*raw::TEE_tcpSocket).error)(handle) }; + SocketError::ErrorProtocol(protocol_error) + } + raw::TEE_ISOCKET_WARNING_PROTOCOL => { + let protocol_error = unsafe { ((*raw::TEE_tcpSocket).error)(handle) }; + SocketError::WarningProtocol(protocol_error) + } + _ => SocketError::from_raw_error(code, 0), + } +} + +impl SocketAdapter for TcpAdapter { + type Setup = Setup; + type Handle = Self; + + fn open(setup: Self::Setup) -> Result<Self::Handle, SocketError> { + let mut handle: raw::TEE_iSocketHandle = ptr::null_mut(); + let mut protocol_error: u32 = 0; + let mut setup = raw::TEE_tcpSocket_Setup { + ipVersion: setup.version, + server_addr: setup.addr.as_ptr() as _, + server_port: setup.port, + }; + let ret = unsafe { + ((*raw::TEE_tcpSocket).open)( + &mut handle, + &mut setup as *mut raw::TEE_tcpSocket_Setup as _, + &mut protocol_error, + ) + }; + match ret { + raw::TEE_SUCCESS => Ok(Self(handle)), + _ => Err(SocketError::from_raw_error(ret, protocol_error)), + } + } + fn send(handle: &mut Self::Handle, buf: &[u8], timeout: u32) -> Result<usize, SocketError> { + let mut length: u32 = buf.len() as _; + let ret = unsafe { + ((*raw::TEE_tcpSocket).send)( + handle.0, + buf.as_ptr() as *const u8 as _, + &mut length, + timeout, + ) + }; + match ret { + raw::TEE_SUCCESS => Ok(length as usize), + _ => Err(handle_socket_operation_error(handle.0, ret)), + } + } + fn recv(handle: &mut Self::Handle, buf: &mut [u8], timeout: u32) -> Result<usize, SocketError> { + let mut length: u32 = buf.len() as _; + let ret = unsafe { + ((*raw::TEE_tcpSocket).recv)(handle.0, buf.as_mut_ptr() as _, &mut length, timeout) + }; + match ret { + raw::TEE_SUCCESS => Ok(length as usize), + _ => Err(handle_socket_operation_error(handle.0, ret)), + } + } +} + +impl Drop for TcpAdapter { + fn drop(&mut self) { + // Ignore any errors on close. + unsafe { + ((*raw::TEE_tcpSocket).close)(self.0); + } + } +} + +impl SocketAdapter for UdpAdapter { + type Setup = Setup; + type Handle = Self; + + fn open(setup: Self::Setup) -> Result<Self::Handle, SocketError> { + let mut handle: raw::TEE_iSocketHandle = ptr::null_mut(); + let mut protocol_error: u32 = 0; + let mut setup = raw::TEE_udpSocket_Setup { + ipVersion: setup.version, + server_addr: setup.addr.as_ptr() as _, + server_port: setup.port, + }; + let ret = unsafe { + ((*raw::TEE_udpSocket).open)( + &mut handle, + &mut setup as *mut raw::TEE_udpSocket_Setup as _, + &mut protocol_error, + ) + }; + match ret { + raw::TEE_SUCCESS => Ok(Self(handle)), + _ => Err(SocketError::from_raw_error(ret, protocol_error)), + } + } + fn send(handle: &mut Self::Handle, buf: &[u8], timeout: u32) -> Result<usize, SocketError> { + let mut length: u32 = buf.len() as _; + let ret = unsafe { + ((*raw::TEE_udpSocket).send)( + handle.0, + buf.as_ptr() as *const u8 as _, + &mut length, + timeout, + ) + }; + match ret { + raw::TEE_SUCCESS => Ok(length as usize), + _ => Err(handle_socket_operation_error(handle.0, ret)), + } + } + fn recv(handle: &mut Self::Handle, buf: &mut [u8], timeout: u32) -> Result<usize, SocketError> { + let mut length: u32 = buf.len() as _; + let ret = unsafe { + ((*raw::TEE_udpSocket).recv)(handle.0, buf.as_mut_ptr() as _, &mut length, timeout) + }; + match ret { + raw::TEE_SUCCESS => Ok(length as usize), + _ => Err(handle_socket_operation_error(handle.0, ret)), + } + } +} + +impl Drop for UdpAdapter { + fn drop(&mut self) { + // Ignore any errors on close. + unsafe { + ((*raw::TEE_udpSocket).close)(self.0); + } + } +} diff --git a/optee-utee/src/net/optee_no_std.rs b/optee-utee/src/net/optee_no_std.rs new file mode 100644 index 0000000..dff4648 --- /dev/null +++ b/optee-utee/src/net/optee_no_std.rs @@ -0,0 +1,150 @@ +// 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. +use super::{Setup, Socket, SocketAdapter, SocketError}; + +/// A trait used for convenience; import it so that the code remains consistent +/// with the std version (with the only difference being the return error type). +/// +/// Take TcpStream as example: +/// ```no_run +/// use optee_utee::net::TcpStream; +/// +/// fn connect_without_compact_trait(host: &str, port: u16) -> Result<TcpStream, SocketError> { +/// let setup = Setup::new_v4(host, port)?; +/// TcpStream::open(setup) +/// } +/// +/// fn connect_with_compact_trait(host: &str, port: u16) -> Result<TcpStream, SocketError> { +/// use optee_utee::net::StdCompatConnect; +/// +/// TcpStream::connect_v4(host, port) +/// } +/// ``` +pub trait StdCompatConnect: Sized { + fn connect_v4(address: &str, port: u16) -> Result<Self, SocketError>; + fn connect_v6(address: &str, port: u16) -> Result<Self, SocketError>; + fn connect(address: &str, port: u16) -> Result<Self, SocketError> { + Self::connect_v4(address, port) + } +} + +/// A trait used for convenience; import it so that the code remains consistent +/// with the std version (with the only difference being the return error type). +/// +/// Take TcpStream as example: +/// ```no_run +/// use optee_utee::net::TcpStream; +/// +/// fn write_without_compact_trait(stream: &mut Stream, mut buf: &[u8]) -> Result<usize, SocketError> { +/// use optee_utee::ErrorKind; +/// +/// while !buf.is_empty() { +/// match stream.send(buf) { +/// Ok(0) => return Err(SocketError::Tee(ErrorKind::Generic)), +/// Ok(n) => buf = &buf[n..], +/// Err(e) => return Err(e), +/// } +/// } +/// Ok(()) +/// } +/// +/// fn write_with_compact_trait(stream: &mut Stream, buf: &[u8]) -> Result<usize, SocketError> { +/// use optee_utee::net::StdCompatWrite; +/// +/// stream.write_all(buf) +/// } +/// ``` +pub trait StdCompatWrite { + fn write(&mut self, buf: &[u8]) -> Result<usize, SocketError>; + fn write_all(&mut self, mut buf: &[u8]) -> Result<(), SocketError> { + while !buf.is_empty() { + match self.write(buf)? { + 0 => return Err(SocketError::Tee(crate::ErrorKind::Generic)), + n => buf = &buf[n..], + } + } + Ok(()) + } +} + +/// A trait used for convenience; import it so that the code remains consistent +/// with the std version (with the only difference being the return error type). +/// +/// Take TcpStream as example: +/// ```no_run +/// use optee_utee::net::TcpStream; +/// +/// fn read_without_compact_trait(stream: &mut Stream, mut buf: &mut [u8]) -> Result<usize, SocketError> { +/// use optee_utee::ErrorKind; +/// +/// while !buf.is_empty() { +/// match stream.recv(buf) { +/// Ok(0) => break; +/// Ok(n) => buf = &mut buf[n..], +/// Err(e) => return Err(e), +/// } +/// } +/// if !buf.is_empty() { +/// return Err(SocketError::Tee(ErrorKind::Generic)); +/// } +/// Ok(()) +/// } +/// +/// fn read_with_compact_trait(stream: &mut Stream, buf: &mut [u8]) -> Result<usize, SocketError> { +/// use optee_utee::net::StdCompatRead; +/// +/// stream.read_exact(buf) +/// } +/// ``` +pub trait StdCompatRead { + fn read(&mut self, buf: &mut [u8]) -> Result<usize, SocketError>; + fn read_exact(&mut self, mut buf: &mut [u8]) -> Result<(), SocketError> { + while !buf.is_empty() { + match self.read(buf)? { + 0 => break, + n => buf = &mut buf[n..], + } + } + if !buf.is_empty() { + return Err(SocketError::Tee(crate::ErrorKind::Generic)); + } + Ok(()) + } +} + +impl<T: SocketAdapter<Setup = Setup>> StdCompatConnect for Socket<T> { + fn connect_v4(address: &str, port: u16) -> Result<Self, SocketError> { + let setup = Setup::new_v4(address, port)?; + Self::open(setup) + } + fn connect_v6(address: &str, port: u16) -> Result<Self, SocketError> { + let setup = Setup::new_v6(address, port)?; + Self::open(setup) + } +} + +impl<T: SocketAdapter<Setup = Setup>> StdCompatWrite for Socket<T> { + fn write(&mut self, buf: &[u8]) -> Result<usize, SocketError> { + self.send(buf) + } +} + +impl<T: SocketAdapter<Setup = Setup>> StdCompatRead for Socket<T> { + fn read(&mut self, buf: &mut [u8]) -> Result<usize, SocketError> { + self.recv(buf) + } +} diff --git a/optee-utee/src/net/optee_std.rs b/optee-utee/src/net/optee_std.rs new file mode 100644 index 0000000..e1aa2fb --- /dev/null +++ b/optee-utee/src/net/optee_std.rs @@ -0,0 +1,146 @@ +// 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. + +use optee_utee_sys as raw; + +use super::optee::Setup; +use super::SocketError; +use super::{TcpStream, UdpSocket}; +use alloc::format; + +impl TcpStream { + fn connect_with_ip_version( + address: &str, + port: u16, + ip_version: raw::TEE_ipSocket_ipVersion, + ) -> std::io::Result<Self> { + let setup = Setup::new(address, port, ip_version) + .map_err(|_| std::io::Error::new(std::io::ErrorKind::Other, "Invalid address"))?; + Ok(Self::open(setup).map_err(|err| Into::<std::io::Error>::into(err))?) + } + pub fn connect_v4(address: &str, port: u16) -> std::io::Result<Self> { + Self::connect_with_ip_version(address, port, raw::TEE_ipSocket_ipVersion::TEE_IP_VERSION_4) + } + pub fn connect_v6(address: &str, port: u16) -> std::io::Result<Self> { + Self::connect_with_ip_version(address, port, raw::TEE_ipSocket_ipVersion::TEE_IP_VERSION_6) + } + pub fn connect(address: &str, port: u16) -> std::io::Result<Self> { + Self::connect_v4(address, port) + } +} + +impl std::io::Read for TcpStream { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> { + match self.recv(buf) { + Ok(v) => Ok(v as usize), + Err(err) => Err(Into::<std::io::Error>::into(err)), + } + } +} + +impl std::io::Write for TcpStream { + fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> { + match self.send(buf) { + Ok(v) => Ok(v as usize), + Err(err) => Err(Into::<std::io::Error>::into(err)), + } + } + fn flush(&mut self) -> std::io::Result<()> { + Ok(()) + } +} + +impl UdpSocket { + fn connect_with_ip_version( + address: &str, + port: u16, + ip_version: raw::TEE_ipSocket_ipVersion, + ) -> std::io::Result<Self> { + let setup = Setup::new(address, port, ip_version) + .map_err(|_| std::io::Error::new(std::io::ErrorKind::Other, "Invalid address"))?; + Ok(Self::open(setup).map_err(|err| Into::<std::io::Error>::into(err))?) + } + pub fn connect_v4(address: &str, port: u16) -> std::io::Result<Self> { + Self::connect_with_ip_version(address, port, raw::TEE_ipSocket_ipVersion::TEE_IP_VERSION_4) + } + pub fn connect_v6(address: &str, port: u16) -> std::io::Result<Self> { + Self::connect_with_ip_version(address, port, raw::TEE_ipSocket_ipVersion::TEE_IP_VERSION_6) + } + pub fn connect(address: &str, port: u16) -> std::io::Result<Self> { + Self::connect_v4(address, port) + } +} + +impl std::io::Read for UdpSocket { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> { + match self.recv(buf) { + Ok(v) => Ok(v as usize), + Err(err) => Err(Into::<std::io::Error>::into(err)), + } + } +} + +impl std::io::Write for UdpSocket { + fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> { + match self.send(buf) { + Ok(v) => Ok(v as usize), + Err(err) => Err(Into::<std::io::Error>::into(err)), + } + } + fn flush(&mut self) -> std::io::Result<()> { + Ok(()) + } +} + +// This is implemented to save developers from having to make numerous map_err +// calls. +impl Into<std::io::Error> for SocketError { + fn into(self) -> std::io::Error { + use std::io::{Error, ErrorKind}; + match self { + SocketError::ErrorProtocol(protocol_error) => Error::new( + ErrorKind::Other, + format!("TEE_ISOCKET_ERROR_PROTOCOL: 0x{:08X}", protocol_error), + ), + SocketError::RemoteClosed => Error::new( + ErrorKind::ConnectionAborted, + "TEE_ISOCKET_ERROR_REMOTE_CLOSED", + ), + SocketError::Timeout => Error::new(ErrorKind::TimedOut, "TEE_ISOCKET_ERROR_TIMEOUT"), + SocketError::OutOfResource => { + Error::new(ErrorKind::Other, "TEE_ISOCKET_ERROR_OUT_OF_RESOURCES") + } + SocketError::LargeBuffer => { + Error::new(ErrorKind::Other, "TEE_ISOCKET_ERROR_LARGE_BUFFER") + } + SocketError::WarningProtocol(protocol_error) => Error::new( + ErrorKind::Other, + format!("TEE_ISOCKET_WARNING_PROTOCOL: 0x{:08X}", protocol_error), + ), + SocketError::Hostname => Error::new(ErrorKind::Other, "TEE_ISOCKET_ERROR_HOSTNAME"), + SocketError::Tee(kind) => match kind { + crate::ErrorKind::OutOfMemory => { + Error::new(ErrorKind::OutOfMemory, "TEE_ERROR_OUT_OF_MEMORY") + } + _ => Error::new(ErrorKind::Other, kind.as_str()), + }, + SocketError::Unknown(code) => { + Error::new(ErrorKind::Other, format!("Unknown: {:08X}", code)) + } + } + } +} diff --git a/optee-utee/src/net/socket.rs b/optee-utee/src/net/socket.rs new file mode 100644 index 0000000..ac3d43b --- /dev/null +++ b/optee-utee/src/net/socket.rs @@ -0,0 +1,102 @@ +// 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. + +use optee_utee_sys as raw; + +use super::SocketError; +use core::time::Duration; + +/// A trait designed to accommodate various implementations of GP TEE Sockets +/// API. +/// +/// An implementation of this trait is responsible for handling all +/// protocol-related tasks, including but not limited to: +/// * Defining its own Setup type and using it to establish a new connection; +/// * Sending and receiving data over the connection, while managing protocol +/// errors (such as permitting certain warnings but raising others). +pub trait SocketAdapter: Sized { + type Setup; + type Handle; + + fn open(setup: Self::Setup) -> Result<Self::Handle, SocketError>; + fn send(handle: &mut Self::Handle, buf: &[u8], timeout: u32) -> Result<usize, SocketError>; + fn recv(handle: &mut Self::Handle, buf: &mut [u8], timeout: u32) -> Result<usize, SocketError>; +} + +/// A struct used for socket operations. +pub struct Socket<T: SocketAdapter> { + handle: T::Handle, + recv_timeout: u32, + send_timeout: u32, +} + +impl<T: SocketAdapter> Socket<T> { + /// create a new connection, and then sending and receiving data over it. + pub fn open(setup: T::Setup) -> Result<Self, SocketError> { + let handle = T::open(setup)?; + Ok(Self { + handle, + recv_timeout: raw::TEE_TIMEOUT_INFINITE, + send_timeout: raw::TEE_TIMEOUT_INFINITE, + }) + } + /// set timeout of recv operation. + pub fn set_recv_timeout_in_milli(&mut self, milliseconds: u32) { + self.recv_timeout = milliseconds; + } + /// set timeout of send operation. + pub fn set_send_timeout_in_milli(&mut self, milliseconds: u32) { + self.send_timeout = milliseconds; + } + /// a wrapper of `set_recv_timeout_in_milli`, similar to `set_read_timeout` + /// in std::net::TcpStream, it will set timeout to `TEE_TIMEOUT_INFINITE` + /// if `Option::None` is provided. + pub fn set_recv_timeout(&mut self, dur: Option<Duration>) -> crate::Result<()> { + let milliseconds = convert_duration_option_to_timeout(dur)?; + self.set_recv_timeout_in_milli(milliseconds); + Ok(()) + } + /// a wrapper of `set_send_timeout_in_milli`, similar to + /// `set_write_timeout` in std::net::TcpStream, it will set timeout to + /// `TEE_TIMEOUT_INFINITE` if `Option::None` is provided. + pub fn set_send_timeout(&mut self, dur: Option<Duration>) -> crate::Result<()> { + let milliseconds = convert_duration_option_to_timeout(dur)?; + self.set_send_timeout_in_milli(milliseconds); + Ok(()) + } + /// send data, similar to `write` in `io::Write` + pub fn send(&mut self, buf: &[u8]) -> Result<usize, SocketError> { + T::send(&mut self.handle, buf, self.send_timeout) + } + /// recv data, similar to `read` in `io::Read` + pub fn recv(&mut self, buf: &mut [u8]) -> Result<usize, SocketError> { + T::recv(&mut self.handle, buf, self.recv_timeout) + } +} + +fn convert_duration_option_to_timeout(dur: Option<Duration>) -> crate::Result<u32> { + match dur { + None => Ok(raw::TEE_TIMEOUT_INFINITE), + Some(v) => { + let milliseconds = v.as_millis(); + if milliseconds > (u32::MAX as u128) { + return Err(crate::ErrorKind::BadParameters.into()); + } + Ok(milliseconds as u32) + } + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
