static int external_enqueue(eventer_t e, int mask, void *closure, struct timeval *now) { external_closure_t *ecl = (external_closure_t *)closure; struct check_info *ci = (struct check_info *)ecl->check->closure; external_data_t *data; int fd, i; if(mask == EVENTER_ASYNCH_CLEANUP) { e->mask = 0; return 0; } if(!(mask & EVENTER_ASYNCH_WORK)) return 0; data = noit_module_get_userdata(ecl->self); fd = data->pipe_n2e[1]; assert_write(fd, &ci->check_no, sizeof(ci->check_no)); assert_write(fd, &ci->argcnt, sizeof(ci->argcnt)); assert_write(fd, ci->arglens, sizeof(*ci->arglens)*ci->argcnt); for(i=0; i<ci->argcnt; i++) assert_write(fd, ci->args[i], ci->arglens[i]); assert_write(fd, &ci->envcnt, sizeof(ci->envcnt)); assert_write(fd, ci->envlens, sizeof(*ci->envlens)*ci->envcnt); for(i=0; i<ci->envcnt; i++) assert_write(fd, ci->envs[i], ci->envlens[i]); return 0; }
static int noit_lua_module_config(noit_module_t *mod, mtev_hash_table *options) { struct module_conf *mc; struct module_tls_conf *mtlsc; LMC_DECL(L, mod, object); mc = noit_module_get_userdata(mod); if(options) { mtevAssert(mc->options == NULL); mc->options = calloc(1, sizeof(*mc->options)); mtev_hash_init(mc->options); mtev_hash_merge_as_dict(mc->options, options); } else options = mc->options; mtlsc = __get_module_tls_conf(&mod->hdr); if(mtlsc->configured) return mtlsc->configured_return; SETUP_CALL(L, object, "config", return 0); noit_lua_setup_module(L, mod); mtev_lua_hash_to_table(L, options); lua_pcall(L, 2, 1, 0); /* If rv == 0, the caller will free options. We've * already freed options, that would be bad. fudge -> 1 */ RETURN_INT(L, object, "config", { mtlsc->configured = 1; mtlsc->configured_return = rv; });
static int noit_httptrap_init(noit_module_t *self) { const char *config_val; httptrap_mod_config_t *conf; conf = noit_module_get_userdata(self); conf->asynch_metrics = mtev_true; if(mtev_hash_retr_str(conf->options, "asynch_metrics", strlen("asynch_metrics"), (const char **)&config_val)) { if(!strcasecmp(config_val, "false") || !strcasecmp(config_val, "off")) conf->asynch_metrics = mtev_false; } httptrap_surrogate = mtev_false; if(mtev_hash_retr_str(conf->options, "surrogate", strlen("surrogate"), (const char **)&config_val)) { if(!strcasecmp(config_val, "true") || !strcasecmp(config_val, "on")) httptrap_surrogate = mtev_true; } noit_module_set_userdata(self, conf); /* register rest handler */ mtev_http_rest_register("PUT", "/module/httptrap/", "^(" UUID_REGEX ")/([^/]*).*$", rest_httptrap_handler); mtev_http_rest_register("POST", "/module/httptrap/", "^(" UUID_REGEX ")/([^/]*).*$", rest_httptrap_handler); return 0; }
static int statsd_handler(eventer_t e, int mask, void *closure, struct timeval *now) { noit_module_t *self = (noit_module_t *)closure; int packets_per_cycle; statsd_mod_config_t *conf; noit_check_t *parent = NULL; conf = noit_module_get_userdata(self); if(conf->primary_active) parent = noit_poller_lookup(conf->primary); packets_per_cycle = MAX(conf->packets_per_cycle, 1); for( ; packets_per_cycle > 0; packets_per_cycle--) { noit_check_t *checks[MAX_CHECKS]; int nchecks = 0; char ip[INET6_ADDRSTRLEN]; union { struct sockaddr_in in; struct sockaddr_in6 in6; } addr; socklen_t addrlen = sizeof(addr); ssize_t len; uuid_t check_id; len = recvfrom(e->fd, conf->payload, conf->payload_len-1, 0, (struct sockaddr *)&addr, &addrlen); if(len < 0) { if(errno != EAGAIN) noitL(nlerr, "statsd: recvfrom() -> %s\n", strerror(errno)); break; } switch(addr.in.sin_family) { case AF_INET: addrlen = sizeof(struct sockaddr_in); inet_ntop(AF_INET, &((struct sockaddr_in *)&addr)->sin_addr, ip, addrlen); break; case AF_INET6: addrlen = sizeof(struct sockaddr_in6); inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&addr)->sin6_addr, ip, addrlen); break; default: ip[0] = '\0'; } conf->payload[len] = '\0'; nchecks = 0; if(*ip) nchecks = noit_poller_lookup_by_ip_module(ip, self->hdr.name, checks, MAX_CHECKS-1); noitL(nldeb, "statsd(%d bytes) from '%s' -> %d checks%s\n", (int)len, ip, (int)nchecks, parent ? " + a parent" : ""); if(parent) checks[nchecks++] = parent; if(nchecks) statsd_handle_payload(checks, nchecks, conf->payload, len); } return EVENTER_READ | EVENTER_EXCEPTION; }
static int statsd_submit(noit_module_t *self, noit_check_t *check, noit_check_t *cause) { statsd_closure_t *ccl; struct timeval duration; statsd_mod_config_t *conf; conf = noit_module_get_userdata(self); if(!conf->primary_active) conf->check = NULL; if(0 == memcmp(conf->primary, check->checkid, sizeof(uuid_t))) { conf->check = check; if(NOIT_CHECK_DISABLED(check) || NOIT_CHECK_KILLED(check)) { conf->check = NULL; return 0; } } /* We are passive, so we don't do anything for transient checks */ if(check->flags & NP_TRANSIENT) return 0; if(!check->closure) { ccl = check->closure = calloc(1, sizeof(*ccl)); ccl->self = self; memset(&check->stats.inprogress, 0, sizeof(check->stats.inprogress)); } else { // Don't count the first run char human_buffer[256]; ccl = (statsd_closure_t*)check->closure; gettimeofday(&check->stats.inprogress.whence, NULL); sub_timeval(check->stats.inprogress.whence, check->last_fire_time, &duration); check->stats.inprogress.duration = duration.tv_sec * 1000 + duration.tv_usec / 1000; snprintf(human_buffer, sizeof(human_buffer), "dur=%d,run=%d,stats=%d", check->stats.inprogress.duration, check->generation, ccl->stats_count); noitL(nldeb, "statsd(%s) [%s]\n", check->target, human_buffer); // Not sure what to do here check->stats.inprogress.available = (ccl->stats_count > 0) ? NP_AVAILABLE : NP_UNAVAILABLE; check->stats.inprogress.state = (ccl->stats_count > 0) ? NP_GOOD : NP_BAD; check->stats.inprogress.status = human_buffer; if(check->last_fire_time.tv_sec) noit_check_passive_set_stats(check, &check->stats.inprogress); memcpy(&check->last_fire_time, &check->stats.inprogress.whence, sizeof(duration)); } ccl->stats_count = 0; noit_check_stats_clear(check, &check->stats.inprogress); return 0; }
static int noit_statsd_config(noit_module_t *self, noit_hash_table *options) { statsd_mod_config_t *conf; conf = noit_module_get_userdata(self); if(conf) { if(conf->options) { noit_hash_destroy(conf->options, free, free); free(conf->options); } } else conf = calloc(1, sizeof(*conf)); conf->options = options; noit_module_set_userdata(self, conf); return 1; }
static int dns_module_init(noit_module_t *self) { const struct dns_nameval *nv; struct dns_ctx *pctx; int i; const char *config_val; dns_mod_config_t *conf; conf = noit_module_get_userdata(self); pthread_mutex_init(&dns_ctx_store_lock, NULL); pthread_mutex_init(&active_events_lock, NULL); conf->contexts = DEFAULT_MAX_CONTEXTS; if(noit_hash_retr_str(conf->options, "contexts", strlen("contexts"), (const char**)&config_val)) { conf->contexts = atoi(config_val); if (conf->contexts <= 0) conf->contexts = DEFAULT_MAX_CONTEXTS; } /* HASH the rr types */ for(i=0, nv = dns_type_index(i); nv->name; nv = dns_type_index(++i)) noit_hash_store(&dns_rtypes, nv->name, strlen(nv->name), (void *)nv); /* HASH the class types */ for(i=0, nv = dns_class_index(i); nv->name; nv = dns_class_index(++i)) noit_hash_store(&dns_ctypes, nv->name, strlen(nv->name), (void *)nv); noit_check_interpolate_register_oper_fn("inaddrarpa", dns_interpolate_inaddr_arpa); noit_check_interpolate_register_oper_fn("reverseip", dns_interpolate_reverse_ip); if (dns_init(NULL, 0) < 0 || (pctx = dns_new(NULL)) == NULL) { noitL(nlerr, "Unable to initialize dns subsystem\n"); return -1; } dns_free(pctx); if(dns_module_dns_ctx_alloc(self, NULL, 0) == NULL) { noitL(nlerr, "Error setting up default dns resolver context.\n"); return -1; } register_console_dns_commands(); return 0; }
static int external_config(noit_module_t *self, noit_hash_table *options) { external_data_t *data; data = noit_module_get_userdata(self); if(data) { if(data->options) { noit_hash_destroy(data->options, free, free); free(data->options); } } else data = calloc(1, sizeof(*data)); data->options = options; if(!data->options) data->options = calloc(1, sizeof(*data->options)); noit_module_set_userdata(self, data); return 1; }
struct target_session * _get_target_session(noit_module_t *self, char *target) { void *vts; struct target_session *ts; snmp_mod_config_t *conf; conf = noit_module_get_userdata(self); if(!noit_hash_retrieve(&conf->target_sessions, target, strlen(target), &vts)) { ts = calloc(1, sizeof(*ts)); ts->self = self; ts->fd = -1; ts->refcnt = 0; ts->target = strdup(target); ts->in_table = 1; noit_hash_store(&conf->target_sessions, ts->target, strlen(ts->target), ts); vts = ts; } return (struct target_session *)vts; }
static int ping_icmp_timeout(eventer_t e, int mask, void *closure, struct timeval *now) { struct ping_closure *pcl = (struct ping_closure *)closure; struct ping_session_key k; struct check_info *data; ping_icmp_data_t *ping_data; if(!NOIT_CHECK_KILLED(pcl->check) && !NOIT_CHECK_DISABLED(pcl->check)) { ping_icmp_log_results(pcl->self, pcl->check); } data = (struct check_info *)pcl->check->closure; data->timeout_event = NULL; pcl->check->flags &= ~NP_RUNNING; ping_data = noit_module_get_userdata(pcl->self); k.addr_of_check = (vpsized_uint)pcl->check ^ random_num; uuid_copy(k.checkid, pcl->check->checkid); mtev_hash_delete(ping_data->in_flight, (const char *)&k, sizeof(k), free, NULL); free(pcl); return 0; }
static mtev_boolean mtev_httptrap_check_aynsch(noit_module_t *self, noit_check_t *check) { const char *config_val; httptrap_mod_config_t *conf; if(!self) return mtev_true; conf = noit_module_get_userdata(self); if(!conf) return mtev_true; mtev_boolean is_asynch = conf->asynch_metrics; if(mtev_hash_retr_str(check->config, "asynch_metrics", strlen("asynch_metrics"), (const char **)&config_val)) { if(!strcasecmp(config_val, "false") || !strcasecmp(config_val, "off")) is_asynch = mtev_false; else if(!strcasecmp(config_val, "true") || !strcasecmp(config_val, "on")) is_asynch = mtev_true; } if(is_asynch) check->flags |= NP_SUPPRESS_METRICS; else check->flags &= ~NP_SUPPRESS_METRICS; return is_asynch; }
struct target_session * _get_target_session(noit_module_t *self, char *target, int version) { char key[128]; void *vts; struct target_session *ts; snmp_mod_config_t *conf; conf = noit_module_get_userdata(self); snprintf(key, sizeof(key), "%s:v%d", target, version); if(!noit_hash_retrieve(&conf->target_sessions, key, strlen(key), &vts)) { ts = calloc(1, sizeof(*ts)); ts->self = self; ts->version = version; ts->fd = -1; ts->refcnt = 0; ts->target = strdup(target); ts->key = strdup(key); ts->in_table = 1; noit_hash_store(&conf->target_sessions, ts->key, strlen(ts->key), ts); vts = ts; } return (struct target_session *)vts; }
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 external_handler(eventer_t e, int mask, void *closure, struct timeval *now) { noit_module_t *self = (noit_module_t *)closure; external_data_t *data; data = noit_module_get_userdata(self); while(1) { int inlen, expectlen; noit_check_t *check; struct check_info *ci; void *vci; if(!data->cr) { struct external_response r; struct msghdr msg; struct iovec v[3]; memset(&r, 0, sizeof(r)); v[0].iov_base = (char *)&r.check_no; v[0].iov_len = sizeof(r.check_no); v[1].iov_base = (char *)&r.exit_code; v[1].iov_len = sizeof(r.exit_code); v[2].iov_base = (char *)&r.stdoutlen; v[2].iov_len = sizeof(r.stdoutlen); expectlen = v[0].iov_len + v[1].iov_len + v[2].iov_len; /* Make this into a recv'ble message so we can PEEK */ memset(&msg, 0, sizeof(msg)); msg.msg_iov = v; msg.msg_iovlen = 3; inlen = recvmsg(e->fd, &msg, MSG_PEEK); if(inlen == 0) goto widowed; if((inlen == -1 && errno == EAGAIN) || (inlen > 0 && inlen < expectlen)) return EVENTER_READ | EVENTER_EXCEPTION; if(inlen == -1) noitL(noit_error, "recvmsg() failed: %s\n", strerror(errno)); assert(inlen == expectlen); while(-1 == (inlen = recvmsg(e->fd, &msg, 0)) && errno == EINTR); assert(inlen == expectlen); data->cr = calloc(sizeof(*data->cr), 1); memcpy(data->cr, &r, sizeof(r)); data->cr->stdoutbuff = malloc(data->cr->stdoutlen); } if(data->cr) { while(data->cr->stdoutlen_sofar < data->cr->stdoutlen) { while((inlen = read(e->fd, data->cr->stdoutbuff + data->cr->stdoutlen_sofar, data->cr->stdoutlen - data->cr->stdoutlen_sofar)) == -1 && errno == EINTR); if(inlen == -1 && errno == EAGAIN) return EVENTER_READ | EVENTER_EXCEPTION; if(inlen == 0) goto widowed; data->cr->stdoutlen_sofar += inlen; } assert(data->cr->stdoutbuff[data->cr->stdoutlen-1] == '\0'); if(!data->cr->stderrbuff) { while((inlen = read(e->fd, &data->cr->stderrlen, sizeof(data->cr->stderrlen))) == -1 && errno == EINTR); if(inlen == -1 && errno == EAGAIN) return EVENTER_READ | EVENTER_EXCEPTION; if(inlen == 0) goto widowed; assert(inlen == sizeof(data->cr->stderrlen)); data->cr->stderrbuff = malloc(data->cr->stderrlen); } while(data->cr->stderrlen_sofar < data->cr->stderrlen) { while((inlen = read(e->fd, data->cr->stderrbuff + data->cr->stderrlen_sofar, data->cr->stderrlen - data->cr->stderrlen_sofar)) == -1 && errno == EINTR); if(inlen == -1 && errno == EAGAIN) return EVENTER_READ | EVENTER_EXCEPTION; if(inlen == 0) goto widowed; data->cr->stderrlen_sofar += inlen; } assert(data->cr->stderrbuff[data->cr->stderrlen-1] == '\0'); } assert(data->cr && data->cr->stdoutbuff && data->cr->stderrbuff); gettimeofday(now, NULL); /* set it, as we care about accuracy */ /* Lookup data in check_no hash */ if(noit_hash_retrieve(&data->external_checks, (const char *)&data->cr->check_no, sizeof(data->cr->check_no), &vci) == 0) vci = NULL; ci = (struct check_info *)vci; /* We've seen it, it ain't coming again... * remove it, we'll free it ourselves */ noit_hash_delete(&data->external_checks, (const char *)&data->cr->check_no, sizeof(data->cr->check_no), NULL, NULL); /* If there is no timeout_event, the check must have completed. * We have nothing to do. */ if(!ci || !ci->timeout_event) { free(data->cr->stdoutbuff); free(data->cr->stderrbuff); free(data->cr); data->cr = NULL; continue; } ci->exit_code = data->cr->exit_code; ci->output = data->cr->stdoutbuff; ci->error = data->cr->stderrbuff; free(data->cr); data->cr = NULL; check = ci->check; external_log_results(self, check); eventer_remove(ci->timeout_event); free(ci->timeout_event->closure); eventer_free(ci->timeout_event); ci->timeout_event = NULL; check->flags &= ~NP_RUNNING; } widowed: noitL(noit_error, "external module terminated, must restart.\n"); exit(1); }
static void external_log_results(noit_module_t *self, noit_check_t *check) { external_data_t *data; struct check_info *ci; stats_t current; struct timeval duration; noit_check_stats_clear(¤t); data = noit_module_get_userdata(self); ci = (struct check_info *)check->closure; noitL(data->nldeb, "external(%s) (timeout: %d, exit: %x)\n", check->target, ci->timedout, ci->exit_code); gettimeofday(¤t.whence, NULL); sub_timeval(current.whence, check->last_fire_time, &duration); current.duration = duration.tv_sec * 1000 + duration.tv_usec / 1000; if(ci->timedout) { current.available = NP_UNAVAILABLE; current.state = NP_BAD; } else if(WEXITSTATUS(ci->exit_code) == 3) { current.available = NP_UNKNOWN; current.state = NP_UNKNOWN; } else { current.available = NP_AVAILABLE; current.state = (WEXITSTATUS(ci->exit_code) == 0) ? NP_GOOD : NP_BAD; } /* Hack the output into metrics */ if(ci->output && ci->matcher) { int rc, len, startoffset = 0; int ovector[30]; len = strlen(ci->output); noitL(data->nldeb, "going to match output at %d/%d\n", startoffset, len); while((rc = pcre_exec(ci->matcher, NULL, ci->output, len, startoffset, 0, ovector, sizeof(ovector)/sizeof(*ovector))) > 0) { char metric[128]; char value[128]; startoffset = ovector[1]; noitL(data->nldeb, "matched at offset %d\n", rc); if(pcre_copy_named_substring(ci->matcher, ci->output, ovector, rc, "key", metric, sizeof(metric)) > 0 && pcre_copy_named_substring(ci->matcher, ci->output, ovector, rc, "value", value, sizeof(value)) > 0) { /* We're able to extract something... */ noit_stats_set_metric(¤t, metric, METRIC_GUESS, value); } noitL(data->nldeb, "going to match output at %d/%d\n", startoffset, len); } noitL(data->nldeb, "match failed.... %d\n", rc); } current.status = ci->output; noit_check_set_stats(self, check, ¤t); /* If we didn't exit normally, or we core, or we have stderr to report... * provide a full report. */ if((WTERMSIG(ci->exit_code) != SIGQUIT && WTERMSIG(ci->exit_code) != 0) || WCOREDUMP(ci->exit_code) || (ci->error && *ci->error)) { char uuid_str[37]; uuid_unparse_lower(check->checkid, uuid_str); noitL(data->nlerr, "external/%s: (sig:%d%s) [%s]\n", uuid_str, WTERMSIG(ci->exit_code), WCOREDUMP(ci->exit_code)?", cored":"", ci->error ? ci->error : ""); } }
static int ping_icmp_handler(eventer_t e, int mask, void *closure, struct timeval *now, u_int8_t family) { noit_module_t *self = (noit_module_t *)closure; ping_icmp_data_t *ping_data; struct check_info *data; char packet[1500]; int packet_len = sizeof(packet); union { struct sockaddr_in in4; struct sockaddr_in6 in6; } from; unsigned int from_len; struct ping_payload *payload; if(family != AF_INET && family != AF_INET6) return EVENTER_READ; ping_data = noit_module_get_userdata(self); while(1) { struct ping_session_key k; int inlen; u_int8_t iphlen = 0; void *vcheck; noit_check_t *check; struct timeval tt, whence; from_len = sizeof(from); inlen = recvfrom(e->fd, packet, packet_len, 0, (struct sockaddr *)&from, &from_len); mtev_gettimeofday(now, NULL); /* set it, as we care about accuracy */ if(inlen < 0) { if(errno == EAGAIN || errno == EINTR) break; mtevLT(nldeb, now, "ping_icmp recvfrom: %s\n", strerror(errno)); break; } if(family == AF_INET) { struct icmp *icp4; iphlen = ((struct ip *)packet)->ip_hl << 2; if((inlen-iphlen) != sizeof(struct icmp)+PING_PAYLOAD_LEN) { mtevLT(nldeb, now, "ping_icmp bad size: %d+%d\n", iphlen, inlen-iphlen); continue; } icp4 = (struct icmp *)(packet + iphlen); payload = (struct ping_payload *)(icp4 + 1); if(icp4->icmp_type != ICMP_ECHOREPLY) { mtevLT(nldeb, now, "ping_icmp bad type: %d\n", icp4->icmp_type); continue; } if(icp4->icmp_id != (((vpsized_uint)self) & 0xffff)) { mtevLT(nldeb, now, "ping_icmp not sent from this instance (%d:%d) vs. %lu\n", icp4->icmp_id, ntohs(icp4->icmp_seq), (unsigned long)(((vpsized_uint)self) & 0xffff)); continue; } } else if(family == AF_INET6) { struct icmp6_hdr *icp6 = (struct icmp6_hdr *)packet; if((inlen) != sizeof(struct icmp6_hdr)+PING_PAYLOAD_LEN) { mtevLT(nldeb, now, "ping_icmp bad size: %d+%d\n", iphlen, inlen-iphlen); continue; } payload = (struct ping_payload *)(icp6+1); if(icp6->icmp6_type != ICMP6_ECHO_REPLY) { mtevLT(nldeb, now, "ping_icmp bad type: %d\n", icp6->icmp6_type); continue; } if(icp6->icmp6_id != (((vpsized_uint)self) & 0xffff)) { mtevLT(nldeb, now, "ping_icmp not sent from this instance (%d:%d) vs. %lu\n", icp6->icmp6_id, ntohs(icp6->icmp6_seq), (unsigned long)(((vpsized_uint)self) & 0xffff)); continue; } } else { /* This should be unreachable */ continue; } check = NULL; k.addr_of_check = payload->addr_of_check; uuid_copy(k.checkid, payload->checkid); if(mtev_hash_retrieve(ping_data->in_flight, (const char *)&k, sizeof(k), &vcheck)) check = vcheck; /* make sure this check is from this generation! */ if(!check) { char uuid_str[37]; uuid_unparse_lower(payload->checkid, uuid_str); mtevLT(nldeb, now, "ping_icmp response for unknown check '%s'\n", uuid_str); continue; } if((check->generation & 0xffff) != payload->generation) { mtevLT(nldeb, now, "ping_icmp response in generation gap\n"); continue; } data = (struct check_info *)check->closure; /* If there is no timeout_event, the check must have completed. * We have nothing to do. */ if(!data->timeout_event) continue; /* Sanity check the payload */ if(payload->check_no != data->check_no) continue; if(payload->check_pack_cnt != data->expected_count) continue; if(payload->check_pack_no >= data->expected_count) continue; whence.tv_sec = payload->tv_sec; whence.tv_usec = payload->tv_usec; sub_timeval(*now, whence, &tt); data->turnaround[payload->check_pack_no] = (float)tt.tv_sec + (float)tt.tv_usec / 1000000.0; if(ping_icmp_is_complete(self, check)) { ping_icmp_log_results(self, check); eventer_remove(data->timeout_event); free(data->timeout_event->closure); eventer_free(data->timeout_event); data->timeout_event = NULL; check->flags &= ~NP_RUNNING; k.addr_of_check = (vpsized_uint)check ^ random_num; uuid_copy(k.checkid, check->checkid); mtev_hash_delete(ping_data->in_flight, (const char *)&k, sizeof(k), free, NULL); } } return EVENTER_READ; }
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; }
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 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; }