view req.c @ 6:8c408176d2b1

scid: past jobs are not listed for new workers
author David Demelier <markand@malikania.fr>
date Wed, 23 Jun 2021 11:44:30 +0200
parents 215c0c3b3609
children 3ef8128e244f
line wrap: on
line source

#include <sys/socket.h>
#include <sys/time.h>
#include <sys/un.h>
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "config.h"
#include "req.h"
#include "types.h"
#include "util.h"

static char path[PATH_MAX] = VARDIR "/run/sci.sock";

static int
attach(const char *path)
{
	struct sockaddr_un sun;
	struct timeval tv = { .tv_sec = 3 };
	int sock;

	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 ||
	    connect(sock, (const struct sockaddr *)&sun, sizeof (sun)) < 0) {
		close(sock);
		return -1;
	}

	return sock;
}

static struct req
exchange(const char *cmd, json_t *doc)
{
	char *json, *response, buf[BUFSIZ];
	struct req res = {0};
	int sock;
	ssize_t nr;
	FILE *fp;

	if ((sock = attach(path)) < 0)
		goto connect_err;

	json_object_set(doc, "cmd", json_string(cmd));
	json = json_dumps(doc, JSON_COMPACT);

	if (send(sock, json, strlen(json), MSG_NOSIGNAL) <= 0 ||
	    send(sock, "\r\n", 2, MSG_NOSIGNAL) <= 0)
		goto send_err;

	response = util_malloc(SCI_MSG_MAX);
	fp = util_fmemopen(response, SCI_MSG_MAX, "w");
	setbuf(fp, NULL);

	while ((nr = recv(sock, buf, sizeof (buf), MSG_NOSIGNAL)) > 0)
		if (fwrite(buf, 1, nr, fp) != (size_t)nr)
			goto io_err;

	if (!(res.msg = json_loads(response, 0, NULL)))
		errno = EILSEQ;
	else
		errno = 0;

	/* TODO: generic error handling */

io_err:
	fclose(fp);
	free(response);

send_err:
	close(sock);
	free(json);

connect_err:
	res.status = errno;
	json_decref(doc);

	return res;
}

void
req_set_path(const char *newpath)
{
	assert(newpath);

	strlcpy(path, newpath, sizeof (path));
}

struct req
req_job_add(const struct job *job)
{
	assert(job);

	return exchange("job-add", job_to(job, 1));
}

struct req
req_job_todo(struct job *jobs, size_t *jobsz, const char *worker)
{
	assert(jobs);
	assert(jobsz);
	assert(worker);

	struct req st;
	struct worker wk;

	/*
	 * Retrieve worker id first, we don't need JSON document to stay
	 * because we only refer to the id field.
	 */
	if ((st = req_worker_find(&wk, worker)).status)
		return st;

	req_finish(&st);

	if ((st = exchange("job-todo", json_pack("{si}", "worker_id", wk.id))).status)
		return st;

	if ((*jobsz = job_from(jobs, *jobsz, st.msg)) == (size_t)-1) {
		json_decref(st.msg);
		st.msg = NULL;
		st.status = errno;
	}

	return st;
}

struct req
req_jobresult_add(const struct jobresult *res)
{
	assert(res);

	return exchange("jobresult-add", jobresult_to(res, 1));
}

struct req
req_project_add(const struct project *p)
{
	assert(p);

	return exchange("project-add", project_to(p, 1));
}

struct req
req_project_find(struct project *p, const char *name)
{
	assert(p);
	assert(name);

	struct req st;

	if ((st = exchange("project-find", json_pack("{ss}", "name", name))).status)
		return st;

	if (project_from(p, 1, st.msg) < 0) {
		json_decref(st.msg);
		st.msg = NULL;
		st.status = errno;
	}

	return st;
}

struct req
req_project_find_id(struct project *p, int id)
{
	assert(p);

	struct req st;

	if ((st = exchange("project-find-id", json_pack("{si}", "id", id))).status)
		return st;

	if (project_from(p, 1, st.msg) < 0) {
		json_decref(st.msg);
		st.msg = NULL;
		st.status = errno;
	}

	return st;
}

struct req
req_project_list(struct project *projects, size_t *projectsz)
{
	assert(projects);
	assert(projectsz);

	struct req st;

	if ((st = exchange("project-list", json_object())).status)
		return st;

	if ((*projectsz = project_from(projects, *projectsz, st.msg)) == (size_t)-1) {
		json_decref(st.msg);
		st.msg = NULL;
		st.status = errno;
	}

	return st;
}

struct req
req_worker_add(const struct worker *w)
{
	assert(w);

	return exchange("worker-add", worker_to(w, 1));
}

struct req
req_worker_find(struct worker *wk, const char *name)
{
	assert(wk);
	assert(name);

	struct req st;

	if ((st = exchange("worker-find", json_pack("{ss}", "name", name))).status)
		return st;
	if (worker_from(wk, 1, st.msg) < 0) {
		json_decref(st.msg);
		st.msg = NULL;
		st.status = errno;
	}

	return st;
}

struct req
req_worker_find_id(struct worker *wk, int id)
{
	assert(wk);

	struct req st;

	if ((st = exchange("worker-find-id", json_pack("{si}", "id", id))).status)
		return st;
	if (worker_from(wk, 1, st.msg) < 0) {
		json_decref(st.msg);
		st.msg = NULL;
		st.status = errno;
	}

	return st;
}

struct req
req_worker_list(struct worker *wk, size_t *wksz)
{
	assert(wk);
	assert(wksz);

	struct req st;

	if ((st = exchange("worker-list", json_object())).status)
		return st;

	if ((*wksz = worker_from(wk, *wksz, st.msg)) == (size_t)-1) {
		json_decref(st.msg);
		st.msg = NULL;
		st.status = errno;
	}

	return st;
}

void
req_finish(struct req *st)
{
	if (st->msg)
		json_decref(st->msg);

	memset(st, 0, sizeof (*st));
}