diff options
Diffstat (limited to 'config.c')
-rw-r--r-- | config.c | 492 |
1 files changed, 0 insertions, 492 deletions
diff --git a/config.c b/config.c deleted file mode 100644 index eb980f8..0000000 --- a/config.c +++ /dev/null @@ -1,492 +0,0 @@ -#define _GNU_SOURCE -#include <stdio.h> -#include <ctype.h> -#include <string.h> -#include <stdbool.h> -#include <errno.h> -#include <unistd.h> -#include <arpa/inet.h> -#include <inttypes.h> - -#include "main.h" -#include "uring.h" -#include "config.h" -#include "server.h" - -static void -eat_whitespace_and_comments(char **pos) -{ - assert_return(pos && *pos); - - while (true) { - while (isspace(**pos)) - (*pos)++; - - if (**pos != '#') - return; - - while (**pos != '\r' && **pos != '\n' && **pos != '\0') - (*pos)++; - } -} - -static char * -get_line(char **pos) -{ - char *begin, *end; - - assert_return(pos && *pos, NULL); - - begin = *pos; - while (isspace(*begin)) - begin++; - - if (*begin == '\0') - return NULL; - - end = begin; - while (*end != '\n' && *end != '\0') - end++; - - if (*end == '\0') - *pos = end; - else - *pos = end + 1; - - while (isspace(*end)) { - *end = '\0'; - end--; - } - - return begin; -} - -static bool -dnslookup(const char *name, uint16_t port, struct cfg_value *rvalue, bool async) -{ - struct sockaddr_in *in4; - struct sockaddr_in6 *in6; - struct dns_async tmp; - struct dns_async *dns; - int mode = async ? GAI_NOWAIT : GAI_WAIT; - struct addrinfo *results = NULL, *ai; - struct saddr *saddr = NULL; - bool rv = false; - int r; - - assert_return(!empty_str(name) && strlen(name) < sizeof(dns->name) && port > 0 && rvalue, false); - - if (async) { - rvalue->type = CFG_VAL_TYPE_ASYNC_ADDRS; - rvalue->dns_async = NULL; - dns = zmalloc(sizeof(*dns)); - if (!dns) { - error("async DNS lookup of %s failed: %m", name); - goto out; - } - debug(DBG_DNS, "doing async DNS lookup of %s: %p", name, dns); - } else { - memset(&tmp, 0, sizeof(tmp)); - dns = &tmp; - debug(DBG_DNS, "doing sync DNS lookup of %s", name); - } - - sprintf(dns->name, "%s", name); - sprintf(dns->port, "%" PRIu16, port); - - dns->req.ai_family = AF_UNSPEC; - dns->req.ai_socktype = SOCK_STREAM; - dns->req.ai_protocol = 0; - dns->req.ai_flags = AI_NUMERICSERV; - - dns->sev.sigev_notify = SIGEV_SIGNAL; - dns->sev.sigev_signo = SIGUSR1; - dns->sev.sigev_value.sival_ptr = dns; - - dns->gcb.ar_name = dns->name; - dns->gcb.ar_service = dns->port; - dns->gcb.ar_request = &dns->req; - - struct gaicb *gcbs[] = { &dns->gcb }; - - r = getaddrinfo_a(mode, gcbs, ARRAY_SIZE(gcbs), &dns->sev); - if (r != 0) { - error("getaddrinfo(%s:%" PRIu16 "): %s", name, port, gai_strerror(r)); - goto out; - } - - if (async) { - rvalue->dns_async = dns; - rv = true; - goto out; - } - - results = dns->gcb.ar_result; - - for (ai = results; ai; ai = ai->ai_next) { - saddr = zmalloc(sizeof(*saddr)); - if (!saddr) { - error("sync DNS lookup of %s failed: %m", name); - goto out; - } - - switch (ai->ai_family) { - case AF_INET: - in4 = (struct sockaddr_in *)ai->ai_addr; - saddr_set_ipv4(saddr, in4->sin_addr.s_addr, in4->sin_port); - error("addrstr: %s", saddr->addrstr); - list_add(&saddr->list, &rvalue->saddrs); - break; - - case AF_INET6: - in6 = (struct sockaddr_in6 *)ai->ai_addr; - saddr_set_ipv6(saddr, &in6->sin6_addr, in6->sin6_port); - error("addrstr: %s", saddr->addrstr); - list_add(&saddr->list, &rvalue->saddrs); - break; - - default: - error("getaddrinfo(%s:%s): unknown address family (%i)", - dns->name, dns->port, ai->ai_family); - xfree(saddr); - break; - } - } - - rv = true; - -out: - freeaddrinfo(results); - return rv; -} - -static bool -strtosockaddrs(const char *str, struct cfg_value *rvalue, bool async) -{ - struct saddr *saddr; - uint16_t port; - char *tmp; - struct list_head *list; - unsigned naddrs = 0; - - assert_return(!empty_str(str) && rvalue, false); - - rvalue->type = CFG_VAL_TYPE_ADDRS; - list = &rvalue->saddrs; - list_init(list); - - if (*str == '[') { - /* IPv6, [a:b:c...h]:p or [*]:p */ - debug(DBG_CFG, "attempting to parse IPv6 addr (%s)", str); - - str++; - tmp = strchr(str, ']'); - if (!tmp) - goto error; - *tmp = '\0'; - - saddr = zmalloc(sizeof(*saddr)); - if (!saddr) - goto error; - - /* early list_add to make sure saddr is free():d on error */ - list_add(&saddr->list, list); - - if (streq(str, "*")) - saddr->in6.sin6_addr = in6addr_any; - else if (inet_pton(AF_INET6, str, &saddr->in6.sin6_addr) <= 0) - goto error; - - tmp++; - if (*tmp != ':') - goto error; - - tmp++; - if (strtou16_strict(tmp, &port) < 0) - goto error; - - saddr_set_ipv6(saddr, NULL, htons(port)); - naddrs++; - - } else if (*str == '*') { - /* IPv4, *:p */ - debug(DBG_CFG, "attempting to parse IPv4 addr (%s)", str); - - str++; - if (*str != ':') - goto error; - - str++; - if (strtou16_strict(str, &port) < 0) - goto error; - - saddr = zmalloc(sizeof(*saddr)); - if (!saddr) - goto error; - - saddr_set_ipv4(saddr, INADDR_ANY, htons(port)); - list_add(&saddr->list, list); - naddrs++; - - } else if ((tmp = strchr(str, ':'))) { - /* IPv4, a.b.c.d:p or IPv4/6 hostname:p */ - debug(DBG_CFG, "attempting to parse IPv4 addr or hostname (%s)", str); - - *tmp = '\0'; - tmp++; - if (strtou16_strict(tmp, &port) < 0) - goto error; - - saddr = zmalloc(sizeof(*saddr)); - if (!saddr) - goto error; - - if (inet_pton(AF_INET, str, &saddr->in4.sin_addr) > 0) { - debug(DBG_CFG, "got an IPv4:port (%s:%" PRIu16 ")", str, port); - saddr_set_ipv4(saddr, saddr->in4.sin_addr.s_addr, htons(port)); - list_add(&saddr->list, list); - naddrs++; - goto success; - } - - xfree(saddr); - debug(DBG_CFG, "maybe got a hostname:port (%s:%" PRIu16 ")", str, port); - if (!dnslookup(str, port, rvalue, async)) - goto error; - - } else if (strtou16_strict(tmp, &port) == 0) { - /* Port */ - debug(DBG_CFG, "attempting to parse a port number (%s)", str); - - saddr = zmalloc(sizeof(*saddr)); - if (!saddr) - goto error; - - saddr_set_ipv6(saddr, &in6addr_any, htons(port)); - list_add(&saddr->list, list); - naddrs++; - - saddr = zmalloc(sizeof(*saddr)); - if (!saddr) - goto error; - - saddr_set_ipv4(saddr, INADDR_ANY, htons(port)); - list_add(&saddr->list, list); - naddrs++; - - } else { - /* Unknown */ - error("unable to parse address: %s", str); - goto error; - } - -success: - switch (rvalue->type) { - case CFG_VAL_TYPE_ADDRS: - if (list_empty(list) || naddrs == 0) { - error("empty address list"); - return false; - } - - debug(DBG_CFG, "parsed to %u addresses", naddrs); - return true; - - case CFG_VAL_TYPE_ASYNC_ADDRS: - debug(DBG_CFG, "looking up address asynchronously"); - return true; - - default: - error("invalid rvalue type"); - rvalue->type = CFG_VAL_TYPE_INVALID; - break; - } - -error: - if (rvalue->type == CFG_VAL_TYPE_ADDRS && !list_empty(list)) { - struct saddr *tmp; - - list_for_each_entry_safe(saddr, tmp, list, list) { - list_del(&saddr->list); - xfree(saddr); - } - } - return false; -} - -/* Returns true if there's data left to parse in buf */ -bool -config_parse_line(const char *filename, char **buf, - struct cfg_key_value_map *kvmap, int *rkey, - const char **rkeyname, struct cfg_value *rvalue) -{ - char *line, *tmp, *key; - int i; - - assert_return(buf && *buf && kvmap && rkey && rkeyname && rvalue, false); - - eat_whitespace_and_comments(buf); - line = get_line(buf); - if (!line) - return false; - - debug(DBG_CFG, "%s: parsing config line: %s", filename, line); - - tmp = line; - while (isspace(*tmp)) - tmp++; - - if (*tmp == '\0') - goto error; - - key = tmp; - while (*tmp != '\0' && !isspace(*tmp)) - tmp++; - - if (*tmp == '\0') - goto error; - - *tmp = '\0'; - tmp++; - - while (isspace(*tmp)) - tmp++; - - if (*tmp != '=') - goto error; - - tmp++; - while (isspace(*tmp)) - tmp++; - - if (*tmp == '\0') - goto error; - - for (i = 0; kvmap[i].key_name; i++) { - if (!streq(kvmap[i].key_name, key)) - continue; - - switch (kvmap[i].value_type) { - - case CFG_VAL_TYPE_STRING: - rvalue->type = CFG_VAL_TYPE_STRING; - rvalue->str = tmp; - break; - - case CFG_VAL_TYPE_UINT16: { - uint16_t v; - - if (strtou16_strict(tmp, &v) < 0) - goto error; - - rvalue->type = CFG_VAL_TYPE_UINT16; - rvalue->uint16 = v; - break; - } - - case CFG_VAL_TYPE_ADDRS: - if (!strtosockaddrs(tmp, rvalue, false)) - goto error; - - if (rvalue->type != CFG_VAL_TYPE_ADDRS) { - error("invalid type returned from strtosockaddrs"); - goto error; - } - - if (list_empty(&rvalue->saddrs)) { - error("empty address list"); - goto error; - } - break; - - case CFG_VAL_TYPE_ASYNC_ADDRS: - if (!strtosockaddrs(tmp, rvalue, true)) - goto error; - - switch (rvalue->type) { - case CFG_VAL_TYPE_ADDRS: - if (list_empty(&rvalue->saddrs)) { - error("empty address list"); - goto error; - } - break; - - case CFG_VAL_TYPE_ASYNC_ADDRS: - if (!rvalue->dns_async) { - error("dns_async not set"); - goto error; - } - break; - - default: - error("invalid type returned from strtosockaddrs"); - goto error; - } - - break; - - case CFG_VAL_TYPE_BOOL: - if (strcaseeq(tmp, "yes") || strcaseeq(tmp, "true")) { - rvalue->type = CFG_VAL_TYPE_BOOL; - rvalue->boolean = true; - } else if (strcaseeq(tmp, "no") || strcaseeq(tmp, "false")) { - rvalue->type = CFG_VAL_TYPE_BOOL; - rvalue->boolean = false; - } else { - error("invalid boolean value (%s)", tmp); - goto error; - } - break; - - case CFG_VAL_TYPE_INVALID: - /* fall through */ - default: - goto error; - } - - /* sanity check */ - if ((rvalue->type != kvmap[i].value_type) && - ((kvmap[i].value_type != CFG_VAL_TYPE_ASYNC_ADDRS) && - (rvalue->type != CFG_VAL_TYPE_ADDRS))) { - error("rvalue->type != kvmap->type"); - goto error; - } - - *rkey = kvmap[i].key_value; - *rkeyname = kvmap[i].key_name; - return true; - } - -error: - /* FIXME: the line is already mangled here, a line number would be nice */ - error("%s: invalid config line: %s", filename, line); - rvalue->type = CFG_VAL_TYPE_INVALID; - *rkey = 0; - *rkeyname = NULL; - return true; -} - -bool -config_parse_header(const char *filename, const char *title, char **buf) -{ - char *line; - - assert_return(!empty_str(filename) && !empty_str(title) && buf && *buf, false); - - eat_whitespace_and_comments(buf); - - line = get_line(buf); - if (!line) { - error("%s: missing header in configuration file", filename); - return false; - } else { - char titlehdr[strlen(title) + 3]; - - sprintf(titlehdr, "[%s]", title); - if (!streq(line, titlehdr)) { - error("%s: incorrect header in configuration file", filename); - return false; - } - } - - return true; -} |