implemented networking for linux
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 17 Oct 2023 02:48:18 +0000 (21:48 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 17 Oct 2023 02:48:18 +0000 (21:48 -0500)
core/io/io.onyx
core/net/net.onyx
core/net/tcp.onyx
core/runtime/platform/onyx/net.onyx
core/runtime/platform/onyx/platform.onyx
docs/ideas/platform_layer.md
runtime/onyx_runtime.c
runtime/src/ort_net.h [deleted file]
runtime/src/ort_net_linux.h [new file with mode: 0644]

index 12b783b6749bc8a605ca301287f1b3bac33ea73c..9b6f13bc550c1e5c72a5073c709f02642c20998e 100644 (file)
@@ -41,4 +41,10 @@ Error :: enum {
 
     // Sockets only. Signals that no data was recieved from a non-blocking operation.
     NoData     :: 0x0d;
+
+    // Failed to create an object.
+    CreationFailed :: 0x0e;
+
+    // The operation failed.
+    OperationFailed :: 0x0f;
 }
index 0dffaaa7a1bd81dcb23dabd7d1243b868022e242..d537041dc481144b86a5a3f13cd1e6179497f0a5 100644 (file)
@@ -14,12 +14,14 @@ Socket :: struct {
     type: SocketType;
     family: SocketFamily;
     proto: SocketProto;
+
+    alive: bool;
 }
 
 // Inject methods for the socket
 #inject Socket {
     close     :: socket_close
-    setting   :: socket_setting
+    option    :: socket_option
     is_alive  :: socket_is_alive
     bind      :: socket_bind
     listen    :: socket_listen
@@ -48,6 +50,7 @@ SocketType :: enum {
 }
 
 SocketProto :: enum {
+    ANY  :: 0x00;
     IP   :: 0x00;
     ICMP :: 0x01;
     IGMP :: 0x02;
@@ -56,7 +59,7 @@ SocketProto :: enum {
     IPV6 :: 0x29;
 }
 
-SocketSetting :: enum {
+SocketOption :: enum {
     NonBlocking  :: 0x01;
     Broadcast    :: 0x02;
     ReuseAddress :: 0x03;
@@ -76,13 +79,17 @@ SocketAddress :: union {
 
     Inet: struct {
         port: u16;
-        addr: u32;
+        addr: u32; // Stored in network byte order
     };
 
     Inet6: struct {
         port: u16;
-        addr_h: u64;
-        addr_l: u64;
+        addr: [16] u8; // Stored in network byte order
+    };
+
+    HostPort: struct {
+        host: str;
+        port: u16;
     };
 }
 
@@ -96,15 +103,24 @@ SocketAddress.addr_as_str :: (this: &SocketAddress, allocator := context.allocat
             return conv.format(&out, "{}:{}", str_addr, inet.port);
         }
         case inet6: .Inet6 => do {
-            str_addr := ipv6_to_str(inet6.addr_h, inet6.addr_l);
+            str_addr := ipv6_to_str(inet6.addr);
             out := make(dyn_str, allocator);
             return conv.format(&out, "{}:{}", str_addr, inet6.port);
         }
+        case host: .HostPort => do {
+            out := make(dyn_str, allocator);
+            return conv.format(&out, "{}:{}", host.host, host.port);
+        }
     };
 }
 
 make_ipv4_address :: (out: &SocketAddress, addr: u32, port: u16) {
-    *out = .{ Inet = .{ port = port, addr = addr } };
+    n :=  (addr & 0xFF) << 24
+        | (addr & 0xFF00) << 8
+        | (addr & 0xFF0000) >> 8
+        | (addr & 0xFF000000) >> 24;
+
+    *out = .{ Inet = .{ port = port, addr = n } };
 }
 
 make_unix_address :: (out: &SocketAddress, path: str) {
@@ -131,6 +147,7 @@ socket_create :: (family: SocketFamily, type: SocketType, proto: SocketProto) ->
     s.handle = socket;
 
     s.flags |= .Block_On_Read;
+    s.alive = true;
 
     return .{ Ok = s };
 }
@@ -139,14 +156,16 @@ socket_from_fd :: (fd: runtime.platform.SocketData) -> Socket {
     return Socket.{
         stream = .{ vtable = &__net_socket_vtable },
         handle = fd,
+        alive = true
     };
 }
 
 socket_close :: (s: &Socket) {
     runtime.platform.__net_sock_close(s.handle);
+    s.alive = false;
 }
 
-socket_setting :: (s: &Socket, setting: SocketSetting, flag: bool) {
+socket_option :: (s: &Socket, setting: SocketOption, flag: bool) {
     if runtime.platform.__net_sock_opt_flag(s.handle, setting, flag) {
         if setting == .NonBlocking {
             if flag do s.flags = ~~ (cast(u32) s.flags & cast(u32) ~io.Stream_Flags.Block_On_Read);
@@ -156,14 +175,14 @@ socket_setting :: (s: &Socket, setting: SocketSetting, flag: bool) {
 }
 
 socket_is_alive :: (s: &Socket) -> bool {
-    return runtime.platform.__net_sock_status(s.handle) == .Open;
+    return s.alive;
 }
 
 socket_connect :: (s: &Socket, addr: &SocketAddress) -> io.Error {
     return runtime.platform.__net_sock_connect(s.handle, addr);
 }
 
-socket_bind :: (s: &Socket, bind_address: &Socket_Address) -> bool {
+socket_bind :: (s: &Socket, bind_address: &SocketAddress) -> bool {
     return runtime.platform.__net_sock_bind(s.handle, bind_address);
 }
 
@@ -172,7 +191,7 @@ socket_listen :: (s: &Socket, backlog := 32) -> bool {
 }
 
 socket_shutdown :: (s: &Socket, how: SocketShutdown) -> io.Error {
-    return runtime.platform.__net_socket_shutdown(s.handle, how);
+    return runtime.platform.__net_sock_shutdown(s.handle, how);
 }
 
 SocketAcceptResult :: struct {
@@ -234,11 +253,23 @@ socket_poll :: (socket: &Socket, timeout := -1) -> Socket_Poll_Status {
 
 socket_send :: (s: &Socket, data: [] u8) -> i32 {
     res := runtime.platform.__net_sock_send(s.handle, data);
+    res.Err->with([err] {
+        if err == .EOF {
+            socket_close(s);
+        }
+    });
+
     return res.Ok ?? -1;
 }
 
 socket_sendto :: (s: &Socket, data: [] u8, addr: &SocketAddress) -> i32 {
-    res := runtime.platform.__net_sock_sendto(s.handle, data, addr);
+    res := runtime.platform.__net_sock_send_to(s.handle, data, addr);
+    res.Err->with([err] {
+        if err == .EOF {
+            socket_close(s);
+        }
+    });
+
     return res.Ok ?? -1;
 }
 
@@ -255,40 +286,32 @@ socket_sendall :: (s: &Socket, data: [] u8) {
 socket_recv :: (s: &Socket, maxlen := 1024, allocator := context.allocator) -> ? [] u8 {
     buffer := alloc.array_from_stack(u8, maxlen);
     res := runtime.platform.__net_sock_recv(s.handle, buffer);
+    res.Err->with([err] {
+        if err == .EOF {
+            socket_close(s);
+        }
+    });
+
     if res.Err {
         return .{};
     }
 
     return slice.copy(buffer[0 .. res.Ok->unwrap()], allocator);
-
-    // buffer := alloc.from_stack(maxlen);
-    // would_block: bool;
-    // received := __net_recv(s.handle, .{ buffer, maxlen }, &would_block);
-    // if received < 0 { 
-    //     if !would_block do s.vtable = null;
-    //     return .[];
-    // }
-
-    // result := memory.make_slice(u8, received, allocator=allocator);
-    // memory.copy(result.data, buffer, received);
-
-    // return result;
 }
 
 socket_recv_into :: (s: &Socket, buffer: [] u8) -> i32 {
     res := runtime.platform.__net_sock_recv(s.handle, buffer);
+    res.Err->with([err] {
+        if err == .EOF {
+            socket_close(s);
+        }
+    });
+
     if res.Err {
         return 0;
     }
 
     return res.Ok->unwrap();
-
-    // would_block: bool;
-    // received := __net_recv(s.handle, buffer, &would_block);
-    // if received < 0 && !would_block do s.vtable = null;
-    // if would_block do return 0;
-
-    // return received;
 }
 
 SocketRecvFromResult :: struct {
@@ -298,19 +321,16 @@ SocketRecvFromResult :: struct {
 
 socket_recvfrom :: (s: &Socket, buffer: [] u8) -> ? SocketRecvFromResult {
     sender_addr: SocketAddress;
-    res := runtime.platform.__net_sock_recvfrom(s.handle, buffer, &sender_addr);
-    if res.Err do return .{};
-
-    return .{ Some = .{ addr = sender_addr, res.Ok->unwrap() } };
-
-    // would_block: bool;
-    // sa: SocketAddress;
+    res := runtime.platform.__net_sock_recv_from(s.handle, buffer, &sender_addr);
+    res.Err->with([err] {
+        if err == .EOF {
+            socket_close(s);
+        }
+    });
 
-    // received := __net_recvfrom(s.handle, buffer, &sa, &would_block);
-    // if received < 0 && !would_block do s.vtable = null;
-    // if would_block do return sa, 0;
+    if res.Err do return .{};
 
-    // return sa, received;
+    return .{ Some = .{ sender_addr, res.Ok->unwrap() } };
 }
 
 // TODO: Add these back
@@ -325,6 +345,7 @@ socket_recvfrom :: (s: &Socket, buffer: [] u8) -> ? SocketRecvFromResult {
 #local __net_socket_vtable := io.Stream_Vtable.{
     read = (use s: &Socket, buffer: [] u8) -> (io.Error, u32) {
         if cast(i32) handle == 0 do return .BadFile, 0;
+        if !alive do return .BadFile, 0;
         
         res := runtime.platform.__net_sock_recv(handle, buffer);
         res->ok()->with([bytes_read] {
@@ -335,6 +356,9 @@ socket_recvfrom :: (s: &Socket, buffer: [] u8) -> ? SocketRecvFromResult {
 
         res->err()->with([err] {
             if err == .NoData do return .ReadLater, 0;
+            if err == .EOF {
+                socket_close(s);
+            }
 
             return err, 0;
         });
@@ -345,6 +369,10 @@ socket_recvfrom :: (s: &Socket, buffer: [] u8) -> ? SocketRecvFromResult {
 
         res := runtime.platform.__net_sock_send(handle, .[ byte ]);
         res->err()->with([err] {
+            if err == .EOF {
+                socket_close(s);
+            }
+
             return err;
         });
 
@@ -355,8 +383,12 @@ socket_recvfrom :: (s: &Socket, buffer: [] u8) -> ? SocketRecvFromResult {
     write = (use s: &Socket, buffer: [] u8) -> (io.Error, u32) {
         if cast(i32) handle == 0 do return .BadFile, 0;
         
-        res := runtime.platform.__net_sock_send(handle, .[ byte ]);
+        res := runtime.platform.__net_sock_send(handle, buffer);
         res->err()->with([err] {
+            if err == .EOF {
+                socket_close(s);
+            }
+
             return err, 0;
         });
 
@@ -412,17 +444,10 @@ ipv4_to_str :: (addr: u32) -> str {
 }
 
 // This returns a volatile buffer that should be copied.
-ipv6_to_str :: (addr_h: u64, addr_l: u64) -> str {
-    #persist out: [64] u8;
-    str_addr := conv.format(out, "{w2b16}:{w2b16}:{w2b16}:{w2b16}:{w2b16}:{w2b16}:{w2b16}:{w2b16}",
-        (addr_h >> 24) & 0xff,
-        (addr_h >> 16) & 0xff,
-        (addr_h >>  8) & 0xff,
-        (addr_h >>  0) & 0xff,
-        (addr_l >> 24) & 0xff,
-        (addr_l >> 16) & 0xff,
-        (addr_l >>  8) & 0xff,
-        (addr_l >>  0) & 0xff);
-    return str_addr;
+ipv6_to_str :: (addr: [16] u8) -> str {
+    return iter.as_iter(addr)
+        |> iter.map(x => tprintf("{w2b16}", cast(u32) x))
+        |> iter.collect()
+        |> string.join(" ");
 }
 
index 7d5f72ebe8b3c4b0c114c5cf1cd1a00cd90eb4ea..faddf2f3a28884395447972b12864e848c9ffa91 100644 (file)
@@ -39,21 +39,21 @@ TCP_Event :: struct {
     }
 
     Connection :: struct {
-        address : &Socket_Address;
+        address : &SocketAddress;
 
         // This is only set when the event is coming from the server.
         client  : &TCP_Server.Client;
     }
 
     Disconnection :: struct {
-        address: &Socket_Address;
+        address: &SocketAddress;
 
         // This is only set when the event is coming from the server.
         client  : &TCP_Server.Client;
     }
 
     Data :: struct {
-        address: &Socket_Address;
+        address: &SocketAddress;
         // This is only set when the event is coming from the server.
         client  : &TCP_Server.Client;
 
@@ -61,7 +61,7 @@ TCP_Event :: struct {
     }
 
     Ready :: struct {
-        address: &Socket_Address;
+        address: &SocketAddress;
         // This is only set when the event is coming from the server.
         client : &TCP_Server.Client;
     }
@@ -127,7 +127,7 @@ TCP_Server :: struct {
 #inject TCP_Server {
     Client :: struct {
         use socket  : Socket;
-        address : Socket_Address;
+        address : SocketAddress;
         state   : State;
 
         recv_ready_event_present := false;
@@ -148,8 +148,10 @@ TCP_Server :: struct {
 }
 
 tcp_server_make :: (max_clients := 32, allocator := context.allocator) -> &TCP_Server {
-    socket, err := socket_create(.Inet, .Stream); // IPv6?
-    if err != .None do return null;
+    maybe_socket := socket_create(.Inet, .Stream, .IP); // IPv6?
+    if maybe_socket.Err do return null;
+
+    socket := maybe_socket.Ok->unwrap();
 
     server := new(TCP_Server, allocator=allocator);
     server.socket = socket;
@@ -164,12 +166,12 @@ tcp_server_make :: (max_clients := 32, allocator := context.allocator) -> &TCP_S
 }
 
 tcp_server_listen :: (use server: &TCP_Server, port: u16) -> bool {
-    sa: Socket_Address;
+    sa: SocketAddress;
     make_ipv4_address(&sa, 0x00000000, port);
     if !(socket->bind(&sa)) do return false;
 
     socket->listen();
-    socket->setting(.NonBlocking, 1);
+    socket->option(.NonBlocking, true);
     return true;
 }
 
@@ -188,12 +190,11 @@ tcp_server_stop :: (use server: &TCP_Server) {
 tcp_server_pulse :: (use server: &TCP_Server) -> bool {
     //
     // Check for new connection
-    client_socket, client_addr := socket->accept();
-    if client_socket.vtable {
+    socket->accept().Ok->with([client_data] {
         client := new(TCP_Server.Client, allocator=client_allocator);
         client.state = .Alive;
-        client.socket = client_socket;
-        client.address = client_addr;
+        client.socket = client_data.socket;
+        client.address = client_data.addr;
 
         for& clients do if *it == null { *it = client; break; }
         server.client_count += 1;
@@ -203,7 +204,7 @@ tcp_server_pulse :: (use server: &TCP_Server) -> bool {
         conn_event.client = client;
 
         server.events << .{ .Connection, conn_event };
-    }
+    });
 
     // 
     // Process dead clients
@@ -238,7 +239,7 @@ tcp_server_pulse :: (use server: &TCP_Server) -> bool {
     if client_count == 0 {
         // Wait for a client to connect.
         status_buffer: [1] Socket_Poll_Status;
-        socket_poll_all(.[&socket], -1, status_buffer);
+        socket_poll_all(.[&socket], status_buffer, -1);
         return server.alive;
     }
 
@@ -364,7 +365,7 @@ wait_to_get_client_messages :: (use server: &TCP_Server) -> [] &TCP_Server.Clien
     }
 
     status_buffer := alloc.array_from_stack(Socket_Poll_Status, client_count);
-    socket_poll_all(cast([] &Socket) active_clients, pulse_time_ms, status_buffer);
+    socket_poll_all(cast([] &Socket) active_clients, status_buffer, pulse_time_ms);
 
     recv_clients: [..] &TCP_Server.Client;
     for it: client_count {
index 2d76888007b5ed1bdc2ca4853bf77ce1af62ec9c..0a619b7383fd3d04cf9dacf95d3a50887ec948a9 100644 (file)
 package runtime.platform
 
-use core.io
 use core.net {
     SocketFamily,
     SocketProto,
-    SocketType
+    SocketType,
+    SocketOption,
+    SocketAddress,
+    SocketShutdown
 }
+use core {Result, string, io}
 
 SocketData :: #distinct i32
 
 __net_sock_create :: (af: SocketFamily, type: SocketType, proto: SocketProto) -> Result(SocketData, io.Error) {
+    sock: SocketData;
 
-}
-
-__net_sock_status :: (s: SocketData) -> SocketStatus {
-
+    err := __net_create_socket(&sock, af, type, proto);
+    if err != .None {
+        return .{ Err = .CreationFailed };
+    }
+    
+    return .{ Ok = sock };
 }
 
 __net_sock_opt_flag :: (s: SocketData, sockopt: SocketOption, flag: bool) -> bool {
+    __net_setting_flag(s, sockopt, flag);
+    return true;
 }
 
 __net_sock_opt_time :: (s: SocketData, sockopt: SocketOption, time: ? u64) -> bool {
-
+    return false;
 }
 
 __net_sock_opt_size :: (s: SocketData, sockopt: SocketOption, size: i64) -> bool {
-
+    return false;
 }
 
 __net_sock_bind :: (s: SocketData, addr: &SocketAddress) -> bool {
+    switch *addr {
+        case &path: .Unix {
+            return __net_bind_unix(s, ~~path);
+        }
+
+        case host: .HostPort {
+            return __net_bind_host(s, host.host, host.port);
+        }
 
+        case #default do return false;
+    }
 }
 
 __net_sock_listen :: (s: SocketData, backlog: i32) -> bool {
-
+    return __net_listen(s, backlog) >= 0;
 }
 
-__net_sock_accept :: (s: SocketData, addr: &SocketAddress) -> Result(SocketData, io.Error) {
+__net_sock_accept :: (s: SocketData, out: &SocketAddress) -> Result(SocketData, io.Error) {
+    addr_buf: [512] u8;
+    addr_len := 512;
+
+    sock := __net_accept(s, &addr_buf, &addr_len);
+    if cast(i32) sock == -1
+    {
+        return .{ Err = .OperationFailed };
+    }
+
+    if cast(i32) sock == -2
+    {
+        return .{ Err = .NoData };
+    }
 
+    addr: &sockaddr_t = ~~addr_buf;
+    sockaddr_to_socket_address(addr, out);
+
+    return .{ Ok = sock };
 }
 
 __net_sock_connect :: (s: SocketData, addr: &SocketAddress) -> io.Error {
+    switch *addr {
+        case &path: .Unix {
+            return __net_connect_unix(s, ~~path)
+                |> translate_error();
+        }
+
+        case i: .Inet {
+            return __net_connect_ipv4(s, i.addr, i.port)
+                |> translate_error();
+        }
+
+        case i: .Inet6 {
+            return __net_connect_ipv6(s, i.addr, i.port)
+                |> translate_error();
+        }
+
+        case h: .HostPort {
+            return __net_connect_host(s, h.host, h.port)
+                |> translate_error();
+        }
+    }
 
+    translate_error :: (s: SocketError) => switch s {
+        case .None => io.Error.None;
+        case .ConnectFailed => .ConnectFailed;
+        case #default => .OperationFailed;
+    }
 }
 
-__net_sock_recv_from :: (s: SocketData, buf: [] u8, addr: &SocketAddress) -> Result(i32, io.Error) {
+__net_sock_recv_from :: (s: SocketData, buf: [] u8, out: &SocketAddress) -> Result(i32, io.Error) {
+    addr_buf: [512] u8;
+    addr_len := 512;
+
+    recieved := __net_recvfrom(s, buf, &addr_buf, &addr_len);
+    if recieved == 0 || recieved == -1
+    {
+        return .{ Err = .EOF };
+    }
+
+    if recieved == -2
+    {
+        return .{ Err = .NoData };
+    }
+
+    addr: &sockaddr_t = ~~ &addr_buf;    
+    sockaddr_to_socket_address(addr, out);
 
+    return .{ Ok = recieved };
 }
 
 __net_sock_send_to :: (s: SocketData, buf: [] u8, addr: &SocketAddress) -> Result(i32, io.Error) {
+    sent := switch *addr {
+        case &path: .Unix => __net_sendto_unix(s, buf, ~~path);
+        case i: .Inet     => __net_sendto_ipv4(s, buf, i.addr, i.port);
+        case i: .Inet6    => __net_sendto_ipv6(s, buf, i.addr, i.port);
+        case h: .HostPort => __net_sendto_host(s, buf, h.host, h.port);
+    };
+
+    if sent == 0 || sent == -1
+    {
+        // If there was an error sending data, call the connection closed.
+        return .{ Err = .EOF };
+    }
 
+    if sent == -2
+    {
+        // -2 is used for signalling a non-blocking send that did not successfully
+        // send anything.
+        return .{ Err = .NoData };
+    }
+
+    return .{ Ok = sent };
 }
 
 __net_sock_recv :: (s: SocketData, buf: [] u8) -> Result(i32, io.Error) {
+    recieved := __net_recv(s, buf);
+    if recieved == 0 || recieved == -1
+    {
+        // If there was an error sending data, call the connection closed.
+        return .{ Err = .EOF };
+    }
 
+    if recieved == -2
+    {
+        return .{ Err = .NoData };
+    }
+
+    return .{ Ok = recieved };
 }
 
 __net_sock_send :: (s: SocketData, buf: [] u8) -> Result(i32, io.Error) {
+    sent := __net_send(s, buf);
+    if sent == 0 || sent == -1
+    {
+        // If there was an error sending data, call the connection closed.
+        return .{ Err = .EOF };
+    }
 
+    if sent == -2
+    {
+        // -2 is used for signalling a non-blocking send that did not successfully
+        // send anything.
+        return .{ Err = .NoData };
+    }
+
+    return .{ Ok = sent };
 }
 
 __net_sock_shutdown :: (s: SocketData, how: SocketShutdown) -> io.Error {
+    if __net_shutdown(s, cast(u32) how) < 0 {
+        return .OperationFailed;
+    }
 
+    return .None;
 }
 
 __net_sock_close :: (s: SocketData) -> void {
-
+    __net_close_socket(s);
 }
 
 __net_resolve :: (host: str, port: u16, out_addrs: [] SocketAddress) -> i32 {
@@ -74,19 +202,78 @@ __net_resolve :: (host: str, port: u16, out_addrs: [] SocketAddress) -> i32 {
 
 
 #package {
+    SocketError :: enum {
+        None :: 0x00;
+        BadSettings :: 0x01;
+        ConnectFailed :: 0x02;
+    }
+
+    sockaddr_t :: struct {
+        family: u16;
+    }
+
+    sockaddr_un_t :: struct {
+        family: u16;
+        path: [256] u8;
+    }
+
+    sockaddr_in_t :: struct {
+        family: u16;
+        port: u16;
+        addr: u32;
+    }
+
+    sockaddr_in6_t :: struct {
+        family: u16;
+        port: u16;
+        flowinfo: u32;
+        addr: [16] u8;
+    }
+
+    sockaddr_to_socket_address :: (addr: &sockaddr_t, out: &SocketAddress) {
+        switch addr.family {
+            case 1 {
+                addr_un: &sockaddr_un_t = ~~addr;
+                *out = .{ Unix = addr_un.path };
+            }
+
+            case 2 {
+                addr_in: &sockaddr_in_t = ~~addr;
+                *out = .{ Inet = .{ addr_in.port, addr_in.addr } };
+            }
+
+            case 10 {
+                addr_in6: &sockaddr_in6_t = ~~addr;
+                *out = .{ Inet6 = .{ addr_in6.port, addr_in6.addr } };
+            }
+        }
+    }
+
     #foreign "onyx_runtime" {
-        __net_create_socket :: (out_handle: &Socket.Handle, domain: SocketDomain, type: SocketType) -> SocketError ---
-        __net_close_socket  :: (handle: Socket.Handle)               -> void ---
-        __net_setting       :: (handle: Socket.Handle, setting: SocketSetting, value: i32) -> void ---
-        __net_bind          :: (handle: Socket.Handle, bind_address: &Socket_Address)    -> bool ---
-        __net_listen        :: (handle: Socket.Handle, backlog: i32) -> void ---
-        __net_accept        :: (handle: Socket.Handle, out_address: &Socket_Address) -> Socket.Handle ---
-        __net_connect_unix  :: (handle: Socket.Handle, path: str) -> SocketError ---
-        __net_connect_ipv4  :: (handle: Socket.Handle, host: str, port: u16) -> SocketError ---
-        __net_shutdown      :: (handle: Socket.Handle, how: u32) -> void ---
-        __net_send          :: (handle: Socket.Handle, data: [] u8)  -> i32 ---
-        __net_sendto        :: (handle: Socket.Handle, data: [] u8, addr: &Socket_Address)  -> i32 ---
-        __net_recv          :: (handle: Socket.Handle, data: [] u8, async_would_block: &bool) -> i32 ---
-        __net_recvfrom      :: (handle: Socket.Handle, data: [] u8, out_recv_addr: &Socket_Address, async_would_block: &bool) -> i32 ---
+        __net_create_socket :: (out_handle: &SocketData, family: SocketFamily, type: SocketType, proto: SocketProto) -> SocketError ---
+        __net_close_socket  :: (handle: SocketData) -> void ---
+        __net_shutdown      :: (handle: SocketData, how: u32) -> i32 ---
+        __net_listen        :: (handle: SocketData, backlog: i32) -> i32 ---
+
+        __net_connect_unix  :: (handle: SocketData, path: cstr) -> SocketError ---
+        __net_connect_ipv4  :: (handle: SocketData, addr: u32, port: u16) -> SocketError ---
+        __net_connect_ipv6  :: (handle: SocketData, addr: [16] u8, port: u16) -> SocketError ---
+        __net_connect_host  :: (handle: SocketData, host: str, port: u16) -> SocketError ---
+
+        __net_bind_unix     :: (handle: SocketData, path: cstr) -> bool ---
+        __net_bind_host     :: (handle: SocketData, host: str, port: u16) -> bool ---
+
+        __net_accept        :: (handle: SocketData, out_buf: rawptr, out_len: &i32) -> SocketData ---
+
+        __net_send          :: (handle: SocketData, data: [] u8)  -> i32 ---
+        __net_sendto_unix   :: (handle: SocketData, data: [] u8, path: cstr)  -> i32 ---
+        __net_sendto_ipv4   :: (handle: SocketData, data: [] u8, addr: u32, port: u16) -> i32 ---
+        __net_sendto_ipv6   :: (handle: SocketData, data: [] u8, addr: [16] u8, port: u16) -> i32 ---
+        __net_sendto_host   :: (handle: SocketData, data: [] u8, host: str, port: u16) -> i32 ---
+
+        __net_recv          :: (handle: SocketData, data: [] u8) -> i32 ---
+        __net_recvfrom      :: (handle: SocketData, data: [] u8, out_buf: rawptr, out_len: &i32) -> i32 ---
+
+        __net_setting_flag  :: (handle: SocketData, setting: SocketOption, value: bool) -> void ---
     }
 }
\ No newline at end of file
index 7325bce90f173cb586db983343a2068e7099371c..4c50afa8bf0f943415918caaf1c32aa68bc435d3 100644 (file)
@@ -11,6 +11,7 @@ use runtime {
 
 #load "./fs"
 #load "./env"
+#load "./net"
 
 #load "core/onyx/cptr"
 #load "core/onyx/cbindgen"
index 06d1065ff7975e1995478e23d5a2598ae3a01ede..fd234c0c9c071d6e7f6d19c46e9258e7e20498e2 100644 (file)
@@ -160,7 +160,6 @@ this document will serve as that "header file"
 
 ### Procedures
 - `__net_sock_create(af: SocketFamily, type: SocketType, proto: SocketProto) -> Result(SocketData, io.Error)`
-- `__net_sock_status(SocketData) -> SocketStatus`
 - `__net_sock_opt_flag(SocketData, sockopt: SocketOption, flag: bool) -> bool`
 - `__net_sock_opt_time(SocketData, sockopt: SocketOption, time: ? u64) -> bool`
 - `__net_sock_opt_size(SocketData, sockopt: SocketOption, size: i64) -> bool`
index c80097bf951e73176622b2e9c40a6153b4fd97bc..879b69c243fd401a001701787ca1dd546454383f 100644 (file)
 #include "src/ort_processes.h"
 #include "src/ort_os.h"
 #include "src/ort_cptr.h"
-#include "src/ort_net.h"
 #include "src/ort_tty.h"
 
+#ifdef _BH_LINUX
+#include "src/ort_net_linux.h"
+#endif
+
+#ifdef _BH_WINDOWS
+#include "src/ort_net_windows.h"
+#endif
+
 
 ONYX_LIBRARY {
     ONYX_FUNC(__file_open_impl)
@@ -86,21 +93,23 @@ ONYX_LIBRARY {
 
     ONYX_FUNC(__net_create_socket)
     ONYX_FUNC(__net_close_socket)
-    ONYX_FUNC(__net_setting)
-    ONYX_FUNC(__net_bind)
+    ONYX_FUNC(__net_setting_flag)
+    ONYX_FUNC(__net_bind_unix)
+    ONYX_FUNC(__net_bind_host)
     ONYX_FUNC(__net_listen)
     ONYX_FUNC(__net_accept)
     ONYX_FUNC(__net_connect_unix)
     ONYX_FUNC(__net_connect_ipv4)
+    ONYX_FUNC(__net_connect_ipv6)
+    ONYX_FUNC(__net_connect_host)
     ONYX_FUNC(__net_shutdown)
     ONYX_FUNC(__net_send)
-    ONYX_FUNC(__net_sendto)
+    ONYX_FUNC(__net_sendto_unix)
+    ONYX_FUNC(__net_sendto_ipv4)
+    ONYX_FUNC(__net_sendto_ipv6)
+    ONYX_FUNC(__net_sendto_host)
     ONYX_FUNC(__net_recv)
     ONYX_FUNC(__net_recvfrom)
-    ONYX_FUNC(__net_host_to_net_s)
-    ONYX_FUNC(__net_host_to_net_l)
-    ONYX_FUNC(__net_net_to_host_s)
-    ONYX_FUNC(__net_net_to_host_l)
 
     ONYX_FUNC(__cptr_make)
     ONYX_FUNC(__cptr_read)
diff --git a/runtime/src/ort_net.h b/runtime/src/ort_net.h
deleted file mode 100644 (file)
index caa407e..0000000
+++ /dev/null
@@ -1,345 +0,0 @@
-
-//
-// Networking
-//
-
-struct onyx_socket_addr {
-    unsigned short family;
-    unsigned short port;
-    unsigned int   addr;
-};
-
-static inline int onyx_socket_domain(int i) {
-    #if defined(_BH_LINUX)
-    switch (i) {    // :EnumDependent
-        case 0: return AF_UNIX;
-        case 1: return AF_INET;
-        case 2: return AF_INET6;
-        default: return -1;
-    }
-    #elif defined(_BH_WINDOWS)
-    return -1;
-    #endif
-}
-
-static inline int onyx_socket_protocol(int i) {
-    #if defined(_BH_LINUX)
-    switch (i) {    // :EnumDependent
-        case 0: return SOCK_STREAM;
-        case 1: return SOCK_DGRAM;
-        default: return -1;
-    }
-    #elif defined(_BH_WINDOWS)
-    return -1;
-    #endif
-}
-
-ONYX_DEF(__net_create_socket, (WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
-
-    #ifdef _BH_LINUX
-    int domain = onyx_socket_domain(params->data[1].of.i32);
-    if (domain == -1) goto bad_settings;
-
-    int type = onyx_socket_protocol(params->data[2].of.i32);
-    if (type == -1) goto bad_settings;
-
-    *((int *) ONYX_PTR(params->data[0].of.i32)) = socket(domain, type, 0);
-
-    results->data[0] = WASM_I32_VAL(0);
-    return NULL;
-    #endif 
-
-    #ifdef _BH_WINDOWS
-    #endif
-
-bad_settings:
-    results->data[0] = WASM_I32_VAL(1); // :EnumDependent
-    return NULL;
-}
-
-ONYX_DEF(__net_close_socket, (WASM_I32), ()) {
-    #ifdef _BH_LINUX
-    shutdown(params->data[0].of.i32, SHUT_RDWR);
-    close(params->data[0].of.i32);
-    #endif
-
-    #ifdef _BH_WINDOWS
-    #endif
-
-    return NULL;
-}
-
-ONYX_DEF(__net_setting, (WASM_I32, WASM_I32, WASM_I32), ()) {
-    #ifdef _BH_LINUX
-    switch (params->data[1].of.i32) {
-        case 1: { // :EnumDependent  Non-Blocking
-            int s = params->data[0].of.i32;
-            int flags = fcntl(s, F_GETFL, 0);
-            if (params->data[2].of.i32) {
-                flags |= O_NONBLOCK;
-            } else {
-                flags &= ~O_NONBLOCK;
-            }
-
-            fcntl(s, F_SETFL, flags);
-            break;
-        }
-
-        case 2: { // :EnumDependent  Broadcast
-            int s = params->data[0].of.i32;
-            setsockopt(s, SOL_SOCKET, SO_BROADCAST, (void *) &params->data[2].of.i32, sizeof(int));
-            break;
-        }
-
-        case 3: { // :EnumDependent  Reuse-Address
-            int s = params->data[0].of.i32;
-            setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *) &params->data[2].of.i32, sizeof(int));
-            break;
-        }
-    }
-    #endif
-
-    return NULL;
-}
-
-ONYX_DEF(__net_bind, (WASM_I32, WASM_I32), (WASM_I32)) {
-
-    #ifdef _BH_LINUX
-    int res = -1;
-
-    struct onyx_socket_addr *oaddr = (void *) ONYX_PTR(params->data[1].of.i32);
-    int family = onyx_socket_domain(oaddr->family);
-    int port   = oaddr->port;
-
-    switch (family) {
-        case AF_INET: {
-            struct sockaddr_in bind_addr;
-            memset(&bind_addr, 0, sizeof(bind_addr));
-
-            bind_addr.sin_family = AF_INET;
-            bind_addr.sin_addr.s_addr = htonl(oaddr->addr);
-            bind_addr.sin_port = htons(port);
-
-            res = bind(params->data[0].of.i32, &bind_addr, sizeof(bind_addr));
-            break;
-        }
-
-        case AF_INET6: {
-            struct sockaddr_in6 bind_addr;
-            memset(&bind_addr, 0, sizeof(bind_addr));
-
-            bind_addr.sin6_family = AF_INET6;
-            memcpy(&bind_addr.sin6_addr.s6_addr, (void *) &oaddr->addr, 16);
-            bind_addr.sin6_port = htons(port);
-            
-            res = bind(params->data[0].of.i32, &bind_addr, sizeof(bind_addr));
-            break;
-        }
-
-        case AF_UNIX: {
-            struct sockaddr_un bind_addr;
-            memset(&bind_addr, 0, sizeof(bind_addr));
-
-            bind_addr.sun_family = AF_UNIX;
-            strncpy(&bind_addr.sun_path, (char *) &oaddr->addr, 108);
-            
-            res = bind(params->data[0].of.i32, &bind_addr, sizeof(bind_addr));
-            break;
-        }
-    }
-
-    results->data[0] = WASM_I32_VAL(res >= 0);
-    #endif
-
-    #ifdef _BH_WINDOWS
-    #endif
-
-    return NULL;
-}
-
-ONYX_DEF(__net_listen, (WASM_I32, WASM_I32), ()) {
-    #ifdef _BH_LINUX
-    listen(params->data[0].of.i32, params->data[1].of.i32);
-    #endif
-
-    #ifdef _BH_WINDOWS
-    #endif
-
-    return NULL;
-}
-
-ONYX_DEF(__net_accept, (WASM_I32, WASM_I32), (WASM_I32)) {
-    #ifdef _BH_LINUX
-    struct sockaddr_in client_addr;
-    int client_len = sizeof(client_addr);
-    memset(&client_addr, 0, client_len);
-
-    int client_socket = accept(params->data[0].of.i32, &client_addr, &client_len);
-
-    struct onyx_socket_addr* out_addr = (struct onyx_socket_addr *) ONYX_PTR(params->data[1].of.i32); 
-    out_addr->family = client_addr.sin_family;
-    out_addr->port   = ntohs(client_addr.sin_port);
-    out_addr->addr   = ntohl(client_addr.sin_addr.s_addr);
-
-    results->data[0] = WASM_I32_VAL(client_socket);
-    #endif
-
-    return NULL;
-}
-
-ONYX_DEF(__net_connect_unix, (WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
-    #ifdef _BH_LINUX
-    int   hostlen  = params->data[2].of.i32;
-    char *hostname = alloca(hostlen + 1);
-    memcpy(hostname, ONYX_PTR(params->data[1].of.i32), hostlen);
-    hostname[hostlen] = '\0';
-
-    struct sockaddr_un server_addr;
-    memset(&server_addr, 0, sizeof(server_addr));
-
-    server_addr.sun_family = AF_UNIX; // See comment above
-    memcpy((char *)&server_addr.sun_path, hostname, hostlen);
-
-    int result = connect(params->data[0].of.i32, &server_addr, sizeof(server_addr));
-    if (result == 0) results->data[0] = WASM_I32_VAL(0);
-    else             results->data[0] = WASM_I32_VAL(3); // :EnumDependent
-    #endif
-    
-    return NULL;
-}
-
-ONYX_DEF(__net_connect_ipv4, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
-    #ifdef _BH_LINUX
-    int   hostlen  = params->data[2].of.i32;
-    char *hostname = alloca(hostlen + 1);
-    memcpy(hostname, ONYX_PTR(params->data[1].of.i32), hostlen);
-    hostname[hostlen] = '\0';
-
-    struct hostent *host;
-    host = gethostbyname(hostname); // TODO: Replace this call, as it is obselete.
-    if (host == NULL) {
-        results->data[0] = WASM_I32_VAL(2);  // :EnumDependent
-        return NULL;
-    }
-
-    struct sockaddr_in server_addr;
-    memset(&server_addr, 0, sizeof(server_addr));
-
-    server_addr.sin_family = AF_INET; // See comment above
-    memcpy((char *)&server_addr.sin_addr.s_addr, (char *)host->h_addr, host->h_length);
-    server_addr.sin_port = htons(params->data[3].of.i32);
-
-    int result = connect(params->data[0].of.i32, &server_addr, sizeof(server_addr));
-    if (result == 0) results->data[0] = WASM_I32_VAL(0);
-    else             results->data[0] = WASM_I32_VAL(3); // :EnumDependent
-
-    return NULL;
-    #endif
-
-    #ifdef _BH_WINDOWS
-    #endif
-}
-
-ONYX_DEF(__net_shutdown, (WASM_I32, WASM_I32), ()) {
-    #ifdef _BH_LINUX
-    shutdown(params->data[0].of.i32, params->data[1].of.i32);
-    return NULL;
-    #endif
-
-    #ifdef _BH_WINDOWS
-    #endif
-}
-
-ONYX_DEF(__net_send, (WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
-    #ifdef _BH_LINUX
-    // TODO: The flags at the end should be controllable.
-    int sent = send(params->data[0].of.i32, ONYX_PTR(params->data[1].of.i32), params->data[2].of.i32, MSG_NOSIGNAL);
-    results->data[0] = WASM_I32_VAL(sent);
-    #endif
-    
-    return NULL;
-}
-
-ONYX_DEF(__net_sendto, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
-    #ifdef _BH_LINUX
-    struct sockaddr_in dest_addr;
-    int dest_addr_len = sizeof(dest_addr);
-    memset(&dest_addr, 0, dest_addr_len);
-
-    struct onyx_socket_addr *o_addr = (struct onyx_socket_addr *) ONYX_PTR(params->data[3].of.i32);
-    dest_addr.sin_family = AF_INET; // TODO: See other comments related to AF_NET above.
-    dest_addr.sin_port = htons(o_addr->port);
-    dest_addr.sin_addr.s_addr = htonl(o_addr->addr);
-
-    // TODO: The flags at the end should be controllable.
-    int sent = sendto(params->data[0].of.i32, ONYX_PTR(params->data[1].of.i32), params->data[2].of.i32, MSG_NOSIGNAL, &dest_addr, dest_addr_len);
-    results->data[0] = WASM_I32_VAL(sent);
-    #endif
-    
-    return NULL;
-}
-
-ONYX_DEF(__net_recv, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
-    *(i32 *) ONYX_PTR(params->data[3].of.i32) = 0;
-
-    #ifdef _BH_LINUX
-    // TODO: The flags at the end should be controllable.
-    int received = recv(params->data[0].of.i32, ONYX_PTR(params->data[1].of.i32), params->data[2].of.i32, 0);
-    results->data[0] = WASM_I32_VAL(received);
-
-    if (received < 0) {
-        if (errno == EAGAIN || errno == EWOULDBLOCK) {
-            *(i32 *) ONYX_PTR(params->data[3].of.i32) = 1;
-        }
-    }
-    #endif
-
-    return NULL;
-}
-
-ONYX_DEF(__net_recvfrom, (WASM_I32, WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
-    *(i32 *) ONYX_PTR(params->data[4].of.i32) = 0;
-
-    #ifdef _BH_LINUX
-    struct onyx_socket_addr *out_addr = (struct onyx_socket_addr *) ONYX_PTR(params->data[3].of.i32);
-
-    struct sockaddr_in client_addr;
-    int socket_len = sizeof(client_addr);
-    memset(&client_addr, 0, socket_len);
-
-    int received = recvfrom(params->data[0].of.i32, ONYX_PTR(params->data[1].of.i32), params->data[2].of.i32, 0, &client_addr, &socket_len);
-    out_addr->family = client_addr.sin_family;
-    out_addr->port   = ntohs(client_addr.sin_port);
-    out_addr->addr   = ntohl(client_addr.sin_addr.s_addr);
-
-    results->data[0] = WASM_I32_VAL(received);
-
-    if (received < 0) {
-        if (errno == EAGAIN || errno == EWOULDBLOCK) {
-            *(i32 *) ONYX_PTR(params->data[3].of.i32) = 1;
-        }
-    }
-    #endif
-
-    return NULL;
-}
-
-ONYX_DEF(__net_host_to_net_s, (WASM_I32), (WASM_I32)) {
-    results->data[0] = WASM_I32_VAL(htons(params->data[0].of.i32));
-    return NULL;
-}
-
-ONYX_DEF(__net_host_to_net_l, (WASM_I32), (WASM_I32)) {
-    results->data[0] = WASM_I32_VAL(htonl(params->data[0].of.i32));
-    return NULL;
-}
-
-ONYX_DEF(__net_net_to_host_s, (WASM_I32), (WASM_I32)) {
-    results->data[0] = WASM_I32_VAL(ntohs(params->data[0].of.i32));
-    return NULL;
-}
-
-ONYX_DEF(__net_net_to_host_l, (WASM_I32), (WASM_I32)) {
-    results->data[0] = WASM_I32_VAL(ntohl(params->data[0].of.i32));
-    return NULL;
-}
diff --git a/runtime/src/ort_net_linux.h b/runtime/src/ort_net_linux.h
new file mode 100644 (file)
index 0000000..a2d2512
--- /dev/null
@@ -0,0 +1,398 @@
+
+//
+// Networking
+//
+
+#include <byteswap.h>
+
+#define SOCKET_ERROR_NONE 0
+#define SOCKET_ERROR_BAD_SETTINGS 1
+#define SOCKET_ERROR_CONNECT_FAILED 1
+
+struct onyx_socket_addr {
+    unsigned short family;
+    unsigned short port;
+    unsigned int   addr;
+};
+
+static inline int onyx_socket_domain(int i) {
+    // :EnumDependent
+    switch (i) {
+        case 1: return AF_INET;
+        case 2: return AF_INET6;
+        case 3: return AF_UNIX;
+        default: return -1;
+    }
+}
+
+static inline int onyx_socket_protocol(int i) {
+    // :EnumDependent
+    switch (i) {
+        case 0: return SOCK_STREAM;
+        case 1: return SOCK_DGRAM;
+        default: return -1;
+    }
+}
+
+ONYX_DEF(__net_create_socket, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+    int domain = onyx_socket_domain(params->data[1].of.i32);
+    if (domain == -1) goto bad_settings;
+
+    int type = onyx_socket_protocol(params->data[2].of.i32);
+    if (type == -1) goto bad_settings;
+
+    int proto = params->data[3].of.i32;
+
+    int sock = socket(domain, type, proto);
+    if (sock >= 0)
+    {
+        *((int *) ONYX_PTR(params->data[0].of.i32)) = sock;
+
+        results->data[0] = WASM_I32_VAL(SOCKET_ERROR_NONE);
+        return NULL;
+    }
+
+bad_settings:
+    results->data[0] = WASM_I32_VAL(SOCKET_ERROR_BAD_SETTINGS);
+    return NULL;
+}
+
+ONYX_DEF(__net_close_socket, (WASM_I32), ()) {
+    shutdown(params->data[0].of.i32, SHUT_RDWR);
+    close(params->data[0].of.i32);
+
+    return NULL;
+}
+
+ONYX_DEF(__net_setting_flag, (WASM_I32, WASM_I32, WASM_I32), ()) {
+    switch (params->data[1].of.i32) {
+        case 1: { // :EnumDependent  Non-Blocking
+            int s = params->data[0].of.i32;
+            int flags = fcntl(s, F_GETFL, 0);
+            if (params->data[2].of.i32 > 0) {
+                flags |= O_NONBLOCK;
+            } else {
+                flags &= ~O_NONBLOCK;
+            }
+
+            fcntl(s, F_SETFL, flags);
+            break;
+        }
+
+        case 2: { // :EnumDependent  Broadcast
+            int s = params->data[0].of.i32;
+            setsockopt(s, SOL_SOCKET, SO_BROADCAST, (void *) &params->data[2].of.i32, sizeof(int));
+            break;
+        }
+
+        case 3: { // :EnumDependent  Reuse-Address
+            int s = params->data[0].of.i32;
+            setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *) &params->data[2].of.i32, sizeof(int));
+            break;
+        }
+    }
+
+    return NULL;
+}
+
+ONYX_DEF(__net_bind_unix, (WASM_I32, WASM_I32), (WASM_I32)) {
+    char *hostname = ONYX_PTR(params->data[1].of.i32);
+
+    struct sockaddr_un bind_addr;
+    memset(&bind_addr, 0, sizeof(bind_addr));
+
+    bind_addr.sun_family = AF_UNIX;
+    strncpy(&bind_addr.sun_path, hostname, 108);
+    
+    if (bind(params->data[0].of.i32, &bind_addr, sizeof(bind_addr)) >= 0) {
+        results->data[0] = WASM_I32_VAL(1);
+    } else {
+        results->data[0] = WASM_I32_VAL(0);
+    }
+
+    return NULL;
+}
+
+ONYX_DEF(__net_bind_host, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+    int   hostlen  = params->data[2].of.i32;
+    char *hostname = alloca(hostlen + 1);
+    memcpy(hostname, ONYX_PTR(params->data[1].of.i32), hostlen);
+    hostname[hostlen] = '\0';
+
+    char portstr[8] = { 0 };
+    bh_snprintf(portstr, 8, "%d", params->data[3].of.i32);
+
+    struct addrinfo *result;
+    if (getaddrinfo(hostname, portstr, NULL, &result) < 0)
+    {
+        results->data[0] = WASM_I32_VAL(0);
+        return NULL;
+    }
+
+    if (bind(params->data[0].of.i32, result->ai_addr, result->ai_addrlen) >= 0) {
+        results->data[0] = WASM_I32_VAL(1);
+    } else {
+        results->data[0] = WASM_I32_VAL(0);
+    }
+
+    return NULL;
+}
+
+ONYX_DEF(__net_listen, (WASM_I32, WASM_I32), (WASM_I32)) {
+    results->data[0] = WASM_I32_VAL(listen(params->data[0].of.i32, params->data[1].of.i32));
+    return NULL;
+}
+
+ONYX_DEF(__net_accept, (WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+    int client_socket = accept(
+        params->data[0].of.i32,
+        ONYX_PTR(params->data[1].of.i32),
+        ONYX_PTR(params->data[2].of.i32)
+    );
+
+    if (client_socket < 0) {
+        if (errno == EWOULDBLOCK || errno == EAGAIN) {
+            client_socket = -2;
+        }
+    }
+
+    results->data[0] = WASM_I32_VAL(client_socket);
+
+    return NULL;
+}
+
+ONYX_DEF(__net_connect_unix, (WASM_I32, WASM_I32), (WASM_I32)) {
+    char *hostname = ONYX_PTR(params->data[1].of.i32);
+
+    struct sockaddr_un server_addr;
+    memset(&server_addr, 0, sizeof(server_addr));
+
+    server_addr.sun_family = AF_UNIX; // See comment above
+    memcpy((char *)& server_addr.sun_path, hostname, strnlen(hostname, 512)); // Arbitrary max path length
+
+    int result = connect(params->data[0].of.i32, &server_addr, sizeof(server_addr));
+    if (result == 0) {
+        results->data[0] = WASM_I32_VAL(SOCKET_ERROR_NONE);
+    } else {
+        results->data[0] = WASM_I32_VAL(SOCKET_ERROR_CONNECT_FAILED);
+    }
+    
+    return NULL;
+}
+
+ONYX_DEF(__net_connect_ipv4, (WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+    struct sockaddr_in server_addr;
+    memset(&server_addr, 0, sizeof(server_addr));
+
+    server_addr.sin_family = AF_INET;
+    server_addr.sin_addr.s_addr = params->data[1].of.i32;
+    server_addr.sin_port = htons(params->data[2].of.i32);
+
+    int result = connect(params->data[0].of.i32, &server_addr, sizeof(server_addr));
+    if (result == 0) {
+        results->data[0] = WASM_I32_VAL(SOCKET_ERROR_NONE);
+    } else {
+        results->data[0] = WASM_I32_VAL(SOCKET_ERROR_CONNECT_FAILED);
+    }
+
+    return NULL;
+}
+
+ONYX_DEF(__net_connect_ipv6, (WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+    struct sockaddr_in6 server_addr;
+    memset(&server_addr, 0, sizeof(server_addr));
+
+    char *addr = ONYX_PTR(params->data[1].of.i32);
+
+    server_addr.sin6_family = AF_INET6;
+    memcpy(&server_addr.sin6_addr.s6_addr, addr, 16);
+    server_addr.sin6_port = htons(params->data[2].of.i32);
+
+    int result = connect(params->data[0].of.i32, &server_addr, sizeof(server_addr));
+    if (result == 0) {
+        results->data[0] = WASM_I32_VAL(SOCKET_ERROR_NONE);
+    } else {
+        results->data[0] = WASM_I32_VAL(SOCKET_ERROR_CONNECT_FAILED);
+    }
+
+    return NULL;
+}
+
+ONYX_DEF(__net_connect_host, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+    int   hostlen  = params->data[2].of.i32;
+    char *hostname = alloca(hostlen + 1);
+    memcpy(hostname, ONYX_PTR(params->data[1].of.i32), hostlen);
+    hostname[hostlen] = '\0';
+
+    char portstr[8] = { 0 };
+    bh_snprintf(portstr, 8, "%d", params->data[3].of.i32);
+
+    struct addrinfo *result;
+    if (getaddrinfo(hostname, portstr, NULL, &result) < 0)
+    {
+        results->data[0] = WASM_I32_VAL(SOCKET_ERROR_CONNECT_FAILED);
+        return NULL;
+    }
+
+    int res = connect(params->data[0].of.i32, result->ai_addr, result->ai_addrlen);
+    if (res == 0) {
+        results->data[0] = WASM_I32_VAL(SOCKET_ERROR_NONE);
+    } else {
+        results->data[0] = WASM_I32_VAL(SOCKET_ERROR_CONNECT_FAILED);
+    }
+
+    return NULL;
+}
+
+ONYX_DEF(__net_shutdown, (WASM_I32, WASM_I32), (WASM_I32)) {
+    // This assumes that the `SocketShutdown` enum uses
+    // the same values as what this function is expecting.
+    //  Closing READ = 0
+    //  Closing WRITE = 1
+    //  Closing READ and WRITE = 2
+    results->data[0] = WASM_I32_VAL(shutdown(params->data[0].of.i32, params->data[1].of.i32));
+    return NULL;
+}
+
+ONYX_DEF(__net_send, (WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+    int sent = send(params->data[0].of.i32, ONYX_PTR(params->data[1].of.i32), params->data[2].of.i32, MSG_NOSIGNAL);
+    results->data[0] = WASM_I32_VAL(sent);
+
+    // If there was an error sending, see if it was just a non-blocking issue.
+    // In that case, return -2 to signal no error, but no data sent.
+    if (sent < 0) {
+        if (errno == EAGAIN || errno == EWOULDBLOCK) {
+            results->data[0] = WASM_I32_VAL(-2);
+        }
+    }
+    
+    return NULL;
+}
+
+ONYX_DEF(__net_sendto_unix, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+    struct sockaddr_un dest_addr;
+    memset(&dest_addr, 0, sizeof(dest_addr));
+
+    char *hostname = ONYX_PTR(params->data[3].of.i32);
+
+    dest_addr.sun_family = AF_UNIX;
+    memcpy((char *)& dest_addr.sun_path, hostname, strnlen(hostname, 512)); // Arbitrary max path length
+
+    int sent = sendto(
+        params->data[0].of.i32, ONYX_PTR(params->data[1].of.i32), params->data[2].of.i32,
+        MSG_NOSIGNAL, &dest_addr, sizeof(dest_addr));
+    results->data[0] = WASM_I32_VAL(sent);
+
+    if (sent < 0) {
+        if (errno == EAGAIN || errno == EWOULDBLOCK) {
+            results->data[0] = WASM_I32_VAL(-2);
+        }
+    }
+    return NULL;
+}
+
+ONYX_DEF(__net_sendto_ipv4, (WASM_I32, WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+    struct sockaddr_in dest_addr;
+    memset(&dest_addr, 0, sizeof(dest_addr));
+
+    char *addr = ONYX_PTR(params->data[3].of.i32);
+
+    dest_addr.sin_family = AF_INET;
+    dest_addr.sin_addr.s_addr = params->data[3].of.i32;
+    dest_addr.sin_port = htons(params->data[4].of.i32);
+
+    int sent = sendto(
+        params->data[0].of.i32, ONYX_PTR(params->data[1].of.i32), params->data[2].of.i32,
+        MSG_NOSIGNAL, &dest_addr, sizeof(dest_addr));
+    results->data[0] = WASM_I32_VAL(sent);
+
+    if (sent < 0) {
+        if (errno == EAGAIN || errno == EWOULDBLOCK) {
+            results->data[0] = WASM_I32_VAL(-2);
+        }
+    }
+    return NULL;
+}
+
+ONYX_DEF(__net_sendto_ipv6, (WASM_I32, WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+    struct sockaddr_in6 dest_addr;
+    memset(&dest_addr, 0, sizeof(dest_addr));
+
+    char *addr = ONYX_PTR(params->data[3].of.i32);
+
+    dest_addr.sin6_family = AF_INET6;
+    memcpy(&dest_addr.sin6_addr.s6_addr, addr, 16);
+    dest_addr.sin6_port = htons(params->data[4].of.i32);
+
+    int sent = sendto(
+        params->data[0].of.i32, ONYX_PTR(params->data[1].of.i32), params->data[2].of.i32,
+        MSG_NOSIGNAL, &dest_addr, sizeof(dest_addr));
+    results->data[0] = WASM_I32_VAL(sent);
+
+    if (sent < 0) {
+        if (errno == EAGAIN || errno == EWOULDBLOCK) {
+            results->data[0] = WASM_I32_VAL(-2);
+        }
+    }
+    return NULL;
+}
+
+ONYX_DEF(__net_sendto_host, (WASM_I32, WASM_I32, WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+    int   hostlen  = params->data[4].of.i32;
+    char *hostname = alloca(hostlen + 1);
+    memcpy(hostname, ONYX_PTR(params->data[3].of.i32), hostlen);
+    hostname[hostlen] = '\0';
+
+    char portstr[8] = { 0 };
+    bh_snprintf(portstr, 8, "%d", params->data[5].of.i32);
+
+    struct addrinfo *result;
+    if (getaddrinfo(hostname, portstr, NULL, &result) < 0)
+    {
+        results->data[0] = WASM_I32_VAL(-1);
+        return NULL;
+    }
+
+    int sent = sendto(
+        params->data[0].of.i32, ONYX_PTR(params->data[1].of.i32), params->data[2].of.i32,
+        MSG_NOSIGNAL, result->ai_addr, result->ai_addrlen);
+    results->data[0] = WASM_I32_VAL(sent);
+
+    if (sent < 0) {
+        if (errno == EAGAIN || errno == EWOULDBLOCK) {
+            results->data[0] = WASM_I32_VAL(-2);
+        }
+    }
+    return NULL;
+}
+
+ONYX_DEF(__net_recv, (WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+    // TODO: The flags at the end should be controllable.
+    int received = recv(params->data[0].of.i32, ONYX_PTR(params->data[1].of.i32), params->data[2].of.i32, MSG_NOSIGNAL);
+    results->data[0] = WASM_I32_VAL(received);
+
+    if (received < 0) {
+        if (errno == EAGAIN || errno == EWOULDBLOCK) {
+            results->data[0] = WASM_I32_VAL(received);
+        }
+    }
+
+    return NULL;
+}
+
+ONYX_DEF(__net_recvfrom, (WASM_I32, WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+    int received = recvfrom(
+        params->data[0].of.i32,
+        ONYX_PTR(params->data[1].of.i32), params->data[2].of.i32,
+        MSG_NOSIGNAL,
+        ONYX_PTR(params->data[3].of.i32), ONYX_PTR(params->data[4].of.i32));
+    results->data[0] = WASM_I32_VAL(received);
+
+    if (received < 0) {
+        if (errno == EAGAIN || errno == EWOULDBLOCK) {
+            results->data[0] = WASM_I32_VAL(-2);
+        }
+    }
+
+    return NULL;
+}