1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-13 19:29:04 +00:00

Manage expiration times via a heap queue.

This prevents nsock from iterating over the whole list of events at
each runloop, thus improving performance.

It made it necessary to have pointers from the msevents to the event
lists they belong to. The patch therefore also changes gh_list from
autonomous containers to embedded structures.

Added unit tests accordingly and cosmetic changes to make things look
more consistent.
This commit is contained in:
henri
2013-08-10 23:59:30 +00:00
parent 23457a77c0
commit 853aaff586
28 changed files with 1304 additions and 801 deletions

View File

@@ -1,5 +1,10 @@
# Nmap Changelog ($Id$); -*-text-*-
o [Nsock] Handle timers and timeouts via a priority queue (using a heap)
for improved performance. Nsock now only iterates over events which are
completed or expired instead of inspecting the entire event set at each
iteration. [Henri Doreau]
o [NSE] Update dns-cache-snoop script to use a new list of top 50
domains rather than a 2010 list. [Nicolle Neulist]

View File

@@ -186,7 +186,7 @@
<ClCompile Include="src\engine_select.c" />
<ClCompile Include="src\error.c" />
<ClCompile Include="src\filespace.c" />
<ClCompile Include="src\gh_list.c" />
<ClCompile Include="src\gh_heap.c" />
<ClCompile Include="src\netutils.c" />
<ClCompile Include="src\nsock_connect.c" />
<ClCompile Include="src\nsock_core.c" />
@@ -207,6 +207,7 @@
<ItemGroup>
<ClInclude Include="src\error.h" />
<ClInclude Include="src\filespace.h" />
<ClInclude Include="src\gh_heap.h" />
<ClInclude Include="src\gh_list.h" />
<ClInclude Include="src\netutils.h" />
<ClInclude Include="include\nsock.h" />

View File

@@ -28,20 +28,21 @@ NSOCKTESTDIR=@NSOCKTESTDIR@
TARGET = libnsock.a
SRCS = error.c filespace.c gh_list.c nsock_connect.c nsock_core.c \
SRCS = error.c filespace.c gh_heap.c nsock_connect.c nsock_core.c \
nsock_iod.c nsock_read.c nsock_timers.c nsock_write.c \
nsock_ssl.c nsock_event.c nsock_pool.c netutils.c nsock_pcap.c \
nsock_engines.c engine_select.c engine_epoll.c engine_kqueue.c \
engine_poll.c nsock_proxy.c nsock_log.c proxy_http.c proxy_socks4.c
OBJS = error.o filespace.o gh_list.o nsock_connect.o nsock_core.o \
OBJS = error.o filespace.o gh_heap.o nsock_connect.o nsock_core.o \
nsock_iod.o nsock_read.o nsock_timers.o nsock_write.o \
nsock_ssl.o nsock_event.o nsock_pool.o netutils.o nsock_pcap.o \
nsock_engines.o engine_select.o engine_epoll.o engine_kqueue.o \
engine_poll.o nsock_proxy.o nsock_log.o proxy_http.o proxy_socks4.o
DEPS = error.h filespace.h gh_list.h nsock_internal.h netutils.h nsock_pcap.h \
nsock_log.h nsock_proxy.h ../include/nsock.h $(NBASEDIR)/libnbase.a
nsock_log.h nsock_proxy.h gh_heap.h ../include/nsock.h \
$(NBASEDIR)/libnbase.a
.c.o:
$(CC) -c $(CPPFLAGS) $(CFLAGS) $< -o $@

View File

@@ -109,7 +109,8 @@ static void iterate_through_event_lists(mspool *nsp, int evcount);
/* defined in nsock_core.c */
void process_iod_events(mspool *nsp, msiod *nsi, int ev);
void process_event(mspool *nsp, gh_list *evlist, msevent *nse, int ev);
void process_event(mspool *nsp, gh_list_t *evlist, msevent *nse, int ev);
void process_expired_events(mspool *nsp);
#if HAVE_PCAP
#ifndef PCAP_CAN_DO_SELECT
int pcap_read_on_nonselect(mspool *nsp);
@@ -247,6 +248,7 @@ int epoll_loop(mspool *nsp, int msec_timeout) {
int event_msecs; /* msecs before an event goes off */
int combined_msecs;
int sock_err = 0;
unsigned int iod_count;
struct epoll_engine_info *einfo = (struct epoll_engine_info *)nsp->engine_data;
assert(msec_timeout >= -1);
@@ -255,24 +257,28 @@ int epoll_loop(mspool *nsp, int msec_timeout) {
return 0; /* No need to wait on 0 events ... */
if (GH_LIST_COUNT(&nsp->active_iods) > einfo->evlen) {
einfo->evlen = GH_LIST_COUNT(&nsp->active_iods) * 2;
iod_count = gh_list_count(&nsp->active_iods);
if (iod_count > einfo->evlen) {
einfo->evlen = iod_count * 2;
einfo->events = (struct epoll_event *)safe_realloc(einfo->events, einfo->evlen * sizeof(struct epoll_event));
}
do {
msevent *nse;
nsock_log_debug_all(nsp, "wait for events");
if (nsp->next_ev.tv_sec == 0)
nse = next_expirable_event(nsp);
if (!nse)
event_msecs = -1; /* None of the events specified a timeout */
else
event_msecs = MAX(0, TIMEVAL_MSEC_SUBTRACT(nsp->next_ev, nsock_tod));
event_msecs = MAX(0, TIMEVAL_MSEC_SUBTRACT(nse->timeout, 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 (gh_list_count(&nsp->pcap_read_events) > 0)
if (event_msecs > PCAP_POLL_INTERVAL)
event_msecs = PCAP_POLL_INTERVAL;
#endif
@@ -334,80 +340,25 @@ static inline int get_evmask(struct epoll_engine_info *einfo, int n) {
* 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);
int n;
for (n = 0; n < evcount; n++) {
nsi = (msiod *)einfo->events[n].data.ptr;
assert(nsi);
msiod *nsi = (msiod *)einfo->events[n].data.ptr;
if (nsi->entry_in_nsp_active_iods == last)
last = GH_LIST_ELEM_PREV(nsi->entry_in_nsp_active_iods);
assert(nsi);
/* 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);
gh_list_remove(&nsp->active_iods, &nsi->nodeq);
gh_list_prepend(&nsp->free_iods, &nsi->nodeq);
}
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);
}
/* iterate through timers and expired events */
process_expired_events(nsp);
}
#endif /* HAVE_EPOLL */

View File

@@ -102,7 +102,8 @@ static void iterate_through_event_lists(mspool *nsp, int evcount);
/* defined in nsock_core.c */
void process_iod_events(mspool *nsp, msiod *nsi, int ev);
void process_event(mspool *nsp, gh_list *evlist, msevent *nse, int ev);
void process_event(mspool *nsp, gh_list_t *evlist, msevent *nse, int ev);
void process_expired_events(mspool *nsp);
#if HAVE_PCAP
#ifndef PCAP_CAN_DO_SELECT
int pcap_read_on_nonselect(mspool *nsp);
@@ -231,24 +232,27 @@ int kqueue_loop(mspool *nsp, int msec_timeout) {
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;
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 {
msevent *nse;
nsock_log_debug_all(nsp, "wait for events");
if (nsp->next_ev.tv_sec == 0)
nse = next_expirable_event(nsp);
if (!nse)
event_msecs = -1; /* None of the events specified a timeout */
else
event_msecs = MAX(0, TIMEVAL_MSEC_SUBTRACT(nsp->next_ev, nsock_tod));
event_msecs = MAX(0, TIMEVAL_MSEC_SUBTRACT(nse->timeout, 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 (gh_list_count(&nsp->pcap_read_events) > 0)
if (event_msecs > PCAP_POLL_INTERVAL)
event_msecs = PCAP_POLL_INTERVAL;
#endif
@@ -332,16 +336,8 @@ static inline int get_evmask(msiod *nsi, const struct kevent *kev) {
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];
@@ -353,37 +349,22 @@ void iterate_through_event_lists(mspool *nsp, int evcount) {
IOD_PROPSET(nsi, IOD_PROCESSED);
}
current = GH_LIST_FIRST_ELEM(&nsp->active_iods);
for (n = 0; n < evcount; n++) {
struct kevent *kev = &kinfo->events[n];
/* cull timeouts amongst the non active IODs */
while (current != NULL && GH_LIST_ELEM_PREV(current) != last) {
msiod *nsi = (msiod *)GH_LIST_ELEM_DATA(current);
nsi = (msiod *)kev->udata;
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);
if (IOD_PROPGET(nsi, IOD_PROCESSED)) {
IOD_PROPCLR(nsi, IOD_PROCESSED);
gh_list_remove(&nsp->active_iods, &nsi->nodeq);
gh_list_prepend(&nsp->free_iods, &nsi->nodeq);
}
}
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);
}
/* iterate through timers and expired events */
process_expired_events(nsp);
}
#endif /* HAVE_KQUEUE */

View File

@@ -134,7 +134,8 @@ static void iterate_through_event_lists(mspool *nsp);
/* defined in nsock_core.c */
void process_iod_events(mspool *nsp, msiod *nsi, int ev);
void process_event(mspool *nsp, gh_list *evlist, msevent *nse, int ev);
void process_event(mspool *nsp, gh_list_t *evlist, msevent *nse, int ev);
void process_expired_events(mspool *nsp);
#if HAVE_PCAP
#ifndef PCAP_CAN_DO_SELECT
int pcap_read_on_nonselect(mspool *nsp);
@@ -313,18 +314,21 @@ int poll_loop(mspool *nsp, int msec_timeout) {
return 0; /* No need to wait on 0 events ... */
do {
msevent *nse;
nsock_log_debug_all(nsp, "wait for events");
if (nsp->next_ev.tv_sec == 0)
nse = next_expirable_event(nsp);
if (!nse)
event_msecs = -1; /* None of the events specified a timeout */
else
event_msecs = MAX(0, TIMEVAL_MSEC_SUBTRACT(nsp->next_ev, nsock_tod));
event_msecs = MAX(0, TIMEVAL_MSEC_SUBTRACT(nse->timeout, 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 (gh_list_count(&nsp->pcap_read_events) > 0)
if (event_msecs > PCAP_POLL_INTERVAL)
event_msecs = PCAP_POLL_INTERVAL;
#endif
@@ -403,41 +407,26 @@ static inline int get_evmask(mspool *nsp, msiod *nsi) {
* 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;
gh_lnode_t *current, *next, *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);
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);
for (current = gh_list_first_elem(&nsp->active_iods);
current != NULL && gh_lnode_prev(current) != last;
current = next) {
msiod *nsi = container_of(current, msiod, nodeq);
process_iod_events(nsp, nsi, get_evmask(nsp, nsi));
next = GH_LIST_ELEM_NEXT(current);
next = gh_lnode_next(current);
if (nsi->state == NSIOD_STATE_DELETED) {
gh_list_remove_elem(&nsp->active_iods, current);
gh_list_prepend(&nsp->free_iods, nsi);
gh_list_remove(&nsp->active_iods, current);
gh_list_prepend(&nsp->free_iods, current);
}
}
/* 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);
}
/* iterate through timers and expired events */
process_expired_events(nsp);
}
#endif /* HAVE_POLL */

View File

@@ -94,8 +94,9 @@ struct io_engine engine_select = {
static void iterate_through_event_lists(mspool *nsp);
/* defined in nsock_core.c */
void process_event(mspool *nsp, gh_list *evlist, msevent *nse, int ev);
void process_event(mspool *nsp, gh_list_t *evlist, msevent *nse, int ev);
void process_iod_events(mspool *nsp, msiod *nsi, int ev);
void process_expired_events(mspool *nsp);
#if HAVE_PCAP
#ifndef PCAP_CAN_DO_SELECT
@@ -252,18 +253,21 @@ int select_loop(mspool *nsp, int msec_timeout) {
return 0; /* No need to wait on 0 events ... */
do {
msevent *nse;
nsock_log_debug_all(nsp, "wait for events");
if (nsp->next_ev.tv_sec == 0)
nse = next_expirable_event(nsp);
if (!nse)
event_msecs = -1; /* None of the events specified a timeout */
else
event_msecs = MAX(0, TIMEVAL_MSEC_SUBTRACT(nsp->next_ev, nsock_tod));
event_msecs = MAX(0, TIMEVAL_MSEC_SUBTRACT(nse->timeout, 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 (gh_list_count(&nsp->pcap_read_events))
if (event_msecs > PCAP_POLL_INTERVAL)
event_msecs = PCAP_POLL_INTERVAL;
#endif
@@ -366,39 +370,25 @@ static inline int get_evmask(const mspool *nsp, const msiod *nsi) {
* 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;
gh_lnode_t *current, *next, *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);
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);
for (current = gh_list_first_elem(&nsp->active_iods);
current != NULL && gh_lnode_prev(current) != last;
current = next) {
msiod *nsi = container_of(current, msiod, nodeq);
if (nsi->state != NSIOD_STATE_DELETED && nsi->events_pending)
process_iod_events(nsp, nsi, get_evmask(nsp, nsi));
next = GH_LIST_ELEM_NEXT(current);
next = gh_lnode_next(current);
if (nsi->state == NSIOD_STATE_DELETED) {
gh_list_remove_elem(&nsp->active_iods, current);
gh_list_prepend(&nsp->free_iods, nsi);
gh_list_remove(&nsp->active_iods, current);
gh_list_prepend(&nsp->free_iods, current);
}
}
/* 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);
}
/* iterate through timers and expired events */
process_expired_events(nsp);
}

248
nsock/src/gh_heap.c Normal file
View File

@@ -0,0 +1,248 @@
/***************************************************************************
* gh_heap.c -- heap based priority queue. *
* *
***********************IMPORTANT NSOCK LICENSE TERMS***********************
* *
* The nsock parallel socket event library is (C) 1999-2013 Insecure.Com *
* LLC This library is free software; you may redistribute and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; Version 2. This guarantees *
* your right to use, modify, and redistribute this software under certain *
* conditions. If this license is unacceptable to you, Insecure.Com LLC *
* may be willing to sell alternative licenses (contact *
* sales@insecure.com ). *
* *
* As a special exception to the GPL terms, Insecure.Com LLC grants *
* permission to link the code of this program with any version of the *
* OpenSSL library which is distributed under a license identical to that *
* listed in the included docs/licenses/OpenSSL.txt file, and distribute *
* linked combinations including the two. You must obey the GNU GPL in all *
* respects for all of the code used other than OpenSSL. If you modify *
* this file, you may extend this exception to your version of the file, *
* but you are not obligated to do so. *
* *
* If you received these files with a written license agreement stating *
* terms other than the (GPL) terms above, then that alternative license *
* agreement takes precedence over this comment. *
* *
* Source is provided to this software because we believe users have a *
* right to know exactly what a program is going to do before they run it. *
* This also allows you to audit the software for security holes (none *
* have been found so far). *
* *
* Source code also allows you to port Nmap to new platforms, fix bugs, *
* and add new features. You are highly encouraged to send your changes *
* to the dev@nmap.org mailing list for possible incorporation into the *
* main distribution. By sending these changes to Fyodor or one of the *
* Insecure.Org development mailing lists, or checking them into the Nmap *
* source code repository, it is understood (unless you specify otherwise) *
* that you are offering the Nmap Project (Insecure.Com LLC) the *
* unlimited, non-exclusive right to reuse, modify, and relicense the *
* code. Nmap will always be available Open Source, but this is important *
* because the inability to relicense code has caused devastating problems *
* for other Free Software projects (such as KDE and NASM). We also *
* occasionally relicense the code to third parties as discussed above. *
* If you wish to specify special license conditions of your *
* contributions, just say so when you send them. *
* *
* This program is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* General Public License v2.0 for more details *
* (http://www.gnu.org/licenses/gpl-2.0.html). *
* *
***************************************************************************/
/* $Id$ */
#ifdef HAVE_CONFIG_H
#include "nsock_config.h"
#include "nbase_config.h"
#endif
#ifdef WIN32
#include "nbase_winconfig.h"
#endif
#include <nbase.h>
#include "gh_heap.h"
#define GH_SLOTS 128
static gh_hnode_t **hnode_ptr(gh_heap_t *heap, unsigned int index) {
assert(index >= 0);
assert(index <= heap->count);
return &(heap->slots[index]);
}
gh_hnode_t *gh_heap_find(gh_heap_t *heap, unsigned int index) {
if (index >= heap->count)
return NULL;
return *hnode_ptr(heap, index);
}
static int hnode_up(gh_heap_t *heap, gh_hnode_t *hnode)
{
unsigned int cur_idx = hnode->index;
gh_hnode_t **cur_ptr = hnode_ptr(heap, cur_idx);
unsigned int parent_idx;
gh_hnode_t **parent_ptr;
int action = 0;
assert(*cur_ptr == hnode);
while (cur_idx > 0) {
parent_idx = (cur_idx - 1) >> 1;
parent_ptr = hnode_ptr(heap, parent_idx);
assert((*parent_ptr)->index == parent_idx);
if (heap->cmp_op(*parent_ptr, hnode))
break;
(*parent_ptr)->index = cur_idx;
*cur_ptr = *parent_ptr;
cur_ptr = parent_ptr;
cur_idx = parent_idx;
action = 1;
}
hnode->index = cur_idx;
*cur_ptr = hnode;
return action;
}
static int hnode_down(gh_heap_t *heap, gh_hnode_t *hnode)
{
unsigned int count = heap->count;
unsigned int ch1_idx, ch2_idx, cur_idx;
gh_hnode_t **ch1_ptr, **ch2_ptr, **cur_ptr;
gh_hnode_t *ch1, *ch2;
int action = 0;
cur_idx = hnode->index;
cur_ptr = hnode_ptr(heap, cur_idx);
assert(*cur_ptr == hnode);
while (cur_idx < count) {
ch1_idx = (cur_idx << 1) + 1;
if (ch1_idx >= count)
break;
ch1_ptr = hnode_ptr(heap, ch1_idx);
ch1 = *ch1_ptr;
ch2_idx = ch1_idx + 1;
if (ch2_idx < count) {
ch2_ptr = hnode_ptr(heap, ch2_idx);
ch2 = *ch2_ptr;
if (heap->cmp_op(ch2, ch1)) {
ch1_idx = ch2_idx;
ch1_ptr = ch2_ptr;
ch1 = ch2;
}
}
assert(ch1->index == ch1_idx);
if (heap->cmp_op(hnode, ch1))
break;
ch1->index = cur_idx;
*cur_ptr = ch1;
cur_ptr = ch1_ptr;
cur_idx = ch1_idx;
action = 1;
}
hnode->index = cur_idx;
*cur_ptr = hnode;
return action;
}
static int heap_grow(gh_heap_t *heap) {
/* Do we really need to grow? */
assert(heap->count == heap->highwm);
heap->slots = safe_realloc(heap->slots,
(heap->count + GH_SLOTS) * sizeof(gh_hnode_t *));
heap->highwm += GH_SLOTS;
return 0;
}
int gh_heap_init(gh_heap_t *heap, gh_heap_cmp_t cmp_op) {
int rc;
if (!cmp_op)
return -1;
heap->cmp_op = cmp_op;
heap->count = 0;
heap->highwm = 0;
heap->slots = NULL;
rc = heap_grow(heap);
if (rc)
gh_heap_free(heap);
return rc;
}
void gh_heap_free(gh_heap_t *heap) {
if (heap->highwm) {
assert(heap->slots);
free(heap->slots);
}
memset(heap, 0, sizeof(gh_heap_t));
}
int gh_heap_push(gh_heap_t *heap, gh_hnode_t *hnode) {
gh_hnode_t **new_ptr;
unsigned int new_index = heap->count;
assert(!gh_hnode_is_valid(hnode));
if (new_index == heap->highwm)
heap_grow(heap);
hnode->index = new_index;
new_ptr = hnode_ptr(heap, new_index);
heap->count++;
*new_ptr = hnode;
hnode_up(heap, hnode);
return 0;
}
int gh_heap_remove(gh_heap_t *heap, gh_hnode_t *hnode)
{
unsigned int count = heap->count;
unsigned int cur_idx = hnode->index;
gh_hnode_t **cur_ptr;
gh_hnode_t *last;
assert(gh_hnode_is_valid(hnode));
assert(cur_idx < count);
cur_ptr = hnode_ptr(heap, cur_idx);
assert(*cur_ptr == hnode);
count--;
last = *hnode_ptr(heap, count);
heap->count = count;
if (last == hnode)
return 0;
last->index = cur_idx;
*cur_ptr = last;
if (!hnode_up(heap, *cur_ptr))
hnode_down(heap, *cur_ptr);
gh_hnode_invalidate(hnode);
return 0;
}

146
nsock/src/gh_heap.h Normal file
View File

@@ -0,0 +1,146 @@
/***************************************************************************
* gh_heap.h -- heap based priority queues. *
* *
***********************IMPORTANT NSOCK LICENSE TERMS***********************
* *
* The nsock parallel socket event library is (C) 1999-2013 Insecure.Com *
* LLC This library is free software; you may redistribute and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; Version 2. This guarantees *
* your right to use, modify, and redistribute this software under certain *
* conditions. If this license is unacceptable to you, Insecure.Com LLC *
* may be willing to sell alternative licenses (contact *
* sales@insecure.com ). *
* *
* As a special exception to the GPL terms, Insecure.Com LLC grants *
* permission to link the code of this program with any version of the *
* OpenSSL library which is distributed under a license identical to that *
* listed in the included docs/licenses/OpenSSL.txt file, and distribute *
* linked combinations including the two. You must obey the GNU GPL in all *
* respects for all of the code used other than OpenSSL. If you modify *
* this file, you may extend this exception to your version of the file, *
* but you are not obligated to do so. *
* *
* If you received these files with a written license agreement stating *
* terms other than the (GPL) terms above, then that alternative license *
* agreement takes precedence over this comment. *
* *
* Source is provided to this software because we believe users have a *
* right to know exactly what a program is going to do before they run it. *
* This also allows you to audit the software for security holes (none *
* have been found so far). *
* *
* Source code also allows you to port Nmap to new platforms, fix bugs, *
* and add new features. You are highly encouraged to send your changes *
* to the dev@nmap.org mailing list for possible incorporation into the *
* main distribution. By sending these changes to Fyodor or one of the *
* Insecure.Org development mailing lists, or checking them into the Nmap *
* source code repository, it is understood (unless you specify otherwise) *
* that you are offering the Nmap Project (Insecure.Com LLC) the *
* unlimited, non-exclusive right to reuse, modify, and relicense the *
* code. Nmap will always be available Open Source, but this is important *
* because the inability to relicense code has caused devastating problems *
* for other Free Software projects (such as KDE and NASM). We also *
* occasionally relicense the code to third parties as discussed above. *
* If you wish to specify special license conditions of your *
* contributions, just say so when you send them. *
* *
* This program is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* General Public License v2.0 for more details *
* (http://www.gnu.org/licenses/gpl-2.0.html). *
* *
***************************************************************************/
/* $Id$ */
#ifndef GH_HEAP_H
#define GH_HEAP_H
#ifdef HAVE_CONFIG_H
#include "nsock_config.h"
#include "nbase_config.h"
#endif
#ifdef WIN32
#include "nbase_winconfig.h"
#endif
#include "error.h"
#include <assert.h>
#if !defined(container_of)
#define container_of(ptr, type, member) \
((type *)((char *)(ptr)-(char *)(&((type *)0)->member)))
#endif
typedef struct {
unsigned int index;
} gh_hnode_t;
/* POISON value, set heap node index to this value to indicate that the node is
* inactive (not part of a heap) */
#define GH_HEAP_GUARD 0x19890721
/* Node comparison function.
* Here lies all the intelligence of the tree.
* Return 1 if hnode1 < hnode2, 0 otherwise. */
typedef int (*gh_heap_cmp_t)(gh_hnode_t *hnode1, gh_hnode_t *hnode2);
typedef struct gh_heap {
gh_heap_cmp_t cmp_op;
unsigned int count;
unsigned int highwm;
gh_hnode_t **slots;
} gh_heap_t;
int gh_heap_init(gh_heap_t *heap, gh_heap_cmp_t cmp_op);
void gh_heap_free(gh_heap_t *heap);
int gh_heap_push(gh_heap_t *heap, gh_hnode_t *node);
int gh_heap_remove(gh_heap_t *heap, gh_hnode_t *node);
gh_hnode_t *gh_heap_find(gh_heap_t *heap, unsigned int index);
static inline gh_hnode_t *gh_heap_min(gh_heap_t *heap) {
if (heap->count == 0)
return NULL;
return gh_heap_find(heap, 0);
}
static inline gh_hnode_t *gh_heap_pop(gh_heap_t *heap) {
gh_hnode_t *hnode;
hnode = gh_heap_find(heap, 0);
if (hnode != NULL)
gh_heap_remove(heap, hnode);
return hnode;
}
static inline size_t gh_heap_count(gh_heap_t *heap) {
return heap->count;
}
static inline int gh_heap_is_empty(gh_heap_t *heap) {
return heap->count == 0;
}
static inline void gh_hnode_invalidate(gh_hnode_t *node) {
node->index = GH_HEAP_GUARD;
}
static inline int gh_hnode_is_valid(const gh_hnode_t *node) {
return (node && node->index != GH_HEAP_GUARD);
}
#endif /* GH_HEAP_H */

View File

@@ -1,346 +0,0 @@
/***************************************************************************
* gh_list.c -- a simple doubly-linked list implementation with a very *
* heavy focus on efficiency. *
* *
***********************IMPORTANT NSOCK LICENSE TERMS***********************
* *
* The nsock parallel socket event library is (C) 1999-2013 Insecure.Com *
* LLC This library is free software; you may redistribute and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; Version 2. This guarantees *
* your right to use, modify, and redistribute this software under certain *
* conditions. If this license is unacceptable to you, Insecure.Com LLC *
* may be willing to sell alternative licenses (contact *
* sales@insecure.com ). *
* *
* As a special exception to the GPL terms, Insecure.Com LLC grants *
* permission to link the code of this program with any version of the *
* OpenSSL library which is distributed under a license identical to that *
* listed in the included docs/licenses/OpenSSL.txt file, and distribute *
* linked combinations including the two. You must obey the GNU GPL in all *
* respects for all of the code used other than OpenSSL. If you modify *
* this file, you may extend this exception to your version of the file, *
* but you are not obligated to do so. *
* *
* If you received these files with a written license agreement stating *
* terms other than the (GPL) terms above, then that alternative license *
* agreement takes precedence over this comment. *
* *
* Source is provided to this software because we believe users have a *
* right to know exactly what a program is going to do before they run it. *
* This also allows you to audit the software for security holes (none *
* have been found so far). *
* *
* Source code also allows you to port Nmap to new platforms, fix bugs, *
* and add new features. You are highly encouraged to send your changes *
* to the dev@nmap.org mailing list for possible incorporation into the *
* main distribution. By sending these changes to Fyodor or one of the *
* Insecure.Org development mailing lists, or checking them into the Nmap *
* source code repository, it is understood (unless you specify otherwise) *
* that you are offering the Nmap Project (Insecure.Com LLC) the *
* unlimited, non-exclusive right to reuse, modify, and relicense the *
* code. Nmap will always be available Open Source, but this is important *
* because the inability to relicense code has caused devastating problems *
* for other Free Software projects (such as KDE and NASM). We also *
* occasionally relicense the code to third parties as discussed above. *
* If you wish to specify special license conditions of your *
* contributions, just say so when you send them. *
* *
* This program is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* General Public License v2.0 for more details *
* (http://www.gnu.org/licenses/gpl-2.0.html). *
* *
***************************************************************************/
/* $Id$ */
#include "nsock.h"
#include "gh_list.h"
#include <nbase.h>
#if HAVE_STRING_H
#include <string.h>
#endif
#if HAVE_STRINGS_H
#include <strings.h>
#endif
#define SAFETY_CHECK_LIST(l) do { \
assert(l); \
assert((l)->magic == GH_LIST_MAGIC); \
assert((l)->count == 0 || ((l)->first && (l)->last)); \
assert((l)->count != 0 || ((l)->first == NULL && (l)->last == NULL)); \
} while (0)
#define SAFETY_CHECK_ELEM(e) do { \
assert(e); \
assert((e)->magic == GH_LIST_MAGIC); \
} while (0)
static inline struct gh_list_elem *get_free_buffer(struct gh_list *list) {
struct gh_list_elem *newelem;
int i;
if (!list->free) {
list->last_alloc *= 2;
list->free = (struct gh_list_elem *)safe_malloc(list->last_alloc * sizeof(struct gh_list_elem));
memset(list->free, 0, list->last_alloc * sizeof(struct gh_list_elem));
list->free->allocated = 1;
for (i=0; i < list->last_alloc - 1; i++) {
(list->free + i)->next = list->free + i + 1;
}
}
newelem = list->free;
list->free = list->free->next;
#ifndef NDEBUG
newelem->magic = GH_LIST_MAGIC;
#endif
return newelem;
}
int gh_list_init(gh_list *newlist) {
int i;
if (!newlist)
return -1;
newlist->count = 0;
newlist->first = newlist->last = NULL;
newlist->last_alloc = 16;
newlist->free = (struct gh_list_elem *)safe_malloc(newlist->last_alloc * sizeof(struct gh_list_elem));
memset(newlist->free, 0, newlist->last_alloc * sizeof(struct gh_list_elem));
newlist->free->allocated = 1;
for (i = 0; i < newlist->last_alloc - 1; i++) {
(newlist->free + i)->next = newlist->free + i + 1;
}
/* Not needed (newlist->free + newlist->last_alloc - 1)->next = NULL */
#ifndef NDEBUG
newlist->magic = GH_LIST_MAGIC;
#endif
return 0;
}
gh_list_elem *gh_list_append(gh_list *list, void *data) {
gh_list_elem *newelem;
gh_list_elem *oldlast;
SAFETY_CHECK_LIST(list);
newelem = get_free_buffer(list);
oldlast = list->last;
if (oldlast) {
oldlast->next = newelem;
newelem->prev = oldlast;
} else {
newelem->prev = NULL;
}
newelem->next = NULL;
newelem->data = data;
#ifndef NDEBUG
newelem->magic = GH_LIST_MAGIC;
#endif
list->count++;
list->last = newelem;
if (list->count == 1)
list->first = newelem;
return newelem;
}
gh_list_elem *gh_list_prepend(gh_list *list, void *data) {
gh_list_elem *newelem;
gh_list_elem *oldfirst;
SAFETY_CHECK_LIST(list);
newelem = get_free_buffer(list);
oldfirst = list->first;
if (oldfirst) {
oldfirst->prev = newelem;
newelem->next = oldfirst;
} else {
newelem->next = NULL;
}
newelem->prev = NULL;
newelem->data = data;
#ifndef NDEBUG
newelem->magic = GH_LIST_MAGIC;
#endif
list->count++;
list->first = newelem;
if (list->count == 1)
list->last = newelem;
return newelem;
}
gh_list_elem *gh_list_insert_before(gh_list *list, gh_list_elem *before, void *data) {
gh_list_elem *newelem;
SAFETY_CHECK_LIST(list);
SAFETY_CHECK_ELEM(before);
/* create or reuse a new cell */
newelem = get_free_buffer(list);
newelem->data = data;
newelem->prev = before->prev;
newelem->next = before;
#ifndef NDEBUG
newelem->magic = GH_LIST_MAGIC;
#endif
if (before->prev)
before->prev->next = newelem;
else
list->first = newelem;
before->prev = newelem;
list->count++;
return newelem;
}
void *gh_list_pop(gh_list *list) {
struct gh_list_elem *oldelem;
SAFETY_CHECK_LIST(list);
oldelem = list->first;
if (!oldelem)
return NULL;
list->first = list->first->next;
if (list->first)
list->first->prev = NULL;
list->count--;
if (list->count < 2)
list->last = list->first;
oldelem->next = list->free;
list->free = oldelem;
return oldelem->data;
}
int gh_list_free(gh_list *list) {
struct gh_list_elem *current;
char *free_list[32];
int free_index = 0;
int i = 0;
SAFETY_CHECK_LIST(list);
#ifndef NDEBUG
list->magic++;
#endif
for (current = list->first; current; current = current->next) {
#ifndef NDEBUG
current->magic++;
#endif
if (current->allocated) {
assert(free_index < 32);
free_list[free_index++] = (char *)current;
}
}
for (current = list->free; current; current = current->next)
if (current->allocated) {
assert(free_index < 32);
free_list[free_index++] = (char *)current;
}
for (i = 0; i < free_index; i++)
free(free_list[i]);
return 0;
}
int gh_list_remove_elem(gh_list *list, gh_list_elem *elem) {
SAFETY_CHECK_ELEM(elem);
SAFETY_CHECK_LIST(list);
if (elem->prev) {
elem->prev->next = elem->next;
} else {
assert(list->first == elem);
list->first = elem->next;
}
if (elem->next) {
elem->next->prev = elem->prev;
} else {
assert(list->last == elem);
list->last = elem->prev;
}
#ifndef NDEBUG
elem->magic++;
#endif
elem->next = list->free;
list->free = elem;
list->count--;
return 0;
}
int gh_list_move_front(gh_list *list, gh_list_elem *elem) {
SAFETY_CHECK_LIST(list);
SAFETY_CHECK_ELEM(elem);
if (list->first == elem)
return 0;
/* remove element from its current position */
elem->prev->next = elem->next;
if (elem->next) {
elem->next->prev = elem->prev;
} else {
assert(list->last == elem);
list->last = elem->prev;
}
/* add element to the beginning list */
list->first->prev = elem;
elem->next = list->first;
elem->prev = NULL;
list->first = elem;
return 0;
}
int gh_list_remove(gh_list *list, void *data) {
struct gh_list_elem *current;
SAFETY_CHECK_LIST(list);
for (current = list->first; current; current = current->next) {
if (current->data == data)
return gh_list_remove_elem(list, current);
}
return -1;
}

View File

@@ -1,6 +1,5 @@
/***************************************************************************
* gh_list.h -- a simple doubly-linked list implementation with a very *
* heavy focus on efficiency. *
* gh_list.h -- a simple doubly-linked list implementation. *
* *
***********************IMPORTANT NSOCK LICENSE TERMS***********************
* *
@@ -72,77 +71,229 @@
#include <assert.h>
#define GH_LIST_MAGIC 0xBADFACE
/* Take a LIST ELEMENT (not just the data) and return the next one */
#define GH_LIST_ELEM_NEXT(x) ((x)->next)
/* Same as above but return the previous element */
#define GH_LIST_ELEM_PREV(x) ((x)->prev)
/* Take a LIST (not a list element) and return the first element */
#define GH_LIST_FIRST_ELEM(x) ((x)->first)
/* Same as above but return the last element */
#define GH_LIST_LAST_ELEM(x) ((x)->last)
/* Obtain the actual data stored in an element */
#define GH_LIST_ELEM_DATA(x) ((x)->data)
/* Obtain the number of elements in a list */
#define GH_LIST_COUNT(x) ((x)->count)
#define GH_LIST_PARANOID 0
typedef struct gh_list_elem {
void *data;
struct gh_list_elem *next;
struct gh_list_elem *prev;
/* nonzero if this element was the first (or only) in a group that was
* allocated. This means we can safely free() it as long as we are OK with
* freeing others that were freed with it ... */
int allocated;
#ifndef NDEBUG
unsigned long magic;
#endif
} gh_list_elem;
typedef struct gh_list_node {
struct gh_list_node *next;
struct gh_list_node *prev;
} gh_lnode_t;
typedef struct gh_list {
/* Number of elements in the list */
int count;
struct gh_list_elem *first;
struct gh_list_elem *last;
unsigned int count;
gh_lnode_t *first;
gh_lnode_t *last;
} gh_list_t;
/* Instead of free()ing elements when something is removed from the list, we
* stick them here for the next insert. */
struct gh_list_elem *free;
/* The number of list elements in the most recent malloc */
int last_alloc;
/* That one's an efficiency killer but it should reveal
* any inconsistency in nsock's lists management. To be
* called on every list we get and return. */
static inline void paranoid_list_check(gh_list_t *list) {
#if GH_LIST_PARANOID
switch (list->count) {
case 0:
assert(list->first == NULL);
assert(list->last == NULL);
break;
#ifndef NDEBUG
unsigned long magic;
case 1:
assert(list->first);
assert(list->last);
assert(list->first == list->last);
break;
default:
assert(list->first);
assert(list->last);
assert(list->first != list->last);
break;
}
#endif
} gh_list;
}
static inline int gh_list_init(gh_list_t *newlist) {
newlist->count = 0;
newlist->first = NULL;
newlist->last = NULL;
return 0;
}
int gh_list_init(gh_list *newlist);
static inline int gh_list_append(gh_list_t *list, gh_lnode_t *lnode) {
gh_lnode_t *oldlast;
gh_list_elem *gh_list_append(gh_list *list, void *data);
paranoid_list_check(list);
gh_list_elem *gh_list_prepend(gh_list *list, void *data);
oldlast = list->last;
if (oldlast)
oldlast->next = lnode;
gh_list_elem *gh_list_insert_before(gh_list *list, gh_list_elem *before, void *data);
lnode->prev = oldlast;
lnode->next = NULL;
void *gh_list_pop(gh_list *list);
list->count++;
list->last = lnode;
int gh_list_remove(gh_list *list, void *data);
if (list->count == 1)
list->first = lnode;
int gh_list_free(gh_list *list);
paranoid_list_check(list);
return 0;
}
int gh_list_move_front(gh_list *list, gh_list_elem *elem);
static inline int gh_list_prepend(gh_list_t *list, gh_lnode_t *lnode) {
gh_lnode_t *oldfirst;
int gh_list_remove_elem(gh_list *list, gh_list_elem *elem);
paranoid_list_check(list);
oldfirst = list->first;
if (oldfirst)
oldfirst->prev = lnode;
lnode->next = oldfirst;
lnode->prev = NULL;
list->count++;
list->first = lnode;
if (list->count == 1)
list->last = lnode;
paranoid_list_check(list);
return 0;
}
static inline int gh_list_insert_before(gh_list_t *list, gh_lnode_t *before,
gh_lnode_t *lnode) {
paranoid_list_check(list);
lnode->prev = before->prev;
lnode->next = before;
if (before->prev)
before->prev->next = lnode;
else
list->first = lnode;
before->prev = lnode;
list->count++;
paranoid_list_check(list);
return 0;
}
static inline gh_lnode_t *gh_list_pop(gh_list_t *list) {
gh_lnode_t *elem;
paranoid_list_check(list);
elem = list->first;
if (!elem) {
paranoid_list_check(list);
return NULL;
}
list->first = list->first->next;
if (list->first)
list->first->prev = NULL;
list->count--;
if (list->count < 2)
list->last = list->first;
elem->prev = NULL;
elem->next = NULL;
paranoid_list_check(list);
return elem;
}
static inline int gh_list_remove(gh_list_t *list, gh_lnode_t *lnode) {
paranoid_list_check(list);
if (lnode->prev) {
lnode->prev->next = lnode->next;
} else {
assert(list->first == lnode);
list->first = lnode->next;
}
if (lnode->next) {
lnode->next->prev = lnode->prev;
} else {
assert(list->last == lnode);
list->last = lnode->prev;
}
lnode->prev = NULL;
lnode->next = NULL;
list->count--;
paranoid_list_check(list);
return 0;
}
static inline int gh_list_free(gh_list_t *list) {
paranoid_list_check(list);
while (list->count > 0)
gh_list_pop(list);
paranoid_list_check(list);
memset(list, 0, sizeof(gh_list_t));
return 0;
}
static inline int gh_list_move_front(gh_list_t *list, gh_lnode_t *lnode) {
paranoid_list_check(list);
if (list->first == lnode)
return 0;
/* remove element from its current position */
lnode->prev->next = lnode->next;
if (lnode->next) {
lnode->next->prev = lnode->prev;
} else {
assert(list->last == lnode);
list->last = lnode->prev;
}
/* add element to the beginning of the list */
list->first->prev = lnode;
lnode->next = list->first;
lnode->prev = NULL;
list->first = lnode;
paranoid_list_check(list);
return 0;
}
/* Take a LIST ELEMENT (not just the data) and return the next one */
static inline gh_lnode_t *gh_lnode_next(gh_lnode_t *elem) {
return elem->next;
}
/* Same as above but return the previous element */
static inline gh_lnode_t *gh_lnode_prev(gh_lnode_t *elem) {
return elem->prev;
}
/* Take a LIST (not a list element) and return the first element */
static inline gh_lnode_t *gh_list_first_elem(gh_list_t *list) {
return list->first;
}
/* Same as above but return the last element */
static inline gh_lnode_t *gh_list_last_elem(gh_list_t *list) {
return list->last;
}
static inline unsigned int gh_list_count(gh_list_t *list) {
return list->count;
}
#endif /* GH_LIST_H */

View File

@@ -204,7 +204,7 @@ void nsock_connect_internal(mspool *ms, msevent *nse, int type, int proto, struc
nsock_log_debug_all(ms, "TCP connection request (EID %lu) redirected through proxy chain",
(long)nse->id);
current = proxy_ctx_node_current(iod->px_ctx);
current = iod->px_ctx->px_current;
assert(current != NULL);
memcpy(&iod->px_ctx->target_ss, ss, sslen);

View File

@@ -223,27 +223,33 @@ static void update_events(msiod * iod, mspool *ms, int ev_inc, int ev_dec) {
* loop just after its addition.
*/
static int iod_add_event(msiod *iod, msevent *nse) {
mspool *nsp = iod->nsp;
switch (nse->type) {
case NSE_TYPE_CONNECT:
case NSE_TYPE_CONNECT_SSL:
if (iod->first_connect)
iod->first_connect = gh_list_insert_before(&iod->nsp->connect_events, iod->first_connect, nse);
gh_list_insert_before(&nsp->connect_events,
iod->first_connect, &nse->nodeq_io);
else
iod->first_connect = gh_list_append(&iod->nsp->connect_events, nse);
gh_list_append(&nsp->connect_events, &nse->nodeq_io);
iod->first_connect = &nse->nodeq_io;
break;
case NSE_TYPE_READ:
if (iod->first_read)
iod->first_read = gh_list_insert_before(&iod->nsp->read_events, iod->first_read, nse);
gh_list_insert_before(&nsp->read_events, iod->first_read, &nse->nodeq_io);
else
iod->first_read = gh_list_append(&iod->nsp->read_events, nse);
gh_list_append(&nsp->read_events, &nse->nodeq_io);
iod->first_read = &nse->nodeq_io;
break;
case NSE_TYPE_WRITE:
if (iod->first_write)
iod->first_write = gh_list_insert_before(&iod->nsp->write_events, iod->first_write, nse);
gh_list_insert_before(&nsp->write_events, iod->first_write, &nse->nodeq_io);
else
iod->first_write = gh_list_append(&iod->nsp->write_events, nse);
gh_list_append(&nsp->write_events, &nse->nodeq_io);
iod->first_write = &nse->nodeq_io;
break;
#if HAVE_PCAP
@@ -262,15 +268,18 @@ static int iod_add_event(msiod *iod, msevent *nse) {
#endif
if (add_read) {
if (iod->first_read)
iod->first_read = gh_list_insert_before(&iod->nsp->read_events, iod->first_read, nse);
gh_list_insert_before(&nsp->read_events, iod->first_read, &nse->nodeq_io);
else
iod->first_read = gh_list_append(&iod->nsp->read_events, nse);
gh_list_append(&nsp->read_events, &nse->nodeq_io);
iod->first_read = &nse->nodeq_io;
}
if (add_pcap_read) {
if (iod->first_pcap_read)
iod->first_pcap_read = gh_list_insert_before(&iod->nsp->pcap_read_events, iod->first_pcap_read, nse);
gh_list_insert_before(&nsp->pcap_read_events, iod->first_pcap_read,
&nse->nodeq_pcap);
else
iod->first_pcap_read = gh_list_append(&iod->nsp->pcap_read_events, nse);
gh_list_append(&nsp->pcap_read_events, &nse->nodeq_pcap);
iod->first_pcap_read = &nse->nodeq_pcap;
}
break;
}
@@ -850,20 +859,21 @@ void handle_pcap_read_result(mspool *ms, msevent *nse, enum nse_status status) {
/* Returns whether something was read */
int pcap_read_on_nonselect(mspool *nsp) {
gh_list_elem *current, *next;
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 = (msevent *)GH_LIST_ELEM_DATA(current);
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_LIST_ELEM_NEXT(current);
next = gh_lnode_next(current);
}
return ret;
}
#endif /* HAVE_PCAP */
@@ -935,13 +945,16 @@ enum nsock_loopstatus nsock_loop(nsock_pool nsp, int msec_timeout) {
return quitstatus;
}
void process_event(mspool *nsp, gh_list *evlist, msevent *nse, int ev) {
void process_event(mspool *nsp, gh_list_t *evlist, msevent *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(nsp, "Processing event %lu", nse->id);
nsock_log_debug_all(nsp, "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) {
@@ -1015,18 +1028,24 @@ void process_event(mspool *nsp, gh_list *evlist, msevent *nse, int ev) {
* 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) {
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);
gh_list_remove(&nsp->pcap_read_events, &nse->nodeq_pcap);
nsock_log_debug_all(nsp, "PCAP NSE #%lu: Removing event from PCAP_READ_EVENTS", nse->id);
nsock_log_debug_all(nsp, "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) {
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);
nsock_log_debug_all(nsp, "PCAP NSE #%lu: Removing event from READ_EVENTS", nse->id);
gh_list_remove(&nsp->read_events, &nse->nodeq_io);
nsock_log_debug_all(nsp, "PCAP NSE #%lu: Removing event from READ_EVENTS",
nse->id);
}
#endif
break;
@@ -1034,11 +1053,12 @@ void process_event(mspool *nsp, gh_list *evlist, msevent *nse, int ev) {
#endif
default:
fatal("Event has unknown type (%d)", nse->type);
break; /* unreached */
}
}
if (nse->event_done) {
/* Security sanity check: don't return a functional SSL iod without setting an SSL data structure. */
/* 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);
@@ -1046,14 +1066,6 @@ void process_event(mspool *nsp, gh_list *evlist, msevent *nse, int ev) {
/* WooHoo! The event is ready to be sent */
msevent_dispatch_and_delete(nsp, nse, 1);
} else {
/* Is this event the next-to-timeout? */
if (nse->timeout.tv_sec != 0) {
if (nsp->next_ev.tv_sec == 0)
nsp->next_ev = nse->timeout;
else if (TIMEVAL_AFTER(nsp->next_ev, nse->timeout))
nsp->next_ev = nse->timeout;
}
}
}
@@ -1061,7 +1073,7 @@ 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_list_elem **start_elems[] = {
gh_lnode_t **start_elems[] = {
&nsi->first_connect,
&nsi->first_read,
&nsi->first_write,
@@ -1070,16 +1082,19 @@ void process_iod_events(mspool *nsp, msiod *nsi, int ev) {
#endif
NULL
};
gh_list *evlists[] = {
&nsi->nsp->connect_events,
&nsi->nsp->read_events,
&nsi->nsp->write_events,
gh_list_t *evlists[] = {
&nsp->connect_events,
&nsp->read_events,
&nsp->write_events,
#if HAVE_PCAP
&nsi->nsp->pcap_read_events,
&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:
*
@@ -1091,16 +1106,24 @@ void process_iod_events(mspool *nsp, msiod *nsi, int ev) {
* processed in the same cycle. In the same way, read() often
* leads to write().
*/
for (i = 0; start_elems[i] != NULL; i++) {
gh_list_elem *current, *next, *last;
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 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_LIST_ELEM_PREV(current) != last; current = next) {
msevent *nse = (msevent *)GH_LIST_ELEM_DATA(current);
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 */
@@ -1108,18 +1131,91 @@ void process_iod_events(mspool *nsp, msiod *nsi, int ev) {
break;
process_event(nsp, evlists[i], nse, ev);
next = GH_LIST_ELEM_NEXT(current);
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_elem(evlists[i], current);
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);
}
}
}
}
static int msevent_unref(mspool *nsp, msevent *nse) {
switch (nse->type) {
case NSE_TYPE_CONNECT:
case NSE_TYPE_CONNECT_SSL:
gh_list_remove(&nsp->connect_events, &nse->nodeq_io);
break;
case NSE_TYPE_READ:
gh_list_remove(&nsp->read_events, &nse->nodeq_io);
break;
case NSE_TYPE_WRITE:
gh_list_remove(&nsp->write_events, &nse->nodeq_io);
break;
#if HAVE_PCAP
case NSE_TYPE_PCAP_READ: {
char read = 0;
char pcap = 0;
#if PCAP_BSD_SELECT_HACK
read = pcap = 1;
#else
if (((mspcap *)nse->iod->pcap)->pcap_desc >= 0)
read = 1;
else
pcap = 1;
#endif /* PCAP_BSD_SELECT_HACK */
if (read)
gh_list_remove(&nsp->read_events, &nse->nodeq_io);
if (pcap)
gh_list_remove(&nsp->pcap_read_events, &nse->nodeq_pcap);
break;
}
#endif /* HAVE_PCAP */
case NSE_TYPE_TIMER:
/* Nothing to do */
break;
default:
fatal("Unknown event type %d", nse->type);
}
gh_list_append(&nsp->free_events, &nse->nodeq_io);
return 0;
}
void process_expired_events(mspool *nsp) {
for (;;) {
gh_hnode_t *hnode;
msevent *nse;
hnode = gh_heap_min(&nsp->expirables);
if (!hnode)
break;
nse = container_of(hnode, msevent, expire);
if (msevent_timedout(nse)) {
gh_heap_pop(&nsp->expirables);
process_event(nsp, NULL, nse, EV_NONE);
assert(nse->event_done);
update_first_events(nse);
msevent_unref(nsp, nse);
} else break;
}
}
/* Calling this function will cause nsock_loop to quit on its next iteration
* with a return value of NSOCK_LOOP_QUIT. */
void nsock_loop_quit(nsock_pool nsp) {
@@ -1142,22 +1238,17 @@ const struct timeval *nsock_gettimeofday() {
* adjusting the descriptor select/poll lists, registering the timeout value,
* etc. */
void nsp_add_event(mspool *nsp, msevent *nse) {
nsock_log_debug(nsp, "NSE #%lu: Adding event", nse->id);
/* First lets do the event-type independent stuff, starting with timeouts */
if (nse->event_done) {
nsp->next_ev = nsock_tod;
} else {
if (nse->timeout.tv_sec != 0) {
if (nsp->next_ev.tv_sec == 0)
nsp->next_ev = nse->timeout;
else if (TIMEVAL_AFTER(nsp->next_ev, nse->timeout))
nsp->next_ev = nse->timeout;
}
}
nsock_log_debug(nsp, "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:
@@ -1198,7 +1289,7 @@ void nsp_add_event(mspool *nsp, msevent *nse) {
break;
case NSE_TYPE_TIMER:
gh_list_append(&nsp->timer_events, nse);
/* nothing to do */
break;
#if HAVE_PCAP

View File

@@ -64,7 +64,6 @@
#include "nsock_internal.h"
#if HAVE_EPOLL
extern struct io_engine engine_epoll;
#define ENGINE_EPOLL &engine_epoll,

View File

@@ -119,18 +119,23 @@ char *nse_readbuf(nsock_event nse, int *nbytes) {
return fs_str(&(me->iobuf));
}
static void first_ev_next(msevent *nse, gh_list_elem **first) {
static void first_ev_next(msevent *nse, gh_lnode_t **first, int nodeq2) {
if (!first || !*first)
return;
if ((msevent *)GH_LIST_ELEM_DATA(*first) == nse) {
gh_list_elem *next;
if (&nse->nodeq_io == *first || &nse->nodeq_pcap == *first) {
gh_lnode_t *next;
next = GH_LIST_ELEM_NEXT(*first);
next = gh_lnode_next(*first);
if (next) {
msevent *nse2 = (msevent *)GH_LIST_ELEM_DATA(next);
msevent *newevent;
if (nse2->iod == nse->iod)
if (nodeq2)
newevent = lnode_msevent2(next);
else
newevent = lnode_msevent(next);
if (newevent->iod == nse->iod)
*first = next;
else
*first = NULL;
@@ -144,21 +149,21 @@ void update_first_events(msevent *nse) {
switch (get_event_id_type(nse->id)) {
case NSE_TYPE_CONNECT:
case NSE_TYPE_CONNECT_SSL:
first_ev_next(nse, &nse->iod->first_connect);
first_ev_next(nse, &nse->iod->first_connect, 0);
break;
case NSE_TYPE_READ:
first_ev_next(nse, &nse->iod->first_read);
first_ev_next(nse, &nse->iod->first_read, 0);
break;
case NSE_TYPE_WRITE:
first_ev_next(nse, &nse->iod->first_write);
first_ev_next(nse, &nse->iod->first_write, 0);
break;
#if HAVE_PCAP
case NSE_TYPE_PCAP_READ:
first_ev_next(nse, &nse->iod->first_read);
first_ev_next(nse, &nse->iod->first_pcap_read);
first_ev_next(nse, &nse->iod->first_read, 0);
first_ev_next(nse, &nse->iod->first_pcap_read, 1);
break;
#endif
@@ -181,8 +186,9 @@ void update_first_events(msevent *nse) {
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;
unsigned int i;
gh_list_t *event_list = NULL, *event_list2 = NULL;
gh_lnode_t *current, *next;
msevent *nse = NULL;
assert(nsp);
@@ -205,8 +211,15 @@ int nsock_event_cancel(nsock_pool ms_pool, nsock_event_id id, int notify) {
break;
case NSE_TYPE_TIMER:
event_list = &nsp->timer_events;
break;
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:
@@ -220,18 +233,18 @@ int nsock_event_cancel(nsock_pool ms_pool, nsock_event_id id, int notify) {
}
/* 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);
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){
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);
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;
}
@@ -249,7 +262,8 @@ int nsock_event_cancel(nsock_pool ms_pool, nsock_event_id id, int notify) {
* 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 msevent_cancel(mspool *nsp, msevent *nse, gh_list *event_list, gh_list_elem *elem, int notify) {
int msevent_cancel(mspool *nsp, msevent *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
@@ -257,7 +271,8 @@ int msevent_cancel(mspool *nsp, msevent *nse, gh_list *event_list, gh_list_elem
return 0;
}
nsock_log_info(nsp, "msevent_cancel on event #%li (type %s)", nse->id, nse_type2str(nse->type));
nsock_log_info(nsp, "msevent_cancel on event #%li (type %s)",
nse->id, nse_type2str(nse->type));
/* Now that we found the event... we go through the motions of cleanly
* cancelling it */
@@ -290,8 +305,16 @@ int msevent_cancel(mspool *nsp, msevent *nse, gh_list *event_list, gh_list_elem
}
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_elem(event_list, elem);
gh_list_remove(event_list, elem);
}
gh_list_append(&nsp->free_events, &nse->nodeq_io);
nsock_log_debug_all(nsp, "NSE #%lu: Removing event from list", nse->id);
@@ -309,14 +332,14 @@ int msevent_cancel(mspool *nsp, msevent *nse, gh_list *event_list, gh_list_elem
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);
gh_list_remove(&nsp->pcap_read_events, &nse->nodeq_pcap);
nsock_log_debug_all(nsp, "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);
gh_list_remove(&nsp->read_events, &nse->nodeq_io);
nsock_log_debug_all(nsp, "PCAP NSE #%lu: Removing event from READ_EVENTS", nse->id);
}
@@ -392,6 +415,7 @@ enum nse_type get_event_id_type(nsock_event_id event_id) {
msevent *msevent_new(mspool *nsp, enum nse_type type, msiod *msiod, int timeout_msecs,
nsock_ev_handler handler, void *userdata) {
msevent *nse;
gh_lnode_t *lnode;
/* Bring us up to date for the timeout calculation. */
gettimeofday(&nsock_tod, NULL);
@@ -402,14 +426,18 @@ msevent *msevent_new(mspool *nsp, enum nse_type type, msiod *msiod, int timeout_
}
/* First we check if one is available from the free list ... */
nse = (msevent *)gh_list_pop(&nsp->free_events);
if (!nse)
lnode = gh_list_pop(&nsp->free_events);
if (!lnode)
nse = (msevent *)safe_malloc(sizeof(msevent));
else
nse = lnode_msevent(lnode);
memset(nse, 0, sizeof(msevent));
nse->id = get_new_event_id(nsp, type);
nse->type = type;
nse->status = NSE_STATUS_NONE;
gh_hnode_invalidate(&nse->expire);
#if HAVE_OPENSSL
nse->sslinfo.ssl_desire = SSL_ERROR_NONE;
#endif
@@ -453,7 +481,6 @@ msevent *msevent_new(mspool *nsp, enum nse_type type, msiod *msiod, int timeout_
* has ALREADY been decremented (done during msevent_dispatch_and_delete) -- so
* remember to do this if you call msevent_delete() directly */
void msevent_delete(mspool *nsp, msevent *nse) {
if (nse->iod == NULL)
nsock_log_debug(nsp, "msevent_delete (IOD #NULL) (EID #%li)", nse->id);
else
@@ -471,7 +498,7 @@ void msevent_delete(mspool *nsp, msevent *nse) {
#endif
/* Now we add the event back into the free pool */
gh_list_prepend(&nsp->free_events, nse);
nse->event_done = 1;
}

View File

@@ -73,6 +73,7 @@
#endif
#include "gh_list.h"
#include "gh_heap.h"
#include "filespace.h"
#include "nsock.h" /* The public interface -- I need it for some enum defs */
#include "nsock_ssl.h"
@@ -165,28 +166,21 @@ typedef struct {
void *engine_data;
/* Active network events */
gh_list connect_events;
gh_list read_events;
gh_list write_events;
gh_list timer_events;
gh_list_t connect_events;
gh_list_t read_events;
gh_list_t write_events;
#if HAVE_PCAP
gh_list pcap_read_events;
gh_list_t pcap_read_events;
#endif
gh_heap_t expirables;
/* Active iods and related lists of events */
gh_list active_iods;
gh_list_t active_iods;
/* msiod structures that have been freed for reuse */
gh_list free_iods;
gh_list_t free_iods;
/* When an event is deleted, we stick it here for later reuse */
gh_list free_events;
/* The soonest time that either a timer event goes
* off or a read/write/connect expires. It is
* updated each main loop round as we go through
* the events. It is an absolute time. If there
* are no events, tv_sec is 0 */
struct timeval next_ev;
gh_list_t free_events;
/* Number of events pending (total) on all lists */
int events_pending;
@@ -236,11 +230,11 @@ typedef struct {
int events_pending;
/* Pending events */
gh_list_elem *first_connect;
gh_list_elem *first_read;
gh_list_elem *first_write;
gh_lnode_t *first_connect;
gh_lnode_t *first_read;
gh_lnode_t *first_write;
#if HAVE_PCAP
gh_list_elem *first_pcap_read;
gh_lnode_t *first_pcap_read;
#endif
int readsd_count;
@@ -273,7 +267,7 @@ typedef struct {
/* The mspool keeps track of msiods that have been allocated so that it can
* destroy them if the msp is deleted. This pointer makes it easy to remove
* this msiod from the allocated list when necessary */
gh_list_elem *entry_in_nsp_active_iods;
gh_lnode_t nodeq;
#define IOD_REGISTERED 0x01
#define IOD_PROCESSED 0x02 /* internally used by engine_kqueue.c */
@@ -354,6 +348,18 @@ typedef struct {
/* The handler to call when event is complete */
nsock_ev_handler handler;
/* slot in the expirable binheap */
gh_hnode_t expire;
/* For some reasons (see nsock_pcap.c) we register pcap events as both read
* and pcap_read events when in PCAP_BSD_SELECT_HACK mode. We then need two
* gh_lnode_t handles. To make code simpler, we _always_ use _nodeq_pcap for
* pcap_read events and _nodeq_io for the other ones.
* When not in PCAP_BSD_SELECT_HACK mode we define both handles as members
* of an union to optimize memory footprint. */
gh_lnode_t nodeq_io;
gh_lnode_t nodeq_pcap;
/* Optional (NULL if unset) pointer to pass to the handler */
void *userdata;
@@ -439,7 +445,7 @@ msevent *msevent_new(mspool *nsp, enum nse_type type, msiod *msiod, int timeout_
* 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 msevent_cancel(mspool *nsp, msevent *nse, gh_list *event_list, gh_list_elem *elem, int notify);
int msevent_cancel(mspool *nsp, msevent *nse, gh_list_t *event_list, gh_lnode_t *elem, int notify);
/* Adjust various statistics, dispatches the event handler (if notify is
* nonzero) and then deletes the event. This function does NOT delete the event
@@ -486,5 +492,23 @@ void nsock_trace_handler_callback(mspool *ms, msevent *nse);
void nsi_set_ssl_session(msiod *iod, SSL_SESSION *sessid);
#endif
static inline msevent *next_expirable_event(mspool *nsp) {
gh_hnode_t *hnode;
hnode = gh_heap_min(&nsp->expirables);
if (!hnode)
return NULL;
return container_of(hnode, msevent, expire);
}
static inline msevent *lnode_msevent(gh_lnode_t *lnode) {
return container_of(lnode, msevent, nodeq_io);
}
static inline msevent *lnode_msevent2(gh_lnode_t *lnode) {
return container_of(lnode, msevent, nodeq_pcap);
}
#endif /* NSOCK_INTERNAL_H */

View File

@@ -87,12 +87,15 @@ nsock_iod nsi_new(nsock_pool nsockp, void *userdata) {
* will be destroyed when the nsi is destroyed. */
nsock_iod nsi_new2(nsock_pool nsockp, int sd, void *userdata) {
mspool *nsp = (mspool *)nsockp;
gh_lnode_t *lnode;
msiod *nsi;
nsi = (msiod *)gh_list_pop(&nsp->free_iods);
if (!nsi) {
lnode = gh_list_pop(&nsp->free_iods);
if (!lnode) {
nsi = (msiod *)safe_malloc(sizeof(msiod));
memset(nsi, 0, sizeof(*nsi));
} else {
nsi = container_of(lnode, msiod, nodeq);
}
if (sd == -1) {
@@ -149,7 +152,7 @@ nsock_iod nsi_new2(nsock_pool nsockp, int sd, void *userdata) {
nsi->id = nsp->next_iod_serial++;
/* The nsp keeps track of active msiods so it can delete them if it is deleted */
nsi->entry_in_nsp_active_iods = gh_list_append(&nsp->active_iods, nsi);
gh_list_append(&nsp->active_iods, &nsi->nodeq);
nsock_log_info(nsp, "nsi_new (IOD #%lu)", nsi->id);
@@ -169,10 +172,10 @@ int socket_count_zero(msiod *iod, mspool *ms);
* quiit the program) */
void nsi_delete(nsock_iod nsockiod, int pending_response) {
msiod *nsi = (msiod *)nsockiod;
gh_list_elem *evlist_ar[3];
gh_list *corresp_list[3];
gh_lnode_t *evlist_ar[3];
gh_list_t *corresp_list[3];
int i;
gh_list_elem *current, *next;
gh_lnode_t *current, *next;
assert(nsi);
@@ -207,8 +210,8 @@ void nsi_delete(nsock_iod nsockiod, int pending_response) {
for (current = evlist_ar[i]; current != NULL; current = next) {
msevent *nse;
next = GH_LIST_ELEM_NEXT(current);
nse = (msevent *)GH_LIST_ELEM_DATA(current);
next = gh_lnode_next(current);
nse = lnode_msevent(current);
/* we're done with this list of events for the current IOD */
if (nse->iod != nsi)

View File

@@ -411,12 +411,15 @@ int do_actual_pcap_read(msevent *nse) {
n = (nsock_pcap *)fs_str(&(nse->iobuf));
n->packet = (unsigned char *)fs_str(&(nse->iobuf)) + sizeof(npp);
nsock_log_debug_all(nse->iod->nsp, "PCAP %s READ (IOD #%li) (EID #%li) size=%i",
nsock_log_debug_all(nse->iod->nsp,
"PCAP %s READ (IOD #%li) (EID #%li) size=%i",
__func__, nse->iod->id, nse->id, pkt_header->caplen);
return 1;
rc = 1;
break;
case 0: /* timeout */
return(0);
rc = 0;
break;
case -1: /* error */
fatal("pcap_next_ex() fatal error while reading from pcap: %s\n",
@@ -427,7 +430,8 @@ int do_actual_pcap_read(msevent *nse) {
default:
fatal("Unexpected return code from pcap_next_ex! (%d)\n", rc);
}
return 0;
return rc;
}
void nse_readpcap(nsock_event nsev, const unsigned char **l2_data, size_t *l2_len,

View File

@@ -132,6 +132,16 @@ void nsp_setdevice(nsock_pool nsp, const char *device) {
mt->device = device;
}
static int expirable_cmp(gh_hnode_t *n1, gh_hnode_t *n2) {
msevent *nse1;
msevent *nse2;
nse1 = container_of(n1, msevent, expire);
nse2 = container_of(n2, msevent, expire);
return (TIMEVAL_BEFORE(nse1->timeout, nse2->timeout)) ? 1 : 0;
}
/* And here is how you create an nsock_pool. This allocates, initializes, and
* returns an nsock_pool event aggregator. In the case of error, NULL will be
* returned. If you do not wish to immediately associate any userdata, pass in
@@ -167,8 +177,9 @@ nsock_pool nsp_new(void *userdata) {
#if HAVE_PCAP
gh_list_init(&nsp->pcap_read_events);
#endif
/* initialize timer list */
gh_list_init(&nsp->timer_events);
/* initialize timer heap */
gh_heap_init(&nsp->expirables, expirable_cmp);
/* initialize the list of IODs */
gh_list_init(&nsp->active_iods);
@@ -199,12 +210,11 @@ void nsp_delete(nsock_pool ms_pool) {
msevent *nse;
msiod *nsi;
int i;
gh_list_elem *current, *next;
gh_list *event_lists[] = {
gh_lnode_t *current, *next;
gh_list_t *event_lists[] = {
&nsp->connect_events,
&nsp->read_events,
&nsp->write_events,
&nsp->timer_events,
#if HAVE_PCAP
&nsp->pcap_read_events,
#endif
@@ -215,13 +225,24 @@ void nsp_delete(nsock_pool ms_pool) {
/* 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]);
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);
@@ -231,22 +252,45 @@ void nsp_delete(nsock_pool ms_pool) {
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_LIST_ELEM_NEXT(current);
nsi = (msiod *)GH_LIST_ELEM_DATA(current);
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_elem(&nsp->active_iods, current);
gh_list_prepend(&nsp->free_iods, nsi);
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 ((nsi = (msiod *)gh_list_pop(&nsp->free_iods))) {
while ((current = gh_list_pop(&nsp->free_iods))) {
nsi = container_of(current, msiod, nodeq);
free(nsi);
}
while ((nse = (msevent *)gh_list_pop(&nsp->free_events))) {
while ((current = gh_list_pop(&nsp->free_events))) {
nse = lnode_msevent(current);
free(nse);
}

View File

@@ -103,7 +103,7 @@ int nsock_proxychain_new(const char *proxystr, nsock_proxychain *chain, nsock_po
parser = proxy_parser_new(proxystr);
while (!parser->done) {
gh_list_append(&pxc->nodes, parser->value);
gh_list_append(&pxc->nodes, &parser->value->nodeq);
proxy_parser_next(parser);
}
proxy_parser_delete(parser);
@@ -124,9 +124,12 @@ void nsock_proxychain_delete(nsock_proxychain chain) {
struct proxy_chain *pchain = (struct proxy_chain *)chain;
if (pchain) {
gh_lnode_t *lnode;
while ((lnode = gh_list_pop(&pchain->nodes)) != NULL) {
struct proxy_node *node;
while ((node = (struct proxy_node *)gh_list_pop(&pchain->nodes)) != NULL) {
node = container_of(lnode, struct proxy_node, nodeq);
node->spec->ops->node_delete(node);
}
@@ -147,7 +150,6 @@ int nsp_set_proxychain(nsock_pool nspool, nsock_proxychain chain) {
return 1;
}
struct proxy_chain_context *proxy_chain_context_new(nsock_pool nspool) {
mspool *nsp = (mspool *)nspool;
struct proxy_chain_context *ctx;
@@ -155,7 +157,9 @@ struct proxy_chain_context *proxy_chain_context_new(nsock_pool nspool) {
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);
ctx->px_current = container_of(gh_list_first_elem(&nsp->px_chain->nodes),
struct proxy_node,
nodeq);
return ctx;
}
@@ -437,7 +441,7 @@ void nsock_proxy_ev_dispatch(nsock_pool nspool, nsock_event nsevent, void *udata
if (nse->status == NSE_STATUS_SUCCESS) {
struct proxy_node *current;
current = proxy_ctx_node_current(nse->iod->px_ctx);
current = nse->iod->px_ctx->px_current;
assert(current);
current->spec->ops->handler(nspool, nsevent, udata);
} else {

View File

@@ -110,11 +110,12 @@ struct proxy_node {
size_t sslen;
unsigned short port;
char *nodestr; /* used for log messages */
gh_lnode_t nodeq;
};
/* Ordered list of proxy nodes, as specified in the proxy specification string. */
struct proxy_chain {
gh_list nodes;
gh_list_t nodes;
};
/* IOD-specific context. For each IOD we establish a tunnel through the chain of
@@ -123,7 +124,7 @@ struct proxy_chain_context {
const struct proxy_chain *px_chain;
/* Nodes iterator in px_chain->nodes */
gh_list_elem *px_current;
struct proxy_node *px_current;
/* Current node connection state. */
enum nsock_proxy_state px_state;
@@ -153,18 +154,17 @@ struct proxy_spec {
/* ------------------- UTIL FUNCTIONS ------------------- */
int proxy_resolve(const char *host, struct sockaddr *addr, size_t *addrlen);
static inline struct proxy_node *proxy_ctx_node_current(struct proxy_chain_context *ctx) {
return (struct proxy_node *)GH_LIST_ELEM_DATA(ctx->px_current);
}
static inline struct proxy_node *proxy_ctx_node_next(struct proxy_chain_context *ctx) {
gh_list_elem *next;
gh_lnode_t *next;
next = GH_LIST_ELEM_NEXT(ctx->px_current);
if (next)
return (struct proxy_node *)GH_LIST_ELEM_DATA(next);
assert(ctx);
assert(ctx->px_current);
next = gh_lnode_next(&ctx->px_current->nodeq);
if (!next)
return NULL;
return container_of(next, struct proxy_node, nodeq);
}

View File

@@ -153,19 +153,18 @@ static int handle_state_tcp_connected(mspool *nsp, msevent *nse, void *udata) {
/* TODO string check!! */
if (!((reslen >= 15) && strstr(res, "200 OK"))) {
struct proxy_node *node;
struct proxy_node *node = px_ctx->px_current;
node = proxy_ctx_node_current(px_ctx);
nsock_log_debug(nsp, "Connection refused from proxy %s", node->nodestr);
return -EINVAL;
}
px_ctx->px_state = PROXY_STATE_HTTP_TUNNEL_ESTABLISHED;
if (px_ctx->px_current->next == NULL) {
if (proxy_ctx_node_next(px_ctx) == NULL) {
forward_event(nsp, nse, udata);
} else {
px_ctx->px_current = px_ctx->px_current->next;
px_ctx->px_current = proxy_ctx_node_next(px_ctx);
px_ctx->px_state = PROXY_STATE_INITIAL;
nsock_proxy_ev_dispatch(nsp, nse, udata);
}

View File

@@ -184,9 +184,8 @@ static int handle_state_tcp_connected(mspool *nsp, msevent *nse, void *udata) {
res = nse_readbuf(nse, &reslen);
if (!(reslen == 8 && res[1] == 90)) {
struct proxy_node *node;
struct proxy_node *node = px_ctx->px_current;
node = proxy_ctx_node_current(px_ctx);
nsock_log_debug(nsp, "Ignoring invalid socks4 reply from proxy %s",
node->nodestr);
return -EINVAL;
@@ -194,10 +193,10 @@ static int handle_state_tcp_connected(mspool *nsp, msevent *nse, void *udata) {
px_ctx->px_state = PROXY_STATE_SOCKS4_TUNNEL_ESTABLISHED;
if (px_ctx->px_current->next == NULL) {
if (proxy_ctx_node_next(px_ctx) == NULL) {
forward_event(nsp, nse, udata);
} else {
px_ctx->px_current = px_ctx->px_current->next;
px_ctx->px_current = proxy_ctx_node_next(px_ctx);
px_ctx->px_state = PROXY_STATE_INITIAL;
nsock_proxy_ev_dispatch(nsp, nse, udata);
}

View File

@@ -16,7 +16,8 @@ SRC = tests_main.c \
timer.c \
logs.c \
connect.c \
ghlists.c
ghlists.c \
ghheaps.c
OBJ = $(SRC:.c=.o)

150
nsock/tests/ghheaps.c Normal file
View File

@@ -0,0 +1,150 @@
/*
* Nsock regression test suite
* Same license as nmap -- see http://nmap.org/book/man-legal.html
*/
#include "test-common.h"
#include "../src/gh_heap.h"
#include <stdint.h>
#include <time.h>
#define HEAP_COUNT 1
struct testitem {
int val;
gh_hnode_t node;
};
static int hnode_int_cmp(gh_hnode_t *n1, gh_hnode_t *n2) {
struct testitem *a;
struct testitem *b;
a = container_of(n1, struct testitem, node);
b = container_of(n2, struct testitem, node);
return (a->val < b->val);
}
static gh_hnode_t *mknode(int val) {
struct testitem *item;
item = calloc(1, sizeof(struct testitem));
assert(item != NULL);
item->val = val;
gh_hnode_invalidate(&item->node);
return &item->node;
}
static int node2int(gh_hnode_t *hnode) {
struct testitem *item;
item = container_of(hnode, struct testitem, node);
return item->val;
}
static int ghheap_ordering(void *tdata) {
gh_heap_t heap;
int i, n, k;
gh_heap_init(&heap, hnode_int_cmp);
for (i = 25000; i < 50000; i++)
gh_heap_push(&heap, mknode(i));
for (i = 24999; i >= 0; i--)
gh_heap_push(&heap, mknode(i));
for (i = 25000; i < 50000; i++)
gh_heap_push(&heap, mknode(i));
n = -1;
do {
gh_hnode_t *current;
current = gh_heap_pop(&heap);
k = node2int(current);
if (k < n)
return -EINVAL;
n = k;
free(container_of(current, struct testitem, node));
} while (gh_heap_count(&heap) > 0);
gh_heap_free(&heap);
return 0;
}
static int ghheap_stress(void *tdata) {
gh_heap_t heaps[HEAP_COUNT];
int i, num;
for (i = 0; i < HEAP_COUNT; i++)
gh_heap_init(&heaps[i], hnode_int_cmp);
for (num = 25000; num < 50000; num++) {
for (i = 0; i < HEAP_COUNT; i++) {
gh_heap_push(&heaps[i], mknode(num));
}
}
for (num = 24999; num >= 0; num--) {
for (i = 0; i < HEAP_COUNT; i++) {
gh_heap_push(&heaps[i], mknode(num));
}
}
for (num = 0; num < 50000; num++) {
for (i = 0; i < HEAP_COUNT; i++) {
int r_min, r_pop;
gh_hnode_t *hnode;
r_min = node2int(gh_heap_min(&heaps[i]));
hnode = gh_heap_pop(&heaps[i]);
r_pop = node2int(hnode);
if (r_min != r_pop) {
fprintf(stderr, "Bogus min/pop return values (%d != %d)\n", r_min, r_pop);
return -EINVAL;
}
if (r_min != num) {
fprintf(stderr, "Bogus return value %d when expected %d\n", r_min, num);
return -EINVAL;
}
free(container_of(hnode, struct testitem, node));
}
}
for (i = 0; i < HEAP_COUNT; i++) {
void *ret;
ret = gh_heap_pop(&heaps[i]);
if (ret != NULL) {
fprintf(stderr, "Ret is bogus for heap %d\n", i);
return -EINVAL;
}
}
for (i = 0; i < HEAP_COUNT; i++)
gh_heap_free(&heaps[i]);
return 0;
}
const struct test_case TestGHHeaps = {
.t_name = "test nsock internal ghheaps",
.t_setup = NULL,
.t_run = ghheap_stress,
.t_teardown = NULL
};
const struct test_case TestHeapOrdering = {
.t_name = "test heaps conditions",
.t_setup = NULL,
.t_run = ghheap_ordering,
.t_teardown = NULL
};

View File

@@ -9,138 +9,167 @@
#include <time.h>
#define INT2PTR(i) ((void *)(intptr_t)(i))
#define PTR2INT(p) ((intptr_t)(void *)(p))
#define LIST_COUNT 16
#define ELT_COUNT 2000
struct testlist {
unsigned int val;
gh_lnode_t lnode;
};
static unsigned int nodeval(gh_lnode_t *lnode) {
struct testlist *tl;
tl = container_of(lnode, struct testlist, lnode);
return tl->val;
}
static gh_lnode_t *mknode(unsigned int val) {
struct testlist *tl;
tl = calloc(1, sizeof(struct testlist));
tl->val = val;
return &tl->lnode;
}
static void delnode(gh_lnode_t *lnode) {
if (lnode)
free(container_of(lnode, struct testlist, lnode));
}
static int ghlist_stress(void *tdata) {
gh_list lists[LIST_COUNT];
gh_list_elem *current, *next;
gh_list_t lists[LIST_COUNT];
gh_lnode_t *current, *next;
int num = 0;
int ret;
int i;
for (i=0; i < LIST_COUNT; i++)
for (i = 0; i < LIST_COUNT; i++)
gh_list_init(&lists[i]);
for (num=25000; num < 50000; num++) {
for (i=0; i < LIST_COUNT; i++) {
gh_list_append(&lists[i], INT2PTR(num));
for (num = ELT_COUNT/2; num < ELT_COUNT; num++) {
for (i = 0; i < LIST_COUNT; i++) {
gh_list_append(&lists[i], mknode(num));
}
}
for (num=24999; num >= 0; num--) {
for (i=0; i < LIST_COUNT; i++) {
gh_list_prepend(&lists[i], INT2PTR(num));
for (num = (ELT_COUNT/2 - 1); num >= 0; num--) {
for (i = 0; i < LIST_COUNT; i++) {
gh_list_prepend(&lists[i], mknode(num));
}
}
for (num=0; num < 50000; num++) {
for (i=0; i < LIST_COUNT; i++) {
ret = PTR2INT(gh_list_pop(&lists[i]));
for (num = 0; num < ELT_COUNT; num++) {
for (i = 0; i < LIST_COUNT; i++) {
current = gh_list_pop(&lists[i]);
ret = nodeval(current);
if (ret != num) {
fprintf(stderr, "prepend_test: Bogus return value %d when expected %d\n",
ret, num);
return -EINVAL;
}
delnode(current);
}
}
for (i=0; i < LIST_COUNT; i++) {
ret = PTR2INT(gh_list_pop(&lists[i]));
if (ret != 0) {
for (i = 0; i < LIST_COUNT; i++) {
current = gh_list_pop(&lists[i]);
if (current) {
fprintf(stderr, "Ret is bogus for list %d", i);
return -EINVAL;
}
}
for (num=24999; num >= 0; num--) {
for (i=0; i < LIST_COUNT; i++) {
gh_list_prepend(&lists[i], INT2PTR(num));
for (num = (ELT_COUNT/2 - 1); num >= 0; num--) {
for (i = 0; i < LIST_COUNT; i++) {
gh_list_prepend(&lists[i], mknode(num));
}
}
for (num=25000; num < 50000; num++) {
for (i=0; i < LIST_COUNT; i++) {
gh_list_append(&lists[i], INT2PTR(num));
for (num = ELT_COUNT/2; num < ELT_COUNT; num++) {
for (i = 0; i < LIST_COUNT; i++) {
gh_list_append(&lists[i], mknode(num));
}
}
for (num=0; num < 50000; num++) {
for (num = 0; num < ELT_COUNT; num++) {
for (i=0; i < LIST_COUNT; i++) {
ret = PTR2INT(gh_list_pop(&lists[i]));
current = gh_list_pop(&lists[i]);
ret = nodeval(current);
if (ret != num) {
fprintf(stderr, "prepend_test: Bogus return value %d when expected %d\n",
ret, num);
return -EINVAL;
}
delnode(current);
}
}
for (num=25000; num < 50000; num++) {
for (i=0; i < LIST_COUNT; i++) {
gh_list_append(&lists[i], INT2PTR(num));
}
for (num = ELT_COUNT/2; num < ELT_COUNT; num++) {
for (i = 0; i < LIST_COUNT; i++)
gh_list_append(&lists[i], mknode(num));
}
for (num=24999; num >= 0; num--) {
for (i=0; i < LIST_COUNT; i++) {
gh_list_prepend(&lists[i], INT2PTR(num));
}
for (num = ELT_COUNT/2 - 1; num >= 0; num--) {
for (i = 0; i < LIST_COUNT; i++)
gh_list_prepend(&lists[i], mknode(num));
}
for (num=0; num < 50000; num++) {
for (i=0; i < LIST_COUNT; i++) {
ret = PTR2INT(gh_list_pop(&lists[i]));
for (num = 0; num < ELT_COUNT; num++) {
for (i = 0; i < LIST_COUNT; i++) {
current = gh_list_pop(&lists[i]);
ret = nodeval(current);
if (ret != num) {
fprintf(stderr, "prepend_test: Bogus return value %d when expected %d\n",
ret, num);
return -EINVAL;
}
delnode(current);
}
}
for (num=24999; num >= 0; num--) {
for (i=0; i < LIST_COUNT; i++) {
gh_list_prepend(&lists[i], INT2PTR(num));
}
for (num = ELT_COUNT/2 - 1; num >= 0; num--) {
for (i = 0; i < LIST_COUNT; i++)
gh_list_prepend(&lists[i], mknode(num));
}
for (num=25000; num < 50000; num++) {
for (i=0; i < LIST_COUNT; i++) {
gh_list_append(&lists[i], INT2PTR(num));
}
for (num = ELT_COUNT/2; num < ELT_COUNT; num++) {
for (i=0; i < LIST_COUNT; i++)
gh_list_append(&lists[i], mknode(num));
}
for (i=0; i < LIST_COUNT; i++) {
num=0;
for (current = GH_LIST_FIRST_ELEM(&lists[i]); current;
current = next) {
for (i = 0; i < LIST_COUNT; i++) {
num = 0;
for (current = gh_list_first_elem(&lists[i]); current; current = next) {
int k;
next = GH_LIST_ELEM_NEXT(current);
k = PTR2INT(GH_LIST_ELEM_DATA(current));
next = gh_lnode_next(current);
k = nodeval(current);
if (k != num) {
fprintf(stderr, "Got %d when I expected %d\n", k, num);
return -EINVAL;
}
gh_list_remove_elem(&lists[i], current);
gh_list_remove(&lists[i], current);
delnode(current);
num++;
}
if (num != 50000) {
fprintf(stderr, "Number is %d, even though %d was expected", num, 50000);
if (num != ELT_COUNT) {
fprintf(stderr, "Number is %d, even though %d was expected", num, ELT_COUNT);
return -EINVAL;
}
if (GH_LIST_COUNT(&lists[i]) != 0) {
if (gh_list_count(&lists[i]) != 0) {
fprintf(stderr, "List should be empty, but instead it has %d members!\n",
GH_LIST_COUNT(&lists[i]));
gh_list_count(&lists[i]));
return -EINVAL;
}
}
for (i=0; i < LIST_COUNT; i++) {
for (i = 0; i < LIST_COUNT; i++) {
while ((current = gh_list_pop(&lists[i])) != NULL)
delnode(current);
gh_list_free(&lists[i]);
}

View File

@@ -16,6 +16,12 @@
#include <nsock.h>
#if !defined(container_of)
#define container_of(ptr, type, member) \
((type *)((char *)(ptr)-(char *)(&((type *)0)->member)))
#endif
#define PORT_UDP 55234
#define PORT_TCP 55235
#define PORT_TCPSSL 55236

View File

@@ -31,6 +31,8 @@ extern const struct test_case TestLogLevels;
extern const struct test_case TestErrLevels;
extern const struct test_case TestConnectTCP;
extern const struct test_case TestGHLists;
extern const struct test_case TestGHHeaps;
extern const struct test_case TestHeapOrdering;
static const struct test_case *TestCases[] = {
@@ -45,9 +47,13 @@ static const struct test_case *TestCases[] = {
&TestConnectTCP,
/* ---- ghlists.c */
&TestGHLists,
/* ---- ghheaps.c */
&TestGHHeaps,
&TestHeapOrdering,
NULL
};
static int test_case_run(const struct test_case *test) {
int rc;
void *tdata = NULL;