static void stratcon_ingestor_submit_lookup(struct realtime_tracker *rt, eventer_t completion) { struct realtime_tracker *node; for(node = rt; node; node = node->next) { char uuid_str[UUID_STR_LEN+1]; const char *fqdn, *dsn, *remote_cn; char remote_ip[32]; int storagenode_id; uuid_unparse_lower(node->checkid, uuid_str); if(storage_node_quick_lookup(uuid_str, NULL, &node->sid, &storagenode_id, &remote_cn, &fqdn, &dsn)) continue; noitL(noit_debug, "stratcon_ingest_find <- (%d, %s) @ %s\n", node->sid, remote_cn ? remote_cn : "(null)", dsn ? dsn : "(null)"); if(stratcon_find_noit_ip_by_cn(remote_cn, remote_ip, sizeof(remote_ip)) == 0) { node->noit = strdup(remote_ip); noitL(noit_debug, "lookup(cache): %s -> %s\n", remote_cn, node->noit); continue; } } eventer_add(completion); }
void stratcon_datastore_push(stratcon_datastore_op_t op, struct sockaddr *remote, const char *remote_cn, void *operand, eventer_t completion) { syncset_t *syncset; eventer_t e; struct realtime_tracker *rt; struct datastore_onlooker_list *nnode; for(nnode = onlookers; nnode; nnode = nnode->next) nnode->dispatch(op,remote,remote_cn,operand); switch(op) { case DS_OP_INSERT: stratcon_datastore_journal(remote, remote_cn, (char *)operand); break; case DS_OP_CHKPT: e = eventer_alloc(); syncset = calloc(1, sizeof(*syncset)); e->mask = EVENTER_ASYNCH; e->callback = stratcon_datastore_journal_sync; syncset->ws = stratcon_datastore_journal_remove(remote, remote_cn); syncset->completion = completion; e->closure = syncset; eventer_add(e); break; case DS_OP_FIND_COMPLETE: rt = operand; ingestor->submit_realtime_lookup(rt, completion); break; } }
static void dns_module_eventer_dns_utm_fn(struct dns_ctx *ctx, int timeout, void *data) { dns_ctx_handle_t *h = data; eventer_t e = NULL, newe = NULL; if(ctx == NULL) { if(h && h->timeout) e = eventer_remove(h->timeout); } else { assert(h->ctx == ctx); if(h->timeout) e = eventer_remove(h->timeout); if(timeout > 0) { newe = eventer_alloc(); newe->mask = EVENTER_TIMER; newe->callback = dns_module_invoke_timeouts; newe->closure = h; gettimeofday(&newe->whence, NULL); newe->whence.tv_sec += timeout; } } if(e) { eventer_free(e); if(h) dns_module_dns_ctx_release(h); } if(newe) { dns_module_dns_ctx_acquire(h); eventer_add(newe); } if(h) { h->timeout = newe; } }
static int ssh2_needs_bytes_as_libssh2_is_impatient(eventer_t e, int mask, void *closure, struct timeval *now) { ssh2_check_info_t *ci = closure; eventer_t asynch_e; if(mask & EVENTER_EXCEPTION) { noit_check_t *check = ci->check; ci->timed_out = 0; ci->error = strdup("ssh connection failed"); ssh2_log_results(ci->self, ci->check); ssh2_cleanup(ci->self, ci->check); eventer_remove_fd(e->fd); e->opset->close(e->fd, &mask, e); check->flags &= ~NP_RUNNING; return 0; } /* We steal the timeout_event as it has the exact timeout we want. */ assert(ci->timeout_event); asynch_e = eventer_remove(ci->timeout_event); assert(asynch_e); ci->timeout_event = NULL; ci->synch_fd_event = NULL; asynch_e->fd = e->fd; asynch_e->callback = ssh2_drive_session; asynch_e->closure = closure; asynch_e->mask = EVENTER_ASYNCH; eventer_add(asynch_e); eventer_remove_fd(e->fd); return 0; }
static int stratcon_datastore_journal_sync(eventer_t e, int mask, void *closure, struct timeval *now) { noit_hash_iter iter = NOIT_HASH_ITER_ZERO; const char *k; int klen; void *vij; interim_journal_t *ij; syncset_t *syncset = closure; if((mask & EVENTER_ASYNCH) == EVENTER_ASYNCH) { if(syncset->completion) { eventer_add(syncset->completion); eventer_trigger(syncset->completion, EVENTER_READ | EVENTER_WRITE); } free(syncset); return 0; } if(!((mask & EVENTER_ASYNCH_WORK) == EVENTER_ASYNCH_WORK)) return 0; noitL(ds_deb, "Syncing journal sets...\n"); if (syncset->ws) { while(noit_hash_next(syncset->ws, &iter, &k, &klen, &vij)) { char tmppath[PATH_MAX], id_str[32]; int suffix_idx; ij = vij; noitL(ds_deb, "Syncing journal set [%s,%s,%s]\n", ij->remote_str, ij->remote_cn, ij->fqdn); strlcpy(tmppath, ij->filename, sizeof(tmppath)); suffix_idx = strlen(ij->filename) - 4; /* . t m p */ ij->filename[suffix_idx] = '\0'; if(rename(tmppath, ij->filename) != 0) { if(errno == EEXIST) { unlink(ij->filename); if(rename(tmppath, ij->filename) != 0) goto rename_failed; } else { rename_failed: noitL(noit_error, "rename failed(%s): (%s->%s)\n", strerror(errno), tmppath, ij->filename); exit(-1); } } fsync(ij->fd); close(ij->fd); ij->fd = -1; snprintf(id_str, sizeof(id_str), "%d", ij->storagenode_id); stratcon_ingest(ij->filename, ij->remote_str, ij->remote_cn, id_str); } noit_hash_destroy(syncset->ws, free, interim_journal_free); free(syncset->ws); } else { noitL(noit_error, "attempted to sync non-existing working set\n"); } return 0; }
int noit_check_schedule_next(noit_module_t *self, struct timeval *last_check, noit_check_t *check, struct timeval *now, dispatch_func_t dispatch, noit_check_t *cause) { eventer_t newe; struct timeval period, earliest; recur_closure_t *rcl; assert(cause == NULL); assert(check->fire_event == NULL); if(check->period == 0) return 0; if(NOIT_CHECK_DISABLED(check) || NOIT_CHECK_KILLED(check)) { if(!(check->flags & NP_TRANSIENT)) check_slots_dec_tv(last_check); return 0; } /* If we have an event, we know when we intended it to fire. This means * we should schedule that point + period. */ if(now) memcpy(&earliest, now, sizeof(earliest)); else gettimeofday(&earliest, NULL); /* If the check is unconfigured and needs resolving, we'll set the * period down a bit lower so we can pick up the resolution quickly. */ if(!NOIT_CHECK_RESOLVED(check) && NOIT_CHECK_SHOULD_RESOLVE(check) && check->period > 1000) { period.tv_sec = 1; period.tv_usec = 0; } else { period.tv_sec = check->period / 1000; period.tv_usec = (check->period % 1000) * 1000; } newe = eventer_alloc(); memcpy(&newe->whence, last_check, sizeof(*last_check)); add_timeval(newe->whence, period, &newe->whence); if(compare_timeval(newe->whence, earliest) < 0) memcpy(&newe->whence, &earliest, sizeof(earliest)); newe->mask = EVENTER_TIMER; newe->callback = noit_check_recur_handler; rcl = calloc(1, sizeof(*rcl)); rcl->self = self; rcl->check = check; rcl->cause = cause; rcl->dispatch = dispatch; newe->closure = rcl; eventer_add(newe); check->fire_event = newe; return 0; }
static dns_ctx_handle_t *dns_ctx_alloc(const char *ns, int port) { void *vh; dns_ctx_handle_t *h = NULL; pthread_mutex_lock(&dns_ctx_store_lock); if(ns == NULL && default_ctx_handle != NULL) { /* special case -- default context */ h = default_ctx_handle; noit_atomic_inc32(&h->refcnt); goto bail; } if(ns && noit_hash_retrieve(&dns_ctx_store, ns, strlen(ns), &vh)) { h = (dns_ctx_handle_t *)vh; noit_atomic_inc32(&h->refcnt); } else { int failed = 0; h = calloc(1, sizeof(*h)); h->ns = ns ? strdup(ns) : NULL; h->ctx = dns_new(NULL); if(dns_init(h->ctx, 0) != 0) failed++; if(ns) { if(dns_add_serv(h->ctx, NULL) < 0) failed++; if(dns_add_serv(h->ctx, ns) < 0) failed++; } if(port && port != DNS_PORT) { dns_set_opt(h->ctx, DNS_OPT_PORT, port); } if(dns_open(h->ctx) < 0) failed++; if(failed) { noitL(nlerr, "dns_open failed\n"); free(h->ns); free(h); h = NULL; goto bail; } dns_set_tmcbck(h->ctx, eventer_dns_utm_fn, h); h->e = eventer_alloc(); h->e->mask = EVENTER_READ | EVENTER_EXCEPTION; h->e->closure = h; h->e->callback = dns_eventer_callback; h->e->fd = dns_sock(h->ctx); eventer_add(h->e); h->refcnt = 1; if(!ns) default_ctx_handle = h; else noit_hash_store(&dns_ctx_store, h->ns, strlen(h->ns), h); } bail: pthread_mutex_unlock(&dns_ctx_store_lock); return h; }
static void check_test_schedule_sweeper() { struct timeval now, diff; if(sweeper_event) return; sweeper_event = eventer_alloc(); sweeper_event->mask = EVENTER_TIMER; sweeper_event->callback = check_test_sweeper; diff.tv_sec = 0L; diff.tv_usec = default_sweep_interval * 1000L; gettimeofday(&now, NULL); add_timeval(now, diff, &sweeper_event->whence); eventer_add(sweeper_event); }
static void dns_cache_utm_fn(struct dns_ctx *ctx, int timeout, void *data) { eventer_t e = NULL, newe = NULL; if(ctx == NULL) e = eventer_remove(dns_cache_timeout); else { if(timeout < 0) e = eventer_remove(dns_cache_timeout); else { newe = eventer_in_s_us(dns_invoke_timeouts, dns_ctx, timeout, 0); } } if(e) eventer_free(e); if(newe) eventer_add(newe); dns_cache_timeout = newe; }
void noit_check_run_full_asynch_opts(noit_check_t *check, eventer_func_t callback, int mask) { struct timeval __now, p_int; eventer_t e; e = eventer_alloc(); e->fd = -1; e->mask = EVENTER_ASYNCH | mask; gettimeofday(&__now, NULL); memcpy(&e->whence, &__now, sizeof(__now)); p_int.tv_sec = check->timeout / 1000; p_int.tv_usec = (check->timeout % 1000) * 1000; add_timeval(e->whence, p_int, &e->whence); e->callback = callback; e->closure = check->closure; eventer_add(e); }
static void _set_ts_timeout(struct target_session *ts, struct timeval *t) { struct timeval now; eventer_t e = NULL; if(ts->timeoutevent) { e = eventer_remove(ts->timeoutevent); ts->timeoutevent = NULL; } if(!t) return; gettimeofday(&now, NULL); if(!e) e = eventer_alloc(); e->callback = noit_snmp_session_timeout; e->closure = ts; e->mask = EVENTER_TIMER; add_timeval(now, *t, &e->whence); ts->timeoutevent = e; eventer_add(e); }
static void dns_cache_utm_fn(struct dns_ctx *ctx, int timeout, void *data) { eventer_t e = NULL, newe = NULL; if(ctx == NULL) e = eventer_remove(dns_cache_timeout); else { if(timeout < 0) e = eventer_remove(dns_cache_timeout); else { newe = eventer_alloc(); newe->mask = EVENTER_TIMER; newe->callback = dns_invoke_timeouts; newe->closure = dns_ctx; gettimeofday(&newe->whence, NULL); newe->whence.tv_sec += timeout; } } if(e) eventer_free(e); if(newe) eventer_add(newe); dns_cache_timeout = newe; }
static void eventer_dns_utm_fn(struct dns_ctx *ctx, int timeout, void *data) { dns_ctx_handle_t *h = data; eventer_t e = NULL, newe = NULL; if(ctx == NULL) e = eventer_remove(h->timeout); else { assert(h->ctx == ctx); if(timeout < 0) e = eventer_remove(h->timeout); else { newe = eventer_alloc(); newe->mask = EVENTER_TIMER; newe->callback = dns_invoke_timeouts; newe->closure = h; gettimeofday(&newe->whence, NULL); newe->whence.tv_sec += timeout; } } if(e) eventer_free(e); if(newe) eventer_add(newe); h->timeout = newe; }
static int lua_web_resume(mtev_lua_resume_info_t *ri, int nargs) { const char *err = NULL; int status, base, rv = 0; mtev_lua_resume_rest_info_t *ctx = ri->context_data; mtev_http_rest_closure_t *restc = ctx->restc; eventer_t conne = mtev_http_connection_event(mtev_http_session_connection(restc->http_ctx)); assert(pthread_equal(pthread_self(), ri->bound_thread)); #if LUA_VERSION_NUM >= 502 status = lua_resume(ri->coro_state, ri->lmc->lua_state, nargs); #else status = lua_resume(ri->coro_state, nargs); #endif switch(status) { case 0: break; case LUA_YIELD: lua_gc(ri->coro_state, LUA_GCCOLLECT, 0); return 0; default: /* The complicated case */ ctx->httpcode = 500; base = lua_gettop(ri->coro_state); if(base>=0) { if(lua_isstring(ri->coro_state, base-1)) { err = lua_tostring(ri->coro_state, base-1); mtevL(mtev_error, "err -> %s\n", err); if(!ctx->err) ctx->err = strdup(err); } } rv = -1; } lua_web_restc_fastpath(restc, 0, NULL); eventer_add(conne); eventer_trigger(conne, EVENTER_READ|EVENTER_WRITE); return rv; }
void noit_check_resolver_init() { eventer_t e; if(dns_init(NULL, 0) < 0) noitL(noit_error, "dns initialization failed.\n"); dns_ctx = dns_new(NULL); if(dns_init(dns_ctx, 0) != 0 || dns_open(dns_ctx) < 0) { noitL(noit_error, "dns initialization failed.\n"); } eventer_name_callback("dns_cache_callback", dns_cache_callback); dns_set_tmcbck(dns_ctx, dns_cache_utm_fn, dns_ctx); e = eventer_alloc(); e->mask = EVENTER_READ | EVENTER_EXCEPTION; e->closure = dns_ctx; e->callback = dns_cache_callback; e->fd = dns_sock(dns_ctx); eventer_add(e); noit_skiplist_init(&nc_dns_cache); noit_skiplist_set_compare(&nc_dns_cache, name_lookup, name_lookup_k); noit_skiplist_add_index(&nc_dns_cache, refresh_idx, refresh_idx_k); noit_check_resolver_loop(NULL, 0, NULL, NULL); register_console_dns_cache_commands(); }
static void rest_test_check_result(struct check_test_closure *cl) { xmlDocPtr doc = NULL; xmlNodePtr root, state; noit_http_session_ctx *ctx = cl->restc->http_ctx; noitL(nlerr, "Flushing check test result\n"); if(cl->restc->call_closure_free) cl->restc->call_closure_free(cl->restc->call_closure); cl->restc->call_closure_free = NULL; cl->restc->call_closure = NULL; cl->restc->fastpath = NULL; if(ctx) { eventer_t conne = noit_http_connection_event(noit_http_session_connection(ctx)); doc = xmlNewDoc((xmlChar *)"1.0"); root = xmlNewDocNode(doc, NULL, (xmlChar *)"check", NULL); xmlDocSetRootElement(doc, root); state = noit_check_state_as_xml(cl->check); xmlAddChild(root, state); noit_http_response_ok(ctx, "text/xml"); noit_http_response_xml(ctx, doc); noit_http_response_end(ctx); if(conne) { eventer_add(conne); eventer_trigger(conne, EVENTER_READ | EVENTER_WRITE); } } noit_poller_free_check(cl->check); xmlFreeDoc(doc); free(cl); }
static int mtev_lua_general_init(mtev_dso_generic_t *self) { const char * const *module; int (*f)(lua_State *); lua_general_conf_t *conf = get_config(self); lua_module_closure_t *lmc = pthread_getspecific(conf->key); if(lmc) return 0; if(!lmc) { lmc = calloc(1, sizeof(*lmc)); lmc->self = self; mtev_hash_init(&lmc->state_coros); pthread_setspecific(conf->key, lmc); } if(!conf->module || !conf->function) { mtevL(nlerr, "lua_general cannot be used without module and function config\n"); return -1; } lmc->resume = lua_general_resume; lmc->owner = pthread_self(); lmc->eventer_id = eventer_is_loop(lmc->owner); lmc->lua_state = mtev_lua_open(self->hdr.name, lmc, conf->script_dir, conf->cpath); mtevL(nldeb, "lua_general opening state -> %p\n", lmc->lua_state); if(lmc->lua_state == NULL) { mtevL(mtev_error, "lua_general could not add general functions\n"); return -1; } luaL_openlib(lmc->lua_state, "mtev", general_lua_funcs, 0); /* Load some preloads */ for(module = conf->Cpreloads; module && *module; module++) { int len; char *symbol = NULL; len = strlen(*module) + strlen("luaopen_"); symbol = malloc(len+1); if(!symbol) mtevL(nlerr, "Failed to preload %s: malloc error\n", *module); else { snprintf(symbol, len+1, "luaopen_%s", *module); #ifdef RTLD_DEFAULT f = dlsym(RTLD_DEFAULT, symbol); #else f = dlsym((void *)0, symbol); #endif if(!f) mtevL(nlerr, "Failed to preload %s: %s not found\n", *module, symbol); else f(lmc->lua_state); } free(symbol); } lmc->pending = calloc(1, sizeof(*lmc->pending)); mtev_hash_init(lmc->pending); if(conf->booted) return true; conf->booted = mtev_true; eventer_add_in_s_us(dispatch_general, self, 0, 0); if(conf->concurrent) { int i = 1; pthread_t tgt, thr; thr = eventer_choose_owner(i++); do { eventer_t e = eventer_in_s_us(dispatch_general, self, 0, 0); tgt = eventer_choose_owner(i++); eventer_set_owner(e, tgt); eventer_add(e); } while(!pthread_equal(thr,tgt)); } return 0; }
static int external_invoke(noit_module_t *self, noit_check_t *check, noit_check_t *cause) { struct timeval when, p_int; external_closure_t *ecl; struct check_info *ci = (struct check_info *)check->closure; eventer_t newe; external_data_t *data; noit_hash_table check_attrs_hash = NOIT_HASH_EMPTY; int i, klen; noit_hash_iter iter = NOIT_HASH_ITER_ZERO; const char *name, *value; char interp_fmt[4096], interp_buff[4096]; data = noit_module_get_userdata(self); check->flags |= NP_RUNNING; noitL(data->nldeb, "external_invoke(%p,%s)\n", self, check->target); /* remove a timeout if we still have one -- we should unless someone * has set a lower timeout than the period. */ if(ci->timeout_event) { eventer_remove(ci->timeout_event); free(ci->timeout_event->closure); eventer_free(ci->timeout_event); ci->timeout_event = NULL; } check_info_clean(ci); gettimeofday(&when, NULL); memcpy(&check->last_fire_time, &when, sizeof(when)); /* Setup all our check bits */ ci->check_no = noit_atomic_inc64(&data->check_no_seq); ci->check = check; /* We might want to extract metrics */ if(noit_hash_retr_str(check->config, "output_extract", strlen("output_extract"), &value) != 0) { const char *error; int erroffset; ci->matcher = pcre_compile(value, 0, &error, &erroffset, NULL); if(!ci->matcher) { noitL(data->nlerr, "external pcre /%s/ failed @ %d: %s\n", value, erroffset, error); } } noit_check_make_attrs(check, &check_attrs_hash); /* Count the args */ i = 1; while(1) { char argname[10]; snprintf(argname, sizeof(argname), "arg%d", i); if(noit_hash_retr_str(check->config, argname, strlen(argname), &value) == 0) break; i++; } ci->argcnt = i + 1; /* path, arg0, (i-1 more args) */ ci->arglens = calloc(ci->argcnt, sizeof(*ci->arglens)); ci->args = calloc(ci->argcnt, sizeof(*ci->args)); /* Make the command */ if(noit_hash_retr_str(check->config, "command", strlen("command"), &value) == 0) { value = "/bin/true"; } ci->args[0] = strdup(value); ci->arglens[0] = strlen(ci->args[0]) + 1; i = 0; while(1) { char argname[10]; snprintf(argname, sizeof(argname), "arg%d", i); if(noit_hash_retr_str(check->config, argname, strlen(argname), &value) == 0) { if(i == 0) { /* if we don't have arg0, make it last element of path */ char *cp = ci->args[0] + strlen(ci->args[0]); while(cp > ci->args[0] && *(cp-1) != '/') cp--; value = cp; } else break; /* if we don't have argn, we're done */ } noit_check_interpolate(interp_buff, sizeof(interp_buff), value, &check_attrs_hash, check->config); ci->args[i+1] = strdup(interp_buff); ci->arglens[i+1] = strlen(ci->args[i+1]) + 1; i++; } /* Make the environment */ memset(&iter, 0, sizeof(iter)); ci->envcnt = 0; while(noit_hash_next_str(check->config, &iter, &name, &klen, &value)) if(!strncasecmp(name, "env_", 4)) ci->envcnt++; memset(&iter, 0, sizeof(iter)); ci->envlens = calloc(ci->envcnt, sizeof(*ci->envlens)); ci->envs = calloc(ci->envcnt, sizeof(*ci->envs)); ci->envcnt = 0; while(noit_hash_next_str(check->config, &iter, &name, &klen, &value)) if(!strncasecmp(name, "env_", 4)) { snprintf(interp_fmt, sizeof(interp_fmt), "%s=%s", name+4, value); noit_check_interpolate(interp_buff, sizeof(interp_buff), interp_fmt, &check_attrs_hash, check->config); ci->envs[ci->envcnt] = strdup(interp_buff); ci->envlens[ci->envcnt] = strlen(ci->envs[ci->envcnt]) + 1; ci->envcnt++; } noit_hash_destroy(&check_attrs_hash, NULL, NULL); noit_hash_store(&data->external_checks, (const char *)&ci->check_no, sizeof(ci->check_no), ci); /* Setup a timeout */ newe = eventer_alloc(); newe->mask = EVENTER_TIMER; gettimeofday(&when, NULL); p_int.tv_sec = check->timeout / 1000; p_int.tv_usec = (check->timeout % 1000) * 1000; add_timeval(when, p_int, &newe->whence); ecl = calloc(1, sizeof(*ecl)); ecl->self = self; ecl->check = check; newe->closure = ecl; newe->callback = external_timeout; eventer_add(newe); ci->timeout_event = newe; /* Setup push */ newe = eventer_alloc(); newe->mask = EVENTER_ASYNCH; add_timeval(when, p_int, &newe->whence); ecl = calloc(1, sizeof(*ecl)); ecl->self = self; ecl->check = check; newe->closure = ecl; newe->callback = external_enqueue; eventer_add(newe); return 0; }
static int external_init(noit_module_t *self) { external_data_t *data; data = noit_module_get_userdata(self); if(!data) data = malloc(sizeof(*data)); data->nlerr = noit_log_stream_find("error/external"); data->nldeb = noit_log_stream_find("debug/external"); data->jobq = calloc(1, sizeof(*data->jobq)); eventer_jobq_init(data->jobq, "external"); data->jobq->backq = eventer_default_backq(); eventer_jobq_increase_concurrency(data->jobq); if(socketpair(AF_UNIX, SOCK_STREAM, 0, data->pipe_n2e) != 0 || socketpair(AF_UNIX, SOCK_STREAM, 0, data->pipe_e2n) != 0) { noitL(noit_error, "external: pipe() failed: %s\n", strerror(errno)); return -1; } data->child = fork(); if(data->child == -1) { /* No child, bail. */ noitL(noit_error, "external: fork() failed: %s\n", strerror(errno)); return -1; } /* parent must close the read side of n2e and the write side of e2n */ /* The child must do the opposite */ close(data->pipe_n2e[(data->child == 0) ? 1 : 0]); close(data->pipe_e2n[(data->child == 0) ? 0 : 1]); /* Now the parent must set its bits non-blocking, the child need not */ if(data->child != 0) { /* in the parent */ if(eventer_set_fd_nonblocking(data->pipe_e2n[0]) == -1) { close(data->pipe_n2e[1]); close(data->pipe_e2n[0]); noitL(noit_error, "external: could not set pipe non-blocking: %s\n", strerror(errno)); return -1; } eventer_t newe; newe = eventer_alloc(); newe->fd = data->pipe_e2n[0]; newe->mask = EVENTER_READ | EVENTER_EXCEPTION; newe->callback = external_handler; newe->closure = self; eventer_add(newe); } else { const char *user = NULL, *group = NULL; if(data->options) { noit_hash_retr_str(data->options, "user", 4, &user); noit_hash_retr_str(data->options, "group", 4, &group); } noit_security_usergroup(user, group, noit_false); exit(external_child(data)); } noit_module_set_userdata(self, data); return 0; }
static int ssh2_initiate(noit_module_t *self, noit_check_t *check, noit_check_t *cause) { ssh2_check_info_t *ci = check->closure; struct timeval p_int, __now; int fd = -1, rv = -1; eventer_t e; union { struct sockaddr_in sin; struct sockaddr_in6 sin6; } sockaddr; socklen_t sockaddr_len; unsigned short ssh_port = DEFAULT_SSH_PORT; const char *port_str = NULL; /* We cannot be running */ BAIL_ON_RUNNING_CHECK(check); check->flags |= NP_RUNNING; ci->self = self; ci->check = check; ci->timed_out = 1; if(ci->timeout_event) { eventer_remove(ci->timeout_event); free(ci->timeout_event->closure); eventer_free(ci->timeout_event); ci->timeout_event = NULL; } gettimeofday(&__now, NULL); memcpy(&check->last_fire_time, &__now, sizeof(__now)); if(check->target_ip[0] == '\0') { ci->error = strdup("name resolution failure"); goto fail; } /* Open a socket */ fd = socket(check->target_family, NE_SOCK_CLOEXEC|SOCK_STREAM, 0); if(fd < 0) goto fail; /* Make it non-blocking */ if(eventer_set_fd_nonblocking(fd)) goto fail; if(noit_hash_retr_str(check->config, "port", strlen("port"), &port_str)) { ssh_port = (unsigned short)atoi(port_str); } #define config_method(a) do { \ const char *v; \ if(noit_hash_retr_str(check->config, "method_" #a, strlen("method_" #a), \ &v)) \ ci->methods.a = strdup(v); \ } while(0) config_method(kex); config_method(hostkey); config_method(crypt_cs); config_method(crypt_sc); config_method(mac_cs); config_method(mac_sc); config_method(comp_cs); config_method(comp_sc); memset(&sockaddr, 0, sizeof(sockaddr)); sockaddr.sin6.sin6_family = check->target_family; if(check->target_family == AF_INET) { memcpy(&sockaddr.sin.sin_addr, &check->target_addr.addr, sizeof(sockaddr.sin.sin_addr)); sockaddr.sin.sin_port = htons(ssh_port); sockaddr_len = sizeof(sockaddr.sin); } else { memcpy(&sockaddr.sin6.sin6_addr, &check->target_addr.addr6, sizeof(sockaddr.sin6.sin6_addr)); sockaddr.sin6.sin6_port = htons(ssh_port); sockaddr_len = sizeof(sockaddr.sin6); } /* Initiate a connection */ rv = connect(fd, (struct sockaddr *)&sockaddr, sockaddr_len); if(rv == -1 && errno != EINPROGRESS) goto fail; /* Register a handler for connection completion */ e = eventer_alloc(); e->fd = fd; e->mask = EVENTER_READ | EVENTER_WRITE | EVENTER_EXCEPTION; e->callback = ssh2_connect_complete; e->closure = ci; ci->synch_fd_event = e; eventer_add(e); e = eventer_alloc(); e->mask = EVENTER_TIMER; e->callback = ssh2_connect_timeout; e->closure = ci; memcpy(&e->whence, &__now, sizeof(__now)); p_int.tv_sec = check->timeout / 1000; p_int.tv_usec = (check->timeout % 1000) * 1000; add_timeval(e->whence, p_int, &e->whence); ci->timeout_event = e; eventer_add(e); return 0; fail: if(fd >= 0) close(fd); ssh2_log_results(ci->self, ci->check); ssh2_cleanup(ci->self, ci->check); check->flags &= ~NP_RUNNING; return -1; }
static int eventer_epoll_impl_loop() { struct epoll_event *epev; struct epoll_spec *spec; spec = eventer_get_spec_for_event(NULL); epev = malloc(sizeof(*epev) * maxfds); #ifdef HAVE_SYS_EVENTFD_H if(spec->event_fd >= 0) { eventer_t e = eventer_alloc(); e->callback = eventer_epoll_eventfd_read; e->fd = spec->event_fd; e->mask = EVENTER_READ; eventer_add(e); } #endif while(1) { struct timeval __now, __sleeptime; int fd_cnt = 0; __sleeptime = eventer_max_sleeptime; mtev_gettimeofday(&__now, NULL); eventer_dispatch_timed(&__now, &__sleeptime); /* Handle cross_thread dispatches */ eventer_cross_thread_process(); /* Handle recurrent events */ eventer_dispatch_recurrent(&__now); /* Now we move on to our fd-based events */ do { fd_cnt = epoll_wait(spec->epoll_fd, epev, maxfds, __sleeptime.tv_sec * 1000 + __sleeptime.tv_usec / 1000); } while(fd_cnt < 0 && errno == EINTR); mtevLT(eventer_deb, &__now, "debug: epoll_wait(%d, [], %d) => %d\n", spec->epoll_fd, maxfds, fd_cnt); if(fd_cnt < 0) { mtevLT(eventer_err, &__now, "epoll_wait: %s\n", strerror(errno)); } else { int idx; /* loop once to clear */ for(idx = 0; idx < fd_cnt; idx++) { struct epoll_event *ev; eventer_t e; int fd, mask = 0; ev = &epev[idx]; if(ev->events & (EPOLLIN | EPOLLPRI)) mask |= EVENTER_READ; if(ev->events & (EPOLLOUT)) mask |= EVENTER_WRITE; if(ev->events & (EPOLLERR|EPOLLHUP)) mask |= EVENTER_EXCEPTION; fd = ev->data.fd; e = master_fds[fd].e; /* It's possible that someone removed the event and freed it * before we got here. */ if(!e) continue; eventer_epoll_impl_trigger(e, mask); } } } /* NOTREACHED */ return 0; }
static int noit_listener_acceptor(eventer_t e, int mask, void *closure, struct timeval *tv) { int conn, newmask = EVENTER_READ; socklen_t salen; listener_closure_t listener_closure = (listener_closure_t)closure; acceptor_closure_t *ac = NULL; if(mask & EVENTER_EXCEPTION) { socketfail: if(ac) acceptor_closure_free(ac); /* We don't shut down the socket, it's out listener! */ return EVENTER_READ | EVENTER_WRITE | EVENTER_EXCEPTION; } do { ac = malloc(sizeof(*ac)); memcpy(ac, listener_closure->dispatch_closure, sizeof(*ac)); salen = sizeof(ac->remote); conn = e->opset->accept(e->fd, &ac->remote.remote_addr, &salen, &newmask, e); if(conn >= 0) { eventer_t newe; noitL(nldeb, "noit_listener[%s] accepted fd %d\n", eventer_name_for_callback(listener_closure->dispatch_callback), conn); if(eventer_set_fd_nonblocking(conn)) { close(conn); free(ac); goto accept_bail; } newe = eventer_alloc(); newe->fd = conn; newe->mask = EVENTER_READ | EVENTER_WRITE | EVENTER_EXCEPTION; if(listener_closure->sslconfig->size) { const char *layer, *cert, *key, *ca, *ciphers, *crl; eventer_ssl_ctx_t *ctx; /* We have an SSL configuration. While our socket accept is * complete, we now have to SSL_accept, which could require * several reads and writes and needs its own event callback. */ #define SSLCONFGET(var,name) do { \ if(!noit_hash_retr_str(listener_closure->sslconfig, name, strlen(name), \ &var)) var = NULL; } while(0) SSLCONFGET(layer, "layer"); SSLCONFGET(cert, "certificate_file"); SSLCONFGET(key, "key_file"); SSLCONFGET(ca, "ca_chain"); SSLCONFGET(ciphers, "ciphers"); ctx = eventer_ssl_ctx_new(SSL_SERVER, layer, cert, key, ca, ciphers); if(!ctx) { newe->opset->close(newe->fd, &newmask, e); eventer_free(newe); goto socketfail; } SSLCONFGET(crl, "crl"); if(crl) { if(!eventer_ssl_use_crl(ctx, crl)) { noitL(noit_error, "Failed to load CRL from %s\n", crl); eventer_ssl_ctx_free(ctx); newe->opset->close(newe->fd, &newmask, e); eventer_free(newe); goto socketfail; } } eventer_ssl_ctx_set_verify(ctx, eventer_ssl_verify_cert, listener_closure->sslconfig); EVENTER_ATTACH_SSL(newe, ctx); newe->callback = noit_listener_accept_ssl; newe->closure = malloc(sizeof(*listener_closure)); memcpy(newe->closure, listener_closure, sizeof(*listener_closure)); ((listener_closure_t)newe->closure)->dispatch_closure = ac; } else { newe->callback = listener_closure->dispatch_callback; /* We must make a copy of the acceptor_closure_t for each new * connection. */ newe->closure = ac; } eventer_add(newe); } else { if(errno == EAGAIN) { if(ac) acceptor_closure_free(ac); } else if(errno != EINTR) { noitL(noit_error, "accept socket error: %s\n", strerror(errno)); goto socketfail; } } } while(conn >= 0); accept_bail: return newmask | EVENTER_EXCEPTION; }
static int noit_statsd_init(noit_module_t *self) { unsigned short port = 8125; int packets_per_cycle = 100; int payload_len = 256*1024; struct sockaddr_in skaddr; int sockaddr_len; const char *config_val; statsd_mod_config_t *conf; conf = noit_module_get_userdata(self); eventer_name_callback("statsd/statsd_handler", statsd_handler); if(noit_hash_retr_str(conf->options, "check", strlen("check"), (const char **)&config_val)) { if(uuid_parse((char *)config_val, conf->primary) != 0) noitL(noit_error, "statsd check isn't a UUID\n"); conf->primary_active = 1; conf->check = NULL; } if(noit_hash_retr_str(conf->options, "port", strlen("port"), (const char **)&config_val)) { port = atoi(config_val); } conf->port = port; if(noit_hash_retr_str(conf->options, "packets_per_cycle", strlen("packets_per_cycle"), (const char **)&config_val)) { packets_per_cycle = atoi(config_val); } conf->packets_per_cycle = packets_per_cycle; conf->payload_len = payload_len; conf->payload = malloc(conf->payload_len); if(!conf->payload) { noitL(noit_error, "statsd malloc() failed\n"); return -1; } conf->ipv4_fd = socket(PF_INET, NE_SOCK_CLOEXEC|SOCK_DGRAM, IPPROTO_UDP); if(conf->ipv4_fd < 0) { noitL(noit_error, "statsd: socket failed: %s\n", strerror(errno)); return -1; } else { if(eventer_set_fd_nonblocking(conf->ipv4_fd)) { close(conf->ipv4_fd); conf->ipv4_fd = -1; noitL(noit_error, "collectd: could not set socket non-blocking: %s\n", strerror(errno)); return -1; } } memset(&skaddr, 0, sizeof(skaddr)); skaddr.sin_family = AF_INET; skaddr.sin_addr.s_addr = htonl(INADDR_ANY); skaddr.sin_port = htons(conf->port); sockaddr_len = sizeof(skaddr); if(bind(conf->ipv4_fd, (struct sockaddr *)&skaddr, sockaddr_len) < 0) { noitL(noit_error, "bind failed[%d]: %s\n", conf->port, strerror(errno)); close(conf->ipv4_fd); return -1; } if(conf->ipv4_fd >= 0) { eventer_t newe; newe = eventer_alloc(); newe->fd = conf->ipv4_fd; newe->mask = EVENTER_READ | EVENTER_EXCEPTION; newe->callback = statsd_handler; newe->closure = self; eventer_add(newe); } conf->ipv6_fd = socket(AF_INET6, NE_SOCK_CLOEXEC|SOCK_DGRAM, IPPROTO_UDP); if(conf->ipv6_fd < 0) { noitL(noit_error, "statsd: IPv6 socket failed: %s\n", strerror(errno)); } else { if(eventer_set_fd_nonblocking(conf->ipv6_fd)) { close(conf->ipv6_fd); conf->ipv6_fd = -1; noitL(noit_error, "statsd: could not set socket non-blocking: %s\n", strerror(errno)); } else { struct sockaddr_in6 skaddr6; struct in6_addr in6addr_any; sockaddr_len = sizeof(skaddr6); memset(&skaddr6, 0, sizeof(skaddr6)); skaddr6.sin6_family = AF_INET6; memset(&in6addr_any, 0, sizeof(in6addr_any)); skaddr6.sin6_addr = in6addr_any; skaddr6.sin6_port = htons(conf->port); if(bind(conf->ipv6_fd, (struct sockaddr *)&skaddr6, sockaddr_len) < 0) { noitL(noit_error, "bind(IPv6) failed[%d]: %s\n", conf->port, strerror(errno)); close(conf->ipv6_fd); conf->ipv6_fd = -1; } } } if(conf->ipv6_fd >= 0) { eventer_t newe; newe = eventer_alloc(); newe->fd = conf->ipv6_fd; newe->mask = EVENTER_READ | EVENTER_EXCEPTION; newe->callback = statsd_handler; newe->closure = self; eventer_add(newe); } noit_module_set_userdata(self, conf); return 0; }
int noit_listener(char *host, unsigned short port, int type, int backlog, noit_hash_table *sslconfig, noit_hash_table *config, eventer_func_t handler, void *service_ctx) { int rv, fd; int8_t family; int sockaddr_len; socklen_t reuse; listener_closure_t listener_closure; eventer_t event; union { struct in_addr addr4; struct in6_addr addr6; } a; union { struct sockaddr_in addr4; struct sockaddr_in6 addr6; struct sockaddr_un addru; } s; const char *event_name; noitL(nldeb, "noit_listener(%s, %d, %d, %d, %s, %p)\n", host, port, type, backlog, (event_name = eventer_name_for_callback(handler))?event_name:"??", service_ctx); if(host[0] == '/') { family = AF_UNIX; } else { family = AF_INET; rv = inet_pton(family, host, &a); if(rv != 1) { family = AF_INET6; rv = inet_pton(family, host, &a); if(rv != 1) { if(!strcmp(host, "*")) { family = AF_INET; a.addr4.s_addr = INADDR_ANY; } else { noitL(noit_error, "Cannot translate '%s' to IP\n", host); return -1; } } } } fd = socket(family, NE_SOCK_CLOEXEC|type, 0); if(fd < 0) { noitL(noit_error, "Cannot create socket: %s\n", strerror(errno)); return -1; } if(eventer_set_fd_nonblocking(fd)) { close(fd); noitL(noit_error, "Cannot make socket non-blocking: %s\n", strerror(errno)); return -1; } reuse = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&reuse, sizeof(reuse)) != 0) { close(fd); noitL(noit_error, "Cannot set SO_REUSEADDR: %s\n", strerror(errno)); return -1; } memset(&s, 0, sizeof(s)); if(family == AF_UNIX) { struct stat sb; /* unlink the path if it is a socket */ /* coverity[fs_check_call] */ if(stat(host, &sb) == -1) { if(errno != ENOENT) { noitL(noit_error, "%s: %s\n", host, strerror(errno)); close(fd); return -1; } } else { if(sb.st_mode & S_IFSOCK) { /* coverity[toctou] */ unlink(host); } else { noitL(noit_error, "unlink %s failed: %s\n", host, strerror(errno)); close(fd); return -1; } } s.addru.sun_family = AF_UNIX; strncpy(s.addru.sun_path, host, sizeof(s.addru.sun_path)-1); sockaddr_len = sizeof(s.addru); } else { if(family == AF_INET6) { s.addr6.sin6_family = family; s.addr6.sin6_port = htons(port); memcpy(&s.addr6.sin6_addr, &a.addr6, sizeof(a.addr6)); } else { s.addr4.sin_family = family; s.addr4.sin_port = htons(port); memcpy(&s.addr4.sin_addr, &a.addr4, sizeof(a.addr4)); } sockaddr_len = (family == AF_INET) ? sizeof(s.addr4) : sizeof(s.addr6); } if(bind(fd, (struct sockaddr *)&s, sockaddr_len) < 0) { noitL(noit_error, "bind failed[%s]: %s\n", host, strerror(errno)); close(fd); return -1; } if(type == SOCK_STREAM) { if(listen(fd, backlog) < 0) { close(fd); return -1; } } listener_closure = calloc(1, sizeof(*listener_closure)); listener_closure->family = family; listener_closure->port = htons(port); listener_closure->sslconfig = calloc(1, sizeof(noit_hash_table)); noit_hash_merge_as_dict(listener_closure->sslconfig, sslconfig); listener_closure->dispatch_callback = handler; listener_closure->dispatch_closure = calloc(1, sizeof(*listener_closure->dispatch_closure)); listener_closure->dispatch_closure->config = config; listener_closure->dispatch_closure->dispatch = handler; listener_closure->dispatch_closure->service_ctx = service_ctx; event = eventer_alloc(); event->fd = fd; event->mask = EVENTER_READ | EVENTER_EXCEPTION; event->callback = noit_listener_acceptor; event->closure = listener_closure; eventer_add(event); return 0; }
static int dns_check_send(noit_module_t *self, noit_check_t *check, noit_check_t *cause) { void *vnv_pair = NULL; struct dns_nameval *nv_pair; eventer_t newe; struct timeval p_int, now; struct dns_check_info *ci = check->closure; const char *config_val; const char *rtype = NULL; const char *nameserver = NULL; int port = 0; const char *port_str = NULL; const char *want_sort = NULL; const char *ctype = "IN"; const char *query = NULL; char interpolated_nameserver[1024]; char interpolated_query[1024]; noit_hash_table check_attrs_hash = NOIT_HASH_EMPTY; BAIL_ON_RUNNING_CHECK(check); gettimeofday(&now, NULL); memcpy(&check->last_fire_time, &now, sizeof(now)); ci->current.state = NP_BAD; ci->current.available = NP_UNAVAILABLE; ci->timed_out = 1; ci->nrr = 0; ci->sort = 1; if(!strcmp(check->name, "in-addr.arpa") || (strlen(check->name) >= sizeof("::in-addr.arpa") - 1 && !strcmp(check->name + strlen(check->name) - sizeof("::in-addr.arpa") + 1, "::in-addr.arpa"))) { /* in-addr.arpa defaults: * nameserver to NULL * rtype to PTR * query to %[:inaddrarpa:target] */ nameserver = NULL; rtype = "PTR"; query = "%[:inaddrarpa:target_ip]"; } else { nameserver = "%[target_ip]"; rtype = "A"; query = "%[name]"; } if(noit_hash_retr_str(check->config, "port", strlen("port"), &port_str)) { port = atoi(port_str); } #define CONFIG_OVERRIDE(a) \ if(noit_hash_retr_str(check->config, #a, strlen(#a), \ &config_val) && \ strlen(config_val) > 0) \ a = config_val CONFIG_OVERRIDE(ctype); CONFIG_OVERRIDE(nameserver); CONFIG_OVERRIDE(rtype); CONFIG_OVERRIDE(query); CONFIG_OVERRIDE(want_sort); if(nameserver && !strcmp(nameserver, "default")) nameserver = NULL; if(want_sort && strcasecmp(want_sort, "on") && strcasecmp(want_sort, "true")) ci->sort = 0; noit_check_make_attrs(check, &check_attrs_hash); if(nameserver) { noit_check_interpolate(interpolated_nameserver, sizeof(interpolated_nameserver), nameserver, &check_attrs_hash, check->config); nameserver = interpolated_nameserver; } if(query) { noit_check_interpolate(interpolated_query, sizeof(interpolated_query), query, &check_attrs_hash, check->config); query = interpolated_query; } noit_hash_destroy(&check_attrs_hash, NULL, NULL); check->flags |= NP_RUNNING; noitL(nldeb, "dns_check_send(%p,%s,%s,%s,%s,%s)\n", self, check->target, nameserver ? nameserver : "default", query ? query : "null", ctype, rtype); __activate_ci(ci); /* If this ci has a handle and it isn't the one we need, * we should release it */ if(ci->h && ((ci->h->ns == NULL && nameserver != NULL) || (ci->h->ns != NULL && nameserver == NULL) || (ci->h->ns && strcmp(ci->h->ns, nameserver)))) { dns_ctx_release(ci->h); ci->h = NULL; } /* use the cached one, unless we don't have one */ if(!ci->h) ci->h = dns_ctx_alloc(nameserver, port); if(!ci->h) ci->error = strdup("bad nameserver"); /* Lookup out class */ if(!noit_hash_retrieve(&dns_ctypes, ctype, strlen(ctype), &vnv_pair)) { if(ci->error) free(ci->error); ci->error = strdup("bad class"); } else { nv_pair = (struct dns_nameval *)vnv_pair; ci->query_ctype = nv_pair->val; } /* Lookup out rr type */ if(!noit_hash_retrieve(&dns_rtypes, rtype, strlen(rtype), &vnv_pair)) { if(ci->error) free(ci->error); ci->error = strdup("bad rr type"); } else { nv_pair = (struct dns_nameval *)vnv_pair; ci->query_rtype = nv_pair->val; } if(!ci->error) { /* Submit the query */ int abs; if(!dns_ptodn(query, strlen(query), ci->dn, sizeof(ci->dn), &abs) || !dns_submit_dn(ci->h->ctx, ci->dn, ci->query_ctype, ci->query_rtype, abs | DNS_NOSRCH, NULL, dns_cb, ci)) { ci->error = strdup("submission error"); } else { dns_timeouts(ci->h->ctx, -1, now.tv_sec); } } /* we could have completed by now... if so, we've nothing to do */ if(!__isactive_ci(ci)) return 0; if(ci->error) { /* Errors here are easy, fail and avoid scheduling a timeout */ ci->check->flags &= ~NP_RUNNING; dns_check_log_results(ci); __deactivate_ci(ci); return 0; } newe = eventer_alloc(); newe->mask = EVENTER_TIMER; gettimeofday(&now, NULL); p_int.tv_sec = check->timeout / 1000; p_int.tv_usec = (check->timeout % 1000) * 1000; add_timeval(now, p_int, &newe->whence); newe->closure = ci; newe->callback = dns_check_timeout; ci->timeout_event = newe; eventer_add(newe); return 0; }
void noit_check_resolver_init() { int cnt; mtev_conf_section_t *servers, *searchdomains; eventer_t e; if(dns_init(NULL, 0) < 0) mtevL(noit_error, "dns initialization failed.\n"); dns_ctx = dns_new(NULL); if(dns_init(dns_ctx, 0) != 0) { mtevL(noit_error, "dns initialization failed.\n"); exit(-1); } /* Optional servers */ servers = mtev_conf_get_sections(NULL, "//resolver//server", &cnt); if(cnt) { int i; char server[128]; dns_add_serv(dns_ctx, NULL); /* reset */ for(i=0;i<cnt;i++) { if(mtev_conf_get_stringbuf(servers[i], "self::node()", server, sizeof(server))) { if(dns_add_serv(dns_ctx, server) < 0) { mtevL(noit_error, "Failed adding DNS server: %s\n", server); } } } free(servers); } searchdomains = mtev_conf_get_sections(NULL, "//resolver//search", &cnt); if(cnt) { int i; char search[128]; dns_add_srch(dns_ctx, NULL); /* reset */ for(i=0;i<cnt;i++) { if(mtev_conf_get_stringbuf(searchdomains[i], "self::node()", search, sizeof(search))) { if(dns_add_srch(dns_ctx, search) < 0) { mtevL(noit_error, "Failed adding DNS search path: %s\n", search); } else if(dns_search_flag) dns_search_flag = 0; /* enable search */ } } free(searchdomains); } if(mtev_conf_get_int(NULL, "//resolver/@ndots", &cnt)) dns_set_opt(dns_ctx, DNS_OPT_NDOTS, cnt); if(mtev_conf_get_int(NULL, "//resolver/@ntries", &cnt)) dns_set_opt(dns_ctx, DNS_OPT_NTRIES, cnt); if(mtev_conf_get_int(NULL, "//resolver/@timeout", &cnt)) dns_set_opt(dns_ctx, DNS_OPT_TIMEOUT, cnt); if(dns_open(dns_ctx) < 0) { mtevL(noit_error, "dns open failed.\n"); exit(-1); } eventer_name_callback("dns_cache_callback", dns_cache_callback); dns_set_tmcbck(dns_ctx, dns_cache_utm_fn, dns_ctx); e = eventer_alloc(); e->mask = EVENTER_READ | EVENTER_EXCEPTION; e->closure = dns_ctx; e->callback = dns_cache_callback; e->fd = dns_sock(dns_ctx); eventer_add(e); mtev_skiplist_init(&nc_dns_cache); mtev_skiplist_set_compare(&nc_dns_cache, name_lookup, name_lookup_k); mtev_skiplist_add_index(&nc_dns_cache, refresh_idx, refresh_idx_k); /* maybe load it from cache */ if(noit_resolver_cache_load_hook_exists()) { struct timeval now; char *key; void *data; int len; gettimeofday(&now, NULL); while(noit_resolver_cache_load_hook_invoke(&key, &data, &len) == MTEV_HOOK_CONTINUE) { dns_cache_node *n; n = calloc(1, sizeof(*n)); if(dns_cache_node_deserialize(n, data, len) >= 0) { n->target = strdup(key); /* if the TTL indicates that it will expire in less than 60 seconds * (including stuff that should have already expired), then fudge * the last_updated time to make it expire some random time within * the next 60 seconds. */ if(n->last_needed > now.tv_sec || n->last_updated > now.tv_sec) break; /* impossible */ n->last_needed = now.tv_sec; if(n->last_updated + n->ttl < now.tv_sec + 60) { int fudge = MIN(60, n->ttl) + 1; n->last_updated = now.tv_sec - n->ttl + (lrand48() % fudge); } DCLOCK(); mtev_skiplist_insert(&nc_dns_cache, n); DCUNLOCK(); n = NULL; } else { mtevL(noit_error, "Failed to deserialize resolver cache record.\n"); } if(n) dns_cache_node_free(n); if(key) free(key); if(data) free(data); } } noit_check_resolver_loop(NULL, 0, NULL, NULL); register_console_dns_cache_commands(); mtev_hash_init(&etc_hosts_cache); noit_check_etc_hosts_cache_refresh(NULL, 0, NULL, NULL); }
int noit_check_schedule_next(noit_module_t *self, struct timeval *last_check, noit_check_t *check, struct timeval *now, dispatch_func_t dispatch, noit_check_t *cause) { eventer_t newe; struct timeval period, earliest, diff; int64_t diffms, periodms, offsetms; recur_closure_t *rcl; int initial = last_check ? 1 : 0; assert(cause == NULL); assert(check->fire_event == NULL); if(check->period == 0) return 0; /* if last_check is not passed, we use the initial_schedule_time * otherwise, we set the initial_schedule_time */ if(!last_check) last_check = &check->initial_schedule_time; else memcpy(&check->initial_schedule_time, last_check, sizeof(*last_check)); if(NOIT_CHECK_DISABLED(check) || NOIT_CHECK_KILLED(check)) { if(!(check->flags & NP_TRANSIENT)) check_slots_dec_tv(last_check); memset(&check->initial_schedule_time, 0, sizeof(struct timeval)); return 0; } /* If we have an event, we know when we intended it to fire. This means * we should schedule that point + period. */ if(now) memcpy(&earliest, now, sizeof(earliest)); else gettimeofday(&earliest, NULL); /* If the check is unconfigured and needs resolving, we'll set the * period down a bit lower so we can pick up the resolution quickly. * The one exception is if this is the initial run. */ if(!initial && !NOIT_CHECK_RESOLVED(check) && NOIT_CHECK_SHOULD_RESOLVE(check) && check->period > 1000) { period.tv_sec = 1; period.tv_usec = 0; } else { period.tv_sec = check->period / 1000; period.tv_usec = (check->period % 1000) * 1000; } periodms = period.tv_sec * 1000 + period.tv_usec / 1000; newe = eventer_alloc(); /* calculate the differnet between the initial schedule time and "now" */ if(compare_timeval(earliest, *last_check) >= 0) { sub_timeval(earliest, *last_check, &diff); diffms = (int64_t)diff.tv_sec * 1000 + diff.tv_usec / 1000; } else { noitL(noit_error, "time is going backwards. abort.\n"); abort(); } /* determine the offset from initial schedule time that would place * us at the next period-aligned point past "now" */ offsetms = ((diffms / periodms) + 1) * periodms; diff.tv_sec = offsetms / 1000; diff.tv_usec = (offsetms % 1000) * 1000; memcpy(&newe->whence, last_check, sizeof(*last_check)); add_timeval(newe->whence, diff, &newe->whence); sub_timeval(newe->whence, earliest, &diff); diffms = (int64_t)diff.tv_sec * 1000 + (int)diff.tv_usec / 1000; assert(compare_timeval(newe->whence, earliest) > 0); newe->mask = EVENTER_TIMER; newe->callback = noit_check_recur_handler; rcl = calloc(1, sizeof(*rcl)); rcl->self = self; rcl->check = check; rcl->cause = cause; rcl->dispatch = dispatch; newe->closure = rcl; eventer_add(newe); check->fire_event = newe; return diffms; }
static dns_ctx_handle_t *dns_module_dns_ctx_alloc(noit_module_t *self, const char *ns, int port) { void *vh; char *hk = NULL; dns_mod_config_t *conf = noit_module_get_userdata(self); int randkey = random() % conf->contexts; dns_ctx_handle_t *h = NULL; if(ns && *ns == '\0') ns = NULL; pthread_mutex_lock(&dns_ctx_store_lock); if(ns == NULL && default_ctx_handle != NULL) { /* special case -- default context */ h = default_ctx_handle; dns_module_dns_ctx_acquire(h); goto bail; } if (ns != NULL) { int len = snprintf(NULL, 0, "%s:%d:%d", ns, port, randkey); hk = (char *)malloc(len+1); snprintf(hk, len+1, "%s:%d:%d", ns, port, randkey); } if(ns && noit_hash_retrieve(&dns_ctx_store, hk, strlen(hk), &vh)) { h = (dns_ctx_handle_t *)vh; dns_module_dns_ctx_acquire(h); free(hk); } else { int failed = 0; h = calloc(1, sizeof(*h)); h->ns = ns ? strdup(ns) : NULL; h->ctx = dns_new(NULL); if(dns_init(h->ctx, 0) != 0) { noitL(nlerr, "dns_init failed\n"); failed++; } dns_set_dbgfn(h->ctx, dns_debug_wrap); if(ns) { if(dns_add_serv(h->ctx, NULL) < 0) { noitL(nlerr, "dns_add_serv(NULL) failed\n"); failed++; } if(dns_add_serv(h->ctx, ns) < 0) { noitL(nlerr, "dns_add_serv(%s) failed\n", ns); failed++; } } if(port && port != DNS_PORT) { dns_set_opt(h->ctx, DNS_OPT_PORT, port); } if(dns_open(h->ctx) < 0) { noitL(nlerr, "dns_open failed\n"); failed++; } if(failed) { free(h->ns); dns_free(h->ctx); free(h); free(hk); h = NULL; goto bail; } h->hkey = hk; dns_set_tmcbck(h->ctx, dns_module_eventer_dns_utm_fn, h); h->e = eventer_alloc(); h->e->mask = EVENTER_READ | EVENTER_EXCEPTION; h->e->closure = h; h->e->callback = dns_module_eventer_callback; h->e->fd = dns_sock(h->ctx); eventer_add(h->e); h->refcnt = 1; if(!ns) default_ctx_handle = h; else noit_hash_store(&dns_ctx_store, h->hkey, strlen(h->hkey), h); } bail: pthread_mutex_unlock(&dns_ctx_store_lock); return h; }