From 93385903015c7edb80a00e24ff7f8e97dfc4da6c Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Mon, 16 Oct 2023 21:48:18 -0500 Subject: [PATCH] implemented networking for linux --- core/io/io.onyx | 6 + core/net/net.onyx | 137 ++++---- core/net/tcp.onyx | 33 +- core/runtime/platform/onyx/net.onyx | 237 ++++++++++++-- core/runtime/platform/onyx/platform.onyx | 1 + docs/ideas/platform_layer.md | 1 - runtime/onyx_runtime.c | 25 +- runtime/src/ort_net.h | 345 -------------------- runtime/src/ort_net_linux.h | 398 +++++++++++++++++++++++ 9 files changed, 732 insertions(+), 451 deletions(-) delete mode 100644 runtime/src/ort_net.h create mode 100644 runtime/src/ort_net_linux.h diff --git a/core/io/io.onyx b/core/io/io.onyx index 12b783b6..9b6f13bc 100644 --- a/core/io/io.onyx +++ b/core/io/io.onyx @@ -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; } diff --git a/core/net/net.onyx b/core/net/net.onyx index 0dffaaa7..d537041d 100644 --- a/core/net/net.onyx +++ b/core/net/net.onyx @@ -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(" "); } diff --git a/core/net/tcp.onyx b/core/net/tcp.onyx index 7d5f72eb..faddf2f3 100644 --- a/core/net/tcp.onyx +++ b/core/net/tcp.onyx @@ -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 { diff --git a/core/runtime/platform/onyx/net.onyx b/core/runtime/platform/onyx/net.onyx index 2d768880..0a619b73 100644 --- a/core/runtime/platform/onyx/net.onyx +++ b/core/runtime/platform/onyx/net.onyx @@ -1,71 +1,199 @@ 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 diff --git a/core/runtime/platform/onyx/platform.onyx b/core/runtime/platform/onyx/platform.onyx index 7325bce9..4c50afa8 100644 --- a/core/runtime/platform/onyx/platform.onyx +++ b/core/runtime/platform/onyx/platform.onyx @@ -11,6 +11,7 @@ use runtime { #load "./fs" #load "./env" +#load "./net" #load "core/onyx/cptr" #load "core/onyx/cbindgen" diff --git a/docs/ideas/platform_layer.md b/docs/ideas/platform_layer.md index 06d1065f..fd234c0c 100644 --- a/docs/ideas/platform_layer.md +++ b/docs/ideas/platform_layer.md @@ -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` diff --git a/runtime/onyx_runtime.c b/runtime/onyx_runtime.c index c80097bf..879b69c2 100644 --- a/runtime/onyx_runtime.c +++ b/runtime/onyx_runtime.c @@ -34,9 +34,16 @@ #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 index caa407ef..00000000 --- a/runtime/src/ort_net.h +++ /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 *) ¶ms->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 *) ¶ms->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 index 00000000..a2d25129 --- /dev/null +++ b/runtime/src/ort_net_linux.h @@ -0,0 +1,398 @@ + +// +// Networking +// + +#include + +#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 *) ¶ms->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 *) ¶ms->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; +} -- 2.25.1