static ssl_ctx_cache_node * ssl_ctx_cache_get(const char *key) { void *vnode; ssl_ctx_cache_node *node = NULL; mtev_atomic32_t newval; pthread_mutex_lock(&ssl_ctx_cache_lock); if(mtev_hash_retrieve(&ssl_ctx_cache, key, strlen(key), &vnode)) { node = vnode; newval = mtev_atomic_inc32(&node->refcnt); } pthread_mutex_unlock(&ssl_ctx_cache_lock); if(node) mtevL(eventer_deb, "ssl_ctx_cache->get(%p -> %d)\n", node, newval); return node; }
static ssl_ctx_cache_node * ssl_ctx_cache_set(ssl_ctx_cache_node *node) { void *vnode; mtev_atomic32_t newval; pthread_mutex_lock(&ssl_ctx_cache_lock); if(mtev_hash_retrieve(&ssl_ctx_cache, node->key, strlen(node->key), &vnode)) { node = vnode; } else { mtev_hash_store(&ssl_ctx_cache, node->key, strlen(node->key), node); } newval = mtev_atomic_inc32(&node->refcnt); pthread_mutex_unlock(&ssl_ctx_cache_lock); mtevL(eventer_deb, "ssl_ctx_cache->set(%p -> %d)\n", node, newval); return node; }
void noit_metric_director_message_ref(void *m) { noit_metric_message_t *message = (noit_metric_message_t *)m; mtev_atomic_inc32(&message->refcnt); }
/** * The "noit_livestream" protocol requires a well formed request to come * in via websocket that resembles: * * { * "period_ms": <milliseconds>, * "check_uuid": "<uuid_string>", * "metrics" : ["<metric_name1>", "<metric_name2>"] * } * * There can be only one active livestream request for a single websocket at one time. * However, you can send down a new livestream request at any time to alter the * stream based on new requirements. * * If the "metrics" member exists in the incoming request, then the metrics that are sent will be * filtered to those that match the strings in the array by exact match. If you want to get * all metrics in the check, omit the "metrics" member from the request object. */ int noit_websocket_msg_handler(mtev_http_rest_closure_t *restc, int opcode, const unsigned char *msg, size_t msg_len) { #ifdef HAVE_WSLAY const char *error = NULL; noit_websocket_closure_t *handler_data = restc->call_closure; /* for now this message is JSON, that might change in the future */ struct mtev_json_tokener *tok = mtev_json_tokener_new(); struct mtev_json_object *request = mtev_json_tokener_parse_ex(tok, (const char *)msg, msg_len); enum mtev_json_tokener_error err = tok->err; mtev_json_tokener_free(tok); if (err != mtev_json_tokener_success) { error = "Unable to parse incoming json"; goto websocket_handler_error; } uint64_t period_ms = mtev_json_object_get_uint64(mtev_json_object_object_get(request, "period_ms")); const char *check_uuid = mtev_json_object_get_string(mtev_json_object_object_get(request, "check_uuid")); struct mtev_json_object *metrics = mtev_json_object_object_get(request, "metrics"); if (handler_data != NULL) { /* destroy old subscription */ noit_websocket_closure_free(handler_data); handler_data = NULL; } handler_data = restc->call_closure = noit_websocket_closure_alloc(); handler_data->use_filter = mtev_false; restc->call_closure_free = noit_websocket_closure_free; handler_data->period = period_ms; if (metrics != NULL) { handler_data->use_filter = mtev_true; handler_data->filter_count = mtev_json_object_array_length(metrics); handler_data->filters = calloc(sizeof(char *), handler_data->filter_count); jl_array_list* a = mtev_json_object_get_array(metrics); for (int i = 0; i < handler_data->filter_count; i++) { struct mtev_json_object *o = jl_array_list_get_idx(a, i); if (o != NULL) { handler_data->filters[i] = strdup(mtev_json_object_get_string(o)); } } } handler_data->restc = restc; strncpy(handler_data->uuid_str, check_uuid, UUID_STR_LEN); handler_data->uuid_str[36] = '\0'; if(uuid_parse(handler_data->uuid_str, handler_data->uuid)) { mtevL(noit_error, "bad uuid received in livestream websocket_handler '%s'\n", handler_data->uuid_str); error = "bad uuid received in livestream subscription request"; goto websocket_handler_error; } mtev_json_object_put(request); /* setup subscription to noit_livestream */ asprintf(&handler_data->feed, "websocket_livestream/%d", mtev_atomic_inc32(&ls_counter)); handler_data->log_stream = mtev_log_stream_new(handler_data->feed, "noit_websocket_livestream", handler_data->feed, handler_data, NULL); handler_data->check = noit_check_watch(handler_data->uuid, handler_data->period); if(!handler_data->check) { error = "Cannot locate check"; goto websocket_handler_error; } /* This check must be watched from the livestream */ noit_check_transient_add_feed(handler_data->check, handler_data->feed); /* Note the check */ noit_check_log_check(handler_data->check); /* kick it off, if it isn't running already */ if(!NOIT_CHECK_LIVE(handler_data->check)) noit_check_activate(handler_data->check); return 0; websocket_handler_error: { struct mtev_json_object *e = mtev_json_object_new_object(); mtev_json_object_object_add(e, "success", mtev_json_object_new_int(0)); struct mtev_json_object *errors = mtev_json_object_new_array(); struct mtev_json_object *error_o = mtev_json_object_new_object(); mtev_json_object_object_add(error_o, "error", mtev_json_object_new_string(error)); mtev_json_object_array_add(errors, error_o); mtev_json_object_object_add(e, "errors", errors); const char *json_error = mtev_json_object_to_json_string(e); mtev_http_websocket_queue_msg(restc->http_ctx, WSLAY_TEXT_FRAME | WSLAY_CONNECTION_CLOSE, (const unsigned char *)json_error, strlen(json_error)); mtev_json_object_put(e); } #endif return -1; }
void eventer_ref(eventer_t e) { register int32_t newval; newval = mtev_atomic_inc32(&e->refcnt); assert(newval != 1); (void)newval; }
mtev_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 mtev_true; /* No filter */ if(!filtersets) return mtev_false; /* Couldn't possibly match */ LOCKFS(); if(mtev_hash_retrieve(filtersets, filterset, strlen(filterset), &vfs)) { filterset_t *fs = (filterset_t *)vfs; filterrule_t *r, *skipto_rule = NULL; int idx = 0; mtev_atomic_inc32(&fs->ref_cnt); UNLOCKFS(); #define MATCHES(rname, value) noit_apply_filterrule(r->rname##_ht, r->rname ? r->rname : r->rname##_override, r->rname ? r->rname##_e : NULL, value) for(r = fs->rules; r; r = r->next) { int need_target, need_module, need_name, need_metric; /* If we're targeting a skipto rule, match or continue */ idx++; if(skipto_rule && skipto_rule != r) continue; skipto_rule = NULL; need_target = !MATCHES(target, check->target); need_module = !MATCHES(module, check->module); need_name = !MATCHES(name, check->name); need_metric = !MATCHES(metric, metric->metric_name); if(!need_target && !need_module && !need_name && !need_metric) { if(r->type == NOIT_FILTER_SKIPTO) { skipto_rule = r->skipto_rule; continue; } return (r->type == NOIT_FILTER_ACCEPT) ? mtev_true : mtev_false; } /* If we need some of these and we have an auto setting that isn't fulfilled for each of them, we can add and succeed */ #define CHECK_ADD(rname) (!need_##rname || (r->rname##_auto_hash_max > 0 && r->rname##_ht && mtev_hash_size(r->rname##_ht) < r->rname##_auto_hash_max)) if(CHECK_ADD(target) && CHECK_ADD(module) && CHECK_ADD(name) && CHECK_ADD(metric)) { #define UPDATE_FILTER_RULE(rnum, rname, value) do { \ mtev_hash_replace(r->rname##_ht, strdup(value), strlen(value), NULL, free, NULL); \ if(noit_filter_update_conf_rule(fs->name, rnum, #rname, value) < 0) { \ mtevL(noit_error, "Error updating configuration for new filter auto_add on %s=%s\n", #rname, value); \ } \ } while(0) if(need_target) UPDATE_FILTER_RULE(idx, target, check->target); if(need_module) UPDATE_FILTER_RULE(idx, module, check->module); if(need_name) UPDATE_FILTER_RULE(idx, name, check->name); if(need_metric) UPDATE_FILTER_RULE(idx, metric, metric->metric_name); noit_filterset_log_auto_add(fs->name, check, metric, r->type == NOIT_FILTER_ACCEPT); if(r->type == NOIT_FILTER_SKIPTO) { skipto_rule = r->skipto_rule; continue; } return (r->type == NOIT_FILTER_ACCEPT) ? mtev_true : mtev_false; } } filterset_free(fs); return mtev_false; } UNLOCKFS(); return mtev_false; }
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) { mtev_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(!mtev_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."; mtevL(noit_error, "%s\n", errstr); goto socket_error; } ls = mtev_log_stream_find(logname); if(!ls) { snprintf(errbuff, sizeof(errbuff), "Could not find log '%s' for log_transit.", logname); errstr = errbuff; mtevL(noit_error, "%s\n", errstr); goto socket_error; } type = mtev_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; mtevL(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."; mtevL(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", mtev_atomic_inc32(&tmpfeedcounter)); } jcl->subscriber = strdup(subscriber); strlcpy(path, mtev_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; mtevL(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; mtevL(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); mtev_gettimeofday(&jcl->feed_stats->last_connection, NULL); mtev_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; }