Example #1
0
/* 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;
   gh_list *event_lists[] = { &nsp->evl.connect_events,
                               &nsp->evl.read_events,
                               &nsp->evl.write_events,
                               &nsp->evl.timer_events,
                               0
                             };
   int current_list_idx;
   msevent *nse;
   msiod *nsi;
   gh_list_elem *current, *next;

   assert(nsp);


  /* First I go through all the events sending NSE_STATUS_KILL */
    /* foreach list */
    for(current_list_idx = 0; event_lists[current_list_idx] != NULL;
	current_list_idx++) {
      while(GH_LIST_COUNT(event_lists[current_list_idx]) > 0) {
	nse = (msevent *) gh_list_pop(event_lists[current_list_idx]);
	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[current_list_idx]);
    }

  /* Then I go through and kill the iods */
    for(current = GH_LIST_FIRST_ELEM(&nsp->active_iods);
	current != NULL; current = next) {
      next = GH_LIST_ELEM_NEXT(current);
      nsi = (msiod *) GH_LIST_ELEM_DATA(current);
      nsi_delete(nsi, NSOCK_PENDING_ERROR);
    }

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

    while((nsi = (msiod *) gh_list_pop(&nsp->evl.free_events))) {
      free(nsi);
    }
    gh_list_free(&nsp->evl.free_events);
    gh_list_free(&nsp->active_iods);
    gh_list_free(&nsp->free_iods);

    free(nsp);
}
Example #2
0
/* 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_list_elem *current, *next;
  gh_list *event_lists[] = {
    &nsp->connect_events,
    &nsp->read_events,
    &nsp->write_events,
    &nsp->timer_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) {
      nse = (msevent *)gh_list_pop(event_lists[i]);

      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]);
  }

  /* foreach msiod */
  for (current = GH_LIST_FIRST_ELEM(&nsp->active_iods); current != NULL; current = next) {
    next = GH_LIST_ELEM_NEXT(current);
    nsi = (msiod *)GH_LIST_ELEM_DATA(current);
    nsi_delete(nsi, NSOCK_PENDING_ERROR);

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

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

  while ((nse = (msevent *)gh_list_pop(&nsp->free_events))) {
    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);
}
Example #3
0
int select_loop(mspool *nsp, int msec_timeout) {
  int results_left = 0;
  int event_msecs; /* msecs before an event goes off */
  int combined_msecs;
  int sock_err = 0;
  struct timeval select_tv;
  struct timeval *select_tv_p;
  struct select_engine_info *sinfo = (struct select_engine_info *)nsp->engine_data;

  assert(msec_timeout >= -1);

  if (nsp->events_pending == 0)
    return 0; /* No need to wait on 0 events ... */

  do {
    nsock_log_debug_all(nsp, "wait for events");

    if (nsp->next_ev.tv_sec == 0)
      event_msecs = -1; /* None of the events specified a timeout */
    else
      event_msecs = MAX(0, TIMEVAL_MSEC_SUBTRACT(nsp->next_ev, nsock_tod));

#if HAVE_PCAP
#ifndef PCAP_CAN_DO_SELECT
    /* Force a low timeout when capturing packets on systems where
     * the pcap descriptor is not select()able. */
    if (GH_LIST_COUNT(&nsp->pcap_read_events))
      if (event_msecs > PCAP_POLL_INTERVAL)
        event_msecs = PCAP_POLL_INTERVAL;
#endif
#endif

    /* We cast to unsigned because we want -1 to be very high (since it means no
     * timeout) */
    combined_msecs = MIN((unsigned)event_msecs, (unsigned)msec_timeout);

    /* Set up the timeval pointer we will give to select() */
    memset(&select_tv, 0, sizeof(select_tv));
    if (combined_msecs > 0) {
      select_tv.tv_sec = combined_msecs / 1000;
      select_tv.tv_usec = (combined_msecs % 1000) * 1000;
      select_tv_p = &select_tv;
    } else if (combined_msecs == 0) {
      /* we want the tv_sec and tv_usec to be zero but they already are from bzero */
      select_tv_p = &select_tv;
    } else {
      assert(combined_msecs == -1);
      select_tv_p = NULL;
    }

#if HAVE_PCAP
#ifndef PCAP_CAN_DO_SELECT
    /* do non-blocking read on pcap devices that doesn't support select()
     * If there is anything read, just leave this loop. */
    if (pcap_read_on_nonselect(nsp)) {
      /* okay, something was read. */
    } else
#endif
#endif
    {
      /* Set up the descriptors for select */
      sinfo->fds_results_r = sinfo->fds_master_r;
      sinfo->fds_results_w = sinfo->fds_master_w;
      sinfo->fds_results_x = sinfo->fds_master_x;

      results_left = fselect(sinfo->max_sd + 1, &sinfo->fds_results_r,
                             &sinfo->fds_results_w, &sinfo->fds_results_x, select_tv_p);

      if (results_left == -1)
        sock_err = socket_errno();
    }

    gettimeofday(&nsock_tod, NULL); /* Due to select delay */
  } while (results_left == -1 && sock_err == EINTR); /* repeat only if signal occurred */

  if (results_left == -1 && sock_err != EINTR) {
    nsock_log_error(nsp, "nsock_loop error %d: %s", sock_err, socket_strerror(sock_err));
    nsp->errnum = sock_err;
    return -1;
  }

  iterate_through_event_lists(nsp);

  return 1;
}
Example #4
0
int kqueue_loop(mspool *nsp, int msec_timeout) {
  int results_left = 0;
  int event_msecs; /* msecs before an event goes off */
  int combined_msecs;
  struct timespec ts, *ts_p;
  int sock_err = 0;
  struct kqueue_engine_info *kinfo = (struct kqueue_engine_info *)nsp->engine_data;

  assert(msec_timeout >= -1);

  if (nsp->events_pending == 0)
    return 0; /* No need to wait on 0 events ... */


  if (GH_LIST_COUNT(&nsp->active_iods) > kinfo->evlen) {
    kinfo->evlen = GH_LIST_COUNT(&nsp->active_iods) * 2;
    kinfo->events = (struct kevent *)safe_realloc(kinfo->events, kinfo->evlen * sizeof(struct kevent));
  }

  do {
    if (nsp->tracelevel > 6)
      nsock_trace(nsp, "wait_for_events");

    if (nsp->next_ev.tv_sec == 0)
      event_msecs = -1; /* None of the events specified a timeout */
    else
      event_msecs = MAX(0, TIMEVAL_MSEC_SUBTRACT(nsp->next_ev, nsock_tod));

#if HAVE_PCAP
#ifndef PCAP_CAN_DO_SELECT
    /* Force a low timeout when capturing packets on systems where
     * the pcap descriptor is not select()able. */
    if (GH_LIST_COUNT(&nsp->pcap_read_events) > 0)
      if (event_msecs > PCAP_POLL_INTERVAL)
        event_msecs = PCAP_POLL_INTERVAL;
#endif
#endif

    /* We cast to unsigned because we want -1 to be very high (since it means no
     * timeout) */
    combined_msecs = MIN((unsigned)event_msecs, (unsigned)msec_timeout);

    /* Set up the timeval pointer we will give to kevent() */
    memset(&ts, 0, sizeof(struct timespec));
    if (combined_msecs >= 0) {
      ts.tv_sec = combined_msecs / 1000;
      ts.tv_nsec = (combined_msecs % 1000) * 1000000L;
      ts_p = &ts;
    } else {
      ts_p = NULL;
    }

#if HAVE_PCAP
#ifndef PCAP_CAN_DO_SELECT
    /* do non-blocking read on pcap devices that doesn't support select()
     * If there is anything read, just leave this loop. */
    if (pcap_read_on_nonselect(nsp)) {
      /* okay, something was read. */
    } else
#endif
#endif
    {
      results_left = kevent(kinfo->kqfd, NULL, 0, kinfo->events, kinfo->evlen, ts_p);
      if (results_left == -1)
        sock_err = socket_errno();
    }

    gettimeofday(&nsock_tod, NULL); /* Due to kevent delay */
  } while (results_left == -1 && sock_err == EINTR); /* repeat only if signal occurred */

  if (results_left == -1 && sock_err != EINTR) {
    nsock_trace(nsp, "nsock_loop error %d: %s", sock_err, socket_strerror(sock_err));
    nsp->errnum = sock_err;
    return -1;
  }

  iterate_through_event_lists(nsp, results_left);

  return 1;
}
Example #5
0
/* Iterate through all the event lists (such as connect_events, read_events,
 * timer_events, etc) and take action for those that have completed (due to
 * timeout, i/o, etc) */
void iterate_through_event_lists(mspool *nsp, int evcount) {
  int n, initial_iod_count;
  struct epoll_engine_info *einfo = (struct epoll_engine_info *)nsp->engine_data;
  gh_list_elem *current, *next, *last, *timer_last, *last_active = NULL;
  msevent *nse;
  msiod *nsi;

  /* Clear it -- We will find the next event as we go through the list */
  nsp->next_ev.tv_sec = 0;

  last = GH_LIST_LAST_ELEM(&nsp->active_iods);
  timer_last = GH_LIST_LAST_ELEM(&nsp->timer_events);

  initial_iod_count = GH_LIST_COUNT(&nsp->active_iods);

  for (n = 0; n < evcount; n++) {
    nsi = (msiod *)einfo->events[n].data.ptr;
    assert(nsi);

    if (nsi->entry_in_nsp_active_iods == last)
      last = GH_LIST_ELEM_PREV(nsi->entry_in_nsp_active_iods);

    /* process all the pending events for this IOD */
    process_iod_events(nsp, nsi, get_evmask(einfo, n));

    if (nsi->state != NSIOD_STATE_DELETED) {
      gh_list_move_front(&nsp->active_iods, nsi->entry_in_nsp_active_iods);
      if (last_active == NULL)
        last_active = nsi->entry_in_nsp_active_iods;
    } else {
      gh_list_remove_elem(&nsp->active_iods, nsi->entry_in_nsp_active_iods);
      gh_list_prepend(&nsp->free_iods, nsi);
    }
  }

  if (evcount < initial_iod_count) {
    /* some IODs had no active events and need to be processed */
    if (!last_active)
      /* either no IOD had events or all IODs were deleted after event processing */
      current = GH_LIST_FIRST_ELEM(&nsp->active_iods);
    else
      /* IODs that had active events were pushed to the beginning of the list, start after them */
      current = GH_LIST_ELEM_NEXT(last_active);
  } else {
    /* all the IODs had events and were therefore processed */
    current = NULL;
  }

  /* cull timeouts amongst the non active IODs */
  while (current != NULL && GH_LIST_ELEM_PREV(current) != last) {
    nsi = (msiod *)GH_LIST_ELEM_DATA(current);

    if (nsi->state != NSIOD_STATE_DELETED && nsi->events_pending)
      process_iod_events(nsp, nsi, EV_NONE);

    next = GH_LIST_ELEM_NEXT(current);
    if (nsi->state == NSIOD_STATE_DELETED) {
      gh_list_remove_elem(&nsp->active_iods, current);
      gh_list_prepend(&nsp->free_iods, nsi);
    }
    current = next;
  }

  /* iterate through timers */
  for (current = GH_LIST_FIRST_ELEM(&nsp->timer_events);
      current != NULL && GH_LIST_ELEM_PREV(current) != timer_last; current = next) {

    nse = (msevent *)GH_LIST_ELEM_DATA(current);

    process_event(nsp, &nsp->timer_events, nse, EV_NONE);

    next = GH_LIST_ELEM_NEXT(current);
    if (nse->event_done)
      gh_list_remove_elem(&nsp->timer_events, current);
  }
}
Example #6
0
int poll_loop(mspool *nsp, int msec_timeout) {
  int results_left = 0;
  int event_msecs; /* msecs before an event goes off */
  int combined_msecs;
  int sock_err = 0;
  struct poll_engine_info *pinfo = (struct poll_engine_info *)nsp->engine_data;

  assert(msec_timeout >= -1);

  if (nsp->events_pending == 0)
    return 0; /* No need to wait on 0 events ... */

  do {
    nsock_log_debug_all(nsp, "wait for events");

    if (nsp->next_ev.tv_sec == 0)
      event_msecs = -1; /* None of the events specified a timeout */
    else
      event_msecs = MAX(0, TIMEVAL_MSEC_SUBTRACT(nsp->next_ev, nsock_tod));

#if HAVE_PCAP
#ifndef PCAP_CAN_DO_SELECT
    /* Force a low timeout when capturing packets on systems where
     * the pcap descriptor is not select()able. */
    if (GH_LIST_COUNT(&nsp->pcap_read_events) > 0)
      if (event_msecs > PCAP_POLL_INTERVAL)
        event_msecs = PCAP_POLL_INTERVAL;
#endif
#endif

    /* We cast to unsigned because we want -1 to be very high (since it means no
     * timeout) */
    combined_msecs = MIN((unsigned)event_msecs, (unsigned)msec_timeout);

#if HAVE_PCAP
#ifndef PCAP_CAN_DO_SELECT
    /* do non-blocking read on pcap devices that doesn't support select()
     * If there is anything read, just leave this loop. */
    if (pcap_read_on_nonselect(nsp)) {
      /* okay, something was read. */
    } else
#endif
#endif
    {
      if (pinfo->max_fd > -1)
        results_left = Poll(pinfo->events, pinfo->max_fd + 1, combined_msecs);
      else
        results_left = 0;

      if (results_left == -1)
        sock_err = socket_errno();
    }

    gettimeofday(&nsock_tod, NULL); /* Due to poll delay */
  } while (results_left == -1 && sock_err == EINTR); /* repeat only if signal occurred */

  if (results_left == -1 && sock_err != EINTR) {
    nsock_log_error(nsp, "nsock_loop error %d: %s", sock_err, socket_strerror(sock_err));
    nsp->errnum = sock_err;
    return -1;
  }

  iterate_through_event_lists(nsp);

  return 1;
}
Example #7
0
int main(int argc, char *argv[]) {
  gh_list lists[16];
  gh_list_elem *current, *next;
  int num = 0;
  int ret;
  int i;

  for(i=0; i < 16; i++)
    gh_list_init(&lists[i]);

  for(num=25000; num < 50000; num++) {
    for(i=0; i < 16; i++) {
      gh_list_append(&lists[i], (void *)num);
    }
  }

  for(num=24999; num >= 0; num--) {
    for(i=0; i < 16; i++) {
      gh_list_prepend(&lists[i], (void *)num);
    }
  }

  for(num=0; num < 50000; num++) {
    for(i=0; i < 16; i++) {
      ret = (int) gh_list_pop(&lists[i]);
      if (ret != num)
	fatal("prepend_test: Bogus return value %d when expected %d\n", ret, num);
    }
  }
  for(i=0; i < 16; i++) {
    ret = (int) gh_list_pop(&lists[i]);
    if (ret != 0)
      fatal("Ret is bogus for list %d", i);
  }

  printf("Done with first set\n");

  for(num=24999; num >= 0; num--) {
    for(i=0; i < 16; i++) {
      gh_list_prepend(&lists[i], (void *)num);
    }
  }

  for(num=25000; num < 50000; num++) {
    for(i=0; i < 16; i++) {
      gh_list_append(&lists[i], (void *)num);
    }
  }

  for(num=0; num < 50000; num++) {
    for(i=0; i < 16; i++) {
      ret = (int) gh_list_pop(&lists[i]);
      if (ret != num)
	fatal("prepend_test: Bogus return value %d when expected %d\n", ret, num);
    }
  }

  printf("Done with second set\n");
  for(num=25000; num < 50000; num++) {
    for(i=0; i < 16; i++) {
      gh_list_append(&lists[i], (void *)num);
    }
  }

  for(num=24999; num >= 0; num--) {
    for(i=0; i < 16; i++) {
      gh_list_prepend(&lists[i], (void *)num);
    }
  }

  for(num=0; num < 50000; num++) {
    for(i=0; i < 16; i++) {
      ret = (int) gh_list_pop(&lists[i]);
      if (ret != num)
	fatal("prepend_test: Bogus return value %d when expected %d\n", ret, num);
    }
  }

  printf("Done with third set ...\n");

  for(num=24999; num >= 0; num--) {
    for(i=0; i < 16; i++) {
      gh_list_prepend(&lists[i], (void *)num);
    }
  }

  for(num=25000; num < 50000; num++) {
    for(i=0; i < 16; i++) {
      gh_list_append(&lists[i], (void *)num);
    }
  }

  for(i=0; i < 16; i++) {
    num=0;
    for(current = GH_LIST_FIRST_ELEM(&lists[i]); current;
	current = next) {
      next = GH_LIST_ELEM_NEXT(current);
      if ((int)GH_LIST_ELEM_DATA(current) != num)
	fatal("Got %d when I expected %d\n", (int)GH_LIST_ELEM_DATA(current), num);
      gh_list_remove_elem(&lists[i], current);
      num++;
    }
    if (num != 50000)
      fatal("Number is %d, even though %d was expected", num, 50000);

    if (GH_LIST_COUNT(&lists[i]) != 0) {
      fatal("List should be empty, but instead it has %d members!\n", GH_LIST_COUNT(&lists[i]));
    }
  }

  printf("Done with fourth set, freeing buffers\n");
  for(i=0; i < 16; i++) {
    gh_list_free(&lists[i]);
  }
}