lunatic_networking_api/
lib.rs

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
mod dns;
mod tcp;
mod tls_tcp;
mod udp;

use std::convert::TryInto;
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use std::sync::Arc;
use std::time::Duration;

use anyhow::Result;
use hash_map_id::HashMapId;
use lunatic_error_api::ErrorCtx;
use tokio::io::{split, ReadHalf, WriteHalf};
use tokio::net::tcp::{OwnedReadHalf, OwnedWriteHalf};
use tokio::sync::Mutex;

use anyhow::anyhow;
use tokio::net::{TcpListener, TcpStream, UdpSocket};
use tokio_rustls::rustls::{Certificate, PrivateKey};
use tokio_rustls::TlsStream;
use wasmtime::Memory;
use wasmtime::{Caller, Linker};

use lunatic_common_api::IntoTrap;

pub use dns::DnsIterator;

pub struct TcpConnection {
    pub reader: Mutex<OwnedReadHalf>,
    pub writer: Mutex<OwnedWriteHalf>,
    pub read_timeout: Mutex<Option<Duration>>,
    pub write_timeout: Mutex<Option<Duration>>,
    pub peek_timeout: Mutex<Option<Duration>>,
}

/// This encapsulates the TCP-level connection, some connection
/// state, and the underlying TLS-level session.
pub struct TlsConnection {
    pub reader: Mutex<ReadHalf<TlsStream<TcpStream>>>,
    pub writer: Mutex<WriteHalf<TlsStream<TcpStream>>>,
    pub closing: bool,
    pub clean_closure: bool,
    pub read_timeout: Mutex<Option<Duration>>,
    pub write_timeout: Mutex<Option<Duration>>,
    pub peek_timeout: Mutex<Option<Duration>>,
}

pub struct TlsListener {
    pub listener: TcpListener,
    pub certs: Certificate,
    pub keys: PrivateKey,
}

impl TlsConnection {
    pub fn new(sock: TlsStream<TcpStream>) -> TlsConnection {
        let (read_half, write_half) = split(sock);
        TlsConnection {
            reader: Mutex::new(read_half),
            writer: Mutex::new(write_half),
            closing: false,
            clean_closure: false,
            read_timeout: Mutex::new(None),
            write_timeout: Mutex::new(None),
            peek_timeout: Mutex::new(None),
        }
    }
}

impl TcpConnection {
    pub fn new(stream: TcpStream) -> Self {
        let (read_half, write_half) = stream.into_split();
        TcpConnection {
            reader: Mutex::new(read_half),
            writer: Mutex::new(write_half),
            read_timeout: Mutex::new(None),
            write_timeout: Mutex::new(None),
            peek_timeout: Mutex::new(None),
        }
    }
}

pub type TcpListenerResources = HashMapId<TcpListener>;
pub type TlsListenerResources = HashMapId<TlsListener>;
pub type TcpStreamResources = HashMapId<Arc<TcpConnection>>;
pub type TlsStreamResources = HashMapId<Arc<TlsConnection>>;
pub type UdpResources = HashMapId<Arc<UdpSocket>>;
pub type DnsResources = HashMapId<DnsIterator>;

pub trait NetworkingCtx {
    fn tcp_listener_resources(&self) -> &TcpListenerResources;
    fn tcp_listener_resources_mut(&mut self) -> &mut TcpListenerResources;
    fn tcp_stream_resources(&self) -> &TcpStreamResources;
    fn tcp_stream_resources_mut(&mut self) -> &mut TcpStreamResources;
    fn tls_listener_resources(&self) -> &TlsListenerResources;
    fn tls_listener_resources_mut(&mut self) -> &mut TlsListenerResources;
    fn tls_stream_resources(&self) -> &TlsStreamResources;
    fn tls_stream_resources_mut(&mut self) -> &mut TlsStreamResources;
    fn udp_resources(&self) -> &UdpResources;
    fn udp_resources_mut(&mut self) -> &mut UdpResources;
    fn dns_resources(&self) -> &DnsResources;
    fn dns_resources_mut(&mut self) -> &mut DnsResources;
}

// Register the networking APIs to the linker
pub fn register<T: NetworkingCtx + ErrorCtx + Send + 'static>(
    linker: &mut Linker<T>,
) -> Result<()> {
    dns::register(linker)?;
    tcp::register(linker)?;
    tls_tcp::register(linker)?;
    udp::register(linker)?;
    Ok(())
}

fn socket_address<T: NetworkingCtx>(
    caller: &Caller<T>,
    memory: &Memory,
    addr_type: u32,
    addr_u8_ptr: u32,
    port: u32,
    flow_info: u32,
    scope_id: u32,
) -> Result<SocketAddr> {
    Ok(match addr_type {
        4 => {
            let ip = memory
                .data(caller)
                .get(addr_u8_ptr as usize..(addr_u8_ptr + 4) as usize)
                .or_trap("lunatic::network::socket_address*")?;
            let addr = <Ipv4Addr as From<[u8; 4]>>::from(ip.try_into().expect("exactly 4 bytes"));
            SocketAddrV4::new(addr, port as u16).into()
        }
        6 => {
            let ip = memory
                .data(caller)
                .get(addr_u8_ptr as usize..(addr_u8_ptr + 16) as usize)
                .or_trap("lunatic::network::socket_address*")?;
            let addr = <Ipv6Addr as From<[u8; 16]>>::from(ip.try_into().expect("exactly 16 bytes"));
            SocketAddrV6::new(addr, port as u16, flow_info, scope_id).into()
        }
        _ => return Err(anyhow!("Unsupported address type in socket_address*")),
    })
}