view 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 source

#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;
}