Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
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;
}
Exemplo n.º 3
0
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;
}
Exemplo n.º 5
0
void eventer_ref(eventer_t e) {
  register int32_t newval;
  newval = mtev_atomic_inc32(&e->refcnt);
  assert(newval != 1);
  (void)newval;
}
Exemplo n.º 6
0
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;
}
Exemplo n.º 7
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) {
    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;
}