1*c0dc99f6Sreyk /* $OpenBSD: hce.c,v 1.46 2008/12/05 16:37:55 reyk Exp $ */ 2feb9ff76Sreyk 3feb9ff76Sreyk /* 436f5dc5eSpyr * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org> 5feb9ff76Sreyk * 6feb9ff76Sreyk * Permission to use, copy, modify, and distribute this software for any 7feb9ff76Sreyk * purpose with or without fee is hereby granted, provided that the above 8feb9ff76Sreyk * copyright notice and this permission notice appear in all copies. 9feb9ff76Sreyk * 10feb9ff76Sreyk * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11feb9ff76Sreyk * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12feb9ff76Sreyk * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13feb9ff76Sreyk * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14feb9ff76Sreyk * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15feb9ff76Sreyk * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16feb9ff76Sreyk * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17feb9ff76Sreyk */ 18feb9ff76Sreyk 19feb9ff76Sreyk #include <sys/param.h> 200ca734d7Sreyk #include <sys/queue.h> 21feb9ff76Sreyk #include <sys/time.h> 22feb9ff76Sreyk #include <sys/stat.h> 23feb9ff76Sreyk #include <sys/socket.h> 24feb9ff76Sreyk #include <sys/un.h> 250ca734d7Sreyk 260ca734d7Sreyk #include <net/if.h> 27feb9ff76Sreyk #include <netinet/in_systm.h> 28feb9ff76Sreyk #include <netinet/in.h> 29feb9ff76Sreyk #include <netinet/ip.h> 300ca734d7Sreyk 31feb9ff76Sreyk #include <errno.h> 32feb9ff76Sreyk #include <event.h> 33feb9ff76Sreyk #include <fcntl.h> 34feb9ff76Sreyk #include <stdlib.h> 35feb9ff76Sreyk #include <string.h> 36feb9ff76Sreyk #include <unistd.h> 37feb9ff76Sreyk #include <err.h> 38feb9ff76Sreyk #include <pwd.h> 39feb9ff76Sreyk 40e8fb3979Spyr #include <openssl/ssl.h> 41e8fb3979Spyr 42748ceb64Sreyk #include "relayd.h" 43feb9ff76Sreyk 44c99a0f3cSblambert __dead void hce_shutdown(void); 45feb9ff76Sreyk void hce_sig_handler(int sig, short, void *); 46feb9ff76Sreyk void hce_dispatch_imsg(int, short, void *); 47feb9ff76Sreyk void hce_dispatch_parent(int, short, void *); 48feb9ff76Sreyk void hce_launch_checks(int, short, void *); 49641b8bafSpyr void hce_setup_events(void); 50641b8bafSpyr void hce_disable_events(void); 51feb9ff76Sreyk 52748ceb64Sreyk static struct relayd *env = NULL; 53feb9ff76Sreyk struct imsgbuf *ibuf_pfe; 54feb9ff76Sreyk struct imsgbuf *ibuf_main; 55780e8f79Spyr int running = 0; 56feb9ff76Sreyk 57feb9ff76Sreyk void 58feb9ff76Sreyk hce_sig_handler(int sig, short event, void *arg) 59feb9ff76Sreyk { 60feb9ff76Sreyk switch (sig) { 61feb9ff76Sreyk case SIGINT: 62feb9ff76Sreyk case SIGTERM: 63feb9ff76Sreyk hce_shutdown(); 64780e8f79Spyr break; 65feb9ff76Sreyk default: 66feb9ff76Sreyk fatalx("hce_sig_handler: unexpected signal"); 67feb9ff76Sreyk } 68feb9ff76Sreyk } 69feb9ff76Sreyk 70feb9ff76Sreyk pid_t 71748ceb64Sreyk hce(struct relayd *x_env, int pipe_parent2pfe[2], int pipe_parent2hce[2], 72053249cdSpyr int pipe_parent2relay[RELAY_MAXPROC][2], int pipe_pfe2hce[2], 732edd718bSreyk int pipe_pfe2relay[RELAY_MAXPROC][2]) 74feb9ff76Sreyk { 75feb9ff76Sreyk pid_t pid; 76feb9ff76Sreyk struct passwd *pw; 772edd718bSreyk int i; 78641b8bafSpyr struct event ev_sigint; 79641b8bafSpyr struct event ev_sigterm; 80feb9ff76Sreyk 81feb9ff76Sreyk switch (pid = fork()) { 82feb9ff76Sreyk case -1: 83feb9ff76Sreyk fatal("hce: cannot fork"); 84feb9ff76Sreyk case 0: 85feb9ff76Sreyk break; 86feb9ff76Sreyk default: 87feb9ff76Sreyk return (pid); 88feb9ff76Sreyk } 89feb9ff76Sreyk 90feb9ff76Sreyk env = x_env; 919591a9f7Spyr purge_config(env, PURGE_RDRS|PURGE_RELAYS|PURGE_PROTOS); 92feb9ff76Sreyk 93748ceb64Sreyk if ((pw = getpwnam(RELAYD_USER)) == NULL) 94feb9ff76Sreyk fatal("hce: getpwnam"); 95feb9ff76Sreyk 96adf98c11Spyr #ifndef DEBUG 97feb9ff76Sreyk if (chroot(pw->pw_dir) == -1) 98feb9ff76Sreyk fatal("hce: chroot"); 99feb9ff76Sreyk if (chdir("/") == -1) 100feb9ff76Sreyk fatal("hce: chdir(\"/\")"); 101adf98c11Spyr #else 102adf98c11Spyr #warning disabling privilege revocation and chroot in DEBUG mode 103adf98c11Spyr #endif 104feb9ff76Sreyk 105feb9ff76Sreyk setproctitle("host check engine"); 106748ceb64Sreyk relayd_process = PROC_HCE; 107feb9ff76Sreyk 10801d85ec5Sreyk /* this is needed for icmp tests */ 10901d85ec5Sreyk icmp_init(env); 11001d85ec5Sreyk 111adf98c11Spyr #ifndef DEBUG 112feb9ff76Sreyk if (setgroups(1, &pw->pw_gid) || 113feb9ff76Sreyk setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 114feb9ff76Sreyk setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 115feb9ff76Sreyk fatal("hce: can't drop privileges"); 116adf98c11Spyr #endif 117feb9ff76Sreyk 118641b8bafSpyr event_init(); 119feb9ff76Sreyk 120641b8bafSpyr if ((ibuf_pfe = calloc(1, sizeof(struct imsgbuf))) == NULL || 121641b8bafSpyr (ibuf_main = calloc(1, sizeof(struct imsgbuf))) == NULL) 122641b8bafSpyr fatal("hce"); 123641b8bafSpyr imsg_init(ibuf_pfe, pipe_pfe2hce[0], hce_dispatch_imsg); 124641b8bafSpyr imsg_init(ibuf_main, pipe_parent2hce[1], hce_dispatch_parent); 125641b8bafSpyr 126641b8bafSpyr ibuf_pfe->events = EV_READ; 127641b8bafSpyr event_set(&ibuf_pfe->ev, ibuf_pfe->fd, ibuf_pfe->events, 128641b8bafSpyr ibuf_pfe->handler, ibuf_pfe); 129641b8bafSpyr event_add(&ibuf_pfe->ev, NULL); 130641b8bafSpyr 131641b8bafSpyr ibuf_main->events = EV_READ; 132641b8bafSpyr event_set(&ibuf_main->ev, ibuf_main->fd, ibuf_main->events, 133641b8bafSpyr ibuf_main->handler, ibuf_main); 134641b8bafSpyr event_add(&ibuf_main->ev, NULL); 135641b8bafSpyr 136641b8bafSpyr signal_set(&ev_sigint, SIGINT, hce_sig_handler, NULL); 137641b8bafSpyr signal_set(&ev_sigterm, SIGTERM, hce_sig_handler, NULL); 138641b8bafSpyr signal_add(&ev_sigint, NULL); 139641b8bafSpyr signal_add(&ev_sigterm, NULL); 140641b8bafSpyr signal(SIGPIPE, SIG_IGN); 141fda2844dSpyr signal(SIGHUP, SIG_IGN); 142feb9ff76Sreyk 143feb9ff76Sreyk /* setup pipes */ 144feb9ff76Sreyk close(pipe_pfe2hce[1]); 145feb9ff76Sreyk close(pipe_parent2hce[0]); 146feb9ff76Sreyk close(pipe_parent2pfe[0]); 147feb9ff76Sreyk close(pipe_parent2pfe[1]); 14835d10c30Sreyk for (i = 0; i < env->sc_prefork_relay; i++) { 149053249cdSpyr close(pipe_parent2relay[i][0]); 150053249cdSpyr close(pipe_parent2relay[i][1]); 1512edd718bSreyk close(pipe_pfe2relay[i][0]); 1522edd718bSreyk close(pipe_pfe2relay[i][1]); 1532edd718bSreyk } 154feb9ff76Sreyk 155641b8bafSpyr hce_setup_events(); 156641b8bafSpyr event_dispatch(); 157780e8f79Spyr hce_shutdown(); 158780e8f79Spyr 159780e8f79Spyr return (0); 160780e8f79Spyr } 161780e8f79Spyr 162780e8f79Spyr void 163641b8bafSpyr hce_setup_events(void) 164780e8f79Spyr { 165780e8f79Spyr struct timeval tv; 166780e8f79Spyr struct table *table; 167780e8f79Spyr 168fe250497Sreyk snmp_init(env, ibuf_main); 169fe250497Sreyk 17035d10c30Sreyk if (!TAILQ_EMPTY(env->sc_tables)) { 17135d10c30Sreyk evtimer_set(&env->sc_ev, hce_launch_checks, env); 17201d85ec5Sreyk bzero(&tv, sizeof(tv)); 17335d10c30Sreyk evtimer_add(&env->sc_ev, &tv); 1742edd718bSreyk } 175feb9ff76Sreyk 17635d10c30Sreyk if (env->sc_flags & F_SSL) { 177e8fb3979Spyr ssl_init(env); 17835d10c30Sreyk TAILQ_FOREACH(table, env->sc_tables, entry) { 17968b79041Spyr if (!(table->conf.flags & F_SSL)) 180e8fb3979Spyr continue; 181e8fb3979Spyr table->ssl_ctx = ssl_ctx_create(env); 182e8fb3979Spyr } 183e8fb3979Spyr } 184641b8bafSpyr } 185641b8bafSpyr 186641b8bafSpyr void 187641b8bafSpyr hce_disable_events(void) 188641b8bafSpyr { 189641b8bafSpyr struct table *table; 190641b8bafSpyr struct host *host; 191641b8bafSpyr 19235d10c30Sreyk evtimer_del(&env->sc_ev); 19335d10c30Sreyk TAILQ_FOREACH(table, env->sc_tables, entry) { 194641b8bafSpyr TAILQ_FOREACH(host, &table->hosts, entry) { 195*c0dc99f6Sreyk host->he = HCE_ABORT; 196641b8bafSpyr event_del(&host->cte.ev); 197641b8bafSpyr close(host->cte.s); 198641b8bafSpyr } 199641b8bafSpyr } 20035d10c30Sreyk if (env->sc_has_icmp) { 20135d10c30Sreyk event_del(&env->sc_icmp_send.ev); 20235d10c30Sreyk event_del(&env->sc_icmp_recv.ev); 203641b8bafSpyr } 20435d10c30Sreyk if (env->sc_has_icmp6) { 20535d10c30Sreyk event_del(&env->sc_icmp6_send.ev); 20635d10c30Sreyk event_del(&env->sc_icmp6_recv.ev); 207641b8bafSpyr } 208feb9ff76Sreyk } 209feb9ff76Sreyk 210feb9ff76Sreyk void 211feb9ff76Sreyk hce_launch_checks(int fd, short event, void *arg) 212feb9ff76Sreyk { 213feb9ff76Sreyk struct host *host; 214feb9ff76Sreyk struct table *table; 21501d85ec5Sreyk struct timeval tv; 21601d85ec5Sreyk 21701d85ec5Sreyk /* 21801d85ec5Sreyk * notify pfe checks are done and schedule next check 21901d85ec5Sreyk */ 2207a0be62eSmsf imsg_compose(ibuf_pfe, IMSG_SYNC, 0, 0, -1, NULL, 0); 22135d10c30Sreyk TAILQ_FOREACH(table, env->sc_tables, entry) { 22201d85ec5Sreyk TAILQ_FOREACH(host, &table->hosts, entry) { 223*c0dc99f6Sreyk if ((host->flags & F_CHECK_DONE) == 0) 224*c0dc99f6Sreyk host->he = HCE_INTERVAL_TIMEOUT; 22501d85ec5Sreyk host->flags &= ~(F_CHECK_SENT|F_CHECK_DONE); 22601d85ec5Sreyk event_del(&host->cte.ev); 22701d85ec5Sreyk } 22801d85ec5Sreyk } 22901d85ec5Sreyk 2306a899317Sthib if (gettimeofday(&tv, NULL) == -1) 23101d85ec5Sreyk fatal("hce_launch_checks: gettimeofday"); 232feb9ff76Sreyk 23335d10c30Sreyk TAILQ_FOREACH(table, env->sc_tables, entry) { 23468b79041Spyr if (table->conf.flags & F_DISABLE) 2357e351ffdSreyk continue; 23618de159aSpyr if (table->conf.skip_cnt) { 23718de159aSpyr if (table->skipped++ > table->conf.skip_cnt) 23818de159aSpyr table->skipped = 0; 23918de159aSpyr if (table->skipped != 1) 24018de159aSpyr continue; 24118de159aSpyr } 24268b79041Spyr if (table->conf.check == CHECK_NOCHECK) 2437e351ffdSreyk fatalx("hce_launch_checks: unknown check type"); 24401d85ec5Sreyk 2457e351ffdSreyk TAILQ_FOREACH(host, &table->hosts, entry) { 246c723f8edSreyk if (host->flags & F_DISABLE || host->conf.parentid) 2477e351ffdSreyk continue; 2484156152fSreyk switch (table->conf.check) { 2494156152fSreyk case CHECK_ICMP: 25001d85ec5Sreyk schedule_icmp(env, host); 2514156152fSreyk break; 2524156152fSreyk case CHECK_SCRIPT: 2534156152fSreyk check_script(host); 2544156152fSreyk break; 2554156152fSreyk default: 25601d85ec5Sreyk /* Any other TCP-style checks */ 2577e351ffdSreyk bzero(&host->cte, sizeof(host->cte)); 2587e351ffdSreyk host->last_up = host->up; 2597e351ffdSreyk host->cte.host = host; 2607e351ffdSreyk host->cte.table = table; 26101d85ec5Sreyk bcopy(&tv, &host->cte.tv_start, 26201d85ec5Sreyk sizeof(host->cte.tv_start)); 2637e351ffdSreyk check_tcp(&host->cte); 2644156152fSreyk break; 2654156152fSreyk } 2667e351ffdSreyk } 2677e351ffdSreyk } 26801d85ec5Sreyk check_icmp(env, &tv); 26901d85ec5Sreyk 27035d10c30Sreyk bcopy(&env->sc_interval, &tv, sizeof(tv)); 27135d10c30Sreyk evtimer_add(&env->sc_ev, &tv); 2727e351ffdSreyk } 2737e351ffdSreyk 2747e351ffdSreyk void 275*c0dc99f6Sreyk hce_notify_done(struct host *host, enum host_error he) 2767e351ffdSreyk { 277609cf3a7Sreyk struct table *table; 2787e351ffdSreyk struct ctl_status st; 279609cf3a7Sreyk struct timeval tv_now, tv_dur; 280609cf3a7Sreyk u_long duration; 281609cf3a7Sreyk u_int logopt; 282c723f8edSreyk struct host *h; 283c723f8edSreyk int hostup; 284*c0dc99f6Sreyk const char *msg; 285c723f8edSreyk 286c723f8edSreyk hostup = host->up; 287*c0dc99f6Sreyk host->he = he; 2887e351ffdSreyk 2892edd718bSreyk if (host->up == HOST_DOWN && host->retry_cnt) { 2902edd718bSreyk log_debug("hce_notify_done: host %s retry %d", 29168b79041Spyr host->conf.name, host->retry_cnt); 292bd2508bcSreyk host->up = host->last_up; 2932edd718bSreyk host->retry_cnt--; 2942edd718bSreyk } else 29568b79041Spyr host->retry_cnt = host->conf.retry; 2962edd718bSreyk if (host->up != HOST_UNKNOWN) { 2972edd718bSreyk host->check_cnt++; 2982edd718bSreyk if (host->up == HOST_UP) 2992edd718bSreyk host->up_cnt++; 3002edd718bSreyk } 30168b79041Spyr st.id = host->conf.id; 302feb9ff76Sreyk st.up = host->up; 3032edd718bSreyk st.check_cnt = host->check_cnt; 3042edd718bSreyk st.retry_cnt = host->retry_cnt; 305*c0dc99f6Sreyk st.he = he; 30601d85ec5Sreyk host->flags |= (F_CHECK_SENT|F_CHECK_DONE); 307*c0dc99f6Sreyk msg = host_error(he); 3087e351ffdSreyk if (msg) 30968b79041Spyr log_debug("hce_notify_done: %s (%s)", host->conf.name, msg); 310609cf3a7Sreyk 3117a0be62eSmsf imsg_compose(ibuf_pfe, IMSG_HOST_STATUS, 0, 0, -1, &st, sizeof(st)); 3122edd718bSreyk if (host->up != host->last_up) 313748ceb64Sreyk logopt = RELAYD_OPT_LOGUPDATE; 3142edd718bSreyk else 315748ceb64Sreyk logopt = RELAYD_OPT_LOGNOTIFY; 316609cf3a7Sreyk 3176a899317Sthib if (gettimeofday(&tv_now, NULL) == -1) 318609cf3a7Sreyk fatal("hce_notify_done: gettimeofday"); 319609cf3a7Sreyk timersub(&tv_now, &host->cte.tv_start, &tv_dur); 320609cf3a7Sreyk if (timercmp(&host->cte.tv_start, &tv_dur, >)) 321609cf3a7Sreyk duration = (tv_dur.tv_sec * 1000) + (tv_dur.tv_usec / 1000.0); 322609cf3a7Sreyk else 323609cf3a7Sreyk duration = 0; 324609cf3a7Sreyk 32568b79041Spyr if ((table = table_find(env, host->conf.tableid)) == NULL) 3262edd718bSreyk fatalx("hce_notify_done: invalid table id"); 3272edd718bSreyk 32835d10c30Sreyk if (env->sc_opts & logopt) { 3292edd718bSreyk log_info("host %s, check %s%s (%lums), state %s -> %s, " 3302edd718bSreyk "availability %s", 33168b79041Spyr host->conf.name, table_check(table->conf.check), 33268b79041Spyr (table->conf.flags & F_SSL) ? " use ssl" : "", duration, 3332edd718bSreyk host_status(host->last_up), host_status(host->up), 3342edd718bSreyk print_availability(host->check_cnt, host->up_cnt)); 335feb9ff76Sreyk } 336fe250497Sreyk 337fe250497Sreyk if (host->last_up != host->up) 338fe250497Sreyk snmp_hosttrap(table, host); 339fe250497Sreyk 340609cf3a7Sreyk host->last_up = host->up; 341c723f8edSreyk 3421584e35dSreyk if (SLIST_EMPTY(&host->children)) 343c723f8edSreyk return; 344c723f8edSreyk 345c723f8edSreyk /* Notify for all other hosts that inherit the state from this one */ 3461584e35dSreyk SLIST_FOREACH(h, &host->children, child) { 347c723f8edSreyk h->up = hostup; 348*c0dc99f6Sreyk hce_notify_done(h, he); 349c723f8edSreyk } 350feb9ff76Sreyk } 351feb9ff76Sreyk 352feb9ff76Sreyk void 353feb9ff76Sreyk hce_shutdown(void) 354feb9ff76Sreyk { 355feb9ff76Sreyk log_info("host check engine exiting"); 356feb9ff76Sreyk _exit(0); 357feb9ff76Sreyk } 358feb9ff76Sreyk 359feb9ff76Sreyk void 360feb9ff76Sreyk hce_dispatch_imsg(int fd, short event, void *ptr) 361feb9ff76Sreyk { 362feb9ff76Sreyk struct imsgbuf *ibuf; 363feb9ff76Sreyk struct imsg imsg; 364feb9ff76Sreyk ssize_t n; 365feb9ff76Sreyk objid_t id; 366feb9ff76Sreyk struct host *host; 367feb9ff76Sreyk struct table *table; 368feb9ff76Sreyk 369feb9ff76Sreyk ibuf = ptr; 370feb9ff76Sreyk switch (event) { 371feb9ff76Sreyk case EV_READ: 372feb9ff76Sreyk if ((n = imsg_read(ibuf)) == -1) 373feb9ff76Sreyk fatal("hce_dispatch_imsg: imsg_read_error"); 374ddfd9103Spyr if (n == 0) { 375ddfd9103Spyr /* this pipe is dead, so remove the event handler */ 376ddfd9103Spyr event_del(&ibuf->ev); 377ddfd9103Spyr event_loopexit(NULL); 378ddfd9103Spyr return; 379ddfd9103Spyr } 380feb9ff76Sreyk break; 381feb9ff76Sreyk case EV_WRITE: 382feb9ff76Sreyk if (msgbuf_write(&ibuf->w) == -1) 383feb9ff76Sreyk fatal("hce_dispatch_imsg: msgbuf_write"); 384feb9ff76Sreyk imsg_event_add(ibuf); 385feb9ff76Sreyk return; 386feb9ff76Sreyk default: 387feb9ff76Sreyk fatalx("hce_dispatch_imsg: unknown event"); 388feb9ff76Sreyk } 389feb9ff76Sreyk 390feb9ff76Sreyk for (;;) { 391feb9ff76Sreyk if ((n = imsg_get(ibuf, &imsg)) == -1) 392feb9ff76Sreyk fatal("hce_dispatch_imsg: imsg_read error"); 393feb9ff76Sreyk if (n == 0) 394feb9ff76Sreyk break; 395feb9ff76Sreyk 396feb9ff76Sreyk switch (imsg.hdr.type) { 397feb9ff76Sreyk case IMSG_HOST_DISABLE: 398feb9ff76Sreyk memcpy(&id, imsg.data, sizeof(id)); 399feb9ff76Sreyk if ((host = host_find(env, id)) == NULL) 400feb9ff76Sreyk fatalx("hce_dispatch_imsg: desynchronized"); 401feb9ff76Sreyk host->flags |= F_DISABLE; 402feb9ff76Sreyk host->up = HOST_UNKNOWN; 4032edd718bSreyk host->check_cnt = 0; 4042edd718bSreyk host->up_cnt = 0; 405*c0dc99f6Sreyk host->he = HCE_NONE; 406feb9ff76Sreyk break; 407feb9ff76Sreyk case IMSG_HOST_ENABLE: 408feb9ff76Sreyk memcpy(&id, imsg.data, sizeof(id)); 409feb9ff76Sreyk if ((host = host_find(env, id)) == NULL) 410feb9ff76Sreyk fatalx("hce_dispatch_imsg: desynchronized"); 411feb9ff76Sreyk host->flags &= ~(F_DISABLE); 412feb9ff76Sreyk host->up = HOST_UNKNOWN; 413*c0dc99f6Sreyk host->he = HCE_NONE; 414feb9ff76Sreyk break; 415feb9ff76Sreyk case IMSG_TABLE_DISABLE: 416feb9ff76Sreyk memcpy(&id, imsg.data, sizeof(id)); 417feb9ff76Sreyk if ((table = table_find(env, id)) == NULL) 418feb9ff76Sreyk fatalx("hce_dispatch_imsg: desynchronized"); 41968b79041Spyr table->conf.flags |= F_DISABLE; 420feb9ff76Sreyk TAILQ_FOREACH(host, &table->hosts, entry) 421feb9ff76Sreyk host->up = HOST_UNKNOWN; 422feb9ff76Sreyk break; 423feb9ff76Sreyk case IMSG_TABLE_ENABLE: 424feb9ff76Sreyk memcpy(&id, imsg.data, sizeof(id)); 425feb9ff76Sreyk if ((table = table_find(env, id)) == NULL) 426feb9ff76Sreyk fatalx("hce_dispatch_imsg: desynchronized"); 42768b79041Spyr table->conf.flags &= ~(F_DISABLE); 428feb9ff76Sreyk TAILQ_FOREACH(host, &table->hosts, entry) 429feb9ff76Sreyk host->up = HOST_UNKNOWN; 430feb9ff76Sreyk break; 431cd65ce7bSpyr case IMSG_CTL_POLL: 43235d10c30Sreyk evtimer_del(&env->sc_ev); 43335d10c30Sreyk TAILQ_FOREACH(table, env->sc_tables, entry) 434f98352d8Spyr table->skipped = 0; 435cd65ce7bSpyr hce_launch_checks(-1, EV_TIMEOUT, env); 436cd65ce7bSpyr break; 437feb9ff76Sreyk default: 438feb9ff76Sreyk log_debug("hce_dispatch_msg: unexpected imsg %d", 439feb9ff76Sreyk imsg.hdr.type); 440feb9ff76Sreyk break; 441feb9ff76Sreyk } 442feb9ff76Sreyk imsg_free(&imsg); 443feb9ff76Sreyk } 444feb9ff76Sreyk imsg_event_add(ibuf); 445feb9ff76Sreyk } 446feb9ff76Sreyk 447feb9ff76Sreyk void 448feb9ff76Sreyk hce_dispatch_parent(int fd, short event, void * ptr) 449feb9ff76Sreyk { 450feb9ff76Sreyk struct imsgbuf *ibuf; 451feb9ff76Sreyk struct imsg imsg; 4524156152fSreyk struct ctl_script scr; 453feb9ff76Sreyk ssize_t n; 454adf98c11Spyr size_t len; 455adf98c11Spyr 456adf98c11Spyr static struct table *table = NULL; 457adf98c11Spyr struct host *host; 458feb9ff76Sreyk 459feb9ff76Sreyk ibuf = ptr; 460feb9ff76Sreyk switch (event) { 461feb9ff76Sreyk case EV_READ: 462feb9ff76Sreyk if ((n = imsg_read(ibuf)) == -1) 463feb9ff76Sreyk fatal("hce_dispatch_parent: imsg_read error"); 464ddfd9103Spyr if (n == 0) { 465ddfd9103Spyr /* this pipe is dead, so remove the event handler */ 466ddfd9103Spyr event_del(&ibuf->ev); 467ddfd9103Spyr event_loopexit(NULL); 468ddfd9103Spyr return; 469ddfd9103Spyr } 470feb9ff76Sreyk break; 471feb9ff76Sreyk case EV_WRITE: 472feb9ff76Sreyk if (msgbuf_write(&ibuf->w) == -1) 473feb9ff76Sreyk fatal("hce_dispatch_parent: msgbuf_write"); 474feb9ff76Sreyk imsg_event_add(ibuf); 475feb9ff76Sreyk return; 476feb9ff76Sreyk default: 477feb9ff76Sreyk fatalx("hce_dispatch_parent: unknown event"); 478feb9ff76Sreyk } 479feb9ff76Sreyk 480feb9ff76Sreyk for (;;) { 481feb9ff76Sreyk if ((n = imsg_get(ibuf, &imsg)) == -1) 482feb9ff76Sreyk fatal("hce_dispatch_parent: imsg_read error"); 483feb9ff76Sreyk if (n == 0) 484feb9ff76Sreyk break; 485feb9ff76Sreyk 486feb9ff76Sreyk switch (imsg.hdr.type) { 4874156152fSreyk case IMSG_SCRIPT: 4884156152fSreyk if (imsg.hdr.len - IMSG_HEADER_SIZE != 4894156152fSreyk sizeof(scr)) 4904156152fSreyk fatalx("hce_dispatch_parent: " 4914156152fSreyk "invalid size of script request"); 4924156152fSreyk bcopy(imsg.data, &scr, sizeof(scr)); 4934156152fSreyk script_done(env, &scr); 4944156152fSreyk break; 495adf98c11Spyr case IMSG_RECONF: 496adf98c11Spyr log_debug("hce: reloading configuration"); 497adf98c11Spyr if (imsg.hdr.len != 498748ceb64Sreyk sizeof(struct relayd) + IMSG_HEADER_SIZE) 499adf98c11Spyr fatalx("corrupted reload data"); 500adf98c11Spyr hce_disable_events(); 501adf98c11Spyr purge_config(env, PURGE_TABLES); 502748ceb64Sreyk merge_config(env, (struct relayd *)imsg.data); 503adf98c11Spyr 50435d10c30Sreyk env->sc_tables = calloc(1, sizeof(*env->sc_tables)); 50535d10c30Sreyk if (env->sc_tables == NULL) 506adf98c11Spyr fatal(NULL); 507adf98c11Spyr 50835d10c30Sreyk TAILQ_INIT(env->sc_tables); 509adf98c11Spyr break; 510adf98c11Spyr case IMSG_RECONF_TABLE: 511adf98c11Spyr if ((table = calloc(1, sizeof(*table))) == NULL) 512adf98c11Spyr fatal(NULL); 513adf98c11Spyr memcpy(&table->conf, imsg.data, sizeof(table->conf)); 514adf98c11Spyr TAILQ_INIT(&table->hosts); 51535d10c30Sreyk TAILQ_INSERT_TAIL(env->sc_tables, table, entry); 516adf98c11Spyr break; 517adf98c11Spyr case IMSG_RECONF_SENDBUF: 518adf98c11Spyr len = imsg.hdr.len - IMSG_HEADER_SIZE; 519adf98c11Spyr table->sendbuf = calloc(1, len); 520adf98c11Spyr (void)strlcpy(table->sendbuf, (char *)imsg.data, len); 521adf98c11Spyr break; 522adf98c11Spyr case IMSG_RECONF_HOST: 523adf98c11Spyr if ((host = calloc(1, sizeof(*host))) == NULL) 524adf98c11Spyr fatal(NULL); 525adf98c11Spyr memcpy(&host->conf, imsg.data, sizeof(host->conf)); 526adf98c11Spyr host->tablename = table->conf.name; 527adf98c11Spyr TAILQ_INSERT_TAIL(&table->hosts, host, entry); 528adf98c11Spyr break; 529adf98c11Spyr case IMSG_RECONF_END: 530adf98c11Spyr log_warnx("hce: configuration reloaded"); 531adf98c11Spyr hce_setup_events(); 532adf98c11Spyr break; 533feb9ff76Sreyk default: 534feb9ff76Sreyk log_debug("hce_dispatch_parent: unexpected imsg %d", 535feb9ff76Sreyk imsg.hdr.type); 536feb9ff76Sreyk break; 537feb9ff76Sreyk } 538feb9ff76Sreyk imsg_free(&imsg); 539feb9ff76Sreyk } 5404156152fSreyk imsg_event_add(ibuf); 541feb9ff76Sreyk } 542