package core.net
-use package core
+use core
Socket :: struct {
Handle :: #distinct i32
use stream : io.Stream;
handle: Handle;
type: SocketType;
+ family: SocketDomain;
close :: socket_close
setting :: socket_setting
Broadcast :: 0x02;
}
-// This structure is twenty bytes in size to accommodate IPV6 addresses.
-Socket_Address :: struct #size 20 {
+#local UNIX_SOCKET_PATH_LEN :: 256
+
+Socket_Address :: struct #size (8 + UNIX_SOCKET_PATH_LEN) {
family: u16;
port: u16;
addr: u32;
}
}
+make_ipv4_address :: (out: ^Socket_Address, addr: u32, port: u16) {
+ out.family = ~~ SocketDomain.Inet;
+ out.port = port;
+ out.addr = addr;
+}
+
+make_unix_address :: (out: ^Socket_Address, path: str) {
+ out.family = ~~ SocketDomain.Unix;
+ out.port = 0;
+
+ //
+ // If we are constructing a unix socket, we have to write the path
+ // at the address where the addr field is in the Socket_Address.
+ // We also have to append a null-terminator, as that is what will
+ // be expected from any C function.
+ out_path := cast(^u8) ^out.addr;
+ offset := 0;
+ while offset < math.min(path.count, UNIX_SOCKET_PATH_LEN - 1) {
+ defer offset += 1;
+
+ out_path[offset] = path[offset];
+ }
+
+ out_path[offset] = 0;
+}
+
socket_create :: (domain: SocketDomain, type: SocketType) -> (Socket, SocketError) {
s: Socket;
s.type = type;
+ s.family = domain;
err := __net_create_socket(^s.handle, domain, type);
if err == .None {
return s.vtable != null;
}
-socket_connect :: (s: ^Socket, host: str, port: u16) -> SocketError {
- return __net_connect(s.handle, host, port);
+socket_connect :: (s: ^Socket, host: str, port: u16 = 0) -> SocketError {
+ switch s.family {
+ case .Inet do return __net_connect_ipv4(s.handle, host, port);
+ case .Unix do return __net_connect_unix(s.handle, host);
+ case #default do return .BadSettings;
+ }
}
-socket_bind :: (s: ^Socket, port: u16) -> bool {
- return __net_bind(s.handle, port);
+socket_bind :: (s: ^Socket, bind_address: ^Socket_Address) -> bool {
+ return __net_bind(s.handle, bind_address);
}
socket_listen :: (s: ^Socket, backlog := 32) {
#package __net_create_socket :: (out_handle: ^Socket.Handle, domain: SocketDomain, type: SocketType) -> SocketError ---
#package __net_close_socket :: (handle: Socket.Handle) -> void ---
#package __net_setting :: (handle: Socket.Handle, setting: SocketSetting, value: i32) -> void ---
- #package __net_bind :: (handle: Socket.Handle, port: u16) -> bool ---
+ #package __net_bind :: (handle: Socket.Handle, bind_address: ^Socket_Address) -> bool ---
#package __net_listen :: (handle: Socket.Handle, backlog: i32) -> void ---
#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_connect_unix :: (handle: Socket.Handle, path: str) -> SocketError ---
+ #package __net_connect_ipv4 :: (handle: Socket.Handle, host: str, port: u16) -> SocketError ---
#package __net_send :: (handle: Socket.Handle, data: [] u8) -> 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 ---
(addr >> 8) & 0xff,
(addr >> 0) & 0xff);
return str_addr;
-}
\ No newline at end of file
+}
}
tcp_server_listen :: (use server: ^TCP_Server, port: u16) -> bool {
- if !socket->bind(port) do return false;
+ sa: Socket_Address;
+ make_ipv4_address(^sa, 0x00000000, port);
+ if !socket->bind(^sa) do return false;
socket->listen();
thread.spawn(^listener_thread, server, tcp_server_listener);
bh_arr(AstStructMember *) members;
bh_arr(AstTyped *) meta_tags;
- u32 min_alignment, min_size;
+ // u32 min_alignment, min_size;
+ AstTyped *min_alignment_, *min_size_;
// NOTE: Used to cache the actual type, since building
// a struct type is kind of complicated and should
}
i64 get_expression_integer_value(AstTyped* node, b32 *is_valid) {
+ if (!node) return 0;
+
resolve_expression_type(node);
if (is_valid) *is_valid = 1;
if (s_node->entity_defaults && s_node->entity_defaults->state < Entity_State_Check_Types)
YIELD(s_node->token->pos, "Waiting for struct member defaults to pass symbol resolution.");
+ if (s_node->min_size_) CHECK(expression, &s_node->min_size_);
+ if (s_node->min_alignment_) CHECK(expression, &s_node->min_alignment_);
+
if (s_node->polymorphic_argument_types) {
assert(s_node->polymorphic_arguments);
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
+ #include <sys/un.h>
#include <poll.h>
#endif
unsigned int addr;
};
+static inline int onyx_socket_domain(int i) {
+ switch (i) { // :EnumDependent
+ case 0: return AF_UNIX;
+ case 1: return AF_INET;
+ case 2: return AF_INET6;
+ default: return -1;
+ }
+}
+
+static inline int onyx_socket_protocol(int i) {
+ switch (i) { // :EnumDependent
+ 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)) {
#ifdef _BH_LINUX
- int domain = 0;
- switch (params->data[1].of.i32) { // :EnumDependent
- case 0: domain = AF_UNIX; break;
- case 1: domain = AF_INET; break;
- case 2: domain = AF_INET6; break;
- default: goto bad_settings;
- }
+ int domain = onyx_socket_domain(params->data[1].of.i32);
+ if (domain == -1) goto bad_settings;
- int type = 0;
- switch (params->data[2].of.i32) { // :EnumDependent
- case 0: type = SOCK_STREAM; break;
- case 1: type = SOCK_DGRAM; break;
- default: 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);
ONYX_DEF(__net_bind, (WASM_I32, WASM_I32), (WASM_I32)) {
#ifdef _BH_LINUX
- struct sockaddr_in bind_addr;
- memset(&bind_addr, 0, sizeof(bind_addr));
+ 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; // Should this be configurable? Or is binding only ever done for INET? INET6?
- bind_addr.sin_addr.s_addr = htonl(INADDR_ANY);
- bind_addr.sin_port = htons(params->data[1].of.i32);
+ 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;
+ }
+ }
- int res = bind(params->data[0].of.i32, &bind_addr, sizeof(bind_addr));
results->data[0] = WASM_I32_VAL(res >= 0);
#endif
return NULL;
}
-ONYX_DEF(__net_connect, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+ONYX_DEF(__net_connect_unix, (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';
+
+ 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
+
+ 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);
hostname[hostlen] = '\0';
struct hostent *host;
- host = gethostbyname(hostname);
+ host = gethostbyname(hostname); // TODO: Replace this call, as it is obselete.
if (host == NULL) {
results->data[0] = WASM_I32_VAL(2); // :EnumDependent
return NULL;
ONYX_FUNC(__net_bind)
ONYX_FUNC(__net_listen)
ONYX_FUNC(__net_accept)
- ONYX_FUNC(__net_connect)
+ ONYX_FUNC(__net_connect_unix)
+ ONYX_FUNC(__net_connect_ipv4)
ONYX_FUNC(__net_send)
ONYX_FUNC(__net_sendto)
ONYX_FUNC(__net_recv)
else if (parse_possible_directive(parser, "pack")) s_node->is_packed = 1;
else if (parse_possible_directive(parser, "align")) {
- AstNumLit* numlit = parse_int_literal(parser);
- if (numlit == NULL) return NULL;
-
- s_node->min_alignment = numlit->value.i;
+ s_node->min_alignment_ = parse_expression(parser, 0);
}
else if (parse_possible_directive(parser, "size")) {
- AstNumLit* numlit = parse_int_literal(parser);
- if (numlit == NULL) return NULL;
-
- s_node->min_size = numlit->value.i;
+ s_node->min_size_ = parse_expression(parser, 0);
}
else {
scope_enter(s_node->scope);
}
+
+ if (s_node->min_size_) SYMRES(expression, &s_node->min_size_);
+ if (s_node->min_alignment_) SYMRES(expression, &s_node->min_alignment_);
if (s_node->polymorphic_argument_types) {
assert(s_node->polymorphic_arguments);
idx++;
}
- alignment = bh_max(s_node->min_alignment, alignment);
+ u32 min_alignment = get_expression_integer_value(s_node->min_alignment_, NULL);
+ alignment = bh_max(min_alignment, alignment);
if (!s_node->is_packed) {
bh_align(size, alignment);
}
- size = bh_max(s_node->min_size, size);
+ u32 min_size = get_expression_integer_value(s_node->min_size_, NULL);
+ size = bh_max(min_size, size);
s_type->Struct.alignment = alignment;
s_type->Struct.size = size;