diff --git a/nwatch.c b/nwatch.c new file mode 100644 index 00000000..4c0bed96 --- /dev/null +++ b/nwatch.c @@ -0,0 +1,317 @@ +/* + * N E T W A T C H E R + * + * This module watches network connections for sockets becoming readable or + * writeable and invokes callbacks. It also provides a timer mechanism. + * + * Douglas Clowes, February 2007 + * + */ + +#include +#include +#ifdef CYGNUS +#include +#else +#include +#endif +#include +#include "fortify.h" +#include "nwatch.h" +#include "sics.h" + +#define NWMAGIC 51966 + +typedef struct __netwatcher_s { + pNWContext cq_head; + pNWContext cq_tail; + pNWTimer tq_head; + pNWTimer tq_tail; + long lMagic; +} NetWatch, *pNetWatch; + +static pNetWatch instance = NULL; + +static int NetWatchTask(void* pData); + +int NetWatchInit(void) { + if (instance == NULL) { + instance = (pNetWatch) malloc(sizeof(NetWatch)); + if (instance == NULL) + return 0; + memset(instance, 0, sizeof(NetWatch)); + instance->lMagic = NWMAGIC; + TaskRegister(pServ->pTasker, NetWatchTask, NULL, NULL, NULL, 1); + } + return 1; +} + +typedef struct __netwatchtimer { + pNWTimer next; + struct timeval tv; + pNWCallback func; + void* cntx; + long vrfy; +} NWTimer; + +static int NetWatchTimerInsQue(pNetWatch self, pNWTimer handle) +{ + if (self->tq_head == NULL) /* empty */ + self->tq_head = self->tq_tail = handle; + else if (handle->tv.tv_sec > self->tq_tail->tv.tv_sec || + (handle->tv.tv_sec == self->tq_tail->tv.tv_sec && + handle->tv.tv_usec >= self->tq_tail->tv.tv_usec)) { + /* after last entry */ + self->tq_tail->next = handle; + self->tq_tail = handle; + } else if (handle->tv.tv_sec < self->tq_tail->tv.tv_sec || + (handle->tv.tv_sec == self->tq_tail->tv.tv_sec && + handle->tv.tv_usec <= self->tq_tail->tv.tv_usec)) { + /* before first entry */ + handle->next = self->tq_head; + self->tq_head = handle; + } else { + /* start at the first entry */ + pNWTimer pNxt = self->tq_head; + /* go until the one after is greater */ + while (pNxt->next && + (handle->tv.tv_sec > pNxt->next->tv.tv_sec || + (handle->tv.tv_sec == pNxt->next->tv.tv_sec && + handle->tv.tv_usec > pNxt->next->tv.tv_usec))) + pNxt = pNxt->next; + /* slip it in */ + handle = pNxt->next; + pNxt->next = handle ; + } + return 1; +} + +static int NetWatchTimerRemQue(pNetWatch self, pNWTimer handle) +{ + if (handle == self->tq_head) { /* if first */ + self->tq_head = self->tq_head->next; + if (handle == self->tq_tail) /* if also last */ + self->tq_tail = NULL; + } + else if (handle == self->tq_tail) /* if only last */ + self->tq_tail = NULL; + else { + pNWTimer pNxt = self->tq_head; + while (pNxt) { + if (handle == pNxt->next) { + pNxt->next = pNxt->next->next; + break; + } + } + } + return 1; +} + +int NetWatchRegisterTimer(pNWTimer* handle, int uSec, + pNWCallback callback, void* context) +{ + pNetWatch self = instance; + if(!self || self->lMagic != NWMAGIC) + return 0; + pNWTimer pNew = (pNWTimer) malloc(sizeof(NWTimer)); + if (pNew == NULL) + return 0; + memset(pNew, 0, sizeof(NWTimer)); + gettimeofday(&pNew->tv, NULL); + pNew->tv.tv_usec += uSec; + if (pNew->tv.tv_usec > 1000000) { + pNew->tv.tv_sec += pNew->tv.tv_usec / 1000000; + pNew->tv.tv_usec %= 1000000; + } + pNew->func = callback; + pNew->cntx = context; + pNew->vrfy = NWMAGIC; + NetWatchTimerInsQue(self, pNew); + *handle = pNew; + return 1; +} + +int NetWatchRemoveTimer(pNWTimer handle) +{ + pNetWatch self = instance; + if (!self || self->lMagic != NWMAGIC)\ + return 0; + NetWatchTimerRemQue(self, handle); + free(handle); + return 1; +} + +typedef struct __netwatchcontext { + pNWContext next; + int sock; + int mode; + int actn; + pNWCallback func; + void* cntx; + long vrfy; +} NWContext; + +static int NetWatchContextInsQue(pNetWatch self, pNWContext handle) +{ + if (self->cq_head == NULL) /* empty */ + self->cq_head = self->cq_tail = handle; + else { + self->cq_tail->next = handle; + self->cq_tail = handle; + } + return 1; +} + +static int NetWatchContextRemQue(pNetWatch self, pNWContext handle) +{ + if (handle == self->cq_head) { /* if first */ + self->cq_head = self->cq_head->next; + if (handle == self->cq_tail) /* if also last */ + self->cq_tail = NULL; + } + else if (handle == self->cq_tail) /* if only last */ + self->cq_tail = NULL; + else { + pNWContext pNxt = self->cq_head; + while (pNxt) { + if (handle == pNxt->next) { + pNxt->next = pNxt->next->next; + break; + } + } + } + return 1; +} + +int NetWatchRegisterCallback(pNWContext* handle, int iSocket, + pNWCallback callback, void* context) +{ + pNWContext pNew = NULL; + pNetWatch self = instance; + if(!self || self->lMagic != NWMAGIC) + return 0; + pNew = (pNWContext) malloc(sizeof(NWContext)); + if (pNew == NULL) + return 0; + memset(pNew, 0, sizeof(NWContext)); + pNew->sock = iSocket; + pNew->mode = nwatch_read; + pNew->func = callback; + pNew->cntx = context; + pNew->vrfy = NWMAGIC; + *handle = pNew; + NetWatchContextInsQue(self, pNew); + return 1; +} + +int NetWatchRemoveCallback(pNWContext handle) +{ + pNWContext pOld = NULL; + int iRet; + pNetWatch self = instance; + if(!self || self->lMagic != NWMAGIC) + return 0; + NetWatchContextRemQue(self, handle); + return 1; +} + +int NetWatchGetMode(pNWContext handle) +{ + if (handle == NULL || handle->vrfy != NWMAGIC) + return 0; + return handle->mode; +} + +int NetWatchSetMode(pNWContext handle, int mode) +{ + if (handle == NULL || handle->vrfy != NWMAGIC) + return 0; + handle->mode = mode; + return 1; +} + +int NetWatchTask (void* pData) +{ + pNetWatch self = NULL; + pNWContext pNWC = NULL; + fd_set rMask; + fd_set wMask; + struct timeval tmo = {0,0}; + int iRet; + int iCount; + int iTimeout; + pNWContext action[FD_SETSIZE]; + + self = (pNetWatch) instance; + if(!self || self->lMagic != NWMAGIC) + return 0; + + /* build the select mask */ + FD_ZERO(&rMask); + FD_ZERO(&wMask); + pNWC = self->cq_head; + iCount = -1; + while(pNWC) { + if (pNWC->mode & nwatch_read) + FD_SET(pNWC->sock,&rMask); + if (pNWC->mode & nwatch_write) + FD_SET(pNWC->sock,&wMask); + if(pNWC->sock > iCount) { + iCount = pNWC->sock; + } + pNWC = pNWC->next; + } + + iRet = 0; + if (iCount >= 0) + iRet = select(iCount+1, &rMask, &wMask, NULL, &tmo); + + if(iRet > 0) { + /* now go through all registered things and note the active callbacks */ + iCount = 0; + pNWC = self->cq_head; + while(pNWC) + { + int action_mode = 0; + if ((pNWC->mode & nwatch_read) && FD_ISSET(pNWC->sock,&rMask)) + action_mode |= nwatch_read; + if ((pNWC->mode & nwatch_write) && FD_ISSET(pNWC->sock,&wMask)) + action_mode |= nwatch_write; + pNWC->actn = action_mode; + if (action_mode != 0) + action[iCount++] = pNWC; + pNWC = pNWC->next; + } + + /* now process the callbacks */ + while (iCount > 0) { + pNWC = action[--iCount]; + if (pNWC->vrfy == NWMAGIC) { + int iStatus; + iStatus = (*pNWC->func)(pNWC->cntx, pNWC->actn); + pNWC->actn = 0; + } + } + } + + /* Now do the timers */ + if (self->tq_head) { + int iStatus; + struct timeval tv; + gettimeofday(&tv, NULL); + while (self->tq_head) { + pNWTimer pNew = self->tq_head; + if (tv.tv_sec < pNew->tv.tv_sec || + (tv.tv_sec == pNew->tv.tv_sec && + tv.tv_usec < pNew->tv.tv_usec)) { + break; + } + NetWatchTimerRemQue(self, pNew); + iStatus = pNew->func(pNew->cntx, 0); + free(pNew); + } + } + + /* done, finally */ + return 1; +} diff --git a/nwatch.h b/nwatch.h new file mode 100644 index 00000000..e3379739 --- /dev/null +++ b/nwatch.h @@ -0,0 +1,33 @@ +/* + * N E T W A T C H E R + * + * This module watches network connections for sockets becoming readable or + * writeable and invokes callbacks. It also provides a timer mechanism. + * + * Douglas Clowes, February 2007 + * + */ +#ifndef SICSNETWATCHER +#define SICSNETWATCHER + +#define DFC_NWATCH 1 +#define nwatch_read 1 +#define nwatch_write 2 +/* the callback function */ +typedef int (*pNWCallback)(void* context, int mode); + +/* the timer methods */ +typedef struct __netwatchtimer *pNWTimer; +int NetWatchRegisterTimer(pNWTimer* handle, int uSec, + pNWCallback callback, void* context); +int NetWatchRemoveTimer(pNWTimer handle); + +/* the socket methods */ +typedef struct __netwatchcontext *pNWContext; +int NetWatchRegisterCallback(pNWContext* handle, int iSocket, + pNWCallback callback, void* context); +int NetWatchRemoveCallback(pNWContext handle); +int NetWatchGetMode(pNWContext handle); +int NetWatchSetMode(pNWContext handle, int mode); + +#endif /* SICSNETWATCHER */