// 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;
}
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
}
SocketProto :: enum {
+ ANY :: 0x00;
IP :: 0x00;
ICMP :: 0x01;
IGMP :: 0x02;
IPV6 :: 0x29;
}
-SocketSetting :: enum {
+SocketOption :: enum {
NonBlocking :: 0x01;
Broadcast :: 0x02;
ReuseAddress :: 0x03;
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;
};
}
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) {
s.handle = socket;
s.flags |= .Block_On_Read;
+ s.alive = true;
return .{ Ok = s };
}
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);
}
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);
}
}
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 {
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;
}
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 {
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
#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] {
res->err()->with([err] {
if err == .NoData do return .ReadLater, 0;
+ if err == .EOF {
+ socket_close(s);
+ }
return err, 0;
});
res := runtime.platform.__net_sock_send(handle, .[ byte ]);
res->err()->with([err] {
+ if err == .EOF {
+ socket_close(s);
+ }
+
return err;
});
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;
});
}
// 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(" ");
}
}
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;
}
Ready :: struct {
- address: &Socket_Address;
+ address: &SocketAddress;
// This is only set when the event is coming from the server.
client : &TCP_Server.Client;
}
#inject TCP_Server {
Client :: struct {
use socket : Socket;
- address : Socket_Address;
+ address : SocketAddress;
state : State;
recv_ready_event_present := false;
}
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;
}
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;
}
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;
conn_event.client = client;
server.events << .{ .Connection, conn_event };
- }
+ });
//
// Process dead clients
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;
}
}
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 {
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 {
#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
#load "./fs"
#load "./env"
+#load "./net"
#load "core/onyx/cptr"
#load "core/onyx/cbindgen"
### 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`
#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)
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)
+++ /dev/null
-
-//
-// 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;
-}
--- /dev/null
+
+//
+// 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 *) ¶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;
+}