Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 91 additions & 26 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@
#include <errno.h>
#include <grp.h>
#include <sched.h>
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/event.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/un.h>
#include <unistd.h>
Expand All @@ -19,6 +22,8 @@
#error "Requires macOS 10.15 or later"
#endif

#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))

bool debug = false;

static const char *vmnet_strerror(vmnet_return_t v) {
Expand Down Expand Up @@ -280,12 +285,6 @@ static interface_ref start(struct state *state, struct cli_options *cliopt) {
return iface;
}

static sigjmp_buf jmpbuf;
static void signalhandler(int signal) {
INFOF("Received signal: %s", strsignal(signal));
siglongjmp(jmpbuf, 1);
}

static void stop(struct state *state, interface_ref iface) {
if (iface == NULL) {
return;
Expand Down Expand Up @@ -391,11 +390,55 @@ static int create_pidfile(const char *pidfile)
return fd;
}

static int setup_signals(int kq)
{
struct kevent changes[] = {
{ .ident=SIGHUP, .filter=EVFILT_SIGNAL, .flags=EV_ADD },
{ .ident=SIGINT, .filter=EVFILT_SIGNAL, .flags=EV_ADD },
{ .ident=SIGTERM, .filter=EVFILT_SIGNAL, .flags=EV_ADD },
};

// Block signals we want to receive via kqueue.
sigset_t mask;
sigemptyset(&mask);
for (size_t i = 0; i < ARRAY_SIZE(changes); i++) {
sigaddset(&mask, changes[i].ident);
}
if (sigprocmask(SIG_BLOCK, &mask, NULL) != 0) {
ERRORN("sigprocmask");
return -1;
}

// We will receive EPIPE on the socket.
signal(SIGPIPE, SIG_IGN);

if (kevent(kq, changes, ARRAY_SIZE(changes), NULL, 0, NULL) != 0) {
ERRORN("kevent");
return -1;
}
return 0;
}

static int add_listen_fd(int kq, int fd)
{
struct kevent changes[] = {
{ .ident=fd, .filter=EVFILT_READ, .flags=EV_ADD },
};
if (kevent(kq, changes, ARRAY_SIZE(changes), NULL, 0, NULL) != 0) {
ERRORN("kevent");
return -1;
}
return 0;
}

static void on_accept(struct state *state, int accept_fd, interface_ref iface);

int main(int argc, char *argv[]) {
debug = getenv("DEBUG") != NULL;
int rc = 1, listen_fd = -1;
int rc = 1;
int listen_fd = -1;
int pidfile_fd = -1;
int kq = -1;
__block interface_ref iface = NULL;

struct state state = {0};
Expand All @@ -409,7 +452,18 @@ int main(int argc, char *argv[]) {
WARN("Seems running with SETUID. This is insecure and highly discouraged: See README.md");
}

int pidfile_fd = -1;
kq = kqueue();
if (kq == -1) {
ERRORN("kqueue");
goto done;
}

// Setup signals beofre creating the pidfile so the pidfile to ensure removal
// when terminating by signal.
if (setup_signals(kq)) {
goto done;
}

if (cliopt->pidfile != NULL) {
pidfile_fd = create_pidfile(cliopt->pidfile);
if (pidfile_fd == -1) {
Expand All @@ -425,16 +479,6 @@ int main(int argc, char *argv[]) {
goto done;
}

if (sigsetjmp(jmpbuf, 1) != 0) {
goto done;
}
signal(SIGHUP, signalhandler);
signal(SIGINT, signalhandler);
signal(SIGTERM, signalhandler);

// We will receive EPIPE on the socket.
signal(SIGPIPE, SIG_IGN);

state.sem = dispatch_semaphore_create(1);

// Queue for vm connections, allowing processing vms requests in parallel.
Expand All @@ -451,16 +495,34 @@ int main(int argc, char *argv[]) {
goto done;
}

if (add_listen_fd(kq, listen_fd)) {
goto done;
}

while (1) {
int accept_fd = accept(listen_fd, NULL, NULL);
if (accept_fd < 0) {
ERRORN("accept");
struct kevent events[1];
int n = kevent(kq, NULL, 0, events, 1, NULL);
if (n < 0) {
ERRORN("kevent");
goto done;
}
struct state *state_p = &state;
dispatch_async(state.vms_queue, ^{
on_accept(state_p, accept_fd, iface);
});

if (events[0].filter == EVFILT_SIGNAL) {
INFOF("Received signal %s", strsignal(events[0].ident));
break;
}

if (events[0].filter == EVFILT_READ) {
int accept_fd = accept(listen_fd, NULL, NULL);
if (accept_fd < 0) {
ERRORN("accept");
goto done;
}
struct state *state_p = &state;
dispatch_async(state.vms_queue, ^{
on_accept(state_p, accept_fd, iface);
});
}
}
rc = 0;
done:
Expand All @@ -479,6 +541,9 @@ int main(int argc, char *argv[]) {
dispatch_release(state.vms_queue);
if (state.host_queue != NULL)
dispatch_release(state.host_queue);
if (kq != -1) {
close(kq);
}
cli_options_destroy(cliopt);
return rc;
}
Expand Down