added ability to use unix sockets
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 5 Aug 2022 18:41:52 +0000 (13:41 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 5 Aug 2022 18:41:52 +0000 (13:41 -0500)
core/net/net.onyx
core/net/tcp.onyx
include/astnodes.h
src/astnodes.c
src/checker.c
src/onyx_runtime.c
src/parser.c
src/symres.c
src/types.c

index e89e4b87b0de4b7ff37d6eff849343731a9b263c..b5072aae2d60e6418fa6542445c1f5a0c987f878 100644 (file)
@@ -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
+}
index 40ee4302138341a723d0ffb53a7f63b21629d6c1..e130ef7fe55ead3661861fecdb2b845cf585f84c 100644 (file)
@@ -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);
index 45a665676c8be0ef611b6001240cfb9ba4f9bb3c..0f83350116bfeab878153dd42c4803bc1f3b8a64 100644 (file)
@@ -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
index 63803c61e3ccd52d343403047df3060d459302bf..b0c4194a20e9a4f295029e662d261a5aeded9c2c 100644 (file)
@@ -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;
index 6ed77a31b7976df09446c691c0c841e24481d07f..65e562c975e44cd81053baff382d327041a48656 100644 (file)
@@ -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);
 
index 5e9cf0c23d52708fb8c3109cc1c80665b9c8170a..10f3a82ade22cc9453877fe5810b7594a0b30a02 100644 (file)
@@ -17,6 +17,7 @@
     #include <netdb.h>
     #include <netinet/in.h>
     #include <sys/socket.h>
+    #include <sys/un.h>
     #include <poll.h>
 #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)
index 7f20a628d8cb8bce405d91a2114feacbb75a2ce0..22fcf9d8fef4d230bc942adb351bd0a02e741f7f 100644 (file)
@@ -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 {
index 2d4db285b2b04ae9d77bfa650555b8bd97b5b2e7..ca756ae8801d041e06f697f9741581823b7115aa 100644 (file)
@@ -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);
index 50d592929dc58145f9b835edeb4f6838bb9c425b..a368713184e3a6efda1559fe5f578a7b0fc24d07 100644 (file)
@@ -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;