commit - 6490a1e911df9c4f629efb6a0c6a24ab9dc392dc
commit + 202d187071957eec318c523e66455e0f804ff869
blob - ac01cf603e2090b0c97aa789ce265be2acd8eda7
blob + 815ba754b8247de6076160659c86feb748fab436
--- gotd/gotd.c
+++ gotd/gotd.c
disconnect(client);
}
+ if (proc == gotd.notify_proc)
+ gotd.notify_proc = NULL;
+
evtimer_del(&proc->tmo);
if (proc->iev.ibuf.fd != -1) {
*/
log_warnx("notify child process (pid %d) closed its imsg pipe "
"unexpectedly", proc->pid);
- gotd.notify_proc = NULL;
- imsg_clear(&iev->ibuf);
- free(proc);
+ proc_done(proc);
}
}
}
static const struct got_error *
-connect_notifier(struct gotd_client *client)
+connect_notifier_and_session(struct gotd_client *client)
{
const struct got_error *err = NULL;
- int s;
+ struct gotd_imsgev *session_iev = &client->session->iev;
+ int pipe[2];
- if (gotd.notify_proc) {
- s = dup(gotd.notify_proc->pipe[0]);
- if (s == -1)
- return got_error_from_errno("dup");
- } else
- s = -1;
+ if (gotd.notify_proc == NULL)
+ return NULL;
- if (gotd_imsg_compose_event(&client->session->iev,
- GOTD_IMSG_CONNECT_NOTIFIER, PROC_GOTD, s, NULL, 0) == -1) {
+ if (socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK,
+ PF_UNSPEC, pipe) == -1)
+ return got_error_from_errno("socketpair");
+
+ /* Pass notifier pipe to session . */
+ if (gotd_imsg_compose_event(session_iev, GOTD_IMSG_CONNECT_NOTIFIER,
+ PROC_GOTD, pipe[0], NULL, 0) == -1) {
err = got_error_from_errno("imsg compose CONNECT_NOTIFIER");
- if (s != -1)
- close(s);
+ close(pipe[0]);
+ close(pipe[1]);
return err;
}
+ /* Pass session pipe to notifier. */
+ if (gotd_imsg_compose_event(&gotd.notify_proc->iev,
+ GOTD_IMSG_CONNECT_SESSION, PROC_GOTD, pipe[1], NULL, 0) == -1) {
+ err = got_error_from_errno("imsg compose CONNECT_SESSION");
+ close(pipe[1]);
+ return err;
+ }
+
return NULL;
}
err = connect_session(client);
if (err)
break;
- err = connect_notifier(client);
+ err = connect_notifier_and_session(client);
if (err)
break;
err = connect_repo_child(client, proc);
proc->iev.handler = gotd_dispatch_notifier;
proc->iev.events = EV_READ;
proc->iev.handler_arg = NULL;
+ event_set(&proc->iev.ev, proc->iev.ibuf.fd, EV_READ,
+ gotd_dispatch_notifier, &proc->iev);
gotd.notify_proc = proc;
}
exit(0);
case PROC_NOTIFY:
#ifndef PROFILE
- if (pledge("stdio proc exec unveil", NULL) == -1)
+ if (pledge("stdio proc exec recvfd unveil", NULL) == -1)
err(1, "pledge");
#endif
/*
evtimer_set(&gotd.listen_proc->tmo, kill_proc_timeout,
gotd.listen_proc);
- evtimer_set(&gotd.notify_proc->tmo, kill_proc_timeout,
- gotd.notify_proc);
+ if (gotd.notify_proc) {
+ evtimer_set(&gotd.notify_proc->tmo, kill_proc_timeout,
+ gotd.notify_proc);
+ }
apply_unveil_selfexec();
signal_add(&evsigchld, NULL);
gotd_imsg_event_add(&gotd.listen_proc->iev);
+ if (gotd.notify_proc)
+ gotd_imsg_event_add(&gotd.notify_proc->iev);
event_dispatch();
blob - 97b77d29898f9e0859f385d519bf8e52600928f0
blob + 52cfe7948d93903861aec5c5f4f85960643c6444
--- gotd/gotd.h
+++ gotd/gotd.h
/* Notify child process. */
GOTD_IMSG_CONNECT_NOTIFIER,
+ GOTD_IMSG_CONNECT_SESSION,
GOTD_IMSG_NOTIFY,
};
blob - d8541cd4c711e5330e5a012fabb0dcc19ef71550
blob + 63b435eac961cc3e4ec6d6960946eedd84176f65
--- gotd/notify.c
+++ gotd/notify.c
#include <errno.h>
#include <event.h>
+#include <siphash.h>
#include <limits.h>
#include <sha1.h>
#include <sha2.h>
#include "log.h"
#include "notify.h"
+#ifndef nitems
+#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
+#endif
+
static struct gotd_notify {
pid_t pid;
const char *title;
const char *default_sender;
} gotd_notify;
-void gotd_notify_sighdlr(int sig, short event, void *arg);
+struct gotd_notify_session {
+ STAILQ_ENTRY(gotd_notify_session) entry;
+ uint32_t id;
+ struct gotd_imsgev iev;
+};
+STAILQ_HEAD(gotd_notify_sessions, gotd_notify_session);
+
+static struct gotd_notify_sessions gotd_notify_sessions[GOTD_CLIENT_TABLE_SIZE];
+static SIPHASH_KEY sessions_hash_key;
+
static void gotd_notify_shutdown(void);
-void
+static uint64_t
+session_hash(uint32_t session_id)
+{
+ return SipHash24(&sessions_hash_key, &session_id, sizeof(session_id));
+}
+
+static void
+add_session(struct gotd_notify_session *session)
+{
+ uint64_t slot;
+
+ slot = session_hash(session->id) % nitems(gotd_notify_sessions);
+ STAILQ_INSERT_HEAD(&gotd_notify_sessions[slot], session, entry);
+}
+
+static struct gotd_notify_session *
+find_session(uint32_t session_id)
+{
+ uint64_t slot;
+ struct gotd_notify_session *s;
+
+ slot = session_hash(session_id) % nitems(gotd_notify_sessions);
+ STAILQ_FOREACH(s, &gotd_notify_sessions[slot], entry) {
+ if (s->id == session_id)
+ return s;
+ }
+
+ return NULL;
+}
+
+static struct gotd_notify_session *
+find_session_by_fd(int fd)
+{
+ uint64_t slot;
+ struct gotd_notify_session *s;
+
+ for (slot = 0; slot < nitems(gotd_notify_sessions); slot++) {
+ STAILQ_FOREACH(s, &gotd_notify_sessions[slot], entry) {
+ if (s->iev.ibuf.fd == fd)
+ return s;
+ }
+
+ }
+
+ return NULL;
+}
+
+
+static void
+remove_session(struct gotd_notify_session *session)
+{
+ uint64_t slot;
+
+ slot = session_hash(session->id) % nitems(gotd_notify_sessions);
+ STAILQ_REMOVE(&gotd_notify_sessions[slot], session,
+ gotd_notify_session, entry);
+ free(session);
+}
+
+static uint32_t
+get_session_id(void)
+{
+ int duplicate = 0;
+ uint32_t id;
+
+ do {
+ id = arc4random();
+ duplicate = (find_session(id) != NULL);
+ } while (duplicate || id == 0);
+
+ return id;
+}
+
+static void
gotd_notify_sighdlr(int sig, short event, void *arg)
{
/*
}
static void
-notify_dispatch(int fd, short event, void *arg)
+notify_dispatch_session(int fd, short event, void *arg)
{
struct gotd_imsgev *iev = arg;
struct imsgbuf *ibuf = &iev->ibuf;
switch (imsg.hdr.type) {
case GOTD_IMSG_NOTIFY:
err = send_notifications(&imsg);
- if (err)
- break;
+ break;
+ default:
+ log_debug("unexpected imsg %d", imsg.hdr.type);
+ break;
+ }
+ imsg_free(&imsg);
+
+ if (err)
+ log_warnx("%s: %s", __func__, err->msg);
+ }
+done:
+ if (!shut) {
+ gotd_imsg_event_add(iev);
+ } else {
+ struct gotd_notify_session *session;
+
+ /* This pipe is dead. Remove its event handler */
+ event_del(&iev->ev);
+ imsg_clear(&iev->ibuf);
+
+ session = find_session_by_fd(fd);
+ if (session)
+ remove_session(session);
+ }
+}
+
+static const struct got_error *
+recv_session(struct imsg *imsg)
+{
+ struct gotd_notify_session *session;
+ size_t datalen;
+
+ datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
+ if (datalen != 0)
+ return got_error(GOT_ERR_PRIVSEP_LEN);
+
+ if (imsg->fd == -1)
+ return got_error(GOT_ERR_PRIVSEP_NO_FD);
+
+ session = calloc(1, sizeof(*session));
+ if (session == NULL)
+ return got_error_from_errno("calloc");
+
+ session->id = get_session_id();
+ imsg_init(&session->iev.ibuf, imsg->fd);
+ session->iev.handler = notify_dispatch_session;
+ session->iev.events = EV_READ;
+ session->iev.handler_arg = NULL;
+ event_set(&session->iev.ev, session->iev.ibuf.fd, EV_READ,
+ notify_dispatch_session, &session->iev);
+ gotd_imsg_event_add(&session->iev);
+ add_session(session);
+
+ return NULL;
+}
+
+static void
+notify_dispatch(int fd, short event, void *arg)
+{
+ struct gotd_imsgev *iev = arg;
+ struct imsgbuf *ibuf = &iev->ibuf;
+ ssize_t n;
+ int shut = 0;
+ struct imsg imsg;
+
+ if (event & EV_READ) {
+ if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
+ fatal("imsg_read error");
+ if (n == 0) {
+ /* Connection closed. */
+ shut = 1;
+ goto done;
+ }
+ }
+
+ if (event & EV_WRITE) {
+ n = msgbuf_write(&ibuf->w);
+ if (n == -1 && errno != EAGAIN)
+ fatal("msgbuf_write");
+ if (n == 0) {
+ /* Connection closed. */
+ shut = 1;
+ goto done;
+ }
+ }
+
+ for (;;) {
+ const struct got_error *err = NULL;
+
+ if ((n = imsg_get(ibuf, &imsg)) == -1)
+ fatal("%s: imsg_get error", __func__);
+ if (n == 0) /* No more messages. */
+ break;
+
+ switch (imsg.hdr.type) {
+ case GOTD_IMSG_CONNECT_SESSION:
+ err = recv_session(&imsg);
+ break;
default:
log_debug("unexpected imsg %d", imsg.hdr.type);
break;
const struct got_error *err = NULL;
struct event evsigint, evsigterm, evsighup, evsigusr1;
+ arc4random_buf(&sessions_hash_key, sizeof(sessions_hash_key));
+
gotd_notify.title = title;
gotd_notify.repos = repos;
gotd_notify.default_sender = default_sender;
gotd_notify.parent_iev.handler_arg = NULL;
event_set(&gotd_notify.parent_iev.ev, gotd_notify.parent_iev.ibuf.fd,
EV_READ, notify_dispatch, &gotd_notify.parent_iev);
+ gotd_imsg_event_add(&gotd_notify.parent_iev);
event_dispatch();