Ejemplo n.º 1
0
int
noit_control_dispatch(eventer_t e, int mask, void *closure,
                      struct timeval *now) {
  u_int32_t cmd;
  int len = 0, callmask = mask;
  void *vdelegation_table;
  noit_hash_table *delegation_table = NULL;
  acceptor_closure_t *ac = closure;

  assert(ac->rlen >= 0);
  while(len >= 0 && ac->rlen < sizeof(cmd)) {
    len = e->opset->read(e->fd, ((char *)&cmd) + ac->rlen,
                         sizeof(cmd) - ac->rlen, &mask, e);
    if(len == -1 && errno == EAGAIN)
      return EVENTER_READ | EVENTER_EXCEPTION;

    if(len > 0) ac->rlen += len;
  }
  assert(ac->rlen >= 0 && ac->rlen <= sizeof(cmd));

  if(callmask & EVENTER_EXCEPTION || ac->rlen != sizeof(cmd)) {
    int newmask;
socket_error:
    /* Exceptions cause us to simply snip the connection */
    eventer_remove_fd(e->fd);
    e->opset->close(e->fd, &newmask, e);
    acceptor_closure_free(ac);
    return 0;
  }

  ac->cmd = ntohl(cmd);
  /* Lookup cmd and dispatch */
  if(noit_hash_retrieve(&listener_commands,
                        (char *)&ac->dispatch, sizeof(ac->dispatch),
                        (void **)&vdelegation_table)) {
    void *vfunc;
    delegation_table = (noit_hash_table *)vdelegation_table;
    if(noit_hash_retrieve(delegation_table,
                          (char *)&ac->cmd, sizeof(ac->cmd), &vfunc)) {
      e->callback = *((eventer_func_t *)vfunc);
      return e->callback(e, callmask, closure, now);
    }
    else {
    const char *event_name;
      noitL(noit_error, "listener (%s %p) has no command: 0x%08x\n",
            (event_name = eventer_name_for_callback(ac->dispatch))?event_name:"???",
            delegation_table, cmd);
    }
  }
  else {
    const char *event_name;
    noitL(noit_error, "No delegation table for listener (%s %p)\n",
          (event_name = eventer_name_for_callback(ac->dispatch))?event_name:"???",
          delegation_table);
  }
  goto socket_error;
}
Ejemplo n.º 2
0
static void
noit_console_spit_event(eventer_t e, void *c) {
  struct timeval now, diff;
  noit_console_closure_t ncct = c;
  char fdstr[12];
  char wfn[42];
  char funcptr[20];
  const char *cname;

  cname = eventer_name_for_callback(e->callback);
  snprintf(fdstr, sizeof(fdstr), " fd: %d", e->fd);
  gettimeofday(&now, NULL);
  sub_timeval(e->whence, now, &diff);
  snprintf(wfn, sizeof(wfn), " fires: %lld.%06ds", (long long)diff.tv_sec, (int)diff.tv_usec);
  snprintf(funcptr, sizeof(funcptr), "%p", e->callback);
  nc_printf(ncct, "  [%p]%s%s [%c%c%c%c] -> %s(%p)\n",
            e,
            e->mask & (EVENTER_READ | EVENTER_WRITE | EVENTER_EXCEPTION) ? fdstr : "",
            e->mask & (EVENTER_TIMER) ?  wfn : "",
            e->mask & EVENTER_READ ? 'r' : '-',
            e->mask & EVENTER_WRITE ? 'w' : '-',
            e->mask & EVENTER_EXCEPTION ? 'e' : '-',
            e->mask & EVENTER_TIMER ? 't' : '-',
            cname ? cname : funcptr, e->closure);
}
Ejemplo n.º 3
0
static void eventer_ports_impl_add(eventer_t e) {
  assert(e->mask);
  ev_lock_state_t lockstate;
  const char *cbname;
  cbname = eventer_name_for_callback(e->callback);

  if(e->mask & EVENTER_ASYNCH) {
    noitL(eventer_deb, "debug: eventer_add asynch (%s)\n", cbname ? cbname : "???");
    eventer_add_asynch(NULL, e);
    return;
  }

  /* Recurrent delegation */
  if(e->mask & EVENTER_RECURRENT) {
    noitL(eventer_deb, "debug: eventer_add recurrent (%s)\n", cbname ? cbname : "???");
    eventer_add_recurrent(e);
    return;
  }

  /* Timed events are simple */
  if(e->mask & EVENTER_TIMER) {
    eventer_add_timed(e);
    return;
  }

  /* file descriptor event */
  noitL(eventer_deb, "debug: eventer_add fd (%s,%d,0x%04x)\n", cbname ? cbname : "???", e->fd, e->mask);
  lockstate = acquire_master_fd(e->fd);
  assert(e->whence.tv_sec == 0 && e->whence.tv_usec == 0);
  master_fds[e->fd].e = e;
  alter_fd(e, e->mask);
  release_master_fd(e->fd, lockstate);
}
Ejemplo n.º 4
0
static void
eventer_ports_impl_trigger(eventer_t e, int mask) {
  ev_lock_state_t lockstate;
  const char *cbname;
  struct timeval __now;
  int fd, oldmask, newmask;

  fd = e->fd;
  if(e != master_fds[fd].e) return;
  lockstate = acquire_master_fd(fd);
  if(lockstate == EV_ALREADY_OWNED) return;
  assert(lockstate == EV_OWNED);

  gettimeofday(&__now, NULL);
  oldmask = e->mask;
  cbname = eventer_name_for_callback(e->callback);
  noitLT(eventer_deb, &__now, "ports: fire on %d/%x to %s(%p)\n",
         fd, mask, cbname?cbname:"???", e->callback);
  EVENTER_CALLBACK_ENTRY((void *)e->callback, (char *)cbname, fd, e->mask, mask);
  newmask = e->callback(e, mask, e->closure, &__now);
  EVENTER_CALLBACK_RETURN((void *)e->callback, (char *)cbname, newmask);

  if(newmask) {
    alter_fd(e, newmask);
    /* Set our mask */
    e->mask = newmask;
    noitLT(eventer_deb, &__now, "ports: complete on %d/(%x->%x) to %s(%p)\n",
           fd, mask, newmask, cbname?cbname:"???", e->callback);
  }
  else {
    noitLT(eventer_deb, &__now, "ports: complete on %d/none to %s(%p)\n",
           fd, cbname?cbname:"???", e->callback);
    /*
     * Long story long:
     *  When integrating with a few external event systems, we find
     *  it difficult to make their use of remove+add as an update
     *  as it can be recurrent in a single handler call and you cannot
     *  remove completely from the event system if you are going to
     *  just update (otherwise the eventer_t in your call stack could
     *  be stale).  What we do is perform a superficial remove, marking
     *  the mask as 0, but not eventer_remove_fd.  Then on an add, if
     *  we already have an event, we just update the mask (as we
     *  have not yet returned to the eventer's loop.
     *  This leaves us in a tricky situation when a remove is called
     *  and the add doesn't roll in, we return 0 (mask == 0) and hit
     *  this spot.  We have intended to remove the event, but it still
     *  resides at master_fds[fd].e -- even after we free it.
     *  So, in the evnet that we return 0 and the event that
     *  master_fds[fd].e == the event we're about to free... we NULL
     *  it out.
     */
    if(master_fds[fd].e == e) master_fds[fd].e = NULL;
    eventer_free(e);
  }
  release_master_fd(fd, lockstate);
}
Ejemplo n.º 5
0
static void eventer_epoll_impl_trigger(eventer_t e, int mask) {
  struct timeval __now;
  int fd, newmask;
  const char *cbname;
  ev_lock_state_t lockstate;

  fd = e->fd;
  if(e != master_fds[fd].e) return;
  lockstate = acquire_master_fd(fd);
  if(lockstate == EV_ALREADY_OWNED) return;
  assert(lockstate == EV_OWNED);

  gettimeofday(&__now, NULL);
  cbname = eventer_name_for_callback(e->callback);
  noitLT(eventer_deb, &__now, "epoll: fire on %d/%x to %s(%p)\n",
         fd, mask, cbname?cbname:"???", e->callback);
  EVENTER_CALLBACK_ENTRY((void *)e->callback, (char *)cbname, fd, e->mask, mask);
  newmask = e->callback(e, mask, e->closure, &__now);
  EVENTER_CALLBACK_RETURN((void *)e->callback, (char *)cbname, newmask);

  if(newmask) {
    struct epoll_event _ev;
    memset(&_ev, 0, sizeof(_ev));
    _ev.data.fd = fd;
    if(newmask & EVENTER_READ) _ev.events |= (EPOLLIN|EPOLLPRI);
    if(newmask & EVENTER_WRITE) _ev.events |= (EPOLLOUT);
    if(newmask & EVENTER_EXCEPTION) _ev.events |= (EPOLLERR|EPOLLHUP);
    if(master_fds[fd].e == NULL) {
      noitL(noit_error, "eventer %s(%p) epoll asked to modify descheduled fd: %d\n",
            cbname?cbname:"???", e->callback, fd);
    } else {
      assert(epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &_ev) == 0);
    }
    /* Set our mask */
    e->mask = newmask;
  }
  else {
    /* see kqueue implementation for details on the next line */
    if(master_fds[fd].e == e) master_fds[fd].e = NULL;
    eventer_free(e);
  }
  release_master_fd(fd, lockstate);
}
Ejemplo n.º 6
0
static void eventer_kqueue_impl_trigger(eventer_t e, int mask) {
  ev_lock_state_t lockstate;
  struct timeval __now;
  int oldmask, newmask;
  const char *cbname;
  int fd;

  fd = e->fd;
  if(e != master_fds[fd].e) return;
  lockstate = acquire_master_fd(fd);
  if(lockstate == EV_ALREADY_OWNED) return;
  assert(lockstate == EV_OWNED);

  gettimeofday(&__now, NULL);
  /* We're going to lie to ourselves.  You'd think this should be:
   * oldmask = e->mask;  However, we just fired with masks[fd], so
   * kqueue is clearly looking for all of the events in masks[fd].
   * So, we combine them "just to be safe."
   */
  oldmask = e->mask | masks[fd];
  cbname = eventer_name_for_callback(e->callback);
  noitLT(eventer_deb, &__now, "kqueue: fire on %d/%x to %s(%p)\n",
         fd, masks[fd], cbname?cbname:"???", e->callback);
  newmask = e->callback(e, mask, e->closure, &__now);

  if(newmask) {
    /* toggle the read bits if needed */
    if(newmask & (EVENTER_READ | EVENTER_EXCEPTION)) {
      if(!(oldmask & (EVENTER_READ | EVENTER_EXCEPTION)))
        ke_change(fd, EVFILT_READ, EV_ADD | EV_ENABLE, e);
    }
    else if(oldmask & (EVENTER_READ | EVENTER_EXCEPTION))
      ke_change(fd, EVFILT_READ, EV_DELETE | EV_DISABLE, e);

    /* toggle the write bits if needed */
    if(newmask & EVENTER_WRITE) {
      if(!(oldmask & EVENTER_WRITE))
        ke_change(fd, EVFILT_WRITE, EV_ADD | EV_ENABLE, e);
    }
    else if(oldmask & EVENTER_WRITE)
      ke_change(fd, EVFILT_WRITE, EV_DELETE | EV_DISABLE, e);

    /* Set our mask */
    e->mask = newmask;
  }
  else {
    /*
     * Long story long:
     *  When integrating with a few external event systems, we find
     *  it difficult to make their use of remove+add as an update
     *  as it can be recurrent in a single handler call and you cannot
     *  remove completely from the event system if you are going to
     *  just update (otherwise the eventer_t in your call stack could
     *  be stale).  What we do is perform a superficial remove, marking
     *  the mask as 0, but not eventer_remove_fd.  Then on an add, if
     *  we already have an event, we just update the mask (as we
     *  have not yet returned to the eventer's loop.
     *  This leaves us in a tricky situation when a remove is called
     *  and the add doesn't roll in, we return 0 (mask == 0) and hit
     *  this spot.  We have intended to remove the event, but it still
     *  resides at master_fds[fd].e -- even after we free it.
     *  So, in the evnet that we return 0 and the event that
     *  master_fds[fd].e == the event we're about to free... we NULL
     *  it out.
     */
    if(master_fds[fd].e == e) master_fds[fd].e = NULL;
    eventer_free(e);
  }
  release_master_fd(fd, lockstate);
}
static void
mtev_capabilities_tobuff(mtev_capsvc_closure_t *cl, eventer_func_t curr) {
    const char **mod_names;
    struct utsname utsn;
    char vbuff[128], bwstr[4];
    mtev_hash_table *lc;
    mtev_hash_iter iter = MTEV_HASH_ITER_ZERO;
    const char *k;
    int klen, i, nmods;
    void *data;
    struct timeval now;
    struct dso_type *t;

    xmlDocPtr xmldoc;
    xmlNodePtr root, cmds, bi, ri, mods, feat;

    /* fill out capabilities */

    /* Create an XML Document */
    xmldoc = xmlNewDoc((xmlChar *)"1.0");
    root = xmlNewDocNode(xmldoc, NULL, (xmlChar *)capabilities_namespace, NULL);
    xmlDocSetRootElement(xmldoc, root);

    /* Fill in the document */
    mtev_build_version(vbuff, sizeof(vbuff));
    xmlNewTextChild(root, NULL, (xmlChar *)"version", (xmlChar *)vbuff);

    snprintf(bwstr, sizeof(bwstr), "%d", (int)sizeof(void *)*8);
    /* Build info */
    bi = xmlNewNode(NULL, (xmlChar *)"unameBuild");
    xmlSetProp(bi, (xmlChar *)"bitwidth", (xmlChar *)bwstr);
    xmlAddChild(root, bi);
    xmlNewTextChild(bi, NULL, (xmlChar *)"sysname", (xmlChar *)UNAME_S);
    xmlNewTextChild(bi, NULL, (xmlChar *)"nodename", (xmlChar *)UNAME_N);
    xmlNewTextChild(bi, NULL, (xmlChar *)"release", (xmlChar *)UNAME_R);
    xmlNewTextChild(bi, NULL, (xmlChar *)"version", (xmlChar *)UNAME_V);
    xmlNewTextChild(bi, NULL, (xmlChar *)"machine", (xmlChar *)UNAME_M);

    /* Run info */
    ri = xmlNewNode(NULL, (xmlChar *)"unameRun");
    xmlSetProp(ri, (xmlChar *)"bitwidth", (xmlChar *)bwstr);
    xmlAddChild(root, ri);
    if(uname(&utsn) < 0) {
      xmlNewTextChild(ri, NULL, (xmlChar *)"error", (xmlChar *)strerror(errno));
    } else {
      xmlNewTextChild(ri, NULL, (xmlChar *)"sysname", (xmlChar *)utsn.sysname);
      xmlNewTextChild(ri, NULL, (xmlChar *)"nodename", (xmlChar *)utsn.nodename);
      xmlNewTextChild(ri, NULL, (xmlChar *)"release", (xmlChar *)utsn.release);
      xmlNewTextChild(ri, NULL, (xmlChar *)"version", (xmlChar *)utsn.version);
      xmlNewTextChild(ri, NULL, (xmlChar *)"machine", (xmlChar *)utsn.machine);
    }

    /* features */
    feat = xmlNewNode(NULL, (xmlChar *)"features");
    xmlAddChild(root, feat);
    if(mtev_hash_size(&features)) {
      mtev_hash_iter iter2 = MTEV_HASH_ITER_ZERO;
      void *vfv;
      const char *f;
      int flen;
      while(mtev_hash_next(&features, &iter2, &f, &flen, &vfv)) {
        xmlNodePtr featnode;
        featnode = xmlNewNode(NULL, (xmlChar *)"feature");
        xmlSetProp(featnode, (xmlChar *)"name", (xmlChar *)f);
        if(vfv) xmlSetProp(featnode, (xmlChar *)"version", (xmlChar *)vfv);
        xmlAddChild(feat, featnode);
      }
    }

    /* time (poor man's time check) */
    gettimeofday(&now, NULL);
    snprintf(vbuff, sizeof(vbuff), "%llu.%03d", (unsigned long long)now.tv_sec,
             (int)(now.tv_usec / 1000));
    xmlNewTextChild(root, NULL, (xmlChar *)"current_time", (xmlChar *)vbuff);

    cmds = xmlNewNode(NULL, (xmlChar *)"services");
    xmlAddChild(root, cmds);
    lc = mtev_listener_commands();
    while(mtev_hash_next(lc, &iter, &k, &klen, &data)) {
      xmlNodePtr cnode;
      char hexcode[11];
      const char *name;
      eventer_func_t *f = (eventer_func_t *)k;
      mtev_hash_table *sc = (mtev_hash_table *)data;
      mtev_hash_iter sc_iter = MTEV_HASH_ITER_ZERO;
      const char *sc_k;
      int sc_klen;
      void *sc_data;

      name = eventer_name_for_callback(*f);
      cnode = xmlNewNode(NULL, (xmlChar *)"service");
      xmlSetProp(cnode, (xmlChar *)"name", name ? (xmlChar *)name : NULL);
      if(*f == curr)
        xmlSetProp(cnode, (xmlChar *)"connected", (xmlChar *)"true");
      xmlAddChild(cmds, cnode);
      while(mtev_hash_next(sc, &sc_iter, &sc_k, &sc_klen, &sc_data)) {
        xmlNodePtr scnode;
        char *name_copy, *version = NULL;
        eventer_func_t *f = (eventer_func_t *)sc_data;

        snprintf(hexcode, sizeof(hexcode), "0x%08x", *((u_int32_t *)sc_k));
        name = eventer_name_for_callback(*f);
        name_copy = strdup(name ? name : "[[unknown]]");
        version = strchr(name_copy, '/');
        if(version) *version++ = '\0';

        scnode = xmlNewNode(NULL, (xmlChar *)"command");
        xmlSetProp(scnode, (xmlChar *)"name", (xmlChar *)name_copy);
        if(version)
          xmlSetProp(scnode, (xmlChar *)"version", (xmlChar *)version);
        xmlSetProp(scnode, (xmlChar *)"code", (xmlChar *)hexcode);
        xmlAddChild(cnode, scnode);
        free(name_copy);
      }
    }

    mods = xmlNewNode(NULL, (xmlChar *)"modules");
    xmlAddChild(root, mods);

#define list_modules(func, name) do { \
    nmods = func(&mod_names); \
    for(i=0; i<nmods; i++) { \
      xmlNodePtr pnode; \
      pnode = xmlNewNode(NULL, (xmlChar *)"module"); \
      xmlSetProp(pnode, (xmlChar *)"type", (xmlChar *)name); \
      xmlSetProp(pnode, (xmlChar *)"name", (xmlChar *)mod_names[i]); \
      xmlAddChild(mods, pnode); \
    } \
    if(mod_names) free(mod_names); \
} while(0)
    for(t = mtev_dso_get_types(); t; t = t->next)
      list_modules(t->list, t->name);

    /* Write it out to a buffer and copy it for writing */
    cl->buff = mtev_xmlSaveToBuffer(xmldoc);
    cl->towrite = strlen(cl->buff);

    /* Clean up after ourselves */
    xmlFreeDoc(xmldoc);
}
static void
mtev_capabilities_tobuff_json(mtev_capsvc_closure_t *cl, eventer_func_t curr) {
    const char **mod_names;
    struct utsname utsn;
    char vbuff[128];
    mtev_hash_table *lc;
    mtev_hash_iter iter = MTEV_HASH_ITER_ZERO;
    const char *k;
    int klen, i, nmods;
    void *data;
    struct timeval now;
    struct dso_type *t;

    struct json_object *doc;
    struct json_object *svcs, *bi, *ri, *mods, *feat;

    /* fill out capabilities */

    /* Create an XML Document */
    doc = json_object_new_object();

    /* Fill in the document */
    mtev_build_version(vbuff, sizeof(vbuff));
    json_object_object_add(doc, "version", json_object_new_string(vbuff));

    /* Build info */
    bi = json_object_new_object();
    json_object_object_add(bi, "bitwidth", json_object_new_int(sizeof(void *)*8));
    json_object_object_add(bi, "sysname", json_object_new_string(UNAME_S));
    json_object_object_add(bi, "nodename", json_object_new_string(UNAME_N));
    json_object_object_add(bi, "release", json_object_new_string(UNAME_R));
    json_object_object_add(bi, "version", json_object_new_string(UNAME_V));
    json_object_object_add(bi, "machine", json_object_new_string(UNAME_M));
    json_object_object_add(doc, "unameBuild", bi);

    /* Run info */
    ri = json_object_new_object();
    json_object_object_add(ri, "bitwidth", json_object_new_int(sizeof(void *)*8));
    if(uname(&utsn) < 0) {
      json_object_object_add(ri, "error", json_object_new_string(strerror(errno)));
    } else {
      json_object_object_add(ri, "sysname", json_object_new_string(utsn.sysname));
      json_object_object_add(ri, "nodename", json_object_new_string(utsn.nodename));
      json_object_object_add(ri, "release", json_object_new_string(utsn.release));
      json_object_object_add(ri, "version", json_object_new_string(utsn.version));
      json_object_object_add(ri, "machine", json_object_new_string(utsn.machine));
    }
    json_object_object_add(doc, "unameRun", ri);

    /* features */
    feat = json_object_new_object();
    if(mtev_hash_size(&features)) {
      mtev_hash_iter iter2 = MTEV_HASH_ITER_ZERO;
      void *vfv;
      const char *f;
      int flen;
      while(mtev_hash_next(&features, &iter2, &f, &flen, &vfv)) {
        struct json_object *featnode;
        featnode = json_object_new_object();
        if(vfv) json_object_object_add(featnode, "version", json_object_new_string(vfv));
        json_object_object_add(feat, f, featnode);
      }
    }
    json_object_object_add(doc, "features", feat);

    /* time (poor man's time check) */
    gettimeofday(&now, NULL);
    snprintf(vbuff, sizeof(vbuff), "%llu%03d", (unsigned long long)now.tv_sec,
             (int)(now.tv_usec / 1000));
    json_object_object_add(doc, "current_time", json_object_new_string(vbuff));

    svcs = json_object_new_object();
    lc = mtev_listener_commands();
    while(mtev_hash_next(lc, &iter, &k, &klen, &data)) {
      struct json_object *cnode, *cmds;
      char hexcode[11];
      const char *name;
      eventer_func_t *f = (eventer_func_t *)k;
      mtev_hash_table *sc = (mtev_hash_table *)data;
      mtev_hash_iter sc_iter = MTEV_HASH_ITER_ZERO;
      const char *sc_k;
      int sc_klen;
      void *sc_data;

      name = eventer_name_for_callback(*f);
      cnode = json_object_new_object();
      if(klen == 8)
        snprintf(hexcode, sizeof(hexcode), "0x%0llx",
                 (unsigned long long int)(vpsized_uint)**f);
      else
        snprintf(hexcode, sizeof(hexcode), "0x%0x",
                 (unsigned int)(vpsized_uint)**f);
      json_object_object_add(svcs, hexcode, cnode);
      if(name) json_object_object_add(cnode, name, json_object_new_string(name));
      cmds = json_object_new_object();
      json_object_object_add(cnode, "commands", cmds);
      while(mtev_hash_next(sc, &sc_iter, &sc_k, &sc_klen, &sc_data)) {
        struct json_object *scnode;
        char *name_copy, *version = NULL;
        eventer_func_t *f = (eventer_func_t *)sc_data;

        scnode = json_object_new_object();
        snprintf(hexcode, sizeof(hexcode), "0x%08x", *((u_int32_t *)sc_k));
        name = eventer_name_for_callback(*f);
        name_copy = strdup(name ? name : "[[unknown]]");
        version = strchr(name_copy, '/');
        if(version) *version++ = '\0';

        json_object_object_add(scnode, "name", json_object_new_string(name_copy));
        if(version) json_object_object_add(scnode, "version", json_object_new_string(version));
        json_object_object_add(cmds, hexcode, scnode);
        free(name_copy);
      }
    }
    json_object_object_add(doc, "services", svcs);

    mods = json_object_new_object();

#define list_modules_json(func, name) do { \
    nmods = func(&mod_names); \
    for(i=0; i<nmods; i++) { \
      struct json_object *pnode; \
      pnode = json_object_new_object(); \
      json_object_object_add(pnode, "type", json_object_new_string(name)); \
      json_object_object_add(mods, mod_names[i], pnode); \
    } \
    if(mod_names) free(mod_names); \
} while(0)
    for(t = mtev_dso_get_types(); t; t = t->next)
      list_modules_json(t->list, t->name);
    json_object_object_add(doc, "modules", mods);

    /* Write it out to a buffer and copy it for writing */
    cl->buff = strdup(json_object_to_json_string(doc));
    cl->towrite = strlen(cl->buff);

    /* Clean up after ourselves */
    json_object_put(doc);
}
static void
noit_capabilities_tobuff(noit_capsvc_closure_t *cl, eventer_func_t curr) {
    char vbuff[128];
    noit_hash_table *lc;
    noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
    const char *k;
    int klen;
    void *data;
    struct timeval now;

    xmlDocPtr xmldoc;
    xmlNodePtr root, cmds;

    /* fill out capabilities */

    /* Create an XML Document */
    xmldoc = xmlNewDoc((xmlChar *)"1.0");
    root = xmlNewDocNode(xmldoc, NULL, (xmlChar *)"noit_capabilities", NULL);
    xmlDocSetRootElement(xmldoc, root);

    /* Fill in the document */
    noit_build_version(vbuff, sizeof(vbuff));
    xmlNewTextChild(root, NULL, (xmlChar *)"version", (xmlChar *)vbuff);

    /* time (poor man's time check) */
    gettimeofday(&now, NULL);
    snprintf(vbuff, sizeof(vbuff), "%llu.%03d", (unsigned long long)now.tv_sec,
             (int)(now.tv_usec / 1000));
    xmlNewTextChild(root, NULL, (xmlChar *)"current_time", (xmlChar *)vbuff);

    cmds = xmlNewNode(NULL, (xmlChar *)"services");
    xmlAddChild(root, cmds);
    lc = noit_listener_commands();
    while(noit_hash_next(lc, &iter, &k, &klen, &data)) {
      xmlNodePtr cnode;
      char hexcode[11];
      const char *name;
      eventer_func_t *f = (eventer_func_t *)k;
      noit_hash_table *sc = (noit_hash_table *)data;
      noit_hash_iter sc_iter = NOIT_HASH_ITER_ZERO;
      const char *sc_k;
      int sc_klen;
      void *sc_data;

      name = eventer_name_for_callback(*f);
      cnode = xmlNewNode(NULL, (xmlChar *)"service");
      xmlSetProp(cnode, (xmlChar *)"name", name ? (xmlChar *)name : NULL);
      if(*f == curr)
        xmlSetProp(cnode, (xmlChar *)"connected", (xmlChar *)"true");
      xmlAddChild(cmds, cnode);
      while(noit_hash_next(sc, &sc_iter, &sc_k, &sc_klen, &sc_data)) {
        xmlNodePtr scnode;
        char *name_copy, *version = NULL;
        eventer_func_t *f = (eventer_func_t *)sc_data;

        snprintf(hexcode, sizeof(hexcode), "0x%08x", *((u_int32_t *)sc_k));
        name = eventer_name_for_callback(*f);
        name_copy = strdup(name ? name : "[[unknown]]");
        version = strchr(name_copy, '/');
        if(version) *version++ = '\0';

        scnode = xmlNewNode(NULL, (xmlChar *)"command");
        xmlSetProp(scnode, (xmlChar *)"name", (xmlChar *)name_copy);
        if(version)
          xmlSetProp(scnode, (xmlChar *)"version", (xmlChar *)version);
        xmlSetProp(scnode, (xmlChar *)"code", (xmlChar *)hexcode);
        xmlAddChild(cnode, scnode);
        free(name_copy);
      }
    }

    /* Write it out to a buffer and copy it for writing */
    cl->buff = noit_xmlSaveToBuffer(xmldoc);
    cl->towrite = strlen(cl->buff);

    /* Clean up after ourselves */
    xmlFreeDoc(xmldoc);
}
Ejemplo n.º 10
0
int
noit_capabilities_handler(eventer_t e, int mask, void *closure,
                          struct timeval *now) {
  int newmask = EVENTER_WRITE | EVENTER_EXCEPTION;
  acceptor_closure_t *ac = closure;
  noit_capsvc_closure_t *cl = ac->service_ctx;

  if(mask & EVENTER_EXCEPTION) {
socket_error:
    /* Exceptions cause us to simply snip the connection */
cleanup_shutdown:
    eventer_remove_fd(e->fd);
    e->opset->close(e->fd, &newmask, e);
    if(cl) {
      if(cl->buff) free(cl->buff);
      free(cl);
    }
    if(ac) acceptor_closure_free(ac);
    return 0;
  }

  if(!ac->service_ctx) {
    char vbuff[128];
    noit_hash_table *lc;
    noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
    const char *k;
    int klen;
    void *data;

    xmlDocPtr xmldoc;
    xmlNodePtr root, cmds;

    cl = ac->service_ctx = calloc(1, sizeof(*cl));
    /* fill out capabilities */
    noit_build_version(vbuff, sizeof(vbuff));

    /* Create an XML Document */
    xmldoc = xmlNewDoc((xmlChar *)"1.0");
    root = xmlNewDocNode(xmldoc, NULL, (xmlChar *)"noit_capabilities", NULL);
    xmlDocSetRootElement(xmldoc, root);

    /* Fill in the document */
    xmlNewTextChild(root, NULL, (xmlChar *)"version", (xmlChar *)vbuff);

    cmds = xmlNewNode(NULL, (xmlChar *)"services");
    xmlAddChild(root, cmds);
    lc = noit_listener_commands();
    while(noit_hash_next(lc, &iter, &k, &klen, &data)) {
      xmlNodePtr cnode;
      char hexcode[11];
      const char *name;
      eventer_func_t *f = (eventer_func_t *)k;
      noit_hash_table *sc = (noit_hash_table *)data;
      noit_hash_iter sc_iter = NOIT_HASH_ITER_ZERO;
      const char *sc_k;
      int sc_klen;
      void *sc_data;

      name = eventer_name_for_callback(*f);
      cnode = xmlNewNode(NULL, (xmlChar *)"service");
      xmlSetProp(cnode, (xmlChar *)"name", name ? (xmlChar *)name : NULL);
      if(*f == ac->dispatch)
        xmlSetProp(cnode, (xmlChar *)"connected", (xmlChar *)"true");
      xmlAddChild(cmds, cnode);
      while(noit_hash_next(sc, &sc_iter, &sc_k, &sc_klen, &sc_data)) {
        xmlNodePtr scnode;
        char *name_copy, *version = NULL;
        eventer_func_t *f = (eventer_func_t *)sc_data;

        snprintf(hexcode, sizeof(hexcode), "0x%08x", *((u_int32_t *)sc_k));
        name = eventer_name_for_callback(*f);
        name_copy = strdup(name ? name : "[[unknown]]");
        version = strchr(name_copy, '/');
        if(version) *version++ = '\0';

        scnode = xmlNewNode(NULL, (xmlChar *)"command");
        xmlSetProp(scnode, (xmlChar *)"name", (xmlChar *)name_copy);
        if(version)
          xmlSetProp(scnode, (xmlChar *)"version", (xmlChar *)version);
        xmlSetProp(scnode, (xmlChar *)"code", (xmlChar *)hexcode);
        xmlAddChild(cnode, scnode);
        free(name_copy);
      }
    }

    /* Write it out to a buffer and copy it for writing */
    cl->buff = noit_xmlSaveToBuffer(xmldoc);
    cl->towrite = strlen(cl->buff);

    /* Clean up after ourselves */
    xmlFreeDoc(xmldoc);
  }

  while(cl->towrite > cl->written) {
    int len;
    while((len = e->opset->write(e->fd, cl->buff + cl->written,
                                 cl->towrite - cl->written,
                                 &newmask, e)) == -1 && errno == EINTR);
    if(len < 0) {
      if(errno == EAGAIN) return newmask | EVENTER_EXCEPTION;
      goto socket_error;
    }
    cl->written += len;
  }
  goto cleanup_shutdown;
}
Ejemplo n.º 11
0
int
noit_listener(char *host, unsigned short port, int type,
              int backlog, noit_hash_table *sslconfig,
              noit_hash_table *config,
              eventer_func_t handler, void *service_ctx) {
  int rv, fd;
  int8_t family;
  int sockaddr_len;
  socklen_t reuse;
  listener_closure_t listener_closure;
  eventer_t event;
  union {
    struct in_addr addr4;
    struct in6_addr addr6;
  } a;
  union {
    struct sockaddr_in addr4;
    struct sockaddr_in6 addr6;
    struct sockaddr_un addru;
  } s;
  const char *event_name;

  noitL(nldeb, "noit_listener(%s, %d, %d, %d, %s, %p)\n",
        host, port, type, backlog,
        (event_name = eventer_name_for_callback(handler))?event_name:"??",
        service_ctx);
  if(host[0] == '/') {
    family = AF_UNIX;
  }
  else {
    family = AF_INET;
    rv = inet_pton(family, host, &a);
    if(rv != 1) {
      family = AF_INET6;
      rv = inet_pton(family, host, &a);
      if(rv != 1) {
        if(!strcmp(host, "*")) {
          family = AF_INET;
          a.addr4.s_addr = INADDR_ANY;
        } else {
          noitL(noit_error, "Cannot translate '%s' to IP\n", host);
          return -1;
        }
      }
    }
  }

  fd = socket(family, NE_SOCK_CLOEXEC|type, 0);
  if(fd < 0) {
    noitL(noit_error, "Cannot create socket: %s\n", strerror(errno));
    return -1;
  }

  if(eventer_set_fd_nonblocking(fd)) {
    close(fd);
    noitL(noit_error, "Cannot make socket non-blocking: %s\n",
          strerror(errno));
    return -1;
  }

  reuse = 1;
  if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
                 (void*)&reuse, sizeof(reuse)) != 0) {
    close(fd);
    noitL(noit_error, "Cannot set SO_REUSEADDR: %s\n", strerror(errno));
    return -1;
  }

  memset(&s, 0, sizeof(s));
  if(family == AF_UNIX) {
    struct stat sb;
    /* unlink the path if it is a socket */
    /* coverity[fs_check_call] */
    if(stat(host, &sb) == -1) {
      if(errno != ENOENT) {
        noitL(noit_error, "%s: %s\n", host, strerror(errno));
        close(fd);
        return -1;
      }
    }
    else {
      if(sb.st_mode & S_IFSOCK) {
        /* coverity[toctou] */
        unlink(host);
      }
      else {
        noitL(noit_error, "unlink %s failed: %s\n", host, strerror(errno));
        close(fd);
        return -1;
      }
    }
    s.addru.sun_family = AF_UNIX;
    strncpy(s.addru.sun_path, host, sizeof(s.addru.sun_path)-1);
    sockaddr_len = sizeof(s.addru);
  }
  else {
    if(family == AF_INET6) {
      s.addr6.sin6_family = family;
      s.addr6.sin6_port = htons(port);
      memcpy(&s.addr6.sin6_addr, &a.addr6, sizeof(a.addr6));
    }
    else {
      s.addr4.sin_family = family;
      s.addr4.sin_port = htons(port);
      memcpy(&s.addr4.sin_addr, &a.addr4, sizeof(a.addr4));
    }
    sockaddr_len = (family == AF_INET) ?  sizeof(s.addr4) : sizeof(s.addr6);
  }
  if(bind(fd, (struct sockaddr *)&s, sockaddr_len) < 0) {
    noitL(noit_error, "bind failed[%s]: %s\n", host, strerror(errno));
    close(fd);
    return -1;
  }

  if(type == SOCK_STREAM) {
    if(listen(fd, backlog) < 0) {
      close(fd);
      return -1;
    }
  }

  listener_closure = calloc(1, sizeof(*listener_closure));
  listener_closure->family = family;
  listener_closure->port = htons(port);
  listener_closure->sslconfig = calloc(1, sizeof(noit_hash_table));
  noit_hash_merge_as_dict(listener_closure->sslconfig, sslconfig);
  listener_closure->dispatch_callback = handler;

  listener_closure->dispatch_closure =
    calloc(1, sizeof(*listener_closure->dispatch_closure));
  listener_closure->dispatch_closure->config = config;
  listener_closure->dispatch_closure->dispatch = handler;
  listener_closure->dispatch_closure->service_ctx = service_ctx;

  event = eventer_alloc();
  event->fd = fd;
  event->mask = EVENTER_READ | EVENTER_EXCEPTION;
  event->callback = noit_listener_acceptor;
  event->closure = listener_closure;

  eventer_add(event);
  return 0;
}
Ejemplo n.º 12
0
static int
noit_listener_acceptor(eventer_t e, int mask,
                       void *closure, struct timeval *tv) {
  int conn, newmask = EVENTER_READ;
  socklen_t salen;
  listener_closure_t listener_closure = (listener_closure_t)closure;
  acceptor_closure_t *ac = NULL;

  if(mask & EVENTER_EXCEPTION) {
 socketfail:
    if(ac) acceptor_closure_free(ac);
    /* We don't shut down the socket, it's out listener! */
    return EVENTER_READ | EVENTER_WRITE | EVENTER_EXCEPTION;
  }

  do {
    ac = malloc(sizeof(*ac));
    memcpy(ac, listener_closure->dispatch_closure, sizeof(*ac));
    salen = sizeof(ac->remote);
    conn = e->opset->accept(e->fd, &ac->remote.remote_addr, &salen, &newmask, e);
    if(conn >= 0) {
      eventer_t newe;
      noitL(nldeb, "noit_listener[%s] accepted fd %d\n",
            eventer_name_for_callback(listener_closure->dispatch_callback),
            conn);
      if(eventer_set_fd_nonblocking(conn)) {
        close(conn);
        free(ac);
        goto accept_bail;
      }
      newe = eventer_alloc();
      newe->fd = conn;
      newe->mask = EVENTER_READ | EVENTER_WRITE | EVENTER_EXCEPTION;
  
      if(listener_closure->sslconfig->size) {
        const char *layer, *cert, *key, *ca, *ciphers, *crl;
        eventer_ssl_ctx_t *ctx;
        /* We have an SSL configuration.  While our socket accept is
         * complete, we now have to SSL_accept, which could require
         * several reads and writes and needs its own event callback.
         */
  #define SSLCONFGET(var,name) do { \
    if(!noit_hash_retr_str(listener_closure->sslconfig, name, strlen(name), \
                           &var)) var = NULL; } while(0)
        SSLCONFGET(layer, "layer");
        SSLCONFGET(cert, "certificate_file");
        SSLCONFGET(key, "key_file");
        SSLCONFGET(ca, "ca_chain");
        SSLCONFGET(ciphers, "ciphers");
        ctx = eventer_ssl_ctx_new(SSL_SERVER, layer, cert, key, ca, ciphers);
        if(!ctx) {
          newe->opset->close(newe->fd, &newmask, e);
          eventer_free(newe);
          goto socketfail;
        }
        SSLCONFGET(crl, "crl");
        if(crl) {
          if(!eventer_ssl_use_crl(ctx, crl)) {
            noitL(noit_error, "Failed to load CRL from %s\n", crl);
            eventer_ssl_ctx_free(ctx);
            newe->opset->close(newe->fd, &newmask, e);
            eventer_free(newe);
            goto socketfail;
          }
        }

        eventer_ssl_ctx_set_verify(ctx, eventer_ssl_verify_cert,
                                   listener_closure->sslconfig);
        EVENTER_ATTACH_SSL(newe, ctx);
        newe->callback = noit_listener_accept_ssl;
        newe->closure = malloc(sizeof(*listener_closure));
        memcpy(newe->closure, listener_closure, sizeof(*listener_closure));
        ((listener_closure_t)newe->closure)->dispatch_closure = ac;
      }
      else {
        newe->callback = listener_closure->dispatch_callback;
        /* We must make a copy of the acceptor_closure_t for each new
         * connection.
         */
        newe->closure = ac;
      }
      eventer_add(newe);
    }
    else {
      if(errno == EAGAIN) {
        if(ac) acceptor_closure_free(ac);
      }
      else if(errno != EINTR) {
        noitL(noit_error, "accept socket error: %s\n", strerror(errno));
        goto socketfail;
      }
    }
  } while(conn >= 0);
 accept_bail:
  return newmask | EVENTER_EXCEPTION;
}