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