summaryrefslogtreecommitdiff
path: root/config.c
diff options
context:
space:
mode:
Diffstat (limited to 'config.c')
-rw-r--r--config.c456
1 files changed, 52 insertions, 404 deletions
diff --git a/config.c b/config.c
index f362920..f13191b 100644
--- a/config.c
+++ b/config.c
@@ -2,8 +2,6 @@
#include <ctype.h>
#include <string.h>
#include <stdbool.h>
-#include <sys/inotify.h>
-#include <dirent.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
@@ -252,80 +250,37 @@ out:
return false;
}
-enum scfg_keys {
- SCFG_KEY_TYPE,
- SCFG_KEY_NAME,
- SCFG_KEY_PORT,
- SCFG_KEY_LOCAL,
- SCFG_KEY_REMOTE,
- SCFG_KEY_INVALID
-};
-
-enum value_type {
- VAL_TYPE_STRING,
- VAL_TYPE_UINT16,
- VAL_TYPE_ADDR,
- VAL_TYPE_INVALID
-};
-
-struct scfg_key_map {
- const char *key_name;
- enum scfg_keys key_value;
- enum value_type value_type;
-} scfg_key_map[] = {
- {
- .key_name = "type",
- .key_value = SCFG_KEY_TYPE,
- .value_type = VAL_TYPE_STRING,
- }, {
- .key_name = "name",
- .key_value = SCFG_KEY_NAME,
- .value_type = VAL_TYPE_STRING,
- }, {
- .key_name = "port",
- .key_value = SCFG_KEY_PORT,
- .value_type = VAL_TYPE_UINT16,
- }, {
- .key_name = "local",
- .key_value = SCFG_KEY_LOCAL,
- .value_type = VAL_TYPE_ADDR,
- }, {
- .key_name = "remote",
- .key_value = SCFG_KEY_REMOTE,
- .value_type = VAL_TYPE_ADDR,
- }
-};
-
-union cfg_value {
- const char *str;
- uint16_t uint16;
- struct list_head addr_list;
-};
-
-
-static void
-line_get_key_value(char *line, enum scfg_keys *rkey, union cfg_value *rvalue)
+/* Returns true if theres data left to parse in buf */
+bool
+config_parse_line(struct cfg *cfg, char **buf, struct cfg_key_value_map *kvmap,
+ int *rkey, union cfg_value *rvalue)
{
- char *tmp, *key;
+ char *line, *tmp, *key;
int i;
- *rkey = SCFG_KEY_INVALID;
+ if (!cfg || !buf || !*buf || !kvmap || !rkey || !rvalue)
+ die("%s: called with invalid parameters\n", __func__);
+
+ eat_whitespace_and_comments(buf);
+ line = get_line(buf);
if (!line)
- return;
+ return false;
+
+ printf("%s: examining line: %s\n", __func__, line);
tmp = line;
while (isspace(*tmp))
tmp++;
if (*tmp == '\0')
- return;
+ goto out;
key = tmp;
while (*tmp != '\0' && !isspace(*tmp))
tmp++;
if (*tmp == '\0')
- return;
+ goto out;
*tmp = '\0';
tmp++;
@@ -334,397 +289,90 @@ line_get_key_value(char *line, enum scfg_keys *rkey, union cfg_value *rvalue)
tmp++;
if (*tmp != '=')
- return;
+ goto out;
tmp++;
while (isspace(*tmp))
tmp++;
if (*tmp == '\0')
- return;
+ goto out;
- for (i = 0; i < ARRAY_SIZE(scfg_key_map); i++) {
- if (strcmp(scfg_key_map[i].key_name, key))
+ for (i = 0; kvmap[i].key_name; i++) {
+ if (strcmp(kvmap[i].key_name, key))
continue;
- switch (scfg_key_map[i].value_type) {
+ switch (kvmap[i].value_type) {
- case VAL_TYPE_STRING:
+ case CFG_VAL_TYPE_STRING:
rvalue->str = tmp;
break;
- case VAL_TYPE_UINT16: {
+ case CFG_VAL_TYPE_UINT16: {
uint16_t v;
if (strtou16_strict(tmp, &v) < 0)
- return;
+ goto out;
rvalue->uint16 = v;
break;
}
- case VAL_TYPE_ADDR: {
+ case CFG_VAL_TYPE_ADDRS: {
if (!strtosockaddrs(tmp, &rvalue->addr_list))
- return;
+ goto out;
if (list_empty(&rvalue->addr_list)) {
- fprintf(stderr, "VAL_TYPE_ADDR with zero list!?\n");
- return;
+ fprintf(stderr, "CFG_VAL_TYPE_ADDRS with zero list!?\n");
+ goto out;
} else {
int i = 0;
struct list_head *pos;
list_for_each(pos, &rvalue->addr_list)
i++;
- fprintf(stderr, "VAL_TYPE_ADDR with list %i entries\n", i);
+ fprintf(stderr, "CFG_VAL_TYPE_ADDRS with list %i entries\n", i);
}
break;
}
- case VAL_TYPE_INVALID:
+ case CFG_VAL_TYPE_INVALID:
/* fall through */
default:
- return;
- }
- *rkey = scfg_key_map[i].key_value;
- break;
- }
-}
-
-static void
-scfg_parse(struct cfg *cfg, struct server *scfg)
-{
- char *pos = &scfg->buf[0];
- char *line;
-
- eat_whitespace_and_comments(&pos);
-
- line = get_line(&pos);
- if (!line) {
- printf("Cfg: premature EOF\n");
- return;
- }
-
- if (strcmp(line, "[server]")) {
- printf("Invalid line: %s\n", line);
- return;
- }
-
- while (true) {
- enum scfg_keys key;
- union cfg_value value;
-
- eat_whitespace_and_comments(&pos);
- line = get_line(&pos);
- printf("Examining line: %s\n", line);
- line_get_key_value(line, &key, &value);
- if (key == SCFG_KEY_INVALID)
- break;
- printf("Got a key-value pair: %i = something\n", key);
-
- switch (key) {
-
- case SCFG_KEY_TYPE:
- if (!strcmp(value.str, "proxy")) {
- if (!server_set_type(cfg, scfg, SERVER_TYPE_PROXY))
- return;
- } else if (!strcmp(value.str, "announce")) {
- if (!server_set_type(cfg, scfg, SERVER_TYPE_ANNOUNCE))
- return;
- }
- break;
-
- case SCFG_KEY_NAME:
- if (!server_set_pretty_name(cfg, scfg, value.str))
- return;
- break;
-
- case SCFG_KEY_PORT:
- if (!server_set_port(cfg, scfg, value.uint16))
- return;
- break;
-
- case SCFG_KEY_LOCAL: {
- struct sockaddr_in46 *addr, *tmp;
-
- list_for_each_entry_safe(addr, tmp, &value.addr_list, list) {
- list_del(&addr->list);
- server_add_local(cfg, scfg, addr);
- }
- break;
- }
-
- case SCFG_KEY_REMOTE: {
- struct sockaddr_in46 *addr, *tmp;
-
- list_for_each_entry_safe(addr, tmp, &value.addr_list, list) {
- list_del(&addr->list);
- server_add_remote(cfg, scfg, addr);
- }
- break;
- }
-
- case SCFG_KEY_INVALID:
- default:
- break;
- }
- }
-
- //printf("Cfg:\n%s\n\n", pos);
-}
-
-static void
-scfg_read_cb(struct cfg *cfg, struct uring_task *task, int res)
-{
- struct server *scfg = container_of(task, struct server, task);
-
- printf("Asked to parse server cfg %s (bytes %i)\n", scfg->name, res);
-
- if (res < 0) {
- perrordie("read");
- } else if (res > 0) {
- scfg->len += res;
- if (scfg->len + 1 >= sizeof(scfg->buf)) {
- fprintf(stderr, "Server config too large\n");
- server_delete(cfg, scfg);
- return;
+ goto out;
}
- uring_read(cfg, &scfg->task, scfg->buf + scfg->len, sizeof(scfg->buf) - scfg->len, scfg->len, scfg_read_cb);
- return;
- } else {
- /* EOF */
- scfg->buf[scfg->len] = '\0';
- uring_task_close_fd(cfg, &scfg->task);
- scfg_parse(cfg, scfg);
- server_commit(cfg, scfg);
+ *rkey = kvmap[i].key_value;
+ return true;
}
-}
-
-static void
-scfg_open_cb(struct cfg *cfg, struct uring_task *task, int res)
-{
- struct server *scfg = container_of(task, struct server, task);
-
- if (res < 0) {
- fprintf(stderr, "Open failed\n");
- server_delete(cfg, scfg);
- return;
- }
-
- printf("Asked to read server cfg %s (fd %i)\n", scfg->name, res);
- uring_task_set_fd(&scfg->task, res);
- scfg->len = 0;
- uring_read(cfg, &scfg->task, scfg->buf, sizeof(scfg->buf), 0, scfg_read_cb);
-}
-
-static bool
-scfg_valid_filename(const char *name)
-{
- const char *suffix;
-
- if (!name)
- return false;
- if (name[0] == '\0')
- return false;
- if (name[0] == '.')
- return false;
- if ((suffix = strrchr(name, '.')) == NULL)
- return false;
- if (strcmp(suffix, ".server"))
- return false;
+out:
+ fprintf(stderr, "Invalid line\n");
+ *rkey = 0;
return true;
}
-struct inotify_ev {
- struct uring_task task;
- char buf[4096] __attribute__((aligned(__alignof__(struct inotify_event))));
-};
-
-static void
-inotify_free(struct uring_task *task)
+bool
+config_parse_header(struct cfg *cfg, const char *title, char **buf)
{
- struct inotify_ev *iev = container_of(task, struct inotify_ev, task);
- struct cfg *cfg = container_of(task->parent, struct cfg, task);
-
- fprintf(stderr, "%s called\n", __func__);
- if (!iev || !cfg)
- die("%s: iev or cfg is NULL!?\n", __func__);
-
- free(iev);
- cfg->iev = NULL;
- uring_task_put(cfg, &cfg->task);
-}
-
-static void
-inotify_event_dump(const struct inotify_event *event)
-{
- printf("Event:\n");
- printf(" * WD : %i\n", event->wd);
- printf(" * Cookie : %" PRIu32 "\n", event->cookie);
- printf(" * Length : %" PRIu32 "\n", event->len);
- printf(" * Name : %s\n", event->name);
- printf(" * Mask : %" PRIu32 "\n", event->mask);
- if (event->mask & IN_ACCESS)
- printf("\tIN_ACCESS\n");
- else if(event->mask & IN_MODIFY)
- printf("\tIN_MODIFY\n");
- else if(event->mask & IN_ATTRIB)
- printf("\tIN_ATTRIB\n");
- else if(event->mask & IN_CLOSE_WRITE)
- printf("\tIN_CLOSE_WRITE\n");
- else if(event->mask & IN_CLOSE_NOWRITE)
- printf("\tIN_CLOSE_NOWRITE\n");
- else if(event->mask & IN_OPEN)
- printf("\tIN_OPEN\n");
- else if(event->mask & IN_MOVED_FROM)
- printf("\tIN_MOVED_FROM\n");
- else if(event->mask & IN_MOVED_TO)
- printf("\tIN_MOVED_TO\n");
- else if(event->mask & IN_CREATE)
- printf("\tIN_CREATE\n");
- else if(event->mask & IN_DELETE)
- printf("\tIN_DELETE\n");
- else if(event->mask & IN_DELETE_SELF)
- printf("\tIN_DELETE_SELF\n");
- else if(event->mask & IN_MOVE_SELF)
- printf("\tIN_MOVE_SELF\n");
- else if(event->mask & IN_UNMOUNT)
- printf("\tIN_UNMOUNT\n");
- else if(event->mask & IN_Q_OVERFLOW)
- printf("\tIN_Q_OVERFLOW\n");
- else if(event->mask & IN_IGNORED)
- printf("\tIN_IGNORED\n");
- printf("\n");
-}
-
-static void
-inotify_cb(struct cfg *cfg, struct uring_task *task, int res)
-{
- struct inotify_ev *iev = container_of(task, struct inotify_ev, task);
- const struct inotify_event *event;
- char *ptr;
- struct server *scfg;
-
- fprintf(stderr, "%s: ret is %i (ref %u)\n", __func__, res, task->refcount);
-
- if (task->dead) {
- fprintf(stderr, "%s: task is dead\n", __func__);
- uring_task_put(cfg, task);
- return;
- }
-
- if (res <= 0)
- perrordie("inotify_read");
+ char *line;
- for (ptr = iev->buf; ptr < iev->buf + res; ptr += sizeof(struct inotify_event) + event->len) {
- event = (const struct inotify_event *)ptr;
+ if (!cfg || !title || !buf || !*buf)
+ return false;
- if (debuglvl > 0)
- inotify_event_dump(event);
+ eat_whitespace_and_comments(buf);
- if (event->mask & (IN_IGNORED | IN_MOVE_SELF | IN_DELETE_SELF | IN_UNMOUNT))
- die("Configuration directory gone, exiting\n");
+ line = get_line(buf);
+ if (!line) {
+ printf("Cfg: premature EOF\n");
+ return false;
+ } else {
+ char titlehdr[strlen(title) + 3];
- if (event->mask & IN_Q_OVERFLOW) {
- error("inotify queue overflow!\n");
- continue;
+ sprintf(titlehdr, "[%s]", title);
+ if (strcmp(line, titlehdr)) {
+ printf("Invalid header: %s\n", line);
+ return false;
}
-
- if (!scfg_valid_filename(event->name))
- continue;
-
- if (event->mask & (IN_MOVED_FROM | IN_DELETE))
- server_delete_by_name(cfg, event->name);
- else if (event->mask & (IN_MOVED_TO | IN_CREATE | IN_CLOSE_WRITE)) {
- scfg = server_new(cfg, event->name);
- uring_openat(cfg, &scfg->task, event->name, scfg_open_cb);
- } else
- error("inotify: weird, unknown event: 0x%08x\n", event->mask);
- }
-
- uring_read(cfg, &iev->task, iev->buf, sizeof(iev->buf), 0, inotify_cb);
-}
-
-void
-inotify_refdump(struct inotify_ev *iev)
-{
- uring_task_refdump(&iev->task);
-}
-
-void
-scfg_stop_monitor_dir(struct cfg *cfg)
-{
- if (!cfg->iev) {
- fprintf(stderr, "%s called with no iev!\n", __func__);
- return;
}
- fprintf(stderr, "%s called, closing fd %i\n", __func__, cfg->iev->task.fd);
- uring_cancel(cfg, &cfg->iev->task);
- cfg->iev = NULL;
-}
-
-void
-scfg_monitor_dir(struct cfg *cfg)
-{
- int ifd;
- int iwd;
- struct inotify_ev *iev;
-
- iev = malloc(sizeof(*iev));
- if (!iev)
- perrordie("malloc");
-
- ifd = inotify_init1(IN_CLOEXEC);
- if (ifd < 0)
- perrordie("inotify_init1");
-
- /* ln = IN_CREATE, cp/vi/mv = IN_CREATE, IN_OPEN, IN_CLOSE_WRITE */
- iwd = inotify_add_watch(ifd, ".",
- IN_CLOSE_WRITE | IN_DELETE | IN_CREATE |
- IN_DELETE_SELF | IN_MOVE_SELF | IN_MOVED_TO |
- IN_MOVED_FROM | IN_DONT_FOLLOW |
- IN_EXCL_UNLINK | IN_ONLYDIR );
- if (iwd < 0)
- perrordie("inotify_add_watch");
-
- uring_task_init(&iev->task, "iev", &cfg->task, inotify_free);
- uring_task_set_fd(&iev->task, ifd);
- cfg->iev = iev;
- uring_read(cfg, &iev->task, iev->buf, sizeof(iev->buf), 0, inotify_cb);
-}
-
-void
-scfg_read_all(struct cfg *cfg)
-{
-
- DIR *cfgdir;
- struct dirent *dent;
- struct server *scfg;
-
- cfgdir = opendir(".");
- if (!cfgdir) {
- perror("opendir");
- free(cfg);
- return;
- }
-
- while ((dent = readdir(cfgdir)) != NULL) {
- char *suffix;
-
- if (dent->d_name[0] == '.')
- continue;
- if (dent->d_type != DT_REG && dent->d_type != DT_UNKNOWN)
- continue;
- if ((suffix = strrchr(dent->d_name, '.')) == NULL)
- continue;
- if (strcmp(suffix, ".server"))
- continue;
-
- scfg = server_new(cfg, dent->d_name);
- uring_openat(cfg, &scfg->task, dent->d_name, scfg_open_cb);
- }
-
- closedir(cfgdir);
+ return true;
}
-