From 972c3dc5d43a114ae59386d4edfdfb8ce0f3793e Mon Sep 17 00:00:00 2001 From: default Date: Mon, 5 Aug 2024 06:01:21 +0200 Subject: [PATCH] Added support for listening on unix sockets. --- httpd.c | 19 ++++++++---- snac.c | 1 + xs.h | 77 ++++++++++++++++++++++++++++++++++++++++++----- xs_json.h | 2 +- xs_socket.h | 4 ++- xs_unicode.h | 10 +++---- xs_unix_socket.h | 78 ++++++++++++++++++++++++++++++++++++++++++++++++ xs_version.h | 2 +- 8 files changed, 172 insertions(+), 21 deletions(-) create mode 100644 xs_unix_socket.h diff --git a/httpd.c b/httpd.c index 287965e..fd3d9e4 100644 --- a/httpd.c +++ b/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); - if ((rs = xs_socket_server(address, port)) == -1) { + rs = xs_socket_server(address, port); + } + + if (rs == -1) { srv_log(xs_fmt("cannot bind socket to %s", full_address)); return; } diff --git a/snac.c b/snac.c index 0df8691..25d3f5e 100644 --- a/snac.c +++ b/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" diff --git a/xs.h b/xs.h index f250764..d1a874c 100644 --- a/xs.h +++ b/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) diff --git a/xs_json.h b/xs_json.h index b65e825..a4112b0 100644 --- a/xs_json.h +++ b/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; diff --git a/xs_socket.h b/xs_socket.h index 1c73a22..1bd053a 100644 --- a/xs_socket.h +++ b/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; + } } } diff --git a/xs_unicode.h b/xs_unicode.h index 1799d89..2e9a754 100644 --- a/xs_unicode.h +++ b/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); } diff --git a/xs_unix_socket.h b/xs_unix_socket.h new file mode 100644 index 0000000..5b64282 --- /dev/null +++ b/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 +#include +#include + +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 */ diff --git a/xs_version.h b/xs_version.h index 1f05b57..98a46d0 100644 --- a/xs_version.h +++ b/xs_version.h @@ -1 +1 @@ -/* 3896c5f782089f0dca68455565bbcd65dd724c91 2024-07-01T08:55:34+02:00 */ +/* fb6646ef1b1d5f24768bc829680eb70272755584 2024-08-05T05:32:08+02:00 */