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 * asynch_logio_writer(void *vls) { noit_log_stream_t ls = vls; asynch_log_ctx *actx = ls->op_ctx; asynch_log_line *iter = NULL; int gen; gen = noit_atomic_inc32(&actx->gen); noitL(noit_debug, "starting asynchronous %s writer[%d/%p]\n", actx->name, (int)getpid(), (void *)(vpsized_int)pthread_self()); while(gen == actx->gen) { pthread_rwlock_t *lock; int fast = 0, max = 1000; asynch_log_line *line; lock = ls->lock; if(lock) pthread_rwlock_rdlock(lock); while(max > 0 && NULL != (line = asynch_log_pop(actx, &iter))) { if(actx->write(actx, line) == -1) abort(); if(line->buf_dynamic != NULL) free(line->buf_dynamic); free(line); fast = 1; max--; } if(lock) pthread_rwlock_unlock(lock); if(max > 0) { /* we didn't hit our limit... so we ran the queue dry */ /* 200ms if there was nothing, 10ms otherwise */ usleep(fast ? 10000 : 200000); } } noitL(noit_debug, "stopping asynchronous %s writer[%d/%p]\n", actx->name, (int)getpid(), (void *)(vpsized_int)pthread_self()); pthread_exit((void *)0); }
noit_boolean noit_apply_filterset(const char *filterset, noit_check_t *check, metric_t *metric) { /* We pass in filterset here just in case someone wants to apply * a filterset other than check->filterset.. You never know. */ void *vfs; if(!filterset) return noit_true; /* No filter */ if(!filtersets) return noit_false; /* Couldn't possibly match */ LOCKFS(); if(noit_hash_retrieve(filtersets, filterset, strlen(filterset), &vfs)) { filterset_t *fs = (filterset_t *)vfs; filterrule_t *r; noit_atomic_inc32(&fs->ref_cnt); UNLOCKFS(); #define MATCHES(rname, value) noit_apply_filterrule(r->rname, r->rname##_e, value) for(r = fs->rules; r; r = r->next) { if(MATCHES(target, check->target) && MATCHES(module, check->module) && MATCHES(name, check->name) && MATCHES(metric, metric->metric_name)) return (r->type == NOIT_FILTER_ACCEPT) ? noit_true : noit_false; } filterset_free(fs); return noit_false; } UNLOCKFS(); return noit_false; }
static int noit_lua_dns_lookup(lua_State *L) { dns_lookup_ctx_t *dlc, **holder; const char *c, *query = "", *ctype = "IN", *rtype = "A"; char *ctype_up, *rtype_up, *d; void *vnv_pair; noit_lua_check_info_t *ci; ci = get_ci(L); assert(ci); holder = (dns_lookup_ctx_t **)lua_touserdata(L, lua_upvalueindex(1)); if(holder != lua_touserdata(L,1)) luaL_error(L, "Must be called as method\n"); dlc = *holder; if(lua_gettop(L) > 1) query = lua_tostring(L, 2); if(lua_gettop(L) > 2) rtype = lua_tostring(L, 3); if(lua_gettop(L) > 3) ctype = lua_tostring(L, 4); ctype_up = alloca(strlen(ctype)+1); for(d = ctype_up, c = ctype; *c; d++, c++) *d = toupper(*c); *d = '\0'; rtype_up = alloca(strlen(rtype)+1); for(d = rtype_up, c = rtype; *c; d++, c++) *d = toupper(*c); *d = '\0'; if(!noit_hash_retrieve(&dns_ctypes, ctype_up, strlen(ctype_up), &vnv_pair)) dlc->error = strdup("bad class"); else dlc->query_ctype = ((struct dns_nameval *)vnv_pair)->val; if(!noit_hash_retrieve(&dns_rtypes, rtype_up, strlen(rtype_up), &vnv_pair)) dlc->error = strdup("bad rr type"); else dlc->query_rtype = ((struct dns_nameval *)vnv_pair)->val; dlc->active = 1; noit_atomic_inc32(&dlc->refcnt); if(!dlc->error) { int abs; if(!dns_ptodn(query, strlen(query), dlc->dn, sizeof(dlc->dn), &abs) || !dns_submit_dn(dlc->h->ctx, dlc->dn, dlc->query_ctype, dlc->query_rtype, abs | DNS_NOSRCH, NULL, dns_cb, dlc)) { dlc->error = strdup("submission error"); noit_atomic_dec32(&dlc->refcnt); } else { struct timeval now; gettimeofday(&now, NULL); dns_timeouts(dlc->h->ctx, -1, now.tv_sec); } } if(dlc->error) { dlc->active = 0; luaL_error(L, "dns: %s\n", dlc->error); } return noit_lua_yield(ci, 0); }
static void * jlog_logio_asynch_writer(void *vls) { noit_log_stream_t ls = vls; jlog_asynch_ctx *actx = ls->op_ctx; jlog_line *iter = NULL; int gen; gen = noit_atomic_inc32(&actx->gen); noitL(noit_error, "starting asynchronous jlog writer[%d/%p]\n", (int)getpid(), (void *)pthread_self()); while(gen == actx->gen) { pthread_rwlock_t *lock; int fast = 0, max = 1000; jlog_line *line; lock = ls->lock; if(lock) pthread_rwlock_rdlock(lock); while(max > 0 && NULL != (line = jlog_asynch_pop(actx, &iter))) { if(jlog_ctx_write(actx->log, line->buf_dynamic ? line->buf_dynamic : line->buf_static, line->len) == -1) { noitL(noit_error, "jlog_ctx_write failed(%d): %s\n", jlog_ctx_errno(actx->log), jlog_ctx_err_string(actx->log)); abort(); } if(line->buf_dynamic != NULL) free(line->buf_dynamic); free(line); fast = 1; max--; } if(lock) pthread_rwlock_unlock(lock); if(max > 0) { /* we didn't hit our limit... so we ran the queue dry */ /* 200ms if there was nothing, 10ms otherwise */ usleep(fast ? 10000 : 200000); } } noitL(noit_error, "stopping asynchronous jlog writer[%d/%p]\n", (int)getpid(), (void *)pthread_self()); pthread_exit((void *)0); }
int noit_jlog_handler(eventer_t e, int mask, void *closure, struct timeval *now) { eventer_t newe; pthread_t tid; pthread_attr_t tattr; int newmask = EVENTER_READ | EVENTER_EXCEPTION; acceptor_closure_t *ac = closure; noit_jlog_closure_t *jcl = ac->service_ctx; char errbuff[256]; const char *errstr = "unknown error"; if(mask & EVENTER_EXCEPTION || (jcl && jcl->wants_shutdown)) { int len, nlen; socket_error: /* Exceptions cause us to simply snip the connection */ len = strlen(errstr); nlen = htonl(0 - len); e->opset->write(e->fd, &nlen, sizeof(nlen), &newmask, e); e->opset->write(e->fd, errstr, strlen(errstr), &newmask, e); eventer_remove_fd(e->fd); e->opset->close(e->fd, &newmask, e); if(jcl) noit_jlog_closure_free(jcl); acceptor_closure_free(ac); return 0; } if(!ac->service_ctx) { noit_log_stream_t ls; const char *logname, *type; int first_attempt = 1; char path[PATH_MAX], subscriber[256], *sub; jcl = ac->service_ctx = noit_jlog_closure_alloc(); if(!noit_hash_retr_str(ac->config, "log_transit_feed_name", strlen("log_transit_feed_name"), &logname)) { errstr = "No 'log_transit_feed_name' specified in log_transit."; noitL(noit_error, "%s\n", errstr); goto socket_error; } ls = noit_log_stream_find(logname); if(!ls) { snprintf(errbuff, sizeof(errbuff), "Could not find log '%s' for log_transit.", logname); errstr = errbuff; noitL(noit_error, "%s\n", errstr); goto socket_error; } type = noit_log_stream_get_type(ls); if(!type || strcmp(type, "jlog")) { snprintf(errbuff, sizeof(errbuff), "Log '%s' for log_transit is not a jlog.", logname); errstr = errbuff; noitL(noit_error, "%s\n", errstr); goto socket_error; } if(ac->cmd == NOIT_JLOG_DATA_FEED) { if(!ac->remote_cn) { errstr = "jlog transit started to unidentified party."; noitL(noit_error, "%s\n", errstr); goto socket_error; } strlcpy(subscriber, ac->remote_cn, sizeof(subscriber)); jcl->feed_stats = noit_jlog_feed_stats(subscriber); } else { jcl->feed_stats = noit_jlog_feed_stats("~"); snprintf(subscriber, sizeof(subscriber), "~%07d", noit_atomic_inc32(&tmpfeedcounter)); } jcl->subscriber = strdup(subscriber); strlcpy(path, noit_log_stream_get_path(ls), sizeof(path)); sub = strchr(path, '('); if(sub) { char *esub = strchr(sub, ')'); if(esub) { *esub = '\0'; *sub++ = '\0'; } } jcl->jlog = jlog_new(path); if(ac->cmd == NOIT_JLOG_DATA_TEMP_FEED) { add_sub: if(jlog_ctx_add_subscriber(jcl->jlog, jcl->subscriber, JLOG_END) == -1) { snprintf(errbuff, sizeof(errbuff), "jlog reader[%s] error: %s", jcl->subscriber, jlog_ctx_err_string(jcl->jlog)); errstr = errbuff; noitL(noit_error, "%s\n", errstr); } } if(jlog_ctx_open_reader(jcl->jlog, jcl->subscriber) == -1) { if(sub && !strcmp(sub, "*")) { if(first_attempt) { jlog_ctx_close(jcl->jlog); jcl->jlog = jlog_new(path); first_attempt = 0; goto add_sub; } } snprintf(errbuff, sizeof(errbuff), "jlog reader[%s] error: %s", jcl->subscriber, jlog_ctx_err_string(jcl->jlog)); errstr = errbuff; noitL(noit_error, "%s\n", errstr); goto socket_error; } } /* The jlog stuff is disk I/O and can block us. * We'll create a new thread to just handle this connection. */ eventer_remove_fd(e->fd); newe = eventer_alloc(); memcpy(newe, e, sizeof(*e)); pthread_attr_init(&tattr); pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); gettimeofday(&jcl->feed_stats->last_connection, NULL); noit_atomic_inc32(&jcl->feed_stats->connections); if(pthread_create(&tid, &tattr, noit_jlog_thread_main, newe) == 0) { return 0; } /* Undo our dup */ eventer_free(newe); /* Creating the thread failed, close it down and deschedule. */ e->opset->close(e->fd, &newmask, e); return 0; }
int noit_livestream_handler(eventer_t e, int mask, void *closure, struct timeval *now) { eventer_t newe; pthread_t tid; int newmask = EVENTER_READ | EVENTER_EXCEPTION; acceptor_closure_t *ac = closure; noit_livestream_closure_t *jcl = ac->service_ctx; if(mask & EVENTER_EXCEPTION || (jcl && jcl->wants_shutdown)) { socket_error: /* Exceptions cause us to simply snip the connection */ eventer_remove_fd(e->fd); e->opset->close(e->fd, &newmask, e); if(jcl) noit_livestream_closure_free(jcl); if(ac) acceptor_closure_free(ac); return 0; } if(!ac->service_ctx || !jcl->feed) { int len; jcl = ac->service_ctx = noit_livestream_closure_alloc(); /* Setup logger to this channel */ if(!jcl->period) { u_int32_t nperiod; len = e->opset->read(e->fd, &nperiod, sizeof(nperiod), &mask, e); if(len == -1 && errno == EAGAIN) return mask | EVENTER_EXCEPTION; if(len != sizeof(nperiod)) goto socket_error; jcl->period = ntohl(nperiod); if(!jcl->period) { noitL(noit_error, "period of 0 specified in livestream. not allowed.\n"); goto socket_error; } } while(jcl->uuid_read < 36) { len = e->opset->read(e->fd, jcl->uuid_str + jcl->uuid_read, 36 - jcl->uuid_read, &mask, e); if(len == -1 && errno == EAGAIN) return mask | EVENTER_EXCEPTION; if(len == 0) goto socket_error; jcl->uuid_read += len; } jcl->uuid_str[36] = '\0'; if(uuid_parse(jcl->uuid_str, jcl->uuid)) { noitL(noit_error, "bad uuid received in livestream handler '%s'\n", jcl->uuid_str); goto socket_error; } jcl->feed = malloc(32); snprintf(jcl->feed, 32, "livestream/%d", noit_atomic_inc32(&ls_counter)); noit_log_stream_new(jcl->feed, "noit_livestream", jcl->feed, jcl, NULL); jcl->check = noit_check_watch(jcl->uuid, jcl->period); if(!jcl->check) { e->opset->close(e->fd, &newmask, e); return 0; } /* This check must be watched from the livestream */ noit_check_transient_add_feed(jcl->check, jcl->feed); /* Note the check */ noit_check_log_check(jcl->check); /* kick it off, if it isn't running already */ if(!NOIT_CHECK_LIVE(jcl->check)) noit_check_activate(jcl->check); } eventer_remove_fd(e->fd); newe = eventer_alloc(); memcpy(newe, e, sizeof(*e)); if(pthread_create(&tid, NULL, noit_livestream_thread_main, newe) == 0) { return 0; } noit_check_transient_remove_feed(jcl->check, jcl->feed); noit_livestream_closure_free(jcl); /* Undo our dup */ eventer_free(newe); /* Creating the thread failed, close it down and deschedule. */ e->opset->close(e->fd, &newmask, e); return 0; }
static void dns_module_dns_ctx_acquire(dns_ctx_handle_t *h) { noit_atomic_inc32(&h->refcnt); }
int stratcon_request_dispatcher(noit_http_session_ctx *ctx) { const char *key, *value; realtime_context *rc = ctx->dispatcher_closure; int klen; noit_hash_iter iter = NOIT_HASH_ITER_ZERO; noit_http_request *req = &ctx->req; if(rc->setup == RC_INITIAL) { eventer_t completion; struct realtime_tracker *node; char c[1024]; int num_interests; num_interests = stratcon_realtime_uri_parse(rc, ctx->req.uri_str); if(num_interests == 0) { noit_http_response_status_set(ctx, 404, "OK"); noit_http_response_option_set(ctx, NOIT_HTTP_CLOSE); noit_http_response_end(ctx); return 0; } noitL(noit_error, "http: %s %s %s\n", req->method_str, req->uri_str, req->protocol_str); while(noit_hash_next_str(&req->headers, &iter, &key, &klen, &value)) { noitL(noit_error, "http: [%s: %s]\n", key, value); } noit_http_response_status_set(ctx, 200, "OK"); noit_http_response_option_set(ctx, NOIT_HTTP_CHUNKED); /*noit_http_response_option_set(ctx, NOIT_HTTP_GZIP);*/ /*noit_http_response_option_set(ctx, NOIT_HTTP_DEFLATE);*/ noit_http_response_header_set(ctx, "Content-Type", "text/html"); snprintf(c, sizeof(c), "<html><head><script>document.domain='%s';</script></head><body>\n", rc->document_domain); noit_http_response_append(ctx, c, strlen(c)); /* this dumb crap is to make some browsers happy (Safari) */ memset(c, ' ', sizeof(c)); noit_http_response_append(ctx, c, sizeof(c)); noit_http_response_flush(ctx, noit_false); rc->setup = RC_REQ_RECV; /* Each interest references the ctx */ for(node = rc->checklist; node; node = node->next) { char uuid_str[UUID_STR_LEN+1]; noit_atomic_inc32(&ctx->ref_cnt); uuid_unparse_lower(node->checkid, uuid_str); noitL(noit_error, "Resolving uuid: %s\n", uuid_str); } completion = eventer_alloc(); completion->mask = EVENTER_TIMER; completion->callback = stratcon_realtime_http_postresolve; completion->closure = ctx; gettimeofday(&completion->whence, NULL); stratcon_datastore_push(DS_OP_FIND_COMPLETE, NULL, NULL, rc->checklist, completion); } return EVENTER_EXCEPTION; }