예제 #1
0
/* Adds an event to the appropriate nsp event list, handles housekeeping such as
 * adjusting the descriptor select/poll lists, registering the timeout value,
 * etc. */
void nsock_pool_add_event(struct npool *nsp, struct nevent *nse) {
  nsock_log_debug("NSE #%lu: Adding event (timeout in %ldms)",
                  nse->id,
                  (long)TIMEVAL_MSEC_SUBTRACT(nse->timeout, nsock_tod));

  nsp->events_pending++;

  if (!nse->event_done && nse->timeout.tv_sec) {
    /* This event is expirable, add it to the queue */
    gh_heap_push(&nsp->expirables, &nse->expire);
  }

  /* Now we do the event type specific actions */
  switch (nse->type) {
    case NSE_TYPE_CONNECT:
    case NSE_TYPE_CONNECT_SSL:
      if (!nse->event_done) {
        assert(nse->iod->sd >= 0);
        socket_count_read_inc(nse->iod);
        socket_count_write_inc(nse->iod);
        update_events(nse->iod, nsp, EV_READ|EV_WRITE|EV_EXCEPT, EV_NONE);
      }
      iod_add_event(nse->iod, nse);
      break;

    case NSE_TYPE_READ:
      if (!nse->event_done) {
        assert(nse->iod->sd >= 0);
        socket_count_read_inc(nse->iod);
        update_events(nse->iod, nsp, EV_READ, EV_NONE);
#if HAVE_OPENSSL
        if (nse->iod->ssl)
          nse->sslinfo.ssl_desire = SSL_ERROR_WANT_READ;
#endif
      }
      iod_add_event(nse->iod, nse);
      break;

    case NSE_TYPE_WRITE:
      if (!nse->event_done) {
        assert(nse->iod->sd >= 0);
        socket_count_write_inc(nse->iod);
        update_events(nse->iod, nsp, EV_WRITE, EV_NONE);
#if HAVE_OPENSSL
        if (nse->iod->ssl)
          nse->sslinfo.ssl_desire = SSL_ERROR_WANT_WRITE;
#endif
      }
      iod_add_event(nse->iod, nse);
      break;

    case NSE_TYPE_TIMER:
      /* nothing to do */
      break;

#if HAVE_PCAP
    case NSE_TYPE_PCAP_READ: {
      mspcap *mp = (mspcap *)nse->iod->pcap;

      assert(mp);
      if (mp->pcap_desc >= 0) { /* pcap descriptor present */
        if (!nse->event_done) {
          socket_count_readpcap_inc(nse->iod);
          update_events(nse->iod, nsp, EV_READ, EV_NONE);
        }
        nsock_log_debug_all("PCAP NSE #%lu: Adding event to READ_EVENTS", nse->id);

        #if PCAP_BSD_SELECT_HACK
        /* when using BSD hack we must do pcap_next() after select().
         * Let's insert this pcap to bot queues, to selectable and nonselectable.
         * This will result in doing pcap_next_ex() just before select() */
        nsock_log_debug_all("PCAP NSE #%lu: Adding event to PCAP_READ_EVENTS", nse->id);
        #endif
      } else {
        /* pcap isn't selectable. Add it to pcap-specific queue. */
        nsock_log_debug_all("PCAP NSE #%lu: Adding event to PCAP_READ_EVENTS", nse->id);
      }
      iod_add_event(nse->iod, nse);
      break;
    }
#endif

    default:
      fatal("Unknown nsock event type (%d)", nse->type);
  }

  /* It can happen that the event already completed. In which case we can
   * already deliver it, even though we're probably not inside nsock_loop(). */
  if (nse->event_done) {
    event_dispatch_and_delete(nsp, nse, 1);
    update_first_events(nse);
    nevent_unref(nsp, nse);
  }
}
예제 #2
0
void process_event(struct npool *nsp, gh_list_t *evlist, struct nevent *nse, int ev) {
  int match_r = 0, match_w = 0;
#if HAVE_OPENSSL
  int desire_r = 0, desire_w = 0;
#endif

  nsock_log_debug_all("Processing event %lu (timeout in %ldms, done=%d)",
                      nse->id,
                      (long)TIMEVAL_MSEC_SUBTRACT(nse->timeout, nsock_tod),
                      nse->event_done);

  if (!nse->event_done) {
    switch (nse->type) {
      case NSE_TYPE_CONNECT:
      case NSE_TYPE_CONNECT_SSL:
        if (ev != EV_NONE)
          handle_connect_result(nsp, nse, NSE_STATUS_SUCCESS);
        if (event_timedout(nse))
          handle_connect_result(nsp, nse, NSE_STATUS_TIMEOUT);
        break;

      case NSE_TYPE_READ:
        match_r = ev & EV_READ;
        match_w = ev & EV_WRITE;
#if HAVE_OPENSSL
        desire_r = nse->sslinfo.ssl_desire == SSL_ERROR_WANT_READ;
        desire_w = nse->sslinfo.ssl_desire == SSL_ERROR_WANT_WRITE;
        if (nse->iod->ssl && ((desire_r && match_r) || (desire_w && match_w)))
          handle_read_result(nsp, nse, NSE_STATUS_SUCCESS);
        else
#endif
        if (!nse->iod->ssl && match_r)
          handle_read_result(nsp, nse, NSE_STATUS_SUCCESS);

        if (event_timedout(nse))
          handle_read_result(nsp, nse, NSE_STATUS_TIMEOUT);
        break;

      case NSE_TYPE_WRITE:
        match_r = ev & EV_READ;
        match_w = ev & EV_WRITE;
#if HAVE_OPENSSL
        desire_r = nse->sslinfo.ssl_desire == SSL_ERROR_WANT_READ;
        desire_w = nse->sslinfo.ssl_desire == SSL_ERROR_WANT_WRITE;
        if (nse->iod->ssl && ((desire_r && match_r) || (desire_w && match_w)))
          handle_write_result(nsp, nse, NSE_STATUS_SUCCESS);
        else
#endif
          if (!nse->iod->ssl && match_w)
            handle_write_result(nsp, nse, NSE_STATUS_SUCCESS);

          if (event_timedout(nse))
            handle_write_result(nsp, nse, NSE_STATUS_TIMEOUT);
          break;

      case NSE_TYPE_TIMER:
        if (event_timedout(nse))
          handle_timer_result(nsp, nse, NSE_STATUS_SUCCESS);
        break;

#if HAVE_PCAP
      case NSE_TYPE_PCAP_READ:{
        nsock_log_debug_all("PCAP iterating %lu", nse->id);

        if (ev & EV_READ) {
          /* buffer empty? check it! */
          if (fs_length(&(nse->iobuf)) == 0)
            do_actual_pcap_read(nse);
        }

        /* if already received something */
        if (fs_length(&(nse->iobuf)) > 0)
          handle_pcap_read_result(nsp, nse, NSE_STATUS_SUCCESS);

        if (event_timedout(nse))
          handle_pcap_read_result(nsp, nse, NSE_STATUS_TIMEOUT);

        #if PCAP_BSD_SELECT_HACK
        /* If event occurred, and we're in BSD_HACK mode, then this event was added
         * to two queues. read_event and pcap_read_event
         * Of course we should destroy it only once.
         * I assume we're now in read_event, so just unlink this event from
         * pcap_read_event */
        if (((mspcap *)nse->iod->pcap)->pcap_desc >= 0
            && nse->event_done
            && evlist == &nsp->read_events) {
          /* event is done, list is read_events and we're in BSD_HACK mode.
           * So unlink event from pcap_read_events */
          update_first_events(nse);
          gh_list_remove(&nsp->pcap_read_events, &nse->nodeq_pcap);

          nsock_log_debug_all("PCAP NSE #%lu: Removing event from PCAP_READ_EVENTS",
                              nse->id);
        }
        if (((mspcap *)nse->iod->pcap)->pcap_desc >= 0
            && nse->event_done
            && evlist == &nsp->pcap_read_events) {
          update_first_events(nse);
          gh_list_remove(&nsp->read_events, &nse->nodeq_io);
          nsock_log_debug_all("PCAP NSE #%lu: Removing event from READ_EVENTS",
                              nse->id);
        }
        #endif
        break;
      }
#endif
      default:
        fatal("Event has unknown type (%d)", nse->type);
    }
  }

  if (nse->event_done) {
    /* Security sanity check: don't return a functional SSL iod without
     * setting an SSL data structure. */
    if (nse->type == NSE_TYPE_CONNECT_SSL && nse->status == NSE_STATUS_SUCCESS)
      assert(nse->iod->ssl != NULL);

    nsock_log_debug_all("NSE #%lu: Sending event", nse->id);

    /* WooHoo!  The event is ready to be sent */
    event_dispatch_and_delete(nsp, nse, 1);
  }
}
예제 #3
0
/* An internal function for cancelling an event when you already have a pointer
 * to the struct nevent (use nsock_event_cancel if you just have an ID). The
 * event_list passed in should correspond to the type of the event. For example,
 * with NSE_TYPE_READ, you would pass in &nsp->read_events;. elem is the list
 * element in event_list which holds the event.  Pass a nonzero for notify if
 * you want the program owning the event to be notified that it has been
 * cancelled */
int nevent_delete(struct npool *nsp, struct nevent *nse, gh_list_t *event_list,
                   gh_lnode_t *elem, int notify) {
  if (nse->event_done) {
    /* This event has already been marked for death somewhere else -- it will be
     * gone soon (and if we try to kill it now all hell will break loose due to
     * reentrancy. */
    return 0;
  }

  nsock_log_info("%s on event #%li (type %s)", __func__, nse->id,
                 nse_type2str(nse->type));

  /* Now that we found the event... we go through the motions of cleanly
   * cancelling it */
  switch (nse->type) {
    case NSE_TYPE_CONNECT:
    case NSE_TYPE_CONNECT_SSL:
      handle_connect_result(nsp, nse, NSE_STATUS_CANCELLED);
      break;

    case NSE_TYPE_READ:
      handle_read_result(nsp, nse, NSE_STATUS_CANCELLED);
      break;

    case NSE_TYPE_WRITE:
      handle_write_result(nsp, nse, NSE_STATUS_CANCELLED);
      break;

    case NSE_TYPE_TIMER:
      handle_timer_result(nsp, nse, NSE_STATUS_CANCELLED);
      break;

#if HAVE_PCAP
    case NSE_TYPE_PCAP_READ:
      handle_pcap_read_result(nsp, nse, NSE_STATUS_CANCELLED);
      break;
#endif

    default:
      fatal("Invalid nsock event type (%d)", nse->type);
  }

  assert(nse->event_done);

  if (nse->timeout.tv_sec)
    gh_heap_remove(&nsp->expirables, &nse->expire);

  if (event_list) {
    update_first_events(nse);
    gh_list_remove(event_list, elem);
  }

  gh_list_append(&nsp->free_events, &nse->nodeq_io);

  nsock_log_debug_all("NSE #%lu: Removing event from list", nse->id);

#if HAVE_PCAP
#if PCAP_BSD_SELECT_HACK
  if (nse->type == NSE_TYPE_PCAP_READ) {
    nsock_log_debug_all("PCAP NSE #%lu: CANCEL TEST pcap=%p read=%p curr=%p sd=%i",
                        nse->id, &nsp->pcap_read_events, &nsp->read_events,
                        event_list,((mspcap *)nse->iod->pcap)->pcap_desc);

    /* If event occurred, and we're in BSD_HACK mode, then this event was added to
     * two queues. read_event and pcap_read_event Of course we should
     * destroy it only once.  I assume we're now in read_event, so just unlink
     * this event from pcap_read_event */
    if (((mspcap *)nse->iod->pcap)->pcap_desc >= 0 && event_list == &nsp->read_events) {
      /* event is done, list is read_events and we're in BSD_HACK mode. So unlink
       * event from pcap_read_events */
      gh_list_remove(&nsp->pcap_read_events, &nse->nodeq_pcap);
      nsock_log_debug_all("PCAP NSE #%lu: Removing event from PCAP_READ_EVENTS", nse->id);
    }

    if (((mspcap *)nse->iod->pcap)->pcap_desc >= 0 && event_list == &nsp->pcap_read_events) {
      /* event is done, list is read_events and we're in BSD_HACK mode.
       * So unlink event from read_events */
      gh_list_remove(&nsp->read_events, &nse->nodeq_io);

      nsock_log_debug_all("PCAP NSE #%lu: Removing event from READ_EVENTS", nse->id);
    }
  }
#endif
#endif
  event_dispatch_and_delete(nsp, nse, notify);
  return 1;
}