Browse Source

Added support for listening on unix sockets.

default 7 months ago
parent
commit
972c3dc5d4
8 changed files with 172 additions and 21 deletions
  1. 14 5
      httpd.c
  2. 1 0
      snac.c
  3. 69 8
      xs.h
  4. 1 1
      xs_json.h
  5. 3 1
      xs_socket.h
  6. 5 5
      xs_unicode.h
  7. 78 0
      xs_unix_socket.h
  8. 1 1
      xs_version.h

+ 14 - 5
httpd.c

@@ -5,6 +5,7 @@
 #include "xs_io.h"
 #include "xs_json.h"
 #include "xs_socket.h"
+#include "xs_unix_socket.h"
 #include "xs_httpd.h"
 #include "xs_mime.h"
 #include "xs_time.h"
@@ -761,8 +762,8 @@ srv_state *srv_state_op(xs_str **fname, int op)
 void httpd(void)
 /* starts the server */
 {
-    const char *address;
-    const char *port;
+    const char *address = NULL;
+    const char *port = NULL;
     xs *full_address = NULL;
     int rs;
     pthread_t threads[MAX_THREADS] = {0};
@@ -772,11 +773,19 @@ void httpd(void)
     sem_t anon_job_sem;
 
     address = xs_dict_get(srv_config, "address");
-    port    = xs_number_str(xs_dict_get(srv_config, "port"));
 
-    full_address = xs_fmt("%s:%s", address, port);
+    if (*address == '/') {
+        rs = xs_unix_socket_server(address, NULL);
+        full_address = xs_fmt("unix:%s", address);
+    }
+    else {
+        port = xs_number_str(xs_dict_get(srv_config, "port"));
+        full_address = xs_fmt("%s:%s", address, port);
+
+        rs = xs_socket_server(address, port);
+    }
 
-    if ((rs = xs_socket_server(address, port)) == -1) {
+    if (rs == -1) {
         srv_log(xs_fmt("cannot bind socket to %s", full_address));
         return;
     }

+ 1 - 0
snac.c

@@ -11,6 +11,7 @@
 #include "xs_curl.h"
 #include "xs_openssl.h"
 #include "xs_socket.h"
+#include "xs_unix_socket.h"
 #include "xs_url.h"
 #include "xs_httpd.h"
 #include "xs_mime.h"

+ 69 - 8
xs.h

@@ -123,7 +123,12 @@ const xs_val *xs_dict_get_def(const xs_dict *dict, const xs_str *key, const xs_v
 #define xs_dict_get(dict, key) xs_dict_get_def(dict, key, NULL)
 xs_dict *xs_dict_del(xs_dict *dict, const xs_str *key);
 xs_dict *xs_dict_set(xs_dict *dict, const xs_str *key, const xs_val *data);
-xs_dict *xs_dict_gc(xs_dict *dict);
+xs_dict *xs_dict_gc(const xs_dict *dict);
+
+const xs_val *xs_dict_get_path_sep(const xs_dict *dict, const char *path, const char *sep);
+#define xs_dict_get_path(dict, path) xs_dict_get_path_sep(dict, path, ".")
+xs_dict *xs_dict_set_path_sep(xs_dict *dict, const char *path, const xs_val *value, const char *sep);
+#define xs_dict_set_path(dict, path, value) xs_dict_set_path_sep(dict, path, value, ".")
 
 xs_val *xs_val_new(xstype t);
 xs_number *xs_number_new(double f);
@@ -1258,24 +1263,80 @@ int xs_dict_next(const xs_dict *dict, const xs_str **key, const xs_val **value,
 }
 
 
-xs_dict *xs_dict_gc(xs_dict *dict)
-/* collects garbage (leaked values) inside a dict */
+xs_dict *xs_dict_gc(const xs_dict *dict)
+/* creates a copy of dict, but garbage-collected */
 {
     xs_dict *nd = xs_dict_new();
     const xs_str *k;
     const xs_val *v;
     int c = 0;
 
-    /* shamelessly create a new dict with the same content */
-    while (xs_dict_next(dict, &k, &v, &c))
-        nd = xs_dict_set(nd, k, v);
-
-    xs_free(dict);
+    while (xs_dict_next(dict, &k, &v, &c)) {
+        if (xs_type(v) == XSTYPE_DICT) {
+            xs *sd = xs_dict_gc(v);
+            nd = xs_dict_set(nd, k, sd);
+        }
+        else
+            nd = xs_dict_set(nd, k, v);
+    }
 
     return nd;
 }
 
 
+const xs_val *xs_dict_get_path_sep(const xs_dict *dict, const char *path, const char *sep)
+/* gets a value from dict given a path separated by sep */
+{
+    /* split by the separator */
+    xs *l = xs_split_n(path, sep, 1);
+
+    /* only one part? just get */
+    if (xs_list_len(l) == 1)
+        return xs_dict_get(dict, path);
+
+    const char *prefix = xs_list_get(l, 0);
+    const char *rest   = xs_list_get(l, 1);
+    const xs_dict *sd  = xs_dict_get(dict, prefix);
+
+    if (xs_type(sd) == XSTYPE_DICT)
+        return xs_dict_get_path_sep(sd, rest, sep);
+
+    return NULL;
+}
+
+
+xs_dict *xs_dict_set_path_sep(xs_dict *dict, const char *path, const xs_val *value, const char *sep)
+/* sets a value into dict given a path separated by sep;
+   intermediate dicts are created if needed */
+{
+    /* split by the separator */
+    xs *l = xs_split_n(path, sep, 1);
+
+    /* only one part? just set */
+    if (xs_list_len(l) == 1)
+        return xs_dict_set(dict, path, value);
+
+    const char *prefix = xs_list_get(l, 0);
+    const char *rest   = xs_list_get(l, 1);
+
+    xs *nd = NULL;
+
+    /* does the first part of path exist? */
+    const xs_dict *cd = xs_dict_get(dict, prefix);
+
+    if (xs_type(cd) == XSTYPE_DICT)
+        nd = xs_dup(cd);
+    else
+        nd = xs_dict_new();
+
+    /* move down the path */
+    nd = xs_dict_set_path_sep(nd, rest, value, sep);
+
+    /* set */
+    return xs_dict_set(dict, prefix, nd);
+}
+
+
 /** other values **/
 
 xs_val *xs_val_new(xstype t)

+ 1 - 1
xs_json.h

@@ -274,7 +274,7 @@ static xs_val *_xs_json_load_lexer(FILE *f, js_type *t)
                     break;
                 }
 
-                v = xs_utf8_enc(v, cp);
+                v = xs_utf8_cat(v, cp);
             }
             else {
                 char cc = c;

+ 3 - 1
xs_socket.h

@@ -182,8 +182,10 @@ int xs_socket_connect(const char *addr, const char *serv)
             host.sin_port = htons(atoi(serv));
 
         if ((d = socket(AF_INET, SOCK_STREAM, 0)) != -1) {
-            if (connect(d, (struct sockaddr *)&host, sizeof(host)) == -1)
+            if (connect(d, (struct sockaddr *)&host, sizeof(host)) == -1) {
+                close(d);
                 d = -1;
+            }
         }
     }
 

+ 5 - 5
xs_unicode.h

@@ -4,7 +4,7 @@
 
 #define _XS_UNICODE_H
 
- int _xs_utf8_enc(char buf[4], unsigned int cpoint);
+ int xs_utf8_enc(char buf[4], unsigned int cpoint);
  int xs_is_utf8_cont_byte(char c);
  unsigned int xs_utf8_dec(const char **str);
  int xs_unicode_width(unsigned int cpoint);
@@ -22,7 +22,7 @@
  int xs_unicode_is_alpha(unsigned int cpoint);
 
 #ifdef _XS_H
- xs_str *xs_utf8_enc(xs_str *str, unsigned int cpoint);
+ xs_str *xs_utf8_cat(xs_str *str, unsigned int cpoint);
 #endif
 
 #ifdef XS_IMPLEMENTATION
@@ -31,7 +31,7 @@
 #define xs_countof(a) (sizeof((a)) / sizeof((*a)))
 #endif
 
-int _xs_utf8_enc(char buf[4], unsigned int cpoint)
+int xs_utf8_enc(char buf[4], unsigned int cpoint)
 /* encodes an Unicode codepoint to utf-8 into buf and returns the size in bytes */
 {
     char *p = buf;
@@ -172,12 +172,12 @@ unsigned int xs_surrogate_enc(unsigned int cpoint)
 
 #ifdef _XS_H
 
-xs_str *xs_utf8_enc(xs_str *str, unsigned int cpoint)
+xs_str *xs_utf8_cat(xs_str *str, unsigned int cpoint)
 /* encodes an Unicode codepoint to utf-8 into str */
 {
     char tmp[4];
 
-    int c = _xs_utf8_enc(tmp, cpoint);
+    int c = xs_utf8_enc(tmp, cpoint);
 
     return xs_append_m(str, tmp, c);
 }

+ 78 - 0
xs_unix_socket.h

@@ -0,0 +1,78 @@
+/* copyright (c) 2022 - 2024 grunfink et al. / MIT license */
+
+#ifndef _XS_UNIX_SOCKET_H
+
+#define _XS_UNIX_SOCKET_H
+
+ int xs_unix_socket_server(const char *path, const char *grp);
+ int xs_unix_socket_connect(const char *path);
+
+
+#ifdef XS_IMPLEMENTATION
+
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <grp.h>
+
+int xs_unix_socket_server(const char *path, const char *grp)
+/* opens a unix-type server socket */
+{
+    int rs = -1;
+
+    if ((rs = socket(AF_UNIX, SOCK_STREAM, 0)) != -1) {
+        struct sockaddr_un sun = {0};
+        mode_t mode = 0666;
+
+        sun.sun_family = AF_UNIX;
+        strncpy(sun.sun_path, path, sizeof(sun.sun_path));
+
+        unlink(path);
+
+        if (bind(rs, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
+            close(rs);
+            return -1;
+        }
+
+        listen(rs, SOMAXCONN);
+
+        if (grp != NULL) {
+            struct group *g = NULL;
+
+            /* if there is a group name, get its gid_t */
+            g = getgrnam(grp);
+
+            if (g != NULL && chown(path, -1, g->gr_gid) != -1)
+                mode = 0660;
+        }
+
+        chmod(path, mode);
+    }
+
+    return rs;
+}
+
+
+int xs_unix_socket_connect(const char *path)
+/* connects to a unix-type socket */
+{
+    int d = -1;
+
+    if ((d = socket(AF_UNIX, SOCK_STREAM, 0)) != -1) {
+        struct sockaddr_un sun = {0};
+
+        sun.sun_family = AF_UNIX;
+        strncpy(sun.sun_path, path, sizeof(sun.sun_path));
+
+        if (connect(d, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
+            close(d);
+            d = -1;
+        }
+    }
+
+    return d;
+}
+
+
+#endif /* XS_IMPLEMENTATION */
+
+#endif /* _XS_UNIX_SOCKET_H */

+ 1 - 1
xs_version.h

@@ -1 +1 @@
-/* 3896c5f782089f0dca68455565bbcd65dd724c91 2024-07-01T08:55:34+02:00 */
+/* fb6646ef1b1d5f24768bc829680eb70272755584 2024-08-05T05:32:08+02:00 */