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]


Reply via email to