commit 972c3dc

default  ·  2024-08-05 04:01:21 +0000 UTC
parent e9b108a
Added support for listening on unix sockets.
8 files changed,  +172, -21
M snac.c
M xs.h
+14, -5
 1@@ -5,6 +5,7 @@
 2 #include "xs_io.h"
 3 #include "xs_json.h"
 4 #include "xs_socket.h"
 5+#include "xs_unix_socket.h"
 6 #include "xs_httpd.h"
 7 #include "xs_mime.h"
 8 #include "xs_time.h"
 9@@ -761,8 +762,8 @@ srv_state *srv_state_op(xs_str **fname, int op)
10 void httpd(void)
11 /* starts the server */
12 {
13-    const char *address;
14-    const char *port;
15+    const char *address = NULL;
16+    const char *port = NULL;
17     xs *full_address = NULL;
18     int rs;
19     pthread_t threads[MAX_THREADS] = {0};
20@@ -772,11 +773,19 @@ void httpd(void)
21     sem_t anon_job_sem;
22 
23     address = xs_dict_get(srv_config, "address");
24-    port    = xs_number_str(xs_dict_get(srv_config, "port"));
25 
26-    full_address = xs_fmt("%s:%s", address, port);
27+    if (*address == '/') {
28+        rs = xs_unix_socket_server(address, NULL);
29+        full_address = xs_fmt("unix:%s", address);
30+    }
31+    else {
32+        port = xs_number_str(xs_dict_get(srv_config, "port"));
33+        full_address = xs_fmt("%s:%s", address, port);
34+
35+        rs = xs_socket_server(address, port);
36+    }
37 
38-    if ((rs = xs_socket_server(address, port)) == -1) {
39+    if (rs == -1) {
40         srv_log(xs_fmt("cannot bind socket to %s", full_address));
41         return;
42     }
M snac.c
+1, -0
1@@ -11,6 +11,7 @@
2 #include "xs_curl.h"
3 #include "xs_openssl.h"
4 #include "xs_socket.h"
5+#include "xs_unix_socket.h"
6 #include "xs_url.h"
7 #include "xs_httpd.h"
8 #include "xs_mime.h"
M xs.h
+69, -8
  1@@ -123,7 +123,12 @@ const xs_val *xs_dict_get_def(const xs_dict *dict, const xs_str *key, const xs_v
  2 #define xs_dict_get(dict, key) xs_dict_get_def(dict, key, NULL)
  3 xs_dict *xs_dict_del(xs_dict *dict, const xs_str *key);
  4 xs_dict *xs_dict_set(xs_dict *dict, const xs_str *key, const xs_val *data);
  5-xs_dict *xs_dict_gc(xs_dict *dict);
  6+xs_dict *xs_dict_gc(const xs_dict *dict);
  7+
  8+const xs_val *xs_dict_get_path_sep(const xs_dict *dict, const char *path, const char *sep);
  9+#define xs_dict_get_path(dict, path) xs_dict_get_path_sep(dict, path, ".")
 10+xs_dict *xs_dict_set_path_sep(xs_dict *dict, const char *path, const xs_val *value, const char *sep);
 11+#define xs_dict_set_path(dict, path, value) xs_dict_set_path_sep(dict, path, value, ".")
 12 
 13 xs_val *xs_val_new(xstype t);
 14 xs_number *xs_number_new(double f);
 15@@ -1258,24 +1263,80 @@ int xs_dict_next(const xs_dict *dict, const xs_str **key, const xs_val **value,
 16 }
 17 
 18 
 19-xs_dict *xs_dict_gc(xs_dict *dict)
 20-/* collects garbage (leaked values) inside a dict */
 21+xs_dict *xs_dict_gc(const xs_dict *dict)
 22+/* creates a copy of dict, but garbage-collected */
 23 {
 24     xs_dict *nd = xs_dict_new();
 25     const xs_str *k;
 26     const xs_val *v;
 27     int c = 0;
 28 
 29-    /* shamelessly create a new dict with the same content */
 30-    while (xs_dict_next(dict, &k, &v, &c))
 31-        nd = xs_dict_set(nd, k, v);
 32-
 33-    xs_free(dict);
 34+    while (xs_dict_next(dict, &k, &v, &c)) {
 35+        if (xs_type(v) == XSTYPE_DICT) {
 36+            xs *sd = xs_dict_gc(v);
 37+            nd = xs_dict_set(nd, k, sd);
 38+        }
 39+        else
 40+            nd = xs_dict_set(nd, k, v);
 41+    }
 42 
 43     return nd;
 44 }
 45 
 46 
 47+const xs_val *xs_dict_get_path_sep(const xs_dict *dict, const char *path, const char *sep)
 48+/* gets a value from dict given a path separated by sep */
 49+{
 50+    /* split by the separator */
 51+    xs *l = xs_split_n(path, sep, 1);
 52+
 53+    /* only one part? just get */
 54+    if (xs_list_len(l) == 1)
 55+        return xs_dict_get(dict, path);
 56+
 57+    const char *prefix = xs_list_get(l, 0);
 58+    const char *rest   = xs_list_get(l, 1);
 59+    const xs_dict *sd  = xs_dict_get(dict, prefix);
 60+
 61+    if (xs_type(sd) == XSTYPE_DICT)
 62+        return xs_dict_get_path_sep(sd, rest, sep);
 63+
 64+    return NULL;
 65+}
 66+
 67+
 68+xs_dict *xs_dict_set_path_sep(xs_dict *dict, const char *path, const xs_val *value, const char *sep)
 69+/* sets a value into dict given a path separated by sep;
 70+   intermediate dicts are created if needed */
 71+{
 72+    /* split by the separator */
 73+    xs *l = xs_split_n(path, sep, 1);
 74+
 75+    /* only one part? just set */
 76+    if (xs_list_len(l) == 1)
 77+        return xs_dict_set(dict, path, value);
 78+
 79+    const char *prefix = xs_list_get(l, 0);
 80+    const char *rest   = xs_list_get(l, 1);
 81+
 82+    xs *nd = NULL;
 83+
 84+    /* does the first part of path exist? */
 85+    const xs_dict *cd = xs_dict_get(dict, prefix);
 86+
 87+    if (xs_type(cd) == XSTYPE_DICT)
 88+        nd = xs_dup(cd);
 89+    else
 90+        nd = xs_dict_new();
 91+
 92+    /* move down the path */
 93+    nd = xs_dict_set_path_sep(nd, rest, value, sep);
 94+
 95+    /* set */
 96+    return xs_dict_set(dict, prefix, nd);
 97+}
 98+
 99+
100 /** other values **/
101 
102 xs_val *xs_val_new(xstype t)
+1, -1
1@@ -274,7 +274,7 @@ static xs_val *_xs_json_load_lexer(FILE *f, js_type *t)
2                     break;
3                 }
4 
5-                v = xs_utf8_enc(v, cp);
6+                v = xs_utf8_cat(v, cp);
7             }
8             else {
9                 char cc = c;
+3, -1
 1@@ -182,8 +182,10 @@ int xs_socket_connect(const char *addr, const char *serv)
 2             host.sin_port = htons(atoi(serv));
 3 
 4         if ((d = socket(AF_INET, SOCK_STREAM, 0)) != -1) {
 5-            if (connect(d, (struct sockaddr *)&host, sizeof(host)) == -1)
 6+            if (connect(d, (struct sockaddr *)&host, sizeof(host)) == -1) {
 7+                close(d);
 8                 d = -1;
 9+            }
10         }
11     }
12 
+5, -5
 1@@ -4,7 +4,7 @@
 2 
 3 #define _XS_UNICODE_H
 4 
 5- int _xs_utf8_enc(char buf[4], unsigned int cpoint);
 6+ int xs_utf8_enc(char buf[4], unsigned int cpoint);
 7  int xs_is_utf8_cont_byte(char c);
 8  unsigned int xs_utf8_dec(const char **str);
 9  int xs_unicode_width(unsigned int cpoint);
10@@ -22,7 +22,7 @@
11  int xs_unicode_is_alpha(unsigned int cpoint);
12 
13 #ifdef _XS_H
14- xs_str *xs_utf8_enc(xs_str *str, unsigned int cpoint);
15+ xs_str *xs_utf8_cat(xs_str *str, unsigned int cpoint);
16 #endif
17 
18 #ifdef XS_IMPLEMENTATION
19@@ -31,7 +31,7 @@
20 #define xs_countof(a) (sizeof((a)) / sizeof((*a)))
21 #endif
22 
23-int _xs_utf8_enc(char buf[4], unsigned int cpoint)
24+int xs_utf8_enc(char buf[4], unsigned int cpoint)
25 /* encodes an Unicode codepoint to utf-8 into buf and returns the size in bytes */
26 {
27     char *p = buf;
28@@ -172,12 +172,12 @@ unsigned int xs_surrogate_enc(unsigned int cpoint)
29 
30 #ifdef _XS_H
31 
32-xs_str *xs_utf8_enc(xs_str *str, unsigned int cpoint)
33+xs_str *xs_utf8_cat(xs_str *str, unsigned int cpoint)
34 /* encodes an Unicode codepoint to utf-8 into str */
35 {
36     char tmp[4];
37 
38-    int c = _xs_utf8_enc(tmp, cpoint);
39+    int c = xs_utf8_enc(tmp, cpoint);
40 
41     return xs_append_m(str, tmp, c);
42 }
+78, -0
 1@@ -0,0 +1,78 @@
 2+/* copyright (c) 2022 - 2024 grunfink et al. / MIT license */
 3+
 4+#ifndef _XS_UNIX_SOCKET_H
 5+
 6+#define _XS_UNIX_SOCKET_H
 7+
 8+ int xs_unix_socket_server(const char *path, const char *grp);
 9+ int xs_unix_socket_connect(const char *path);
10+
11+
12+#ifdef XS_IMPLEMENTATION
13+
14+#include <sys/stat.h>
15+#include <sys/un.h>
16+#include <grp.h>
17+
18+int xs_unix_socket_server(const char *path, const char *grp)
19+/* opens a unix-type server socket */
20+{
21+    int rs = -1;
22+
23+    if ((rs = socket(AF_UNIX, SOCK_STREAM, 0)) != -1) {
24+        struct sockaddr_un sun = {0};
25+        mode_t mode = 0666;
26+
27+        sun.sun_family = AF_UNIX;
28+        strncpy(sun.sun_path, path, sizeof(sun.sun_path));
29+
30+        unlink(path);
31+
32+        if (bind(rs, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
33+            close(rs);
34+            return -1;
35+        }
36+
37+        listen(rs, SOMAXCONN);
38+
39+        if (grp != NULL) {
40+            struct group *g = NULL;
41+
42+            /* if there is a group name, get its gid_t */
43+            g = getgrnam(grp);
44+
45+            if (g != NULL && chown(path, -1, g->gr_gid) != -1)
46+                mode = 0660;
47+        }
48+
49+        chmod(path, mode);
50+    }
51+
52+    return rs;
53+}
54+
55+
56+int xs_unix_socket_connect(const char *path)
57+/* connects to a unix-type socket */
58+{
59+    int d = -1;
60+
61+    if ((d = socket(AF_UNIX, SOCK_STREAM, 0)) != -1) {
62+        struct sockaddr_un sun = {0};
63+
64+        sun.sun_family = AF_UNIX;
65+        strncpy(sun.sun_path, path, sizeof(sun.sun_path));
66+
67+        if (connect(d, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
68+            close(d);
69+            d = -1;
70+        }
71+    }
72+
73+    return d;
74+}
75+
76+
77+#endif /* XS_IMPLEMENTATION */
78+
79+#endif /* _XS_UNIX_SOCKET_H */
+1, -1
1@@ -1 +1 @@
2-/* 3896c5f782089f0dca68455565bbcd65dd724c91 2024-07-01T08:55:34+02:00 */
3+/* fb6646ef1b1d5f24768bc829680eb70272755584 2024-08-05T05:32:08+02:00 */