Hi [2024-05-30 21:54] Philipp <phil...@bureaucracy.de> > I'm currently working on the C API for the tables implementations. The > current API has the problem that the callbacks mixes request and > response. So I have created a new C api with callbacks for requests > and extra functios for response. The callbacks looks the following: > > void update_cb(const char *id, const char *tname) > void check_cb(const char *id, const char *tname, int service, const char *key) > void lookup_cb(const char *id, const char *tname, int service, const char > *key) > void fetch_cb(const char *id, const char *tname, int service) > > These are called on for each request. The backend register these callbacks > and calles a response function: > > void table_api_update_finish(const char *id) > void table_api_check_result(const char *id, bool found) > void table_api_lookup_result(const char *id, const char *buf) > void table_api_lookup_finish(const char *id) > void table_api_fetch_result(const char *id, const char *buf) > table_api_error(const char *id, const char *error) > > In most cases the return value (found/not-found/ok) is implicit. For > lookup there are two functions for response, one for the value and one > to finish the lookup. This has two reasons: First this makes it simpler > to handle multible (i.e. for alias) responses. Secound this allows to > change the protokoll for more flexible lookup tables (usefull for dns > tables). The error function implicit respones with the correct result > type. > > What do you think about the new API? > > I have also implement some fallback handler for the old api. They are > primary for simpler testing and development. Patcher are tested with > table-ldap and attached. The patches are currenty seperated by query > type. For the push I would put them togetter in one commit. > > My next step is to change the getline loop to a pool based loop. Then > add some registration for other fd. This way the backend can be full > asyncron.
I now also have implemented a simple poll based event loop. So a table implementation can register fds with the following api: void table_api_register_fd(int fd, short events, fd_callback cb); void table_api_replace_fd(int old, int new); void table_api_remove_fd(int fd); The callback looks like this: typedef void (*fd_callback)(int fd, short revent); So you the registered callback gets called with the fd and the revent from poll. This make it easy to implement a full async table. Patches[0] are attached. I don't have full tested them but first tests look good. Philipp [0] I have included the previous patches, because I don't know if I have send all updates and haven't rebased my local branch.
From c3996e9007e198f3c69f31c580890d8d1f42c938 Mon Sep 17 00:00:00 2001 From: Philipp Takacs <phil...@bureaucracy.de> Date: Sun, 19 May 2024 11:18:26 +0200 Subject: [PATCH 01/16] move request handling to seperate function --- table_stdio.c | 230 ++++++++++++++++++++++++++------------------------ 1 file changed, 121 insertions(+), 109 deletions(-) diff --git a/table_stdio.c b/table_stdio.c index 289deab..98b8df4 100644 --- a/table_stdio.c +++ b/table_stdio.c @@ -123,15 +123,132 @@ table_api_get_name(void) return tablename; } -int -table_api_dispatch(void) +static void +handle_request(char *line, size_t linelen) { char buf[LINE_MAX]; char *t, *vers, *tname, *type, *service, *id, *key; + int sid, r; + + t = line; + (void) linelen; + + if (strncmp(t, "table|", 6)) + errx(1, "malformed line"); + t += 6; + + vers = t; + if ((t = strchr(t, '|')) == NULL) + errx(1, "malformed line: missing version"); + *t++ = '\0'; + + if (strcmp(vers, "0.1") != 0) + errx(1, "unsupported protocol version: %s", vers); + + /* skip timestamp */ + if ((t = strchr(t, '|')) == NULL) + errx(1, "malformed line: missing timestamp"); + *t++ = '\0'; + + tname = t; + if ((t = strchr(t, '|')) == NULL) + errx(1, "malformed line: missing table name"); + *t++ = '\0'; + strlcpy(tablename, tname, sizeof(tablename)); + + type = t; + if ((t = strchr(t, '|')) == NULL) + errx(1, "malformed line: missing type"); + *t++ = '\0'; + + if (!strcmp(type, "update")) { + if (handler_update == NULL) + errx(1, "no update handler registered"); + + id = t; + r = handler_update(); + printf("update-result|%s|%s\n", id, + r == -1 ? "error" : "ok"); + if (fflush(stdout) == EOF) + err(1, "fflush"); + return; + } + + service = t; + if ((t = strchr(t, '|')) == NULL) + errx(1, "malformed line: missing service"); + *t++ = '\0'; + sid = service_id(service); + + id = t; + + r = -1; + if (!strcmp(type, "fetch")) { + if (handler_fetch == NULL) + errx(1, "no fetch handler registered"); + + if (registered_services & sid) { + r = handler_fetch(sid, ¶ms, + buf, sizeof(buf)); + } + if (r == 1) + printf("fetch-result|%s|found|%s\n", id, buf); + else if (r == 0) + printf("fetch-result|%s|not-found\n", id); + else + printf("fetch-result|%s|error\n", id); + if (fflush(stdout) == EOF) + err(1, "fflush"); + memset(buf, 0, sizeof(buf)); + return; + } + + if ((t = strchr(t, '|')) == NULL) + errx(1, "malformed line: missing key"); + *t++ = '\0'; + key = t; + + if (!strcmp(type, "check")) { + if (handler_check == NULL) + errx(1, "no check handler registered"); + if (registered_services & sid) { + r = handler_check(sid, ¶ms, key); + } + if (r == 1) + printf("check-result|%s|found\n", id); + else if (r == 0) + printf("check-result|%s|not-found\n", id); + else + printf("check-result|%s|error\n", id); + } else if (!strcmp(type, "lookup")) { + if (handler_lookup == NULL) + errx(1, "no lookup handler registered"); + if (registered_services & sid) { + r = handler_lookup(sid, ¶ms, key, + buf, sizeof(buf)); + } + if (r == 1) + printf("lookup-result|%s|found|%s\n", id, buf); + else if (r == 0) + printf("lookup-result|%s|not-found\n", id); + else + printf("lookup-result|%s|error\n", id); + memset(buf, 0, sizeof(buf)); + } else + errx(1, "unknown action %s", type); + + if (fflush(stdout) == EOF) + err(1, "fflush"); +} + +int +table_api_dispatch(void) +{ + char *t; char *line = NULL; size_t linesize = 0; ssize_t linelen; - int sid, r, configured = 0; + int configured = 0; dict_init(¶ms); @@ -161,112 +278,7 @@ table_api_dispatch(void) continue; } - if (strncmp(t, "table|", 6)) - errx(1, "malformed line"); - t += 6; - - vers = t; - if ((t = strchr(t, '|')) == NULL) - errx(1, "malformed line: missing version"); - *t++ = '\0'; - - if (strcmp(vers, "0.1") != 0) - errx(1, "unsupported protocol version: %s", vers); - - /* skip timestamp */ - if ((t = strchr(t, '|')) == NULL) - errx(1, "malformed line: missing timestamp"); - *t++ = '\0'; - - tname = t; - if ((t = strchr(t, '|')) == NULL) - errx(1, "malformed line: missing table name"); - *t++ = '\0'; - strlcpy(tablename, tname, sizeof(tablename)); - - type = t; - if ((t = strchr(t, '|')) == NULL) - errx(1, "malformed line: missing type"); - *t++ = '\0'; - - if (!strcmp(type, "update")) { - if (handler_update == NULL) - errx(1, "no update handler registered"); - - id = t; - r = handler_update(); - printf("update-result|%s|%s\n", id, - r == -1 ? "error" : "ok"); - if (fflush(stdout) == EOF) - err(1, "fflush"); - continue; - } - - service = t; - if ((t = strchr(t, '|')) == NULL) - errx(1, "malformed line: missing service"); - *t++ = '\0'; - sid = service_id(service); - - id = t; - - r = -1; - if (!strcmp(type, "fetch")) { - if (handler_fetch == NULL) - errx(1, "no fetch handler registered"); - - if (registered_services & sid) { - r = handler_fetch(sid, ¶ms, - buf, sizeof(buf)); - } - if (r == 1) - printf("fetch-result|%s|found|%s\n", id, buf); - else if (r == 0) - printf("fetch-result|%s|not-found\n", id); - else - printf("fetch-result|%s|error\n", id); - if (fflush(stdout) == EOF) - err(1, "fflush"); - memset(buf, 0, sizeof(buf)); - continue; - } - - if ((t = strchr(t, '|')) == NULL) - errx(1, "malformed line: missing key"); - *t++ = '\0'; - key = t; - - if (!strcmp(type, "check")) { - if (handler_check == NULL) - errx(1, "no check handler registered"); - if (registered_services & sid) { - r = handler_check(sid, ¶ms, key); - } - if (r == 1) - printf("check-result|%s|found\n", id); - else if (r == 0) - printf("check-result|%s|not-found\n", id); - else - printf("check-result|%s|error\n", id); - } else if (!strcmp(type, "lookup")) { - if (handler_lookup == NULL) - errx(1, "no lookup handler registered"); - if (registered_services & sid) { - r = handler_lookup(sid, ¶ms, key, - buf, sizeof(buf)); - } - if (r == 1) - printf("lookup-result|%s|found|%s\n", id, buf); - else if (r == 0) - printf("lookup-result|%s|not-found\n", id); - else - printf("lookup-result|%s|error\n", id); - memset(buf, 0, sizeof(buf)); - } else - errx(1, "unknown action %s", type); - - if (fflush(stdout) == EOF) - err(1, "fflush"); + handle_request(t, linelen); } if (ferror(stdin)) -- 2.39.2
From 192aaef2de70fe0c1a3967eee545e375af2003ce Mon Sep 17 00:00:00 2001 From: Philipp Takacs <phil...@bureaucracy.de> Date: Thu, 23 May 2024 07:09:05 +0200 Subject: [PATCH 02/16] add error result function generic function to response with error --- table_stdio.c | 42 ++++++++++++++++++++++++++++++++++++++++++ table_stdio.h | 1 + 2 files changed, 43 insertions(+) diff --git a/table_stdio.c b/table_stdio.c index 98b8df4..d244c7b 100644 --- a/table_stdio.c +++ b/table_stdio.c @@ -123,6 +123,48 @@ table_api_get_name(void) return tablename; } +void +table_api_error(const char *id, const char *error) +{ + struct request *req; + + req = dict_pop(&requests, id); + + if (!req) { + log_warnx("%s: unknow id %s", __func__, id); + return; + } + + switch(req->o) { + case O_UPDATE: + printf("update-result|%s|error", id); + break; + case O_CHECK: + printf("check-result|%s|error", id); + break; + case O_LOOKUP: + dict_pop(&lookup_entries, id); + printf("lookup-result|%s|error", id); + break; + case O_FETCH: + printf("fetch-result|%s|error", id); + break; + } + +#ifdef errormassage + if (err && *err) { + puts(err); + } else { + puts("unknown"); + } +#else + (void)err; + puts(""); +#endif + if (fflush(stdout) == EOF) + err(1, "fflush"); +} + static void handle_request(char *line, size_t linelen) { diff --git a/table_stdio.h b/table_stdio.h index 3afbbf2..ac6c725 100644 --- a/table_stdio.h +++ b/table_stdio.h @@ -34,4 +34,5 @@ void table_api_on_check(int(*)(int, struct dict *, const char *)); void table_api_on_lookup(int(*)(int, struct dict *, const char *, char *, size_t)); void table_api_on_fetch(int(*)(int, struct dict *, char *, size_t)); int table_api_dispatch(void); +void table_api_error(const char *, const char *); const char *table_api_get_name(void); -- 2.39.2
From b9bbfa09e6644473dd5c814fbdf00ca4ce4cb03c Mon Sep 17 00:00:00 2001 From: Philipp Takacs <phil...@bureaucracy.de> Date: Sun, 19 May 2024 15:02:24 +0200 Subject: [PATCH 03/16] implement async update --- table_stdio.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++----- table_stdio.h | 2 ++ 2 files changed, 80 insertions(+), 7 deletions(-) diff --git a/table_stdio.c b/table_stdio.c index d244c7b..9d040f4 100644 --- a/table_stdio.c +++ b/table_stdio.c @@ -22,12 +22,29 @@ #include <err.h> #include <limits.h> +#include <stdlib.h> #include <stdio.h> #include <string.h> #include "dict.h" +#include "log.h" #include "table_stdio.h" +enum table_operation { + O_UPDATE, + O_CHECK, + O_LOOKUP, + O_FETCH, +}; + +struct request { + enum table_operation o; + char *table; + enum table_service s; + char *key; +}; + +static void (*handler_async_update)(const char *, const char *); static int (*handler_update)(void); static int (*handler_check)(int, struct dict *, const char *); static int (*handler_lookup)(int, struct dict *, const char *, char *, size_t); @@ -44,6 +61,7 @@ static int registered_services = K_ANY; /* Dummy; just kept for backward compatibility */ static struct dict params; +static struct dict requests; static int service_id(const char *service) @@ -87,6 +105,22 @@ table_api_service_name(enum table_service s) } } +static void +fallback_update_handler(const char *id, const char *tname) +{ + int r; + strlcpy(tablename, tname, sizeof(tablename)); + + if (handler_update == NULL) + errx(1, "no update handler registered"); + + r = handler_update(); + if (r == 1) + table_api_update_finish(id); + else + table_api_error(id, NULL); +} + void table_api_register_services(int s) { @@ -99,6 +133,12 @@ table_api_on_update(int(*cb)(void)) handler_update = cb; } +void +table_api_on_update_async(void(*cb)(const char *, const char *)) +{ + handler_async_update = cb; +} + void table_api_on_check(int(*cb)(int, struct dict *, const char *)) { @@ -124,6 +164,7 @@ table_api_get_name(void) } void + table_api_error(const char *id, const char *error) { struct request *req; @@ -165,12 +206,39 @@ table_api_error(const char *id, const char *error) err(1, "fflush"); } +void +table_api_update_finish(const char *id) +{ + struct request *req; + + req = dict_get(&requests, id); + + if (!req) { + log_warnx("%s: unknow id %s", __func__, id); + return; + } + + if (req->o != O_UPDATE) { + table_api_error(id, NULL); + return; + } + + dict_pop(&requests, id); + free(req->table); + free(req); + + printf("update-result|%s|ok\n", id); + if (fflush(stdout) == EOF) + err(1, "fflush"); +} + static void handle_request(char *line, size_t linelen) { char buf[LINE_MAX]; char *t, *vers, *tname, *type, *service, *id, *key; int sid, r; + struct request *req = calloc(1, sizeof(*req)); t = line; (void) linelen; @@ -196,7 +264,7 @@ handle_request(char *line, size_t linelen) if ((t = strchr(t, '|')) == NULL) errx(1, "malformed line: missing table name"); *t++ = '\0'; - strlcpy(tablename, tname, sizeof(tablename)); + req->table = strdup(tname); type = t; if ((t = strchr(t, '|')) == NULL) @@ -204,15 +272,14 @@ handle_request(char *line, size_t linelen) *t++ = '\0'; if (!strcmp(type, "update")) { - if (handler_update == NULL) + if (handler_async_update == NULL) errx(1, "no update handler registered"); id = t; - r = handler_update(); - printf("update-result|%s|%s\n", id, - r == -1 ? "error" : "ok"); - if (fflush(stdout) == EOF) - err(1, "fflush"); + req->o = O_UPDATE; + dict_set(&requests, id, req); + + handler_async_update(id, tname); return; } @@ -293,6 +360,10 @@ table_api_dispatch(void) int configured = 0; dict_init(¶ms); + dict_init(&requests); + + if (!handler_async_update) + table_api_on_update_async(fallback_update_handler); while ((linelen = getline(&line, &linesize, stdin)) != -1) { if (line[linelen - 1] == '\n') diff --git a/table_stdio.h b/table_stdio.h index ac6c725..3db5a78 100644 --- a/table_stdio.h +++ b/table_stdio.h @@ -30,9 +30,11 @@ enum table_service { void table_api_register_services(int); void table_api_on_update(int(*)(void)); +void table_api_on_update_async(void(*)(const char *, const char *)); void table_api_on_check(int(*)(int, struct dict *, const char *)); void table_api_on_lookup(int(*)(int, struct dict *, const char *, char *, size_t)); void table_api_on_fetch(int(*)(int, struct dict *, char *, size_t)); int table_api_dispatch(void); void table_api_error(const char *, const char *); +void table_api_update_finish(const char *); const char *table_api_get_name(void); -- 2.39.2
From a94fd453691fda9284760be338173d8c7f8acdbe Mon Sep 17 00:00:00 2001 From: Philipp Takacs <phil...@bureaucracy.de> Date: Sun, 19 May 2024 16:27:52 +0200 Subject: [PATCH 04/16] implement async check --- table_stdio.c | 77 +++++++++++++++++++++++++++++++++++++++++++++------ table_stdio.h | 2 ++ 2 files changed, 70 insertions(+), 9 deletions(-) diff --git a/table_stdio.c b/table_stdio.c index 9d040f4..7b1fc69 100644 --- a/table_stdio.c +++ b/table_stdio.c @@ -45,6 +45,7 @@ struct request { }; static void (*handler_async_update)(const char *, const char *); +static void (*handler_async_check)(const char *, const char *, int, const char *); static int (*handler_update)(void); static int (*handler_check)(int, struct dict *, const char *); static int (*handler_lookup)(int, struct dict *, const char *, char *, size_t); @@ -121,6 +122,22 @@ fallback_update_handler(const char *id, const char *tname) table_api_error(id, NULL); } +static void +fallback_check_handler(const char *id, const char *tname, int service, const char *key) +{ + int r; + strlcpy(tablename, tname, sizeof(tablename)); + + if (handler_check == NULL) + errx(1, "no check handler registered"); + + r = handler_check(service, ¶ms, key); + if (r == 0 || r == 1) + table_api_check_result(id, r == 1); + else + table_api_error(id, NULL); +} + void table_api_register_services(int s) { @@ -145,6 +162,12 @@ table_api_on_check(int(*cb)(int, struct dict *, const char *)) handler_check = cb; } +void +table_api_on_check_async(void(*cb)(const char *, const char *, int, const char *)) +{ + handler_async_check = cb; +} + void table_api_on_lookup(int(*cb)(int, struct dict *, const char *, char *, size_t)) { @@ -232,6 +255,37 @@ table_api_update_finish(const char *id) err(1, "fflush"); } +void +table_api_check_result(const char *id, bool found) +{ + struct request *req; + + req = dict_get(&requests, id); + + if (!req) { + log_warnx("%s: unknow id %s", __func__, id); + return; + } + + if (req->o != O_CHECK) { + table_api_error(id, NULL); + return; + } + + dict_pop(&requests, id); + free(req->table); + free(req->key); + free(req); + + if (found) + printf("check-result|%s|found\n", id); + else + printf("check-result|%s|not-found\n", id); + + if (fflush(stdout) == EOF) + err(1, "fflush"); +} + static void handle_request(char *line, size_t linelen) { @@ -318,17 +372,20 @@ handle_request(char *line, size_t linelen) key = t; if (!strcmp(type, "check")) { - if (handler_check == NULL) + if (handler_async_check == NULL) errx(1, "no check handler registered"); - if (registered_services & sid) { - r = handler_check(sid, ¶ms, key); - } - if (r == 1) - printf("check-result|%s|found\n", id); - else if (r == 0) - printf("check-result|%s|not-found\n", id); - else + if (!(registered_services & sid)) { printf("check-result|%s|error\n", id); + if (fflush(stdout) == EOF) + err(1, "fflush"); + return; + } + req->o = O_CHECK; + req->s = sid; + req->key = strdup(key); + dict_set(&requests, id, req); + handler_async_check(id, tname, sid, key); + return; } else if (!strcmp(type, "lookup")) { if (handler_lookup == NULL) errx(1, "no lookup handler registered"); @@ -364,6 +421,8 @@ table_api_dispatch(void) if (!handler_async_update) table_api_on_update_async(fallback_update_handler); + if (!handler_async_check) + table_api_on_check_async(fallback_check_handler); while ((linelen = getline(&line, &linesize, stdin)) != -1) { if (line[linelen - 1] == '\n') diff --git a/table_stdio.h b/table_stdio.h index 3db5a78..022356f 100644 --- a/table_stdio.h +++ b/table_stdio.h @@ -32,9 +32,11 @@ void table_api_register_services(int); void table_api_on_update(int(*)(void)); void table_api_on_update_async(void(*)(const char *, const char *)); void table_api_on_check(int(*)(int, struct dict *, const char *)); +void table_api_on_check_async(void(*)(const char *, const char *, int, const char *)); void table_api_on_lookup(int(*)(int, struct dict *, const char *, char *, size_t)); void table_api_on_fetch(int(*)(int, struct dict *, char *, size_t)); int table_api_dispatch(void); void table_api_error(const char *, const char *); void table_api_update_finish(const char *); +void table_api_check_result(const char *, bool); const char *table_api_get_name(void); -- 2.39.2
From 5196109b74bc84f8e45a3b5aeeacae0fee9ddf6f Mon Sep 17 00:00:00 2001 From: Philipp Takacs <phil...@bureaucracy.de> Date: Mon, 20 May 2024 14:46:26 +0200 Subject: [PATCH 05/16] implement async lookup --- table_ldap.c | 1 + table_stdio.c | 150 ++++++++++++++++++++++++++++++++++++++++++++++---- table_stdio.h | 3 + 3 files changed, 143 insertions(+), 11 deletions(-) diff --git a/table_ldap.c b/table_ldap.c index bc8e1c3..bb460ae 100644 --- a/table_ldap.c +++ b/table_ldap.c @@ -25,6 +25,7 @@ #include <netdb.h> #include <ctype.h> +#include <stdbool.h> #include <stdlib.h> #include <stdio.h> #include <string.h> diff --git a/table_stdio.c b/table_stdio.c index 7b1fc69..a62a44f 100644 --- a/table_stdio.c +++ b/table_stdio.c @@ -22,10 +22,13 @@ #include <err.h> #include <limits.h> +#include <stdbool.h> #include <stdlib.h> #include <stdio.h> #include <string.h> +#include <event.h> + #include "dict.h" #include "log.h" #include "table_stdio.h" @@ -46,6 +49,7 @@ struct request { static void (*handler_async_update)(const char *, const char *); static void (*handler_async_check)(const char *, const char *, int, const char *); +static void (*handler_async_lookup)(const char *, const char *, int, const char *); static int (*handler_update)(void); static int (*handler_check)(int, struct dict *, const char *); static int (*handler_lookup)(int, struct dict *, const char *, char *, size_t); @@ -63,6 +67,7 @@ static int registered_services = K_ANY; /* Dummy; just kept for backward compatibility */ static struct dict params; static struct dict requests; +static struct dict lookup_entries; static int service_id(const char *service) @@ -138,6 +143,26 @@ fallback_check_handler(const char *id, const char *tname, int service, const cha table_api_error(id, NULL); } +static void +fallback_lookup_handler(const char *id, const char *tname, int service, const char *key) +{ + char buf[LINE_MAX]; + int r; + strlcpy(tablename, tname, sizeof(tablename)); + + if (handler_lookup == NULL) + errx(1, "no lookup handler registered"); + + r = handler_lookup(service, ¶ms, key, buf, sizeof(buf)); + if (r == 1) { + table_api_lookup_result(id, buf); + } + if (r == 1 || r == 0) + table_api_lookup_finish(id); + else + table_api_error(id, NULL); +} + void table_api_register_services(int s) { @@ -174,6 +199,12 @@ table_api_on_lookup(int(*cb)(int, struct dict *, const char *, char *, size_t)) handler_lookup = cb; } +void +table_api_on_lookup_async(void(*cb)(const char *, const char *, int, const char *)) +{ + handler_async_lookup = cb; +} + void table_api_on_fetch(int(*cb)(int, struct dict *, char *, size_t)) { @@ -286,6 +317,99 @@ table_api_check_result(const char *id, bool found) err(1, "fflush"); } +void +table_api_lookup_result(const char *id, const char *buf) +{ + const char alias_sep[] = ", "; + struct request *req; + struct evbuffer *res; + + req = dict_get(&requests, id); + + if (!req) { + log_warnx("%s: unknow id %s", __func__, id); + return; + } + + if (req->o != O_LOOKUP) { + table_api_error(id, NULL); + return; + } + + res = dict_get(&lookup_entries, id); + + if (!res) { + res = evbuffer_new(); + if (!res) { + table_api_error(id, "can not alloc result"); + return; + } + if (evbuffer_add(res, buf, strlen(buf)) == -1) { + table_api_error(id, "can not alloc result"); + return; + } + dict_set(&lookup_entries, id, res); + return; + } + switch(req->s) { + case K_ALIAS: + if (evbuffer_add(res, alias_sep, sizeof(alias_sep)-1) == -1) { + table_api_error(id, "can not extend result"); + return; + } + if (evbuffer_add(res, buf, 0) == -1) { + table_api_error(id, "can not extend result"); + return; + } + break; + default: + log_warnx("id: %s lookup result override", id); + evbuffer_drain(res, evbuffer_get_length(res)); + if (evbuffer_add(res, buf, sizeof(buf)) == -1) { + table_api_error(id, "can not alloc result"); + return; + } + } +} + +void +table_api_lookup_finish(const char *id) +{ + struct request *req; + struct evbuffer *res; + + req = dict_get(&requests, id); + if (!req) { + log_warnx("%s: unknow id %s", __func__, id); + return; + } + if (req->o != O_LOOKUP) { + table_api_error(id, NULL); + return; + } + + res = dict_get(&lookup_entries, id); + if (res && evbuffer_get_length(res)) { + if (evbuffer_add(res, "\0", 1) == -1) { + table_api_error(id, "can not extend result"); + return; + } + printf("lookup-result|%s|found|%s\n", id, evbuffer_pullup(res, -1)); + } else { + printf("lookup-result|%s|not-found\n", id); + } + + if (fflush(stdout) == EOF) + err(1, "fflush"); + dict_pop(&requests, id); + free(req->table); + free(req->key); + free(req); + res = dict_pop(&lookup_entries, id); + if (res) + evbuffer_free(res); +} + static void handle_request(char *line, size_t linelen) { @@ -387,19 +511,20 @@ handle_request(char *line, size_t linelen) handler_async_check(id, tname, sid, key); return; } else if (!strcmp(type, "lookup")) { - if (handler_lookup == NULL) + if (handler_async_lookup == NULL) errx(1, "no lookup handler registered"); - if (registered_services & sid) { - r = handler_lookup(sid, ¶ms, key, - buf, sizeof(buf)); - } - if (r == 1) - printf("lookup-result|%s|found|%s\n", id, buf); - else if (r == 0) - printf("lookup-result|%s|not-found\n", id); - else + if (!(registered_services & sid)) { printf("lookup-result|%s|error\n", id); - memset(buf, 0, sizeof(buf)); + if (fflush(stdout) == EOF) + err(1, "fflush"); + return; + } + req->o = O_LOOKUP; + req->s = sid; + req->key = strdup(key); + dict_set(&requests, id, req); + handler_async_lookup(id, tname, sid, key); + return; } else errx(1, "unknown action %s", type); @@ -418,11 +543,14 @@ table_api_dispatch(void) dict_init(¶ms); dict_init(&requests); + dict_init(&lookup_entries); if (!handler_async_update) table_api_on_update_async(fallback_update_handler); if (!handler_async_check) table_api_on_check_async(fallback_check_handler); + if (!handler_async_lookup) + table_api_on_lookup_async(fallback_lookup_handler); while ((linelen = getline(&line, &linesize, stdin)) != -1) { if (line[linelen - 1] == '\n') diff --git a/table_stdio.h b/table_stdio.h index 022356f..1313c6a 100644 --- a/table_stdio.h +++ b/table_stdio.h @@ -34,9 +34,12 @@ void table_api_on_update_async(void(*)(const char *, const char *)); void table_api_on_check(int(*)(int, struct dict *, const char *)); void table_api_on_check_async(void(*)(const char *, const char *, int, const char *)); void table_api_on_lookup(int(*)(int, struct dict *, const char *, char *, size_t)); +void table_api_on_lookup_async(void(*)(const char *, const char *, int, const char *)); void table_api_on_fetch(int(*)(int, struct dict *, char *, size_t)); int table_api_dispatch(void); void table_api_error(const char *, const char *); void table_api_update_finish(const char *); void table_api_check_result(const char *, bool); +void table_api_lookup_result(const char *, const char *); +void table_api_lookup_finish(const char *); const char *table_api_get_name(void); -- 2.39.2
From 5c6d587d7d746cbd54484988bb4a5cb6064a9938 Mon Sep 17 00:00:00 2001 From: Philipp Takacs <phil...@bureaucracy.de> Date: Mon, 20 May 2024 16:13:16 +0200 Subject: [PATCH 06/16] implement async fetch --- table_stdio.c | 85 +++++++++++++++++++++++++++++++++++++++++++-------- table_stdio.h | 2 ++ 2 files changed, 74 insertions(+), 13 deletions(-) diff --git a/table_stdio.c b/table_stdio.c index a62a44f..7b39b74 100644 --- a/table_stdio.c +++ b/table_stdio.c @@ -50,6 +50,7 @@ struct request { static void (*handler_async_update)(const char *, const char *); static void (*handler_async_check)(const char *, const char *, int, const char *); static void (*handler_async_lookup)(const char *, const char *, int, const char *); +static void (*handler_async_fetch)(const char *, const char *, int); static int (*handler_update)(void); static int (*handler_check)(int, struct dict *, const char *); static int (*handler_lookup)(int, struct dict *, const char *, char *, size_t); @@ -163,6 +164,29 @@ fallback_lookup_handler(const char *id, const char *tname, int service, const ch table_api_error(id, NULL); } +static void +fallback_fetch_handler(const char *id, const char *tname, int service) +{ + char buf[LINE_MAX]; + int r; + strlcpy(tablename, tname, sizeof(tablename)); + + if (handler_fetch == NULL) + errx(1, "no fetch handler registered"); + + r = handler_fetch(service, ¶ms, buf, sizeof(buf)); + switch(r) { + case 1: + table_api_fetch_result(id, buf); + break; + case 0: + table_api_fetch_result(id, NULL); + break; + default: + table_api_error(id, NULL); + } +} + void table_api_register_services(int s) { @@ -211,6 +235,12 @@ table_api_on_fetch(int(*cb)(int, struct dict *, char *, size_t)) handler_fetch = cb; } +void +table_api_on_fetch_async(void(*cb)(const char *, const char *, int)) +{ + handler_async_fetch = cb; +} + const char * table_api_get_name(void) { @@ -410,6 +440,35 @@ table_api_lookup_finish(const char *id) evbuffer_free(res); } +void +table_api_fetch_result(const char *id, const char *buf) +{ + struct request *req; + + req = dict_get(&requests, id); + + if (!req) { + log_warnx("%s: unknow id %s", __func__, id); + return; + } + + if (req->o != O_FETCH) { + table_api_error(id, NULL); + return; + } + + if (buf && *buf) + printf("fetch-result|%s|found|%s\n", id, buf); + else + printf("fetch-result|%s|not-found\n", id); + + if (fflush(stdout) == EOF) + err(1, "fflush"); + dict_pop(&requests, id); + free(req->table); + free(req); +} + static void handle_request(char *line, size_t linelen) { @@ -471,22 +530,20 @@ handle_request(char *line, size_t linelen) r = -1; if (!strcmp(type, "fetch")) { - if (handler_fetch == NULL) + if (handler_async_fetch == NULL) errx(1, "no fetch handler registered"); - if (registered_services & sid) { - r = handler_fetch(sid, ¶ms, - buf, sizeof(buf)); + if (!(registered_services & sid)) { + printf("check-result|%s|error\n", id); + if (fflush(stdout) == EOF) + err(1, "fflush"); + return; } - if (r == 1) - printf("fetch-result|%s|found|%s\n", id, buf); - else if (r == 0) - printf("fetch-result|%s|not-found\n", id); - else - printf("fetch-result|%s|error\n", id); - if (fflush(stdout) == EOF) - err(1, "fflush"); - memset(buf, 0, sizeof(buf)); + req->o = O_FETCH; + req->s = sid; + req->key = strdup(key); + dict_set(&requests, id, req); + handler_async_check(id, tname, sid, key); return; } @@ -551,6 +608,8 @@ table_api_dispatch(void) table_api_on_check_async(fallback_check_handler); if (!handler_async_lookup) table_api_on_lookup_async(fallback_lookup_handler); + if (!handler_async_fetch) + table_api_on_fetch_async(fallback_fetch_handler); while ((linelen = getline(&line, &linesize, stdin)) != -1) { if (line[linelen - 1] == '\n') diff --git a/table_stdio.h b/table_stdio.h index 1313c6a..fc720ef 100644 --- a/table_stdio.h +++ b/table_stdio.h @@ -36,10 +36,12 @@ void table_api_on_check_async(void(*)(const char *, const char *, int, const c void table_api_on_lookup(int(*)(int, struct dict *, const char *, char *, size_t)); void table_api_on_lookup_async(void(*)(const char *, const char *, int, const char *)); void table_api_on_fetch(int(*)(int, struct dict *, char *, size_t)); +void table_api_on_fetch_async(void(*)(const char *, const char *, int)); int table_api_dispatch(void); void table_api_error(const char *, const char *); void table_api_update_finish(const char *); void table_api_check_result(const char *, bool); void table_api_lookup_result(const char *, const char *); void table_api_lookup_finish(const char *); +void table_api_fetch_result(const char *, const char *); const char *table_api_get_name(void); -- 2.39.2
From 42cac5fa452a4666450ca1a52c4a7f7bda4a88c4 Mon Sep 17 00:00:00 2001 From: Philipp Takacs <phil...@bureaucracy.de> Date: Mon, 20 May 2024 16:27:18 +0200 Subject: [PATCH 07/16] cleanup request handler --- table_stdio.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/table_stdio.c b/table_stdio.c index 7b39b74..c1c096e 100644 --- a/table_stdio.c +++ b/table_stdio.c @@ -472,9 +472,8 @@ table_api_fetch_result(const char *id, const char *buf) static void handle_request(char *line, size_t linelen) { - char buf[LINE_MAX]; char *t, *vers, *tname, *type, *service, *id, *key; - int sid, r; + int sid; struct request *req = calloc(1, sizeof(*req)); t = line; @@ -528,7 +527,6 @@ handle_request(char *line, size_t linelen) id = t; - r = -1; if (!strcmp(type, "fetch")) { if (handler_async_fetch == NULL) errx(1, "no fetch handler registered"); @@ -584,9 +582,6 @@ handle_request(char *line, size_t linelen) return; } else errx(1, "unknown action %s", type); - - if (fflush(stdout) == EOF) - err(1, "fflush"); } int -- 2.39.2
From b903242dde498abb6718305aeb530dcbe6900553 Mon Sep 17 00:00:00 2001 From: Philipp Takacs <phil...@bureaucracy.de> Date: Mon, 20 May 2024 22:21:14 +0200 Subject: [PATCH 08/16] add deprication warnings --- table_stdio.h | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/table_stdio.h b/table_stdio.h index fc720ef..0fa97c9 100644 --- a/table_stdio.h +++ b/table_stdio.h @@ -15,6 +15,12 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#if defined(__clang__) || defined(__GNUC__) +#define DEPRECATED __attribute__((deprecated)) +#else +#define DEPRECATED +#endif + enum table_service { K_ALIAS = 0x001, /* returns struct expand */ K_DOMAIN = 0x002, /* returns struct destination */ @@ -29,11 +35,11 @@ enum table_service { }; void table_api_register_services(int); -void table_api_on_update(int(*)(void)); +void table_api_on_update(int(*)(void)) DEPRECATED; void table_api_on_update_async(void(*)(const char *, const char *)); -void table_api_on_check(int(*)(int, struct dict *, const char *)); +void table_api_on_check(int(*)(int, struct dict *, const char *)) DEPRECATED; void table_api_on_check_async(void(*)(const char *, const char *, int, const char *)); -void table_api_on_lookup(int(*)(int, struct dict *, const char *, char *, size_t)); +void table_api_on_lookup(int(*)(int, struct dict *, const char *, char *, size_t)) DEPRECATED; void table_api_on_lookup_async(void(*)(const char *, const char *, int, const char *)); void table_api_on_fetch(int(*)(int, struct dict *, char *, size_t)); void table_api_on_fetch_async(void(*)(const char *, const char *, int)); -- 2.39.2
From 459dab0d8b0a496ce15c624f7bfd538b9c097e0d Mon Sep 17 00:00:00 2001 From: Philipp Takacs <phil...@bureaucracy.de> Date: Mon, 20 May 2024 22:32:07 +0200 Subject: [PATCH 09/16] rename table_stdio to table_api --- Makefile.am | 4 ++-- table_stdio.c => table_api.c | 2 +- table_stdio.h => table_api.h | 0 table_ldap.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename table_stdio.c => table_api.c (99%) rename table_stdio.h => table_api.h (100%) diff --git a/Makefile.am b/Makefile.am index 5572b66..9132a4f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,11 +1,11 @@ noinst_PROGRAMS = table-ldap -table_ldap_SOURCES = table_ldap.c aldap.c ber.c dict.c log.c table_stdio.c util.c +table_ldap_SOURCES = table_ldap.c aldap.c ber.c dict.c log.c table_api.c util.c LDADD = $(LIBOBJS) EXTRA_DIST = aldap.h ber.h compat.h config.h.in \ - dict.h log.h table_stdio.h util.h + dict.h log.h table_api.h util.h smtpdir = ${prefix}/libexec/smtpd diff --git a/table_stdio.c b/table_api.c similarity index 99% rename from table_stdio.c rename to table_api.c index c1c096e..694be68 100644 --- a/table_stdio.c +++ b/table_api.c @@ -31,7 +31,7 @@ #include "dict.h" #include "log.h" -#include "table_stdio.h" +#include "table_api.h" enum table_operation { O_UPDATE, diff --git a/table_stdio.h b/table_api.h similarity index 100% rename from table_stdio.h rename to table_api.h diff --git a/table_ldap.c b/table_ldap.c index bb460ae..35ae7fb 100644 --- a/table_ldap.c +++ b/table_ldap.c @@ -34,7 +34,7 @@ #include "aldap.h" #include "dict.h" #include "log.h" -#include "table_stdio.h" +#include "table_api.h" #include "util.h" #ifndef MAXIMUM -- 2.39.2
From f1492ea87f501c0949ff410ede064b9431842f82 Mon Sep 17 00:00:00 2001 From: Philipp Takacs <phil...@bureaucracy.de> Date: Fri, 31 May 2024 15:10:12 +0200 Subject: [PATCH 10/16] fixup! add error result function --- table_api.c | 1 + 1 file changed, 1 insertion(+) diff --git a/table_api.c b/table_api.c index 694be68..9f0fe9c 100644 --- a/table_api.c +++ b/table_api.c @@ -288,6 +288,7 @@ table_api_error(const char *id, const char *error) #endif if (fflush(stdout) == EOF) err(1, "fflush"); + free(req); } void -- 2.39.2
From ff1bf8dfe89dbf6a01e5a32c6530ca04b7287866 Mon Sep 17 00:00:00 2001 From: Philipp Takacs <phil...@bureaucracy.de> Date: Fri, 31 May 2024 15:11:09 +0200 Subject: [PATCH 11/16] fixup! implement async lookup --- table_api.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/table_api.c b/table_api.c index 9f0fe9c..b5cce42 100644 --- a/table_api.c +++ b/table_api.c @@ -252,6 +252,7 @@ void table_api_error(const char *id, const char *error) { struct request *req; + struct evbuffer *res; req = dict_pop(&requests, id); @@ -289,6 +290,9 @@ table_api_error(const char *id, const char *error) if (fflush(stdout) == EOF) err(1, "fflush"); free(req); + res = dict_pop(&lookup_entries, id); + if (res) + evbuffer_free(res); } void -- 2.39.2
From 417271b67020cb68693c749c49751c66894b643e Mon Sep 17 00:00:00 2001 From: Philipp Takacs <phil...@bureaucracy.de> Date: Sun, 9 Jun 2024 13:32:06 +0200 Subject: [PATCH 12/16] fixup! implement async fetch --- table_api.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/table_api.c b/table_api.c index b5cce42..b2fd0d6 100644 --- a/table_api.c +++ b/table_api.c @@ -544,9 +544,9 @@ handle_request(char *line, size_t linelen) } req->o = O_FETCH; req->s = sid; - req->key = strdup(key); + req->key = NULL; dict_set(&requests, id, req); - handler_async_check(id, tname, sid, key); + handler_async_fetch(id, tname, sid); return; } -- 2.39.2
From 978e58175873eb7db57a7b4b38a294bf5bb9492e Mon Sep 17 00:00:00 2001 From: Philipp Takacs <phil...@bureaucracy.de> Date: Sun, 9 Jun 2024 13:27:52 +0200 Subject: [PATCH 13/16] switch to poll based api untested --- table_api.c | 129 +++++++++++++++++++++++++++++++++++++++------------- table_api.h | 2 + 2 files changed, 100 insertions(+), 31 deletions(-) diff --git a/table_api.c b/table_api.c index b2fd0d6..397c322 100644 --- a/table_api.c +++ b/table_api.c @@ -22,10 +22,12 @@ #include <err.h> #include <limits.h> +#include <poll.h> #include <stdbool.h> #include <stdlib.h> #include <stdio.h> #include <string.h> +#include <unistd.h> #include <event.h> @@ -33,6 +35,10 @@ #include "log.h" #include "table_api.h" +#ifndef MAXFDS +#define MAXFDS 16 +#endif + enum table_operation { O_UPDATE, O_CHECK, @@ -56,6 +62,14 @@ static int (*handler_check)(int, struct dict *, const char *); static int (*handler_lookup)(int, struct dict *, const char *, char *, size_t); static int (*handler_fetch)(int, struct dict *, char *, size_t); +static nfds_t nfds; +static struct pollfd fds[MAXFDS]; +static fd_callback cbs[MAXFDS]; + +static struct evbuffer *inbuffer; + +static bool configured; + static char tablename[128]; /* @@ -589,14 +603,72 @@ handle_request(char *line, size_t linelen) errx(1, "unknown action %s", type); } +static void +api_callback(int fd, short revents) +{ + bool retry = true; + char buf[BUFSIZ]; + size_t linelen; + int serrno, ret; + char *line, *t; + + + if (revents & (POLLERR|POLLNVAL)) { + exit(1); + } + if (revents & POLLHUP) { + exit(0); + } + + do { + ret = read(fd, buf, sizeof(buf)); + if (ret == 0) { + /* EOF */ + exit(0); + } + if (ret < 0) { + serrno = errno; + if (serrno == EAGAIN || serrno == EWOULDBLOCK) { + retry = false; + continue; + } + } + evbuffer_add(inbuffer, buf, ret); + } while (retry); + + while ((line = evbuffer_readline(inbuffer))) { + t = line; + linelen = strlen(line); + if (configured) { + handle_request(t, linelen); + free(line); + continue; + } + + if (strncmp(t, "config|", 7) != 0) + errx(1, "unexpected config line: %s", line); + t += 7; + + if (!strcmp(t, "ready")) { + configured = 1; + + for (int s = K_ALIAS; s <= K_MAILADDRMAP; s <<= 1) { + printf("register|%s\n", table_api_service_name(s)); + } + + puts("register|ready"); + if (fflush(stdout) == EOF) + err(1, "fflush"); + } + + free(line); + } +} + int table_api_dispatch(void) { - char *t; - char *line = NULL; - size_t linesize = 0; - ssize_t linelen; - int configured = 0; + int serrno, r; dict_init(¶ms); dict_init(&requests); @@ -611,37 +683,32 @@ table_api_dispatch(void) if (!handler_async_fetch) table_api_on_fetch_async(fallback_fetch_handler); - while ((linelen = getline(&line, &linesize, stdin)) != -1) { - if (line[linelen - 1] == '\n') - line[--linelen] = '\0'; - t = line; - - if (!configured) { - if (strncmp(t, "config|", 7) != 0) - errx(1, "unexpected config line: %s", line); - t += 7; - - if (!strcmp(t, "ready")) { - configured = 1; - - for (int s = K_ALIAS; s <= K_MAILADDRMAP; s <<= 1) { - printf("register|%s\n", table_api_service_name(s)); - } - - puts("register|ready"); - if (fflush(stdout) == EOF) - err(1, "fflush"); + fds[0].fd = STDIN_FILENO; + fds[0].events = POLLIN; + fds[0].revents = 0; + cbs[0] = api_callback; + if (!nfds) + nfds++; + + while (nfds) { + r = poll(fds, nfds, 1024); + if (r == 0) { + /* TODO implement some timeout handling */ + continue; + } + if (r < 0) { + serrno = errno; + if (serrno == ENOMEM || serrno == EAGAIN) { continue; } - - continue; } - handle_request(t, linelen); + for (nfds_t i = 0; i < nfds; i++) { + if (fds[i].revents) { + cbs[i](fds[i].fd, fds[i].revents); + } + } } - if (ferror(stdin)) - err(1, "getline"); - return (0); } diff --git a/table_api.h b/table_api.h index 0fa97c9..dd7310b 100644 --- a/table_api.h +++ b/table_api.h @@ -21,6 +21,8 @@ #define DEPRECATED #endif +typedef void (*fd_callback)(int, short); + enum table_service { K_ALIAS = 0x001, /* returns struct expand */ K_DOMAIN = 0x002, /* returns struct destination */ -- 2.39.2
From f8cd9a0d8798047a99151ce0fbef0fb731ca3c78 Mon Sep 17 00:00:00 2001 From: Philipp Takacs <phil...@bureaucracy.de> Date: Sun, 9 Jun 2024 16:31:01 +0200 Subject: [PATCH 14/16] fixup! fixup! add error result function --- table_api.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/table_api.c b/table_api.c index 397c322..ef77258 100644 --- a/table_api.c +++ b/table_api.c @@ -292,13 +292,13 @@ table_api_error(const char *id, const char *error) } #ifdef errormassage - if (err && *err) { - puts(err); + if (error && *error) { + puts(error); } else { puts("unknown"); } #else - (void)err; + (void)error; puts(""); #endif if (fflush(stdout) == EOF) -- 2.39.2
From eea7727c898ac76372571a985935385929ae5e59 Mon Sep 17 00:00:00 2001 From: Philipp Takacs <phil...@bureaucracy.de> Date: Sun, 9 Jun 2024 16:37:26 +0200 Subject: [PATCH 15/16] fixup! switch to poll based api --- table_api.c | 44 +++++++++++++++++++++++++++++++++++++++++++- table_api.h | 3 +++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/table_api.c b/table_api.c index ef77258..469a8c8 100644 --- a/table_api.c +++ b/table_api.c @@ -488,6 +488,49 @@ table_api_fetch_result(const char *id, const char *buf) free(req); } +void +table_api_register_fd(int fd, short events, fd_callback cb) +{ + /* first fd is reservated for stdin */ + if (!nfds) + nfds++; + + if (nfds >= MAXFDS) + exit(1); + + fds[nfds].fd = fd; + fds[nfds].events = events; + cbs[nfds] = cb; + nfds++; +} + +void +table_api_replace_fd(int old, int new) +{ + for (nfds_t i = 1; i < nfds; i++) { + if (fds[i].fd != old) { + continue; + } + fds[i].fd = new; + } +} + +void +table_api_remove_fd(int fd) +{ + for (nfds_t i = 1; i < nfds; i++) { + if (fds[i].fd != fd) { + continue; + } + nfds--; + if (i+1 > nfds) { + break; + } + memmove(fds+i, fds+i+1, (nfds-i)*sizeof(*fds)); + memmove(cbs+i, cbs+i+1, (nfds-i)*sizeof(*cbs)); + } +} + static void handle_request(char *line, size_t linelen) { @@ -611,7 +654,6 @@ api_callback(int fd, short revents) size_t linelen; int serrno, ret; char *line, *t; - if (revents & (POLLERR|POLLNVAL)) { exit(1); diff --git a/table_api.h b/table_api.h index dd7310b..c21b5a5 100644 --- a/table_api.h +++ b/table_api.h @@ -53,3 +53,6 @@ void table_api_lookup_result(const char *, const char *); void table_api_lookup_finish(const char *); void table_api_fetch_result(const char *, const char *); const char *table_api_get_name(void); +void table_api_register_fd(int fd, short events, fd_callback cb); +void table_api_replace_fd(int old, int new); +void table_api_remove_fd(int fd); -- 2.39.2
From 6199916a1bcbf52f680c3ccd7683828fda93a338 Mon Sep 17 00:00:00 2001 From: Philipp Takacs <phil...@bureaucracy.de> Date: Tue, 9 Jul 2024 13:24:30 +0200 Subject: [PATCH 16/16] fixup! fixup! switch to poll based api --- table_api.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/table_api.c b/table_api.c index 469a8c8..2c39b53 100644 --- a/table_api.c +++ b/table_api.c @@ -21,6 +21,7 @@ #include <sys/tree.h> #include <err.h> +#include <fcntl.h> #include <limits.h> #include <poll.h> #include <stdbool.h> @@ -711,6 +712,7 @@ int table_api_dispatch(void) { int serrno, r; + int flags; dict_init(¶ms); dict_init(&requests); @@ -725,6 +727,9 @@ table_api_dispatch(void) if (!handler_async_fetch) table_api_on_fetch_async(fallback_fetch_handler); + flags = fcntl(STDIN_FILENO, F_GETFL, 0); + fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK); + fds[0].fd = STDIN_FILENO; fds[0].events = POLLIN; fds[0].revents = 0; -- 2.39.2