Exemplo n.º 1
0
static void first_ev_next(msevent *nse, gh_lnode_t **first, int nodeq2) {
  if (!first || !*first)
    return;

  if (&nse->nodeq_io == *first || &nse->nodeq_pcap == *first) {
    gh_lnode_t *next;

    next = gh_lnode_next(*first);
    if (next) {
      msevent *newevent;

      if (nodeq2)
        newevent = lnode_msevent2(next);
      else
        newevent = lnode_msevent(next);

      if (newevent->iod == nse->iod)
        *first = next;
      else
        *first = NULL;
    } else {
      *first = NULL;
    }
  }
}
Exemplo n.º 2
0
/* Returns whether something was read */
int pcap_read_on_nonselect(mspool *nsp) {
  gh_lnode_t *current, *next;
  msevent *nse;
  int ret = 0;

  for (current = gh_list_first_elem(&nsp->pcap_read_events);
       current != NULL;
       current = next) {
    nse = lnode_msevent2(current);
    if (do_actual_pcap_read(nse) == 1) {
      /* something received */
      ret++;
      break;
    }
    next = gh_lnode_next(current);
  }
  return ret;
}
Exemplo n.º 3
0
/* Cancel an event (such as a timer or read request).  If notify is nonzero, the
 * requester will be sent an event CANCELLED status back to the given handler.
 * But in some cases there is no need to do this (like if the function deleting
 * it is the one which created it), in which case 0 can be passed to skip the
 * step.  This function returns zero if the event is not found, nonzero
 * otherwise. */
int nsock_event_cancel(nsock_pool ms_pool, nsock_event_id id, int notify) {
  mspool *nsp = (mspool *)ms_pool;
  enum nse_type type;
  unsigned int i;
  gh_list_t *event_list = NULL, *event_list2 = NULL;
  gh_lnode_t *current, *next;
  msevent *nse = NULL;

  assert(nsp);

  type = get_event_id_type(id);
  nsock_log_info(nsp, "Event #%li (type %s) cancelled", id, nse_type2str(type));

  /* First we figure out what list it is in */
  switch (type) {
    case NSE_TYPE_CONNECT:
    case NSE_TYPE_CONNECT_SSL:
      event_list = &nsp->connect_events;
      break;

    case NSE_TYPE_READ:
      event_list = &nsp->read_events;
      break;

    case NSE_TYPE_WRITE:
      event_list = &nsp->write_events;
      break;

    case NSE_TYPE_TIMER:
      for (i = 0; i < gh_heap_count(&nsp->expirables); i++) {
        gh_hnode_t *hnode;

        hnode = gh_heap_find(&nsp->expirables, i);
        nse = container_of(hnode, msevent, expire);
        if (nse->id == id)
          return msevent_cancel(nsp, nse, NULL, NULL, notify);
      }
      return 0;

#if HAVE_PCAP
    case NSE_TYPE_PCAP_READ:
      event_list  = &nsp->read_events;
      event_list2 = &nsp->pcap_read_events;
      break;
#endif

    default:
      fatal("Bogus event type in nsock_event_cancel"); break;
  }

  /* Now we try to find the event in the list */
  for (current = gh_list_first_elem(event_list); current != NULL; current = next) {
    next = gh_lnode_next(current);
    nse = lnode_msevent(current);
    if (nse->id == id)
      break;
  }

  if (current == NULL && event_list2) {
    event_list = event_list2;
    for (current = gh_list_first_elem(event_list); current != NULL; current = next) {
      next = gh_lnode_next(current);
      nse = lnode_msevent2(current);
      if (nse->id == id)
        break;
    }
  }
  if (current == NULL)
    return 0;

  return msevent_cancel(nsp, nse, event_list, current, notify);
}
Exemplo n.º 4
0
void process_iod_events(mspool *nsp, msiod *nsi, int ev) {
  int i = 0;
  /* store addresses of the pointers to the first elements of each kind instead
   * of storing the values, as a connect can add a read for instance */
  gh_lnode_t **start_elems[] = {
    &nsi->first_connect,
    &nsi->first_read,
    &nsi->first_write,
#if HAVE_PCAP
    &nsi->first_pcap_read,
#endif
    NULL
  };
  gh_list_t *evlists[] = {
    &nsp->connect_events,
    &nsp->read_events,
    &nsp->write_events,
#if HAVE_PCAP
    &nsp->pcap_read_events,
#endif
    NULL
  };

  assert(nsp == nsi->nsp);
  nsock_log_debug_all(nsp, "Processing events on IOD %lu (ev=%d)", nsi->id, ev);

  /* We keep the events separate because we want to handle them in the
   * order: connect => read => write => timer for several reasons:
   *
   *  1) Makes sure we have gone through all the net i/o events before
   *     a timer expires (would be a shame to timeout after the data was
   *     available but before we delivered the events
   *
   *  2) The connect() results often lead to a read or write that can be
   *     processed in the same cycle.  In the same way, read() often
   *     leads to write().
   */
  for (i = 0; evlists[i] != NULL; i++) {
    gh_lnode_t *current, *next, *last;

    /* for each list, get the last event and don't look past it as an event
     * could add another event in the same list and so on... */
    last = gh_list_last_elem(evlists[i]);

    for (current = *start_elems[i];
         current != NULL && gh_lnode_prev(current) != last;
         current = next) {
      msevent *nse;

#if HAVE_PCAP
      if (evlists[i] == &nsi->nsp->pcap_read_events)
        nse = lnode_msevent2(current);
      else
#endif
        nse = lnode_msevent(current);

      /* events are grouped by IOD. Break if we're done with the events for the
       * current IOD */
      if (nse->iod != nsi)
        break;

      process_event(nsp, evlists[i], nse, ev);
      next = gh_lnode_next(current);

      if (nse->event_done) {
        /* event is done, remove it from the event list and update IOD pointers
         * to the first events of each kind */
        update_first_events(nse);
        gh_list_remove(evlists[i], current);
        gh_list_append(&nsp->free_events, &nse->nodeq_io);

        if (nse->timeout.tv_sec)
          gh_heap_remove(&nsp->expirables, &nse->expire);
      }
    }
  }
}
/* If nsp_new returned success, you must free the nsp when you are done with it
 * to conserve memory (and in some cases, sockets).  After this call, nsp may no
 * longer be used.  Any pending events are sent an NSE_STATUS_KILL callback and
 * all outstanding iods are deleted. */
void nsp_delete(nsock_pool ms_pool) {
  mspool *nsp = (mspool *)ms_pool;
  msevent *nse;
  msiod *nsi;
  int i;
  gh_lnode_t *current, *next;
  gh_list_t *event_lists[] = {
    &nsp->connect_events,
    &nsp->read_events,
    &nsp->write_events,
#if HAVE_PCAP
    &nsp->pcap_read_events,
#endif
    NULL
  };

  assert(nsp);

  /* First I go through all the events sending NSE_STATUS_KILL */
  for (i = 0; event_lists[i] != NULL; i++) {
    while (gh_list_count(event_lists[i]) > 0) {
      gh_lnode_t *lnode = gh_list_pop(event_lists[i]);

      assert(lnode);

#if HAVE_PCAP
      if (event_lists[i] == &nsp->pcap_read_events)
        nse = lnode_msevent2(lnode);
      else
#endif
        nse = lnode_msevent(lnode);

      assert(nse);

      nse->status = NSE_STATUS_KILL;
      nsock_trace_handler_callback(nsp, nse);
      nse->handler(nsp, nse, nse->userdata);

      if (nse->iod) {
        nse->iod->events_pending--;
        assert(nse->iod->events_pending >= 0);
      }
      msevent_delete(nsp, nse);
    }
    gh_list_free(event_lists[i]);
  }

  /* Kill timers too, they're not in event lists */
  while (gh_heap_count(&nsp->expirables) > 0) {
    gh_hnode_t *hnode;

    hnode = gh_heap_pop(&nsp->expirables);
    nse = container_of(hnode, msevent, expire);

    if (nse->type == NSE_TYPE_TIMER) {
      nse->status = NSE_STATUS_KILL;
      nsock_trace_handler_callback(nsp, nse);
      nse->handler(nsp, nse, nse->userdata);
      msevent_delete(nsp, nse);
      gh_list_append(&nsp->free_events, &nse->nodeq_io);
    }
  }

  gh_heap_free(&nsp->expirables);

  /* foreach msiod */
  for (current = gh_list_first_elem(&nsp->active_iods);
       current != NULL;
       current = next) {
    next = gh_lnode_next(current);
    nsi = container_of(current, msiod, nodeq);

    nsi_delete(nsi, NSOCK_PENDING_ERROR);

    gh_list_remove(&nsp->active_iods, current);
    gh_list_prepend(&nsp->free_iods, &nsi->nodeq);
  }

  /* Now we free all the memory in the free iod list */
  while ((current = gh_list_pop(&nsp->free_iods))) {
    nsi = container_of(current, msiod, nodeq);
    free(nsi);
  }

  while ((current = gh_list_pop(&nsp->free_events))) {
    nse = lnode_msevent(current);
    free(nse);
  }

  gh_list_free(&nsp->active_iods);
  gh_list_free(&nsp->free_iods);
  gh_list_free(&nsp->free_events);

  nsock_engine_destroy(nsp);

#if HAVE_OPENSSL
  if (nsp->sslctx != NULL)
    SSL_CTX_free(nsp->sslctx);
#endif

  free(nsp);
}