X-Git-Url: https://git.distorted.org.uk/~mdw/tripe/blobdiff_plain/11ad66c29764521f87f0dd399a1e592147c7af36..HEAD:/server/tripe.c diff --git a/server/tripe.c b/server/tripe.c index 58bf8a18..e4e4e6a2 100644 --- a/server/tripe.c +++ b/server/tripe.c @@ -36,7 +36,11 @@ sel_state sel; static sel_timer it; #define T_INTERVAL MIN(1) -/*----- Main code ---------------------------------------------------------*/ +static unsigned iv_nreasons = 0; +static struct timeval iv_next = { 0, 0 }; +static int lpdone = 0; + +/*----- The interval timer ------------------------------------------------*/ /* --- @interval@ --- * * @@ -50,279 +54,110 @@ static sel_timer it; static void interval(struct timeval *tv, void *v) { - struct timeval tvv; T( trace(T_PEER, "peer: interval timer"); ) + iv_next = *tv; rand_seed(RAND_GLOBAL, MAXHASHSZ); p_interval(); - tvv = *tv; - tvv.tv_sec += T_INTERVAL; - sel_addtimer(&sel, &it, &tvv, interval, v); + iv_next.tv_sec += T_INTERVAL; + sel_addtimer(&sel, &it, &iv_next, interval, v); } -/* --- @main@ --- * +/* --- @iv_addreason@ --- * * - * Arguments: @int argc@ = number of command line arguments - * @char *argv[]@ = vector of arguments + * Arguments: --- * - * Returns: Zero if OK, nonzero on error. + * Returns: --- * - * Use: Main program. Provides a simple VPN. + * Use: Adds an `interval timer reason'; if there are no others, the + * interval timer is engaged. */ -static void usage(FILE *fp) +void iv_addreason(void) { - pquis(fp, "Usage: $ [-DF] [-d DIR] [-b ADDR] [-p PORT] [-n TUNNEL]\n\ - [-U USER] [-G GROUP] [-a SOCKET] [-m MODE] [-T TRACE-OPTS]\n\ - [-k PRIV-KEYRING] [-K PUB-KEYRING] [-t KEY-TAG]\n"); + struct timeval tv; + + if (!iv_nreasons) { + gettimeofday(&tv, 0); + if (TV_CMP(&tv, >=, &iv_next)) interval(&tv, 0); + else sel_addtimer(&sel, &it, &iv_next, interval, 0); + } + iv_nreasons++; } -static void version(FILE *fp) { pquis(fp, "$, version " VERSION "\n"); } +/* --- @iv_rmreason@ --- * + * + * Arguments: --- + * + * Returns: --- + * + * Use: Removes an interval timer reason; if there are none left, the + * interval timer is disengaged. + */ -static void help(FILE *fp) +void iv_rmreason(void) { - version(fp); - fputc('\n', fp); - usage(fp); - fputs("\n\ -Options:\n\ -\n\ --h, --help Display this help text.\n\ --v, --version Display version number.\n\ --u, --usage Display pointless usage message.\n\ - --tunnels Display IP tunnel drivers and exit.\n\ -\n\ --D, --daemon Run in the background.\n\ --F, --foreground Quit when stdin reports end-of-file.\n\ --d, --directory=DIR Switch to directory DIR [default " CONFIGDIR "].\n\ --b, --bind-address=ADDR Bind UDP socket to this IP ADDR.\n\ --p, --port=PORT Select UDP port to listen to " - "[default " STR(TRIPE_PORT) "].\n\ --n, --tunnel=TUNNEL Seelect default tunnel driver.\n\ --U, --setuid=USER Set uid to USER after initialization.\n\ --G, --setgid=GROUP Set gid to GROUP after initialization.\n\ --k, --priv-keyring=FILE Get private key from FILE.\n\ --K, --pub-keyring=FILE Get public keys from FILE.\n\ --t, --tag=KEYTAG Use private key labelled TAG.\n\ --a, --admin-socket=FILE Use FILE as the adminstration socket.\n\ --m, --admin-perms=MODE Permissions to set on admin socket [default 600].\n\ -" T( "\ --T, --trace=OPTIONS Turn on tracing options.\n\ -" ) "\ -", fp); + assert(iv_nreasons); iv_nreasons--; + if (!iv_nreasons) sel_rmtimer(&it); } -int main(int argc, char *argv[]) -{ - const char *kr_priv = "keyring", *kr_pub = "keyring.pub"; - const char *tag_priv = 0; - const char *csock = SOCKETDIR "/tripesock"; - int csockmode = 0600; - const char *dir = CONFIGDIR; - const char *p; - unsigned port = TRIPE_PORT; - struct in_addr baddr = { INADDR_ANY }; - unsigned f = 0; - int i; - int selerr = 0; - unsigned af; - struct timeval tv; - uid_t u = -1; - gid_t g = -1; - -#define f_bogus 1u -#define f_daemon 2u -#define f_foreground 4u +/*----- The main loop -----------------------------------------------------*/ - ego(argv[0]); - T( trace_on(stderr, 0); ) - - if ((p = getenv("TRIPEDIR")) != 0) - dir = p; - if ((p = getenv("TRIPESOCK")) != 0) - csock = p; - tun_default = tunnels[0]; - - for (;;) { - static const struct option opts[] = { - { "help", 0, 0, 'h' }, - { "version", 0, 0, 'v' }, - { "usage", 0, 0, 'u' }, - { "tunnels", 0, 0, '0' }, - - { "daemon", 0, 0, 'D' }, - { "foreground", 0, 0, 'F' }, - { "uid", OPTF_ARGREQ, 0, 'U' }, - { "setuid", OPTF_ARGREQ, 0, 'U' }, - { "gid", OPTF_ARGREQ, 0, 'G' }, - { "setgid", OPTF_ARGREQ, 0, 'G' }, - { "bind-address", OPTF_ARGREQ, 0, 'b' }, - { "tunnel", OPTF_ARGREQ, 0, 'n' }, - { "port", OPTF_ARGREQ, 0, 'p' }, - { "directory", OPTF_ARGREQ, 0, 'd' }, - { "priv-keyring", OPTF_ARGREQ, 0, 'k' }, - { "pub-keyring", OPTF_ARGREQ, 0, 'K' }, - { "tag", OPTF_ARGREQ, 0, 't' }, - { "admin-socket", OPTF_ARGREQ, 0, 'a' }, - { "admin-perms", OPTF_ARGREQ, 0, 'm' }, -#ifndef NTRACE - { "trace", OPTF_ARGREQ, 0, 'T' }, -#endif - - { 0, 0, 0, 0 } - }; - - i = mdwopt(argc, argv, "hvuDFU:G:b:n:p:d:k:K:t:a:m:" T("T:"), - opts, 0, 0, 0); - if (i < 0) - break; - switch (i) { - case 'h': - help(stdout); - exit(0); - case 'v': - version(stdout); - exit(0); - case 'u': - usage(stdout); - exit(0); - - case 'D': - f |= f_daemon; - break; - case 'U': - u = u_getuser(optarg, &g); - break; - case 'G': - g = u_getgroup(optarg); - break; - case 'F': - f |= f_foreground; - break; +/* --- @lp_init@ --- * + * + * Arguments: --- + * + * Returns: --- + * + * Use: Initializes the main loop. Most importantly, this sets up + * the select multiplexor that everything else hooks onto. + */ - case 'b': { - struct hostent *h = gethostbyname(optarg); - if (!h) - die(EXIT_FAILURE, "unknown host name `%s'", optarg); - memcpy(&baddr, h->h_addr, sizeof(struct in_addr)); - } break; - case 'p': { - char *p; - unsigned long i = strtoul(optarg, &p, 0); - if (*p) { - struct servent *s = getservbyname(optarg, "udp"); - if (!s) - die(EXIT_FAILURE, "unknown service name `%s'", optarg); - i = ntohs(s->s_port); - } - if (i >= 65536) - die(EXIT_FAILURE, "bad port number %lu", i); - port = i; - } break; - case 'n': { - int i; - for (i = 0;; i++) { - if (!tunnels[i]) - die(EXIT_FAILURE, "unknown tunnel `%s'", optarg); - if (mystrieq(optarg, tunnels[i]->name)) - break; - } - tun_default = tunnels[i]; - } break; - case 'd': - dir = optarg; - break; - case 'k': - kr_priv = optarg; - break; - case 'K': - kr_pub = optarg; - break; - case 'a': - csock = optarg; - break; - case 'm': { - char *p; - csockmode = strtol(optarg, &p, 8); - if (*p) die(EXIT_FAILURE, "bad permissions: `%s'", optarg); - } break; - case 't': - tag_priv = optarg; - break; -#ifndef NTRACE - case 'T': - tr_flags = traceopt(tr_opts, optarg, tr_flags, 0); - trace_level(tr_flags); - break; -#endif - case '0': { - int i; - for (i = 0; tunnels[i]; i++) - puts(tunnels[i]->name); - exit(0); - } break; - default: - f |= f_bogus; - break; - } - } +void lp_init(void) +{ + gettimeofday(&iv_next, 0); iv_next.tv_sec += T_INTERVAL; + signal(SIGPIPE, SIG_IGN); + sel_init(&sel); + sig_init(&sel); +} - if (optind < argc || (f & f_bogus)) { - usage(stderr); - exit(EXIT_FAILURE); - } - if (!(~f & (f_daemon | f_foreground))) - die(EXIT_FAILURE, "foreground operation for a daemon is silly"); +/* --- @lp_end@ --- * + * + * Arguments: --- + * + * Returns: --- + * + * Use: Requests an exit from the main loop. + */ - if (chdir(dir)) { - die(EXIT_FAILURE, "can't set current directory to `%s': %s", - dir, strerror(errno)); - } +void lp_end(void) { lpdone = 1; } - sel_init(&sel); - sig_init(&sel); - rand_noisesrc(RAND_GLOBAL, &noise_source); - rand_seed(RAND_GLOBAL, MAXHASHSZ); - signal(SIGPIPE, SIG_IGN); - for (i = 0; tunnels[i]; i++) - tunnels[i]->init(); - p_init(baddr, port); - if (!(f & f_daemon)) { - af = AF_WARN; -#ifndef NTRACE - af |= AF_TRACE; -#endif - if (f & f_foreground) - af |= AF_FOREGROUND; - a_create(STDIN_FILENO, STDOUT_FILENO, af); - } - ps_split(f & f_daemon); - a_init(csock, u, g, csockmode); - u_setugid(u, g); - km_init(kr_priv, kr_pub, tag_priv); - if (f & f_daemon) { - if (daemonize()) - die(EXIT_FAILURE, "couldn't become a daemon: %s", strerror(errno)); - a_daemon(); - } +/* --- @lp_run@ --- * + * + * Arguments: --- + * + * Returns: Zero on successful termination; @-1@ if things went wrong. + * + * Use: Cranks the main loop until it should be cranked no more. + */ - tv.tv_sec = time(0) + T_INTERVAL; - tv.tv_usec = 0; - sel_addtimer(&sel, &it, &tv, interval, 0); +int lp_run(void) +{ + int nerr = 0; for (;;) { a_preselect(); - if (!sel_select(&sel)) - selerr = 0; + if (lpdone) break; + if (!sel_select(&sel)) nerr = 0; else if (errno != EINTR && errno != EAGAIN) { a_warn("SERVER", "select-error", "?ERRNO", A_END); - selerr++; - if (selerr > 8) { + nerr++; + if (nerr > 8) { a_warn("ABORT", "repeated-select-errors", A_END); abort(); } } } - + lpdone = 0; return (0); }