From: Brendan Hansen Date: Fri, 5 Aug 2022 18:41:52 +0000 (-0500) Subject: added ability to use unix sockets X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=bb5b22d98f7288eab7bbd12cede58714a1fd300b;p=onyx.git added ability to use unix sockets --- diff --git a/core/net/net.onyx b/core/net/net.onyx index e89e4b87..b5072aae 100644 --- a/core/net/net.onyx +++ b/core/net/net.onyx @@ -1,6 +1,6 @@ package core.net -use package core +use core Socket :: struct { Handle :: #distinct i32 @@ -8,6 +8,7 @@ Socket :: struct { use stream : io.Stream; handle: Handle; type: SocketType; + family: SocketDomain; close :: socket_close setting :: socket_setting @@ -47,8 +48,9 @@ SocketSetting :: enum { 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; @@ -59,9 +61,36 @@ Socket_Address :: struct #size 20 { } } +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 { @@ -84,12 +113,16 @@ socket_is_alive :: (s: ^Socket) -> bool { 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) { @@ -230,10 +263,11 @@ network_to_host :: #match {} #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 --- @@ -279,4 +313,4 @@ ipv4_to_str :: (addr: u32) -> str { (addr >> 8) & 0xff, (addr >> 0) & 0xff); return str_addr; -} \ No newline at end of file +} diff --git a/core/net/tcp.onyx b/core/net/tcp.onyx index 40ee4302..e130ef7f 100644 --- a/core/net/tcp.onyx +++ b/core/net/tcp.onyx @@ -163,7 +163,9 @@ tcp_server_make :: (max_clients := 32, allocator := context.allocator) -> ^TCP_S } 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); diff --git a/include/astnodes.h b/include/astnodes.h index 45a66567..0f833501 100644 --- a/include/astnodes.h +++ b/include/astnodes.h @@ -912,7 +912,8 @@ struct AstStructType { 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 diff --git a/src/astnodes.c b/src/astnodes.c index 63803c61..b0c4194a 100644 --- a/src/astnodes.c +++ b/src/astnodes.c @@ -907,6 +907,8 @@ Type* resolve_expression_type(AstTyped* node) { } i64 get_expression_integer_value(AstTyped* node, b32 *is_valid) { + if (!node) return 0; + resolve_expression_type(node); if (is_valid) *is_valid = 1; diff --git a/src/checker.c b/src/checker.c index 6ed77a31..65e562c9 100644 --- a/src/checker.c +++ b/src/checker.c @@ -2213,6 +2213,9 @@ CheckStatus check_struct(AstStructType* s_node) { 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); diff --git a/src/onyx_runtime.c b/src/onyx_runtime.c index 5e9cf0c2..10f3a82a 100644 --- a/src/onyx_runtime.c +++ b/src/onyx_runtime.c @@ -17,6 +17,7 @@ #include #include #include + #include #include #endif @@ -922,23 +923,31 @@ struct onyx_socket_addr { 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); @@ -996,14 +1005,49 @@ ONYX_DEF(__net_setting, (WASM_I32, WASM_I32, WASM_I32), ()) { 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 @@ -1043,7 +1087,26 @@ ONYX_DEF(__net_accept, (WASM_I32, WASM_I32), (WASM_I32)) { 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); @@ -1051,7 +1114,7 @@ ONYX_DEF(__net_connect, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) { 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; @@ -1279,7 +1342,8 @@ ONYX_LIBRARY { 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) diff --git a/src/parser.c b/src/parser.c index 7f20a628..22fcf9d8 100644 --- a/src/parser.c +++ b/src/parser.c @@ -1997,17 +1997,11 @@ static AstStructType* parse_struct(OnyxParser* parser) { 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 { diff --git a/src/symres.c b/src/symres.c index 2d4db285..ca756ae8 100644 --- a/src/symres.c +++ b/src/symres.c @@ -118,6 +118,9 @@ static SymresStatus symres_struct_type(AstStructType* s_node) { 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); diff --git a/src/types.c b/src/types.c index 50d59292..a3687131 100644 --- a/src/types.c +++ b/src/types.c @@ -428,12 +428,14 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) { 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;