1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
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);
        }
    }
}