void mtev_skiplist_add_index(mtev_skiplist *sl, mtev_skiplist_comparator_t comp, mtev_skiplist_comparator_t compk) { mtev_skiplist_node *m = NULL; mtev_skiplist *ni; int icount=0; mtev_skiplist_find(sl->index, (void *)comp, &m); if(m) return; /* Index already there! */ ni = (mtev_skiplist *)malloc(sizeof(mtev_skiplist)); mtev_skiplisti_init(ni); mtev_skiplist_set_compare(ni, comp, compk); /* Build the new index... This can be expensive! */ m = mtev_skiplist_insert(sl->index, ni); while(m->prev) m=m->prev, icount++; for(m=mtev_skiplist_getlist(sl); m; mtev_skiplist_next(sl, &m)) { int j=icount-1; mtev_skiplist_node *nsln; nsln = mtev_skiplist_insert(ni, m->data); /* skip from main index down list */ while(j>0) m=m->nextindex, j--; /* insert this node in the indexlist after m */ nsln->nextindex = m->nextindex; if(m->nextindex) m->nextindex->previndex = nsln; nsln->previndex = m; m->nextindex = nsln; } }
static void blank_update_v6(dns_cache_node *n) { if(n->ip6) free(n->ip6); n->ip6 = NULL; n->ip6_cnt = 0; mtev_skiplist_remove(&nc_dns_cache, n->target, NULL); n->last_updated = time(NULL); if (n->lookup_inflight_v4) { n->ttl = DEFAULT_FAILED_TTL; } n->lookup_inflight_v6 = mtev_false; mtev_skiplist_insert(&nc_dns_cache, n); }
static int rest_test_check(mtev_http_rest_closure_t *restc, int npats, char **pats) { noit_check_t *tcheck; mtev_http_session_ctx *ctx = restc->http_ctx; int mask, complete = 0; int error_code = 500; const char *error = "internal error"; xmlDocPtr indoc, doc = NULL; xmlNodePtr attr, config, root; indoc = rest_get_xml_upload(restc, &mask, &complete); if(!complete) return mask; if(indoc == NULL) { error = "xml parse error"; goto error; } if(!noit_validate_check_rest_post(indoc, &attr, &config, &error)) goto error; tcheck = noit_fire_check(attr, config, &error); if(tcheck) { /* push the check and the context into a queue to complete on */ struct check_test_closure *cl; cl = calloc(1, sizeof(*cl)); if(npats == 1 && !strcmp(pats[0], ".json")) cl->output = WANTS_JSON; cl->check = tcheck; cl->restc = restc; mtev_skiplist_insert(&in_progress, cl); check_test_schedule_sweeper(); if(restc->call_closure_free) restc->call_closure_free(restc->call_closure); restc->call_closure_free = NULL; restc->call_closure = NULL; restc->fastpath = rest_test_check_err; goto cleanup; } error: mtev_http_response_standard(ctx, error_code, "ERROR", "text/xml"); doc = xmlNewDoc((xmlChar *)"1.0"); root = xmlNewDocNode(doc, NULL, (xmlChar *)"error", NULL); xmlDocSetRootElement(doc, root); xmlNodeAddContent(root, (xmlChar *)error); mtev_http_response_xml(ctx, doc); mtev_http_response_end(ctx); goto cleanup; cleanup: if(doc) xmlFreeDoc(doc); return 0; }
int external_proc_spawn(struct proc_state *ps) { int i, stdin_fd; char stdoutfile[PATH_MAX]; char stderrfile[PATH_MAX]; mtevL(nldeb, "About to spawn: (%s)\n", ps->path); strlcpy(stdoutfile, "/tmp/noitext.XXXXXX", PATH_MAX); ps->stdout_fd = mkstemp(stdoutfile); if(ps->stdout_fd < 0) goto prefork_fail; unlink(stdoutfile); strlcpy(stderrfile, "/tmp/noitext.XXXXXX", PATH_MAX); ps->stderr_fd = mkstemp(stderrfile); if(ps->stderr_fd < 0) goto prefork_fail; unlink(stderrfile); ps->pid = fork(); if(ps->pid == -1) goto prefork_fail; /* Here.. fork has succeeded */ if(ps->pid) { mtev_skiplist_insert(&active_procs, ps); return 0; } /* Run the process */ stdin_fd = open("/dev/null", O_RDONLY); if(stdin_fd < 0) close(0); else dup2(stdin_fd, 0); dup2(ps->stdout_fd, 1); dup2(ps->stderr_fd, 2); /* Shut off everything but std{in,out,err} */ for(i=3;i<256;i++) close(i); execve(ps->path, ps->argv, ps->envp); exit(-1); prefork_fail: ps->status = -1; mtev_skiplist_insert(&done_procs, ps); return -1; }
static void noit_check_resolver_remind_internal(const char *target, mtev_boolean needs_lock) { dns_cache_node *n; if(!target) return; if(needs_lock) DCLOCK(); n = mtev_skiplist_find(&nc_dns_cache, target, NULL); if(n != NULL) { n->last_needed = time(NULL); if(needs_lock) DCUNLOCK(); return; } n = calloc(1, sizeof(*n)); n->target = strdup(target); n->last_needed = time(NULL); mtev_skiplist_insert(&nc_dns_cache, n); if(needs_lock) DCUNLOCK(); }
static void process_siglist() { mtev_skiplist_node *iter = NULL; struct proc_state *ps; pid_t pid; while(1) { int status = 0; pid = waitpid(0, &status, WNOHANG); if(pid <= 0) break; ps = mtev_skiplist_find_compare(&active_procs, &pid, &iter, __proc_state_pid); mtevL((ps?nldeb:nlerr), "reaped pid %d (check: %lld) -> %x\n", pid, (long long int)(ps?ps->check_no:-1), status); if(ps) { int rv = mtev_skiplist_remove_compare(&active_procs, &ps->pid, NULL, __proc_state_pid); if (!rv) { mtevL(noit_error, "error: couldn't remove PID %d from active_procs in external\n", ps->pid); } mtev_skiplist_insert(&done_procs, ps); } } }
mtev_skiplist_node *mtev_skiplist_insert_compare(mtev_skiplist *sl, const void *data, mtev_skiplist_comparator_t comp) { mtev_skiplist_node *m, *p, *tmp, *ret = NULL, **stack; int nh=1, ch, stacki; if(!sl->top) { sl->height = 1; sl->top = sl->bottom = calloc(1, sizeof(mtev_skiplist_node)); sl->top->sl = sl; } if(sl->preheight) { while(nh < sl->preheight && get_b_rand()) nh++; } else { while(nh <= sl->height && get_b_rand()) nh++; } /* Now we have the new height at which we wish to insert our new node */ /* Let us make sure that our tree is a least that tall (grow if necessary)*/ for(;sl->height<nh;sl->height++) { sl->top->up = (mtev_skiplist_node *)calloc(1, sizeof(mtev_skiplist_node)); sl->top->up->down = sl->top; sl->top = sl->top->up; sl->top->sl = sl; } ch = sl->height; /* Find the node (or node after which we would insert) */ /* Keep a stack to pop back through for insertion */ m = sl->top; stack = (mtev_skiplist_node **)alloca(sizeof(mtev_skiplist_node *)*(nh)); stacki=0; while(m) { int compared=-1; if(m->next) compared=comp(data, m->next->data); if(compared == 0) { return 0; } if(compared<0) { if(ch<=nh) { /* push on stack */ stack[stacki++] = m; } m = m->down; ch--; } else { m = m->next; } } /* Pop the stack and insert nodes */ p = NULL; for(;stacki>0;stacki--) { m = stack[stacki-1]; tmp = calloc(1, sizeof(*tmp)); tmp->next = m->next; if(m->next) m->next->prev=tmp; tmp->prev = m; tmp->down = p; if(p) p->up=tmp; tmp->data = (void *)data; tmp->sl = sl; m->next = tmp; /* This sets ret to the bottom-most node we are inserting */ if(!p) ret=tmp; p = tmp; } if(sl->index != NULL) { /* this is a external insertion, we must insert into each index as well */ mtev_skiplist_node *p, *ni, *li; mtevAssert(ret); li=ret; for(p = mtev_skiplist_getlist(sl->index); p; mtev_skiplist_next(sl->index, &p)) { ni = mtev_skiplist_insert((mtev_skiplist *)p->data, ret->data); mtevAssert(ni); li->nextindex = ni; ni->previndex = li; li = ni; } } sl->size++; return ret; }
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); }
static void dns_cache_resolve(struct dns_ctx *ctx, void *result, void *data, enum dns_type rtype) { int ttl, acnt, r = dns_status(ctx), idnlen; dns_cache_node *n = data; unsigned char idn[DNS_MAXDN], dn[DNS_MAXDN]; struct dns_parse p; struct dns_rr rr; unsigned nrr; struct in_addr *answers4; struct in6_addr *answers6; const unsigned char *pkt, *cur, *end; if(!result) goto blank; dns_dntodn(n->dn, idn, sizeof(idn)); idnlen = dns_dnlen(idn); pkt = result; end = pkt + r; cur = dns_payload(pkt); dns_getdn(pkt, &cur, end, dn, sizeof(dn)); dns_initparse(&p, NULL, pkt, cur, end); p.dnsp_qcls = 0; p.dnsp_qtyp = 0; nrr = 0; ttl = 0; while((r = dns_nextrr(&p, &rr)) > 0) { int dnlen = dns_dnlen(rr.dnsrr_dn); /* if we aren't searching and the don't match... * or if we are searching and the prefixes don't match... */ if ((dns_search_flag && !dns_dnequal(idn, rr.dnsrr_dn)) || (dns_search_flag == 0 && (idnlen > dnlen || memcmp(idn, rr.dnsrr_dn, idnlen-1)))) continue; if (DNS_C_IN == rr.dnsrr_cls && rtype == rr.dnsrr_typ) ++nrr; else if (rr.dnsrr_typ == DNS_T_CNAME && !nrr) { if (dns_getdn(pkt, &rr.dnsrr_dptr, end, p.dnsp_dnbuf, sizeof(p.dnsp_dnbuf)) <= 0 || rr.dnsrr_dptr != rr.dnsrr_dend) { break; } else { if(rr.dnsrr_ttl > 0 && (ttl == 0 || rr.dnsrr_ttl < ttl)) ttl = rr.dnsrr_ttl; dns_dntodn(p.dnsp_dnbuf, idn, sizeof(idn)); idnlen = dns_dnlen(idn); } } } if(!r && !nrr) goto blank; dns_rewind(&p, NULL); p.dnsp_qcls = DNS_C_IN; p.dnsp_qtyp = rtype; if(rtype == DNS_T_A) answers4 = calloc(nrr, sizeof(*answers4)); else if(rtype == DNS_T_AAAA) answers6 = calloc(nrr, sizeof(*answers6)); acnt = 0; while(dns_nextrr(&p, &rr) && nrr < MAX_RR) { int dnlen = dns_dnlen(rr.dnsrr_dn); if ((dns_search_flag && !dns_dnequal(idn, rr.dnsrr_dn)) || (dns_search_flag == 0 && (idnlen > dnlen || memcmp(idn, rr.dnsrr_dn, idnlen-1)))) continue; if (p.dnsp_rrl && !rr.dnsrr_dn[0] && rr.dnsrr_typ == DNS_T_OPT) continue; if (rtype == rr.dnsrr_typ) { if(rr.dnsrr_ttl > 0 && (ttl == 0 || rr.dnsrr_ttl < ttl)) ttl = rr.dnsrr_ttl; switch(rr.dnsrr_typ) { case DNS_T_A: if(rr.dnsrr_dsz != 4) continue; memcpy(&answers4[acnt++], rr.dnsrr_dptr, rr.dnsrr_dsz); break; case DNS_T_AAAA: if(rr.dnsrr_dsz != 16) continue; memcpy(&answers6[acnt++], rr.dnsrr_dptr, rr.dnsrr_dsz); break; default: break; } } } n->ttl = ttl; if(rtype == DNS_T_A) { if(n->ip4) free(n->ip4); n->ip4_cnt = acnt; n->ip4 = answers4; n->lookup_inflight_v4 = mtev_false; } else if(rtype == DNS_T_AAAA) { if(n->ip6) free(n->ip6); n->ip6_cnt = acnt; n->ip6 = answers6; n->lookup_inflight_v6 = mtev_false; } else { if(result) free(result); return; } DCLOCK(); mtev_skiplist_remove(&nc_dns_cache, n->target, NULL); n->last_updated = time(NULL); mtev_skiplist_insert(&nc_dns_cache, n); DCUNLOCK(); mtevL(noit_debug, "Resolved %s/%s -> %d records\n", n->target, (rtype == DNS_T_AAAA ? "IPv6" : (rtype == DNS_T_A ? "IPv4" : "???")), acnt); if(result) free(result); return; blank: DCLOCK(); if(rtype == DNS_T_A) blank_update_v4(n); if(rtype == DNS_T_AAAA) blank_update_v6(n); DCUNLOCK(); mtevL(noit_debug, "Resolved %s/%s -> blank\n", n->target, (rtype == DNS_T_AAAA ? "IPv6" : (rtype == DNS_T_A ? "IPv4" : "???"))); if(result) free(result); return; }