}
}
- case i16, u16 {
- value := *(cast(^i16) v.data);
-
- ibuf : [128] u8;
- istr := i64_to_str(~~value, formatting.base, ~~ibuf, min_length=formatting.minimum_width);
- output->write(istr);
- }
-
- case i32, u32 {
- value := *(cast(^i32) v.data);
+ int_case :: macro (T: type_expr) {
+ case T {
+ value := *(cast(^T) v.data);
- ibuf : [128] u8;
- istr := i64_to_str(~~value, formatting.base, ~~ibuf, min_length=formatting.minimum_width);
- output->write(istr);
+ ibuf : [128] u8;
+ istr := i64_to_str(~~value, formatting.base, ~~ibuf, min_length=formatting.minimum_width);
+ output->write(istr);
+ }
}
- case i64, u64 {
- value := *(cast(^i64) v.data);
-
- ibuf : [128] u8;
- istr := i64_to_str(~~value, formatting.base, ~~ibuf);
- output->write(istr);
- }
+ int_case(i8);
+ int_case(i16);
+ int_case(u16);
+ int_case(i32);
+ int_case(u32);
+ int_case(i64);
+ int_case(u64);
case f32 {
value := *(cast(^f32) v.data);
accept :: socket_accept
connect :: socket_connect
send :: socket_send
+ sendto :: socket_sendto
sendall :: socket_sendall
recv :: socket_recv
recv_into :: socket_recv_into
+ recvfrom :: socket_recvfrom
}
SocketError :: enum {
NonBlocking :: 0x01;
}
-Socket_Address :: struct {
- Handle :: #distinct u64
- addr: Handle;
+// This structure is twenty bytes in size to accommodate IPV6 addresses.
+Socket_Address :: struct #size 20 {
+ family: u16;
+ port: u16;
+ addr: u32;
- get_address :: (s: ^Socket_Address, allocator := context.allocator) -> [] u8 {
- buf: [256] u8;
- addr_len := __net_address_get_address(s.addr, buf);
-
- ret := memory.copy_slice(buf[0 .. addr_len], allocator=allocator);
- return ret;
- }
+ addr_as_str :: (use this: ^Socket_Address, allocator := context.allocator) -> str {
+ out: [64] u8;
+ str_addr := conv.format(out, "{}.{}.{}.{}",
+ (addr >> 24) & 0xff,
+ (addr >> 16) & 0xff,
+ (addr >> 8) & 0xff,
+ (addr >> 0) & 0xff);
- get_port :: (s: ^Socket_Address) -> u32 {
- return __net_address_get_port(s.addr);
+ return string.alloc_copy(str_addr, allocator=allocator);
}
}
socket_accept :: (s: ^Socket) -> (Socket, Socket_Address) {
new_socket: Socket;
new_addr: Socket_Address;
- new_socket.handle = __net_accept(s.handle, ^new_addr.addr);
+ new_socket.handle = __net_accept(s.handle, ^new_addr);
if new_socket.handle >= 0 {
new_socket.vtable = ^__net_socket_vtable;
return sent;
}
+socket_sendto :: (s: ^Socket, data: [] u8, addr: ^Socket_Address) -> i32 {
+ sent := __net_sendto(s.handle, data, addr);
+ if sent < 0 { s.vtable = null; }
+ return sent;
+}
+
socket_sendall :: (s: ^Socket, data: [] u8) {
to_send := data;
return received;
}
+socket_recvfrom :: (s: ^Socket, buffer: [] u8) -> (Socket_Address, i32) {
+ would_block: bool;
+ sa: Socket_Address;
+
+ 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;
+
+ return sa, received;
+}
+
#local __net_socket_vtable := io.Stream_Vtable.{
read = (use s: ^Socket, buffer: [] u8) -> (io.Error, u32) {
if handle == 0 do return .BadFile, 0;
#package __net_setting :: (handle: Socket.Handle, setting: SocketSetting, value: i32) -> void ---
#package __net_bind :: (handle: Socket.Handle, port: u16) -> bool ---
#package __net_listen :: (handle: Socket.Handle, backlog: i32) -> void ---
- #package __net_accept :: (handle: Socket.Handle, out_address: ^Socket_Address.Handle) -> Socket.Handle ---
+ #package __net_accept :: (handle: Socket.Handle, out_address: ^Socket_Address) -> Socket.Handle ---
#package __net_connect :: (handle: Socket.Handle, host: str, port: u16) -> SocketError ---
#package __net_send :: (handle: Socket.Handle, data: [] u8) -> i32 ---
- #package __net_recv :: (handle: Socket.Handle, data: [] u8, async_would_block: ^bool) -> i32 ---
+ #package __net_sendto :: (handle: Socket.Handle, data: [] u8, addr: ^Socket_Address) -> i32 ---
+ #package __net_recv :: (handle: Socket.Handle, data: [] u8, async_would_block: ^bool) -> i32 ---
+ #package __net_recvfrom :: (handle: Socket.Handle, data: [] u8, out_recv_addr: ^Socket_Address, async_would_block: ^bool) -> i32 ---
#package __net_poll_recv :: (handle: [] Socket.Handle, timeout: i32, out_recv_indicies: ^i32) -> i32 ---
-
- #package __net_address_get_address :: (address: Socket_Address.Handle, out_buffer: [] u8) -> i32 ---
- #package __net_address_get_port :: (address: Socket_Address.Handle) -> i32 ---
}
#operator >= macro (a, b: Socket.Handle) => cast(u32) a >= cast(u32) b;
//
// Networking
//
+struct onyx_socket_addr {
+ unsigned short family;
+ unsigned short port;
+ unsigned int addr;
+};
+
ONYX_DEF(__net_create_socket, (WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
#ifdef _BH_LINUX
ONYX_DEF(__net_accept, (WASM_I32, WASM_I32), (WASM_I32)) {
#ifdef _BH_LINUX
- struct sockaddr_in *client_addr = malloc(sizeof(*client_addr));
- int client_len = sizeof(*client_addr);
- memset(client_addr, 0, client_len);
+ 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);
+ 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);
- *(i64 *) ONYX_PTR(params->data[1].of.i32) = (i64) client_addr;
results->data[0] = WASM_I32_VAL(client_socket);
#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;
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_poll_recv, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
#ifdef _BH_LINUX
int i, res, cursor;
ONYX_FUNC(__net_accept)
ONYX_FUNC(__net_connect)
ONYX_FUNC(__net_send)
+ ONYX_FUNC(__net_sendto)
ONYX_FUNC(__net_recv)
+ ONYX_FUNC(__net_recvfrom)
ONYX_FUNC(__net_poll_recv)
- ONYX_FUNC(__net_address_get_address)
- ONYX_FUNC(__net_address_get_port)
ONYX_FUNC(__cptr_make)
ONYX_FUNC(__cptr_read)