/* 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; struct kqueue_engine_info *kinfo = (struct kqueue_engine_info *)nsp->engine_data; gh_list_elem *current, *next, *last, *timer_last; 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); for (n = 0; n < evcount; n++) { struct kevent *kev = &kinfo->events[n]; nsi = (msiod *)kev->udata; /* process all the pending events for this IOD */ process_iod_events(nsp, nsi, get_evmask(nsi, kev)); IOD_PROPSET(nsi, IOD_PROCESSED); } current = GH_LIST_FIRST_ELEM(&nsp->active_iods); /* cull timeouts amongst the non active IODs */ while (current != NULL && GH_LIST_ELEM_PREV(current) != last) { msiod *nsi = (msiod *)GH_LIST_ELEM_DATA(current); if (IOD_PROPGET(nsi, IOD_PROCESSED)) IOD_PROPCLR(nsi, IOD_PROCESSED); else 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); } }
/* 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); }
struct proxy_chain_context *proxy_chain_context_new(nsock_pool nspool) { mspool *nsp = (mspool *)nspool; struct proxy_chain_context *ctx; ctx = (struct proxy_chain_context *)safe_malloc(sizeof(struct proxy_chain_context)); ctx->px_chain = nsp->px_chain; ctx->px_state = PROXY_STATE_INITIAL; ctx->px_current = GH_LIST_FIRST_ELEM(&nsp->px_chain->nodes); return ctx; }
/* 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) { gh_list_elem *current, *next, *last, *timer_last; /* 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); for (current = GH_LIST_FIRST_ELEM(&nsp->active_iods); current != NULL && GH_LIST_ELEM_PREV(current) != last; current = next) { msiod *nsi = (msiod *)GH_LIST_ELEM_DATA(current); if (nsi->state != NSIOD_STATE_DELETED && nsi->events_pending) process_iod_events(nsp, nsi, get_evmask(nsp, nsi)); 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); } } /* iterate through timers */ for (current = GH_LIST_FIRST_ELEM(&nsp->timer_events); current != NULL && GH_LIST_ELEM_PREV(current) != timer_last; current = next) { msevent *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); } }
/* Returns whether something was read */ int pcap_read_on_nonselect(mspool *nsp) { gh_list_elem *current, *next; msevent *nse; int ret = 0; for (current = GH_LIST_FIRST_ELEM(&nsp->pcap_read_events); current != NULL; current = next) { nse = (msevent *)GH_LIST_ELEM_DATA(current); if (do_actual_pcap_read(nse) == 1) { /* something received */ ret++; break; } next = GH_LIST_ELEM_NEXT(current); } return ret; }
/* 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); }
/* 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); } }
/* If msiod_new returned success, you must free the iod when you are done with it to conserve memory (and in some cases, sockets). After this call, nsockiod may no longer be used -- you need to create a new one with nsi_new(). pending_response tells what to do with any events that are pending on this nsock_iod. This can be NSOCK_PENDING_NOTIFY (send a KILL notification to each event), NSOCK_PENDING_SILENT (do not send notification to the killed events), or NSOCK_PENDING_ERROR (print an error message and quiit the program) */ void nsi_delete(nsock_iod nsockiod, int pending_response) { msiod *nsi = (msiod *) nsockiod; gh_list *elist_ar[3]; int elist; gh_list_elem *currev_elem, *next_elem; msevent *currev; assert(nsi); if (nsi->state == NSIOD_STATE_DELETED) { fatal("nsi_delete() called on nsock_iod which appears to have already been deleted"); } if (nsi->events_pending > 0) { /* shit -- they killed the msiod while an event was still pending on it. Maybe I should store the pending events in the msiod. On the other hand, this should be a pretty rare occurance and so I'll save space and hassle by just locating the events here by searching through the active events list */ if (pending_response == NSOCK_PENDING_ERROR) fatal("nsi_delete called with argument NSOCK_PENDING_ERROR on a nsock_iod that has %d pending event(s) associated with it", nsi->events_pending); assert(pending_response == NSOCK_PENDING_NOTIFY || pending_response == NSOCK_PENDING_SILENT); elist_ar[0] = &(nsi->nsp->evl.read_events); elist_ar[1] = &(nsi->nsp->evl.write_events); elist_ar[2] = &(nsi->nsp->evl.connect_events); for(elist = 0; elist < 3 && nsi->events_pending > 0; elist++) { currev_elem = GH_LIST_FIRST_ELEM(elist_ar[elist]); while(currev_elem) { currev = (msevent *) GH_LIST_ELEM_DATA(currev_elem); next_elem = GH_LIST_ELEM_NEXT(currev_elem); if (currev->iod == nsi) { // OK - we found an event pending on this IOD. Kill it. // printf("Found an outstanding event (out of %d), removing\n", nsi->events_pending); msevent_cancel(nsi->nsp, currev, elist_ar[elist], currev_elem, pending_response == NSOCK_PENDING_NOTIFY); } if (nsi->events_pending == 0) break; currev_elem = next_elem; } } } if (nsi->events_pending != 0) fatal("Trying to delete NSI, but could not find %d of the purportedly pending events on that IOD.\n", nsi->events_pending); #if HAVE_OPENSSL /* Close any SSL resources */ if (nsi->ssl) { /* No longer free session because copy nsi stores is not reference counted */ /* if (nsi->ssl_session) SSL_SESSION_free(nsi->ssl_session); nsi->ssl_session = NULL; */ if (SSL_shutdown(nsi->ssl) == -1) { if (nsi->nsp->tracelevel > 1) nsock_trace(nsi->nsp, "nsi_delete(): SSL shutdown failed (%s) on NSI %li", ERR_reason_error_string(SSL_get_error(nsi->ssl, -1)), nsi->id); } /* I don't really care if the SSL_shutdown() succeeded politely. I could make the SD blocking temporarily for this, but I'm hoping it will succeed 95% of the time because we can usually write to a socket. */ SSL_free(nsi->ssl); nsi->ssl = NULL; } #endif if (nsi->sd >= 0) { close(nsi->sd); nsi->sd = -1; } nsi->state = NSIOD_STATE_DELETED; nsi->userdata = NULL; gh_list_remove_elem(&nsi->nsp->active_iods, nsi->entry_in_nsp_active_iods); gh_list_prepend(&nsi->nsp->free_iods, nsi); }
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]); } }
/* 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; gh_list *event_list = NULL, *event_list2 = NULL; gh_list_elem *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: 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: event_list = &nsp->timer_events; break; #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_LIST_ELEM_NEXT(current); nse = (msevent *)GH_LIST_ELEM_DATA(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_LIST_ELEM_NEXT(current); nse = (msevent *)GH_LIST_ELEM_DATA(current); if (nse->id == id) break; } } if (current == NULL) return 0; return msevent_cancel(nsp, nse, event_list, current, notify); }