Hi

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.

Philipp
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 1/9] 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, &params,
+			    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, &params, 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, &params, 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(&params);
 
@@ -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, &params,
-				    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, &params, 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, &params, 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 2/9] 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 3/9] 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(&params);
+	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 4/9] 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, &params, 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, &params, 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 5/9] 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, &params, 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, &params, 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(&params);
 	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 6/9] 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, &params, 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, &params,
-			    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 7/9] 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 8/9] 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 9/9] 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

Reply via email to