Example #1
0
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;
}
Example #2
0
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);
}
Example #3
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;
}
Example #4
0
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);
}
Example #5
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;
}
Example #8
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;
}