Annotation of libwww/Library/src/HTNet.c, revision 2.27
2.23 frystyk 1: /* HTNet.c
2: ** ASYNCRONOUS SOCKET MANAGEMENT
2.1 frystyk 3: **
2.10 frystyk 4: ** (c) COPYRIGHT MIT 1995.
2.4 frystyk 5: ** Please first read the full copyright statement in the file COPYRIGH.
6: **
7: ** This is the implementation of the internal library multithreading
2.1 frystyk 8: ** functions. This includes an interrupt handler and a event loop.
9: **
10: ** History:
2.14 frystyk 11: ** 12 June 94 Written by Henrik Frystyk, frystyk@w3.org
2.17 frystyk 12: ** 31 May 95 Charlie Brooks cbrooks@osf.org
13: **
2.1 frystyk 14: */
15:
2.9 frystyk 16: /* Implemention dependent include files */
17: #include "tcp.h"
18:
2.1 frystyk 19: /* Library include files */
20: #include "HTUtils.h"
2.16 frystyk 21: #include "HTProt.h"
2.1 frystyk 22: #include "HTError.h"
2.25 frystyk 23: #include "HTAlert.h"
2.23 frystyk 24: #include "HTReqMan.h"
2.17 frystyk 25: #include "HTEvntrg.h"
2.23 frystyk 26: #include "HTStream.h"
2.24 frystyk 27: #include "HTNetMan.h" /* Implemented here */
2.1 frystyk 28:
2.9 frystyk 29: #ifdef WIN32
30: #include <io.h>
31: #endif
32:
2.23 frystyk 33: #ifndef HT_MAX_SOCKETS
34: #define HT_MAX_SOCKETS 6
35: #endif
36:
37: typedef struct _CBFInfo {
38: HTNetCallBack * cbf;
39: int status; /* Status associated with this callback */
40: } CBFInfo;
41:
42: struct _HTStream {
43: CONST HTStreamClass * isa;
44: /* ... */
45: };
46:
47: PRIVATE int HTMaxActive = HT_MAX_SOCKETS; /* Max active requests */
2.24 frystyk 48: PRIVATE HTList *HTNetCBF = NULL; /* List of call back functions */
49:
2.23 frystyk 50: PRIVATE HTList *HTNetActive = NULL; /* List of active requests */
51: PRIVATE HTList *HTNetPending = NULL; /* List of pending requests */
2.24 frystyk 52: PRIVATE HTList *HTNetPersistent = NULL; /* List of persistent connections */
2.1 frystyk 53:
54: /* ------------------------------------------------------------------------- */
55:
2.23 frystyk 56: /*
57: ** Set the max number of simultanous sockets. Default is HT_MAX_SOCKETS
2.1 frystyk 58: */
2.23 frystyk 59: PUBLIC BOOL HTNet_setMaxSocket (int newmax)
60: {
61: if (newmax > 0) {
62: HTMaxActive = newmax;
63: return YES;
64: }
65: return NO;
66: }
67:
68: PUBLIC int HTNet_maxSocket (void)
2.1 frystyk 69: {
2.23 frystyk 70: return HTMaxActive;
71: }
72:
73: /* ------------------------------------------------------------------------- */
74: /* Termination Call Back Functions */
75: /* ------------------------------------------------------------------------- */
76:
77: /* HTNet_Register
78: ** --------------
79: ** Register a call back function that is to be called on every
80: ** termination of a request. Several call back functions can be registered
81: ** in which case all of them are called in the order of which they
82: ** were registered.
83: **
84: ** The status signifies which call back function to call depending of the
85: ** result of the request. This can be
86: **
87: ** HT_ERROR An error occured
88: ** HT_LOADED The document was loaded
89: ** HT_NO_DATA OK, but no data
90: ** HT_RETRY Retry request after at a later time
91: ** HT_ALL All of above
92: */
93: PUBLIC BOOL HTNet_register (HTNetCallBack *cbf, int status)
94: {
95: if (THD_TRACE)
96: fprintf(TDEST, "Net register HTNetCallBack %p\n", (void *) cbf);
97: if (cbf) {
98: CBFInfo *cbfinfo = (CBFInfo *) calloc(1, sizeof(CBFInfo));
99: if (!cbfinfo) outofmem(__FILE__, "HTNet_register");
100: cbfinfo->cbf = cbf;
101: cbfinfo->status = status;
102: if (!HTNetCBF) HTNetCBF = HTList_new();
103: return HTList_addObject(HTNetCBF, (void *) cbfinfo);
104: }
105: return NO;
106: }
107:
108: /* HTNet_unregister
109: ** --------------
110: ** Unregister a call back function that is to be called on every
111: ** termination of a request.
112: */
113: PUBLIC BOOL HTNet_unregister (HTNetCallBack *cbf)
114: {
115: if (THD_TRACE)
116: fprintf(TDEST, "Net unreg.. HTNetCallBack %p\n", (void *) cbf);
117: if (HTNetCBF && cbf) {
118: HTList *cur = HTNetCBF;
119: CBFInfo *pres;
120: while ((pres = (CBFInfo *) HTList_nextObject(cur))) {
121: if (pres->cbf == cbf) {
122: HTList_removeObject(HTNetCBF, (void *) pres);
123: free(pres);
124: return YES;
125: }
126: }
127: }
128: return NO;
129: }
2.1 frystyk 130:
2.23 frystyk 131: /* HTNet_unregisterAll
132: ** -------------------
133: ** Unregisters all call back functions
134: */
135: PUBLIC BOOL HTNet_unregisterAll (void)
136: {
137: if (THD_TRACE)
138: fprintf(TDEST, "Net unreg.. All callback functions\n");
139: if (HTNetCBF) {
140: HTList *cur = HTNetCBF;
141: CBFInfo *pres;
142: while ((pres = (CBFInfo *) HTList_nextObject(cur))) {
143: HTList_removeObject(HTNetCBF, (void *) pres);
144: free(pres);
145: }
146: HTList_delete(HTNetCBF);
147: HTNetCBF = NULL;
148: return YES;
149: }
150: return NO;
151: }
152:
153: /* HTNet_callback
154: ** --------------
155: ** Call all the call back functions registered in the list IF not the
156: ** status is HT_IGNORE.
157: ** The callback functions are called in the order of which they
158: ** were registered. At the moment an application callback function is
159: ** called, it can free the request object - it is no longer used by the
160: ** Library.
161: ** Returns YES if OK, else NO.
162: */
163: PUBLIC BOOL HTNet_callback (HTRequest * request, int status)
164: {
165: if (HTNetCBF && request && status != HT_IGNORE) {
166: int cnt = HTList_count(HTNetCBF);
167: while (--cnt >= 0) {
2.26 frystyk 168: CBFInfo *pres = (CBFInfo *) HTList_objectAt(HTNetCBF, cnt);
2.23 frystyk 169: if (pres && (pres->status == status || pres->status == HT_ALL)) {
170: if (THD_TRACE)
171: fprintf(TDEST, "Net callback %p (request=%p, status=%d)\n",
172: (void *) pres->cbf, request, status);
173: (*(pres->cbf))(request, status);
174: }
175: }
176: return YES;
2.1 frystyk 177: }
2.23 frystyk 178: return NO;
2.1 frystyk 179: }
180:
2.23 frystyk 181: /* ------------------------------------------------------------------------- */
182: /* Request Queue */
183: /* ------------------------------------------------------------------------- */
2.1 frystyk 184:
2.23 frystyk 185: /* HTNet_activeQueue
186: ** -----------------
187: ** Returns the list of active requests that are currently having an open
188: ** connection.
189: ** Returns list of HTNet objects or NULL if error
2.1 frystyk 190: */
2.23 frystyk 191: PUBLIC HTList *HTNet_activeQueue (void)
192: {
193: return HTNetActive;
194: }
2.17 frystyk 195:
2.23 frystyk 196: /* HTNet_pendingQueue
197: ** ------------------
198: ** Returns the list of pending requests that are waiting to become active
199: ** Returns list of HTNet objects or NULL if error
200: */
201: PUBLIC HTList *HTNet_pendingQueue (void)
2.1 frystyk 202: {
2.23 frystyk 203: return HTNetPending;
2.1 frystyk 204: }
205:
2.23 frystyk 206: /* ------------------------------------------------------------------------- */
207: /* Creation and deletion methods */
208: /* ------------------------------------------------------------------------- */
209:
2.27 ! frystyk 210: /* HTNet_duplicate
! 211: ** ---------------
! 212: ** Creates a new HTNet object as a duplicate of the same request.
! 213: ** Returns YES if OK, else NO
! 214: ** BUG: We do not check if we have a socket free!
! 215: */
! 216: PUBLIC BOOL HTNet_dup (HTNet *src, HTNet **dest)
! 217: {
! 218: *dest = NULL;
! 219: if (!src) return NO;
! 220: if ((*dest = (HTNet *) calloc(1, sizeof(HTNet))) == NULL)
! 221: outofmem(__FILE__, "HTNet_dup");
! 222: memcpy(*dest, src, sizeof(HTNet));
! 223: return YES;
! 224: }
! 225:
2.23 frystyk 226: /* HTNet_new
2.15 frystyk 227: **
2.23 frystyk 228: ** Create a new HTNet object as a new request to be handled. If we have
229: ** more than HTMaxActive connections already then put this into the
230: ** pending queue, else start the request by calling the call back
231: ** function registered with this access method.
232: ** Returns YES if OK, else NO
233: */
234: PUBLIC BOOL HTNet_new (HTRequest * request, HTPriority priority)
235: {
236: HTNet *me;
237: HTProtocol *prot;
2.27 ! frystyk 238: if (!request) return NO;
2.23 frystyk 239: if (!HTNetActive) HTNetActive = HTList_new();
2.26 frystyk 240: prot = (HTProtocol *) HTAnchor_protocol(request->anchor);
2.23 frystyk 241:
242: /* Create new net object and bind it to the request object */
243: if ((me = (HTNet *) calloc(1, sizeof(HTNet))) == NULL)
244: outofmem(__FILE__, "HTNet_new");
245: me->request = request;
246: request->net = me;
247: me->preemtive = (HTProtocol_preemtive(prot) || request->preemtive);
248: me->priority = priority;
249: me->sockfd = INVSOC;
250: if (!(me->cbf = HTProtocol_callback(prot))) {
251: if (THD_TRACE)
252: fprintf(TDEST, "HTNet_new... NO CALL BACK FUNCTION!\n");
253: free(me);
254: return NO;
255: }
2.25 frystyk 256: request->retrys++;
2.23 frystyk 257:
258: /*
259: ** Check if we can start the request, else put it into pending queue
260: ** If so then call the call back function associated with the anchor.
261: ** We use the INVSOC as we don't have a valid socket yet!
262: */
263: if (HTList_count(HTNetActive) < HTMaxActive) {
264: HTList_addObject(HTNetActive, (void *) me);
265: if (THD_TRACE)
266: fprintf(TDEST, "HTNet_new... starting request %p (retry=%d)\n",
2.25 frystyk 267: request, request->retrys);
268: (*(me->cbf))(me->sockfd, request, FD_NONE);
2.23 frystyk 269: } else {
270: if (!HTNetPending) HTNetPending = HTList_new();
271: if (THD_TRACE)
272: fprintf(TDEST, "HTNet_new... request %p registered as pending\n",
2.25 frystyk 273: request);
274: HTProgress(request, HT_PROG_WAIT, NULL);
275: HTList_addObject(HTNetPending, (void *) me);
2.23 frystyk 276: }
277: return YES;
278: }
279:
280: /* delete_object
281: ** -------------
282: ** Deletes an HTNet object
2.15 frystyk 283: */
2.23 frystyk 284: PRIVATE BOOL delete_object (HTNet *net, int status)
2.15 frystyk 285: {
2.23 frystyk 286: if (THD_TRACE)
287: fprintf(TDEST, "HTNet_delete Remove net object %p\n", net);
288: if (net) {
289: int status = 0;
290:
291: /* Free stream with data FROM network to application */
292: if (net->target) {
293: if (status == HT_INTERRUPTED)
294: (*net->target->isa->abort)(net->target, NULL);
295: else
296: (*net->target->isa->_free)(net->target);
297: }
298:
299: /* Close socket */
300: if (net->sockfd != INVSOC) {
2.24 frystyk 301: if (HTDNS_socket(net->dns) == INVSOC) {
302: if ((status = NETCLOSE(net->sockfd)) < 0)
303: HTErrorSysAdd(net->request, ERR_FATAL, socerrno, NO,
304: "NETCLOSE");
305: if (THD_TRACE)
306: fprintf(TDEST, "HTNet_delete closing %d\n", net->sockfd);
2.25 frystyk 307: HTEvent_UnRegister(net->sockfd, (SockOps) FD_ALL);
2.24 frystyk 308: } else {
309: if (THD_TRACE)
310: fprintf(TDEST, "HTNet_delete keeping %d\n", net->sockfd);
2.25 frystyk 311: HTDNS_clearActive(net->dns);
312: /* Here we should probably use a low priority */
2.27 ! frystyk 313: HTEvent_UnRegister(net->sockfd, (SockOps) FD_ALL);
2.25 frystyk 314: HTEvent_Register(net->sockfd, net->request, (SockOps) FD_READ,
315: HTDNS_closeSocket, net->priority);
2.24 frystyk 316: }
2.23 frystyk 317: }
318: if (net->isoc)
319: HTInputSocket_free(net->isoc);
320: if (net->request)
321: net->request->net = NULL; /* Break link to request */
322: free(net);
323: return status ? NO : YES;
324: }
325: return NO;
326: }
327:
328: /* HTNet_delete
329: ** ------------
330: ** Deletes the HTNet object from the list of active requests and calls
331: ** any registered call back functions IF not the status is HT_IGNORE.
332: ** This is used if we have internal requests that the app doesn't know
333: ** about. We also see if we have pending requests that can be started
334: ** up now when we have a socket free.
335: ** The callback functions are called in the reverse order of which they
336: ** were registered (last one first)
337: */
338: PUBLIC BOOL HTNet_delete (HTNet * net, int status)
339: {
340: if (THD_TRACE)
341: fprintf(TDEST,"HTNetDelete. Net Object and call callback functions\n");
342: if (HTNetActive && net) {
2.25 frystyk 343: SOCKFD cs = net->sockfd; /* Current sockfd */
2.23 frystyk 344:
345: /* Remove object and call callback functions */
346: HTRequest *request = net->request;
347: HTList_removeObject(HTNetActive, (void *) net);
348: delete_object(net, status);
349: HTNet_callback(request, status);
350:
2.25 frystyk 351: /*
352: ** See first if we have a persistent request queued up for this socket
353: ** If not then see if there is a pending request
354: */
355: if (HTNetPersistent) {
356: HTList *cur = HTNetPersistent;
357: HTNet *next;
358: while ((next = (HTNet *) HTList_nextObject(cur))) {
359: if (next->sockfd == cs) {
360: BOOL e1, e2;
361: if (THD_TRACE)
362: fprintf(TDEST, "HTNet delete launch WARM request %p\n",
363: next->request);
364: e1 = HTList_addObject(HTNetActive, (void *) next);
365: e2 = HTList_removeObject(HTNetPersistent, (void *) next);
366: fprintf(TDEST, "TEST........ (%d) and (%d)\n",
367: e1+0x30, e2+0x30);
368: (*(next->cbf))(next->sockfd, next->request, FD_NONE);
369: break;
370: }
371: }
372: } else if (HTList_count(HTNetActive) < HTMaxActive &&
373: HTList_count(HTNetPending)) {
2.23 frystyk 374: HTNet *next = (HTNet *) HTList_removeFirstObject(HTNetPending);
375: if (next) {
376: HTList_addObject(HTNetActive, (void *) next);
377: if (THD_TRACE)
2.25 frystyk 378: fprintf(TDEST,"HTNet delete launch PENDING request %p\n",
2.23 frystyk 379: next->request);
380: (*(next->cbf))(INVSOC, next->request, FD_NONE);
381: }
382: }
383: return YES;
384: }
385: return NO;
386: }
387:
388: /* HTNet_deleteAll
389: ** ---------------
390: ** Deletes all HTNet object that might either be active or pending
2.25 frystyk 391: ** We DO NOT call the call back functions - A crude way of saying goodbye!
2.23 frystyk 392: */
393: PUBLIC BOOL HTNet_deleteAll (void)
394: {
395: if (THD_TRACE)
2.25 frystyk 396: fprintf(TDEST, "HTNetDelete. Remove all Net objects, NO callback\n");
397: if (HTNetPersistent) {
398: HTList *cur = HTNetPersistent;
399: HTNet *pres;
400: while ((pres = (HTNet *) HTList_nextObject(cur))) {
401: pres->sockfd = INVSOC; /* Don't close it more than once */
402: delete_object(pres, HT_INTERRUPTED);
403: }
404: HTList_delete(HTNetPersistent);
405: HTNetPersistent = NULL;
406: }
2.23 frystyk 407: if (HTNetPending) {
408: HTList *cur = HTNetPending;
409: HTNet *pres;
410: while ((pres = (HTNet *) HTList_nextObject(cur)))
411: delete_object(pres, HT_INTERRUPTED);
412: HTList_delete(HTNetPending);
413: HTNetPending = NULL;
414: }
415: if (HTNetActive) {
416: HTList *cur = HTNetActive;
417: HTNet *pres;
418: while ((pres = (HTNet *) HTList_nextObject(cur)))
419: delete_object(pres, HT_INTERRUPTED);
420: HTList_delete(HTNetActive);
421: HTNetActive = NULL;
422: }
423: return NO;
2.15 frystyk 424: }
425:
2.25 frystyk 426: /* HTNet_wait
427: ** ----------
428: ** Let a net object wait for a persistent socket. It will be launched
429: ** from the HTNet_delete() function
430: */
431: PUBLIC BOOL HTNet_wait (HTNet *net)
432: {
433: if (net) {
434: if (THD_TRACE)
435: fprintf(TDEST,"HTNet_wait.. request %p is waiting for socket %d\n",
436: net->request, net->sockfd);
437: if (!HTNetPersistent) HTNetPersistent = HTList_new();
438: HTList_addObject(HTNetPersistent, (void *) net);
439: return YES;
440: }
441: return NO;
442: }
443:
2.23 frystyk 444: /* ------------------------------------------------------------------------- */
445: /* Killing requests */
446: /* ------------------------------------------------------------------------- */
447:
448: /* HTNet_kill
449: ** ----------
450: ** Kill the request by calling the call back function with a request for
451: ** closing the connection. Does not remove the object. This is done by
452: ** HTNet_delete() function which is called by the load routine.
453: ** Returns OK if success, NO on error
454: */
455: PUBLIC BOOL HTNet_kill (HTNet * me)
456: {
457: if (HTNetActive && me) {
2.25 frystyk 458: HTList *cur = HTNetActive;
2.23 frystyk 459: HTNet *pres;
2.25 frystyk 460: while ((pres = (HTNet *) HTList_nextObject(cur))) {
2.23 frystyk 461: if (pres == me) {
2.25 frystyk 462: (*(pres->cbf))(pres->sockfd, pres->request, FD_CLOSE);
2.23 frystyk 463: return YES;
464: }
465: }
466: }
467: if (THD_TRACE)
2.25 frystyk 468: fprintf(TDEST, "HTNet_kill.. object %p is not registered\n", me);
2.23 frystyk 469: return NO;
470: }
471:
472: /* HTNet_killAll
473: ** -------------
474: ** Kills all registered (active+pending) requests by calling the call
475: ** back function with a request for closing the connection. We do not
476: ** remove the HTNet object as it is done by HTNet_delete().
477: ** Returns OK if success, NO on error
478: */
479: PUBLIC BOOL HTNet_killAll (void)
480: {
481: HTNet *pres;
482: if (THD_TRACE)
483: fprintf(TDEST, "HTNet_kill.. ALL registered requests!!!\n");
484:
2.25 frystyk 485: /* We start off in persistent queue so we avoid racing */
486: if (HTNetPersistent) {
487: while ((pres = (HTNet *) HTList_lastObject(HTNetPersistent)) != NULL) {
488: pres->sockfd = INVSOC;
489: (*(pres->cbf))(pres->sockfd, pres->request, FD_CLOSE);
490: HTList_removeObject(HTNetPersistent, pres);
491: }
492: }
2.23 frystyk 493: if (HTNetPending) {
494: while ((pres = (HTNet *) HTList_lastObject(HTNetPending)) != NULL) {
2.25 frystyk 495: (*(pres->cbf))(pres->sockfd, pres->request, FD_CLOSE);
2.23 frystyk 496: HTList_removeObject(HTNetPending, pres);
497: }
498: }
499: if (HTNetActive) {
500: while ((pres = (HTNet *) HTList_lastObject(HTNetActive)) != NULL)
2.25 frystyk 501: (*(pres->cbf))(pres->sockfd, pres->request, FD_CLOSE);
2.23 frystyk 502: }
503: return YES;
504: }
Webmaster