Annotation of libwww/Library/src/HTEvtLst.c, revision 1.1.2.3

1.1.2.1   eric        1: /*                                                                  HTEvntrg.c
                      2: **     EVENT MANAGER
                      3: **
                      4: **     (c) COPYRIGHT MIT 1995.
                      5: **     Please first read the full copyright statement in the file COPYRIGH.
1.1.2.3 ! eric        6: **     @(#) $Id: HTEvtLst.c,v 1.1.2.2 1996/11/02 19:26:27 eric Exp $
1.1.2.1   eric        7: **
                      8: **     Updated HTEvent module 
                      9: **     This new module combines the functions of the old HTEvent module and 
                     10: **     the HTThread module. We retain the old HTThread module, but it
                     11: **     consists of calls to the HTEvent interfaces
                     12: **
                     13: ** Authors:
                     14: **     HFN     Henrik Frystyk <frystyk@w3.org>
                     15: **     CLB     Charlie Brooks <cbrooks@osf.org>
                     16: ** Bugs
                     17: **
                     18: */
                     19: 
                     20: /*   WSAAsyncSelect and windows app stuff need the following definitions:
                     21:  *   WWW_WIN_ASYNC - enable WSAAsyncSelect instead of select
                     22:  *   _WIN23 - win32 libararies - may be window or console app
                     23:  *   _WINSOCKAPI_ - using WINSOCK.DLL - not necessarily the async routines.
                     24:  *   _CONSOLE - the console app for NT
                     25:  *
                     26:  * first pass: EGP - 10/26/95
                     27:  */
                     28: 
                     29: /* Implementation dependent include files */
                     30: #include "sysdep.h"
                     31: #include "WWWUtil.h"
                     32: #include "WWWCore.h"
                     33: #include "HTReqMan.h"
                     34: #include "HTEvtLst.h"                                   /* Implemented here */
                     35: 
                     36: /* Type definitions and global variables etc. local to this module */
                     37: PRIVATE fd_set FdArray[3];
                     38: PRIVATE fd_set all_fds ;                           /* any descriptor at all */
                     39: 
                     40: PRIVATE int HTEndLoop = 0;                    /* If !0 then exit event loop */
                     41: 
                     42: PRIVATE const int SecondsToWait = 5 ;
                     43: 
                     44: PRIVATE void __DumpFDSet( fd_set *, const char *);
                     45: 
                     46: /*
                     47: ** our internal structure to hold a socket, it's request 
                     48: ** and our action. For version 1, we allow one action per socket
                     49: */
                     50: 
                     51: /*
                     52: ** an action consists of a request, a set of requested operations 
                     53: ** a HTEventCallback function
                     54: */
                     55: 
                     56: typedef struct rq_t RQ;
                     57: 
                     58: struct rq_t { 
                     59:     RQ * next ;          
                     60:     SOCKET s ;                 /* our socket */
                     61:     BOOL unregister;           /* notify app when completely unregistered */
                     62:     HTEvent * events[3];
                     63: };
                     64: 
                     65: #define PRIME_TABLE_SIZE       67
                     66: 
                     67: #define HASH(s) ((s) % PRIME_TABLE_SIZE) 
                     68: 
                     69: /*
                     70: ** our internal table of requests,
                     71: ** indexed by socket 
                     72: */
                     73: PRIVATE RQ * table[PRIME_TABLE_SIZE]; 
                     74: PRIVATE SOCKET max_sock = 0 ;          /* max socket value in use */
                     75: 
                     76: /* Select Timeout handling */
                     77: typedef struct _HTTimeout {
                     78:     HTEventTimeout *   tcbf;
                     79:     HTRequest *                request;
                     80:     struct timeval     tv;
                     81:     BOOL               always;
                     82: } HTTimeout;
                     83: 
                     84: PRIVATE HTTimeout      seltime;
                     85: PRIVATE struct timeval *tvptr = NULL;
                     86: 
                     87: /*
                     88: ** Local functions 
                     89: */
                     90: typedef enum {RQ_mayCreate, RQ_find} RQ_action;
                     91: PRIVATE RQ * RQ_get(SOCKET s, RQ_action action)
                     92: {
                     93:     RQ * rqp;
                     94:     RQ * last = NULL;
                     95:     long v = HASH(s);
                     96:     for (rqp = table[v]; rqp; rqp = rqp->next) {
                     97:         if (rqp->s == s) {
                     98:            return rqp;
                     99:        }
                    100:        last = rqp;  /* to set next pointer when creating new */
                    101:     }
                    102:     if (action == RQ_mayCreate) {
                    103:         if ((rqp = (RQ *) HT_CALLOC(1, sizeof(RQ))) == NULL)
                    104:            HT_OUTOFMEM("HTEventList_register");
                    105:        if (last) last->next = rqp;
                    106:        else table[v] = rqp;
                    107:        rqp->s = s;
                    108:        return rqp;
                    109:     }
                    110:     return NULL;
                    111: }
                    112: 
                    113: /* ------------------------------------------------------------------------- */
                    114: 
                    115: /*     HTEventList_registerTimeout 
                    116: **     -----------------------
                    117: **     Set the timeout for sockets. This does only works on NON windows
                    118: **     platforms as we need to poll for the console on windows
                    119: **     The default is no timeout. If the tp points to a zero'ed structure
                    120: **     then the select is basically polling. If always is YES then
                    121: **     the callback is called at all times, if NO then only when Library
                    122: **     sockets are active.
                    123: **     Returns YES if OK else NO
                    124: */
                    125: PUBLIC BOOL HTEventList_registerTimeout (struct timeval *tp, HTRequest * request,
                    126:                                     HTEventTimeout *tcbf, BOOL always)
                    127: {
                    128:     if (tp) {
                    129: #ifdef WWW_WIN_ASYNC
                    130:        /* same window process WWW_WIN_ASYNC stuff and TIMEOUT */
                    131:        SetTimer(HTSocketWin, TIMEOUT, tp->tv_usec/1000 + tp->tv_sec*1000, 0);
                    132: #else
                    133:        tvptr = &seltime.tv;
                    134:        tvptr->tv_sec = tp->tv_sec;
                    135:        tvptr->tv_usec = tp->tv_usec;
                    136: #endif
                    137:        seltime.tcbf = tcbf;
                    138:        seltime.request = request;
                    139:        seltime.always = always;
                    140:        if (THD_TRACE)
                    141:            HTTrace("Timeout cbf. %p %s (req=%p, sec=%d, usec=%d)\n",
                    142:                     tcbf, always ? "always" : "active",
                    143:                     request, (int) tp->tv_sec, (int) tp->tv_usec);
                    144:     }
                    145:     return YES;
                    146: }
                    147: 
                    148: /*     HTEventList_unregisterTimeout 
                    149: **     -------------------------
                    150: **     Disables the callback function.
                    151: **     Returns YES if OK else NO
                    152: */
                    153: PUBLIC BOOL HTEventList_unregisterTimeout(void)
                    154: {
                    155: #ifdef WWW_WIN_ASYNC
                    156:     /* Same window process WWW_WIN_ASYNC stuff and TIMEOUT */
                    157:     KillTimer(HTSocketWin, TIMEOUT);
                    158: #else
                    159:     tvptr = NULL;
                    160: #endif
                    161:     return YES;
                    162: }
                    163: 
                    164: /*
                    165: **  HTEventList_register
                    166: **  for a given socket, reqister a request structure, a set of operations, 
                    167: **  a HTEventCallback function, and a priority. For this implementation, 
                    168: **  we allow only a single HTEventCallback function for all operations.
                    169: **  and the priority field is ignored.
                    170: */
1.1.2.2   eric      171: PUBLIC int HTEventList_register (SOCKET s, HTEventType type, HTEvent * event)
1.1.2.1   eric      172: {
                    173:     RQ * rqp;
                    174:     if (THD_TRACE) 
                    175:        HTTrace("Register.... socket %d, request %p HTEventCallback %p type %x at priority %d\n",
                    176:                s, (void *)event->request,  (void *)event->cbf, (unsigned) type, (unsigned) event->priority) ;
                    177: 
                    178:     if (s==INVSOC) return 0;
                    179:     rqp = RQ_get(s, RQ_mayCreate);
                    180:     rqp->s = s;
                    181:     rqp->events[HTEvent_INDEX(type)] = event;
                    182:  
                    183:     /* insert socket into appropriate file descriptor set */
                    184: 
                    185:     if (THD_TRACE)
                    186:        HTTrace("Register.... Registering socket for %d\n", type);
                    187:     FD_SET(s, FdArray+HTEvent_INDEX(type));
                    188:     if (!FD_ISSET(s, &all_fds))
                    189:        FD_SET(s, &all_fds);
                    190: 
                    191:     if (s > max_sock) 
                    192:         max_sock = s ;
                    193:     
                    194:     return HT_OK;
                    195: }
                    196: 
                    197: /*
                    198: ** HTEventList_unregister
                    199: ** remove the registered information for the specified socket for the actions 
                    200: ** specified in ops. if no actions remain after the unregister, the registered
                    201: ** info is deleted, and, if the socket has been registered for notification, 
                    202: ** the HTEventCallback will be invoked.
                    203: */
1.1.2.2   eric      204: PUBLIC int HTEventList_unregister(SOCKET s, HTEventType type) 
1.1.2.1   eric      205: {
                    206:     RQ * rqp;
                    207:     RQ * last = NULL;
                    208:     long v = HASH(s);
                    209:     for (rqp = table[v]; rqp; rqp = rqp->next) {
                    210:         if (rqp->s == s) {
                    211:            rqp->events[HTEvent_INDEX(type)] = 0;
                    212:            FD_CLR(s, FdArray+HTEvent_INDEX(type));
                    213:            if (rqp->events[HTEvent_INDEX(HTEvent_READ)] == NULL && 
                    214:                rqp->events[HTEvent_INDEX(HTEvent_WRITE)] == NULL && 
                    215:                rqp->events[HTEvent_INDEX(HTEvent_OOB)] == NULL) {
                    216:                HTTrace("UnRegister.. no more events registered for socket %d\n", s);
                    217:                if (last) last->next = rqp->next;
                    218:                else table[v] = rqp->next;
                    219:                HT_FREE(rqp);
                    220:                FD_CLR(s, &all_fds);
                    221:            }
                    222:            if (THD_TRACE)
                    223:                HTTrace("UnRegister.. socket %d unregisterd for %x\n", s, type);
                    224:            return HT_OK;
                    225:        }
                    226:        last = rqp;  /* to set next pointer when creating new */
                    227:     }
                    228:     HTTrace("Unregister.. couldn't find socket %d.\n", s);
                    229:     return HT_ERROR;
                    230: }
                    231: 
                    232: /*
                    233: ** HTEventList_unregisterAll
                    234: ** unregister all sockets 
                    235: ** N.B. we just remove them for our internal data structures: it is up to the 
                    236: ** application to actually close the socket. 
                    237: */
                    238: PUBLIC int HTEventList_unregisterAll( void ) 
                    239: {
                    240:     int i;
                    241:     register RQ * rqp, * next ;
                    242: 
                    243:     /* begin */
                    244:     if (THD_TRACE)
                    245:        HTTrace("Unregister.. all sockets\n");
                    246: 
                    247:     for (i = 0 ; i < PRIME_TABLE_SIZE; i++) {
                    248:        for (rqp = table[i]; rqp != 0; rqp = next) {
                    249:            next = rqp->next;
                    250:            HT_FREE(rqp);
                    251:        }
                    252:        table[i] = NULL;
                    253:     }
                    254: 
                    255:     max_sock = 0 ;
                    256:     FD_ZERO(FdArray+HTEvent_INDEX(HTEvent_READ));
                    257:     FD_ZERO(FdArray+HTEvent_INDEX(HTEvent_WRITE));
                    258:     FD_ZERO(FdArray+HTEvent_INDEX(HTEvent_OOB));
                    259:     FD_ZERO(&all_fds);
                    260: 
                    261:     return 0;
                    262: }
                    263: 
                    264: 
                    265: /*     HTEventList_stopLoop
                    266: **     ----------------
                    267: **     Stops the (select based) event loop. The function does not guarantee
                    268: **     that all requests have terminated. This is for the app to do
                    269: */
                    270: PUBLIC void HTEventList_stopLoop (void)
                    271: {
                    272:     HTEndLoop = 1;
                    273: }
                    274: 
                    275: /*  HTEventList_loop
                    276: **  ------------
                    277: **  event loop: that is, we wait for activity from one of our registered 
                    278: **  channels, and dispatch on that.
                    279: **
                    280: **  There are now two versions of the event loop. The first is if you want
                    281: **  to use async I/O on windows, and the other is if you want to use normal
                    282: **  Unix setup with sockets
                    283: */
                    284: PUBLIC int HTEventList_loop( HTRequest * theRequest ) 
                    285: {
                    286:     fd_set treadset, twriteset, texceptset;
                    287:     int active_sockets;
                    288:     int maxfds;
                    289:     SOCKET s;
                    290:     int status = 0;
                    291:     struct timeval tvsave;
                    292: 
                    293: 
                    294:     HTEndLoop = 0;
                    295:     /* Don't leave this loop until we the application */
                    296:     do { 
                    297:         treadset = FdArray[HTEvent_INDEX(HTEvent_READ)];
                    298:         twriteset = FdArray[HTEvent_INDEX(HTEvent_WRITE)];
                    299:         texceptset = FdArray[HTEvent_INDEX(HTEvent_OOB)];
                    300:         maxfds = max_sock; 
                    301: 
                    302:        if (THD_TRACE)
                    303:            HTTrace("Event Loop.. calling select: maxfds is %d\n", maxfds);
                    304: /*
                    305:  *  timeval struct copy needed for linux, as it set the value to the remaining
                    306:  *  timeout while exiting the select. (and perhaps for other OS).
                    307:  */
                    308:        tvsave.tv_sec = tvptr->tv_sec;
                    309:        tvsave.tv_usec = tvptr->tv_usec;
                    310: 
                    311: #ifdef __hpux 
                    312:         active_sockets = select(maxfds+1, (int *)&treadset, (int *)&twriteset,
                    313:                                (int *)&texceptset, (struct timeval *) &tvsave);
                    314: #else
                    315:         active_sockets = select(maxfds+1, &treadset, &twriteset, &texceptset,
                    316:                                (struct timeval *) &tvsave);
                    317: #endif
                    318:        if (THD_TRACE)
                    319:            HTTrace("Event Loop.. select returns %d\n",active_sockets);
                    320: 
                    321:         if (active_sockets == -1) {
                    322:            HTRequest_addSystemError( theRequest, ERR_FATAL, socerrno, NO, "select");
                    323:            __DumpFDSet(FdArray+HTEvent_INDEX(HTEvent_READ), "Read");
                    324:            __DumpFDSet(FdArray+HTEvent_INDEX(HTEvent_WRITE), "Write") ;
                    325:            __DumpFDSet(FdArray+HTEvent_INDEX(HTEvent_OOB), "Exceptions");
                    326:            return HT_ERROR;
                    327:         }
                    328: 
                    329:        /* If timeout then see if we should call callback function */
                    330:        if (active_sockets == 0) {
                    331:            if (seltime.tcbf && (seltime.always || HTNet_isIdle())) {
                    332: #if 0
                    333:                /* This drives you crazy! */
                    334:                if (THD_TRACE) HTTrace("Event Loop.. select timeout\n");
                    335: #endif
                    336:                if ((status = (*(seltime.tcbf))(seltime.request)) != HT_OK)
                    337:                    return status;
                    338:            } else
                    339:                continue;
                    340:        }
                    341: 
                    342:        /*
                    343:         * there were active sockets. Determine which fd sets they were in
                    344:         */
                    345: 
                    346:        for (s = 0 ; s <= maxfds ; s++) { 
                    347:            { 
                    348:                if (FD_ISSET(s, &texceptset))
                    349:                    if ((status = HTEventList_dispatch(s, HTEvent_OOB)) != HT_OK)
                    350:                        return status;
                    351:                if (FD_ISSET(s, &twriteset))
                    352:                    if ((status = HTEventList_dispatch(s, HTEvent_WRITE)) != HT_OK)
                    353:                        return status;
                    354:                if (FD_ISSET(s, &treadset))
                    355:                    if ((status = HTEventList_dispatch(s, HTEvent_READ)) != HT_OK)
                    356:                        return status;
                    357:            }
                    358:        }
                    359: 
                    360:     } while (!HTEndLoop);
                    361:     return HT_OK;
                    362: }
                    363: 
                    364: /*
                    365: ** HTEventList_dispatch( SOCKET, SockOps ) 
                    366: **
                    367: ** a  little function that just invokes the HTEventCallback routine associated
                    368: ** with the given socket. 
                    369: **
                    370: */
1.1.2.2   eric      371: PUBLIC int HTEventList_dispatch (SOCKET s, HTEventType type)
1.1.2.1   eric      372: {
                    373:     RQ * rqp = NULL;
                    374:     if ((rqp = RQ_get(s, RQ_find)) == NULL || 
                    375:        rqp->events[HTEvent_INDEX(type)]->priority == HT_PRIORITY_OFF) {
                    376:        if (THD_TRACE) HTTrace("Callback.... No callback found\n");
                    377:        return (0);
                    378:     }
                    379:     return (*rqp->events[HTEvent_INDEX(type)]->cbf)(s, rqp->events[HTEvent_INDEX(type)]->param, type);
1.1.2.3 ! eric      380: }
        !           381: 
        !           382: PUBLIC HTEvent * HTEventList_lookup (SOCKET s, HTEventType type)
        !           383: {
        !           384:     RQ * rqp = NULL;
        !           385:     if ((rqp = RQ_get(s, RQ_find)) == NULL)
        !           386:        return NULL;
        !           387:     return rqp->events[HTEvent_INDEX(type)];
1.1.2.1   eric      388: }
                    389: 
                    390: PRIVATE void __DumpFDSet( fd_set * fdp, const char * str) 
                    391: {
                    392:     SOCKET s ;
                    393: #ifdef _WINSOCKAPI_
                    394:     unsigned ui ;
                    395: #endif
                    396:     if (THD_TRACE) {
                    397:        HTTrace("Dumping..... %s file descriptor set\n", str );
                    398: #ifdef _WINSOCKAPI_ 
                    399:         for (ui = 0 ; ui < fdp->fd_count; ui++) { 
                    400:             s = all_fds.fd_array[ui] ;
                    401: #else 
                    402:         for (s = 0 ; s <= max_sock; s++) { 
                    403:             if (FD_ISSET(s, fdp))
                    404: #endif
                    405:            {
                    406:                HTTrace("%4d\n", s);
                    407:            }
                    408:         }      /* for */
                    409:     }           /* if */
                    410:     return ;
                    411: }
                    412: 
                    413: /*     REGISTER DEFULT EVENT MANAGER
                    414: **     -----------------------------
                    415: **     Not done automaticly - may be done by application!
                    416: */
                    417: PUBLIC BOOL HTEventInit (void)
                    418: {
                    419:     HTEvent_setRegisterCallback(HTEventList_register);
                    420:     HTEvent_setUnregisterCallback(HTEventList_unregister);
                    421:     return YES;
                    422: }
                    423: 
                    424: PUBLIC BOOL HTEventTerminate (void)
                    425: {
                    426:     return YES;
                    427: }
                    428: 

Webmaster