Add generic network watcher with timers task.
r1484 | dcl | 2007-02-15 07:48:02 +1100 (Thu, 15 Feb 2007) | 2 lines
This commit is contained in:
317
nwatch.c
Normal file
317
nwatch.c
Normal file
@ -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 <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#ifdef CYGNUS
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#else
|
||||||
|
#include <sys/select.h>
|
||||||
|
#endif
|
||||||
|
#include <sys/time.h>
|
||||||
|
#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;
|
||||||
|
}
|
33
nwatch.h
Normal file
33
nwatch.h
Normal file
@ -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 */
|
Reference in New Issue
Block a user