#include #include #include #include #include #include #include #include "tunnel.h" #include "macro.h" #include "utils.h" static time_t since; static void tunnel_daemon_atexit(void) { unlink(TUNNEL_SOCK_PATH); } static void sighandler(int signo __unused) { exit(EXIT_FAILURE); } static char **parse_args(char *buf, int len) { char **args = NULL; while (len) { addv(&args, buf); char *p = memchr(buf, '\0', len); if (!p) break; len -= p - buf + 1; buf = p + 1; } return args; } static void echo(FILE *fp, char **args) { for (int n = 0; args[n]; n++) fprintf(fp, "%s%s", n ? " " : "", args[n]); } static void tunnel_daemon_loop(int sock) { bool alive = true; while (alive) { char msg[1024]; int len; int fd = accept(sock, NULL, NULL); if (fd < 0) { warn("accept"); continue; } len = read(fd, msg, sizeof(msg) - 1); if (len < 0) { warn("read"); close(fd); continue; } if (! len) { close(fd); continue; } msg[len] = '\0'; char **args = parse_args(msg, len); let (fp, fdopen(fd, "w"), fclose) { char *cmd = *args; if (strequal(cmd, "echo")) echo(fp, args + 1); else if (strequal(cmd, "hello")) fprintf(fp, "hello from %d", getpid()); else if (strequal(cmd, "alive")) fprintf(fp, "since %s", ctime(&since)); else if (strequal(cmd, "stop")) { fprintf(fp, "ok"); alive = false; } else fprintf(fp, "what do you want?"); } free(args); } } bool tunnel_daemon(int sock) { switch (fork()) { case -1: warn("fork"); return false; case 0: break; default: return true; } if (setsid() < 0) err(EXIT_FAILURE, "setsid"); chdir("/"); struct sigaction sa = { .sa_handler = sighandler }; sigaction(SIGTERM, &sa, NULL); sigaction(SIGINT, &sa, NULL); #if 0 int fd = open("/dev/null", O_RDWR); if (fd < 0) err(EXIT_FAILURE, "open /dev/null"); dup2(fd, STDIN_FILENO); dup2(fd, STDOUT_FILENO); dup2(fd, STDERR_FILENO); if (fd > 2) close(fd); #endif time(&since); atexit(tunnel_daemon_atexit); tunnel_daemon_loop(sock); exit(EXIT_SUCCESS); return true; }