diff req.c @ 0:f1de39079243

misc: initial import
author David Demelier <markand@malikania.fr>
date Mon, 07 Jun 2021 09:41:37 +0200
parents
children 5afdb14df924
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/req.c	Mon Jun 07 09:41:37 2021 +0200
@@ -0,0 +1,180 @@
+#define _BSD_SOURCE
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/un.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "req.h"
+#include "project.h"
+#include "worker.h"
+
+static int sock;
+
+static struct req
+ask(const char *fmt, ...)
+{
+	assert(fmt);
+
+	struct req res = {0};
+	char buf[1024], *p;
+	va_list ap;
+	ssize_t bufsz = 0, nr;
+
+	va_start(ap, fmt);
+	vsnprintf(buf, sizeof (buf), fmt, ap);
+	va_end(ap);
+
+	if (strlcat(buf, "\r\n\r\n", sizeof (buf)) >= sizeof (buf)) {
+		res.status = EMSGSIZE;
+		return res;
+	}
+
+	if (send(sock, buf, strlen(buf), MSG_NOSIGNAL) < 0) {
+		res.status = errno;
+		return res;
+	}
+
+	while ((nr = recv(sock, buf + bufsz, sizeof (buf) - bufsz, 0)) > 0) {
+		bufsz += nr;
+
+		if ((size_t)bufsz >= sizeof (buf)) {
+			bufsz = 0;
+			res.status = EMSGSIZE;
+			break;
+		}
+	}
+
+	buf[bufsz] = '\0';
+
+	/* Remove final '\r\n\r\n' */
+	if ((p = strstr(buf, "\r\n\r\n")))
+		*p = '\0';
+
+	/* Check and remove status. */
+	if (strncmp(buf, "ERR", 3) == 0)
+		res.status = -1;
+	if ((p = strchr(buf, '\n')))
+		++p;
+	else
+		p = buf;
+
+	strlcat(res.msg, p, sizeof (res.msg));
+
+	return res;
+}
+
+int
+req_connect(const char *path)
+{
+	assert(path);
+
+	struct sockaddr_un sun;
+	struct timeval tv = { .tv_sec = 3 };
+
+	if ((sock = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0)
+		return -1;
+
+	sun.sun_family = PF_LOCAL;
+	strlcpy(sun.sun_path, path, sizeof (sun.sun_path));
+
+	if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof (tv)) < 0 ||
+	    setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof (tv)) < 0)
+		return -1;
+	if (connect(sock, (const struct sockaddr *)&sun, sizeof (sun)) < 0)
+		return -1;
+
+	return 0;
+}
+
+struct req
+req_job_queue(const char *project, const char *tag)
+{
+	assert(project);
+	assert(tag);
+
+	return ask("job-queue %s|%s", project, tag);
+}
+
+struct req
+req_project_add(const struct project *p)
+{
+	assert(p);
+
+	return ask("project-add %s|%s|%s|%s", p->name, p->desc, p->url, p->script);
+}
+
+struct req
+req_project_list(struct project *pc, size_t *pcsz)
+{
+	assert(pc);
+	assert(pcsz);
+
+	struct req req;
+	char fmt[128], *token, *p = req.msg;
+	size_t tot = 0;
+
+	if ((req = ask("project-list")).status)
+		return req;
+
+	snprintf(fmt, sizeof (fmt), "%%%zu[^|]|%%%zu[^|]|%%%zu[^|]|%%%zu[^\n]\n",
+	    sizeof (pc->name), sizeof (pc->desc), sizeof (pc->url), sizeof (pc->script));
+
+	while ((token = strtok_r(p, "\n", &p)) && tot < *pcsz) {
+		if (sscanf(token, fmt, pc->name, pc->desc, pc->url, pc->script) == 4) {
+			++pc;
+			++tot;
+		}
+	}
+
+	*pcsz = tot;
+
+	return req;
+}
+
+struct req
+req_worker_add(const struct worker *w)
+{
+	assert(w);
+
+	return ask("worker-add %s|%s", w->name, w->desc);
+}
+
+struct req
+req_worker_list(struct worker *wk, size_t *wksz)
+{
+	assert(wk);
+	assert(wksz);
+
+	struct req req;
+	char fmt[128], *token, *p = req.msg;
+	size_t tot = 0;
+
+	if ((req = ask("worker-list")).status)
+		return req;
+
+	snprintf(fmt, sizeof (fmt), "%%%zu[^|]|%%%zu[^\n]\n",
+	    sizeof (wk->name), sizeof (wk->desc));
+
+	while ((token = strtok_r(p, "\n", &p)) && tot < *wksz) {
+		if (sscanf(token, fmt, wk->name, wk->desc) == 2) {
+			wk++;
+			tot++;
+		}
+	}
+
+	*wksz = tot;
+
+	return req;
+}
+
+void
+req_finish(void)
+{
+	close(sock);
+	sock = 0;
+}