/* * 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 mSec, 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 += 1000 * mSec; 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) { 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; 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; }