Skip to content

Instantly share code, notes, and snippets.

@SumiTomohiko
Last active May 21, 2020 13:46
Show Gist options
  • Save SumiTomohiko/ea34cd85c702bc04285f to your computer and use it in GitHub Desktop.
Save SumiTomohiko/ea34cd85c702bc04285f to your computer and use it in GitHub Desktop.
Simple daemon example using kqueue
/*
* This is public domain.
*/
#include <sys/types.h>
#include <sys/event.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <errno.h>
#include <libgen.h>
#include <netinet/in.h>
#include <signal.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
static void
die(const char *fmt, ...)
{
va_list ap;
int errnum;
char buf[8192], buf2[8192];
errnum = errno;
va_start(ap, fmt);
vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
snprintf(buf2, sizeof(buf2), "%s: %s", buf, strerror(errnum));
fputs(buf2, stderr);
syslog(LOG_ERR, "%s", buf2);
exit(1);
}
#define array_sizeof(a) (sizeof((a)) / sizeof((a)[0]))
#define PORT 4226
int
main(int argc, const char *argv[])
{
struct sockaddr_storage addr;
struct sockaddr_in *paddr;
struct kevent changelist[2], eventlist[2];
sigset_t set;
uintptr_t ident;
int fd, i, kq, level, nchanges, nev, nevents, optname, optval, sock;
u_short flags;
char buf[256];
strncpy(buf, argv[0], sizeof(buf));
openlog(basename(buf), LOG_PID, LOG_DAEMON);
sock = socket(PF_INET, SOCK_STREAM, 0);
if (sock == -1)
die("cannot socket(2)");
level = SOL_SOCKET;
optname = SO_REUSEADDR;
optval = 1;
if (setsockopt(sock, level, optname, &optval, sizeof(optval)) == -1)
die("cannot setsockopt(2)");
paddr = (struct sockaddr_in *)&addr;
paddr->sin_len = sizeof(*paddr);
paddr->sin_family = AF_INET;
paddr->sin_port = htons(PORT);
paddr->sin_addr.s_addr = INADDR_ANY;
if (bind(sock, (struct sockaddr *)paddr, paddr->sin_len) == -1)
die("cannot bind(2)");
if (listen(sock, 0) == -1)
die("cannot listen(2)");
if (daemon(1, 0) == -1)
die("cannot daemon(3)");
syslog(LOG_INFO, "started");
kq = kqueue();
if (kq == -1)
die("cannot kqueue(2)");
flags = EV_ADD | EV_ENABLE;
EV_SET(&changelist[0], sock, EVFILT_READ, flags, 0, 0, NULL);
EV_SET(&changelist[1], SIGTERM, EVFILT_SIGNAL, flags, 0, 0, NULL);
nchanges = array_sizeof(changelist);
if (kevent(kq, changelist, nchanges, NULL, 0, NULL) == -1)
die("cannot kevent(2)");
if (sigemptyset(&set) == -1)
die("cannot sigemptyset(3)");
if (sigaddset(&set, SIGTERM) == -1)
die("cannot sigaddset(3)");
if (sigprocmask(SIG_BLOCK, &set, NULL) == -1)
die("cannot sigprocmask(2)");
nevents = array_sizeof(eventlist);
while (0 < (nev = kevent(kq, NULL, 0, eventlist, nevents, NULL)))
for (i = 0; i < nev; i++)
switch (eventlist[i].filter) {
case EVFILT_READ:
if ((fd = accept(sock, NULL, 0)) == -1)
die("cannot accept(2)");
syslog(LOG_INFO, "connected");
if (close(fd) == -1)
die("cannot close(2)");
break;
case EVFILT_SIGNAL:
goto exit;
default:
break;
}
exit:
close(kq);
close(sock);
syslog(LOG_INFO, "exit");
closelog();
return (0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment