Annotation of libwww/Library/src/HTNet.c, revision 2.28
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.28 ! frystyk 196: /* HTNet_activeCount
! 197: ** ----------------
! 198: ** Returns the number of active requests
! 199: */
! 200: PUBLIC int HTNet_activeCount (void)
! 201: {
! 202: return HTList_count(HTNetActive);
! 203: }
! 204:
2.23 frystyk 205: /* HTNet_pendingQueue
206: ** ------------------
207: ** Returns the list of pending requests that are waiting to become active
208: ** Returns list of HTNet objects or NULL if error
209: */
210: PUBLIC HTList *HTNet_pendingQueue (void)
2.1 frystyk 211: {
2.23 frystyk 212: return HTNetPending;
2.1 frystyk 213: }
214:
2.23 frystyk 215: /* ------------------------------------------------------------------------- */
216: /* Creation and deletion methods */
217: /* ------------------------------------------------------------------------- */
218:
2.27 frystyk 219: /* HTNet_duplicate
220: ** ---------------
221: ** Creates a new HTNet object as a duplicate of the same request.
222: ** Returns YES if OK, else NO
223: ** BUG: We do not check if we have a socket free!
224: */
225: PUBLIC BOOL HTNet_dup (HTNet *src, HTNet **dest)
226: {
227: *dest = NULL;
228: if (!src) return NO;
229: if ((*dest = (HTNet *) calloc(1, sizeof(HTNet))) == NULL)
230: outofmem(__FILE__, "HTNet_dup");
231: memcpy(*dest, src, sizeof(HTNet));
232: return YES;
233: }
234:
2.23 frystyk 235: /* HTNet_new
2.15 frystyk 236: **
2.23 frystyk 237: ** Create a new HTNet object as a new request to be handled. If we have
238: ** more than HTMaxActive connections already then put this into the
239: ** pending queue, else start the request by calling the call back
240: ** function registered with this access method.
241: ** Returns YES if OK, else NO
242: */
243: PUBLIC BOOL HTNet_new (HTRequest * request, HTPriority priority)
244: {
245: HTNet *me;
246: HTProtocol *prot;
2.27 frystyk 247: if (!request) return NO;
2.23 frystyk 248: if (!HTNetActive) HTNetActive = HTList_new();
2.26 frystyk 249: prot = (HTProtocol *) HTAnchor_protocol(request->anchor);
2.23 frystyk 250:
251: /* Create new net object and bind it to the request object */
252: if ((me = (HTNet *) calloc(1, sizeof(HTNet))) == NULL)
253: outofmem(__FILE__, "HTNet_new");
254: me->request = request;
255: request->net = me;
256: me->preemtive = (HTProtocol_preemtive(prot) || request->preemtive);
257: me->priority = priority;
258: me->sockfd = INVSOC;
259: if (!(me->cbf = HTProtocol_callback(prot))) {
260: if (THD_TRACE)
261: fprintf(TDEST, "HTNet_new... NO CALL BACK FUNCTION!\n");
262: free(me);
263: return NO;
264: }
2.25 frystyk 265: request->retrys++;
2.23 frystyk 266:
267: /*
268: ** Check if we can start the request, else put it into pending queue
269: ** If so then call the call back function associated with the anchor.
270: ** We use the INVSOC as we don't have a valid socket yet!
271: */
272: if (HTList_count(HTNetActive) < HTMaxActive) {
273: HTList_addObject(HTNetActive, (void *) me);
274: if (THD_TRACE)
275: fprintf(TDEST, "HTNet_new... starting request %p (retry=%d)\n",
2.25 frystyk 276: request, request->retrys);
277: (*(me->cbf))(me->sockfd, request, FD_NONE);
2.23 frystyk 278: } else {
279: if (!HTNetPending) HTNetPending = HTList_new();
280: if (THD_TRACE)
281: fprintf(TDEST, "HTNet_new... request %p registered as pending\n",
2.25 frystyk 282: request);
283: HTProgress(request, HT_PROG_WAIT, NULL);
284: HTList_addObject(HTNetPending, (void *) me);
2.23 frystyk 285: }
286: return YES;
287: }
288:
289: /* delete_object
290: ** -------------
291: ** Deletes an HTNet object
2.15 frystyk 292: */
2.23 frystyk 293: PRIVATE BOOL delete_object (HTNet *net, int status)
2.15 frystyk 294: {
2.23 frystyk 295: if (THD_TRACE)
296: fprintf(TDEST, "HTNet_delete Remove net object %p\n", net);
297: if (net) {
298: int status = 0;
299:
300: /* Free stream with data FROM network to application */
301: if (net->target) {
302: if (status == HT_INTERRUPTED)
303: (*net->target->isa->abort)(net->target, NULL);
304: else
305: (*net->target->isa->_free)(net->target);
306: }
307:
308: /* Close socket */
309: if (net->sockfd != INVSOC) {
2.24 frystyk 310: if (HTDNS_socket(net->dns) == INVSOC) {
311: if ((status = NETCLOSE(net->sockfd)) < 0)
312: HTErrorSysAdd(net->request, ERR_FATAL, socerrno, NO,
313: "NETCLOSE");
314: if (THD_TRACE)
315: fprintf(TDEST, "HTNet_delete closing %d\n", net->sockfd);
2.25 frystyk 316: HTEvent_UnRegister(net->sockfd, (SockOps) FD_ALL);
2.24 frystyk 317: } else {
318: if (THD_TRACE)
319: fprintf(TDEST, "HTNet_delete keeping %d\n", net->sockfd);
2.25 frystyk 320: HTDNS_clearActive(net->dns);
321: /* Here we should probably use a low priority */
2.27 frystyk 322: HTEvent_UnRegister(net->sockfd, (SockOps) FD_ALL);
2.25 frystyk 323: HTEvent_Register(net->sockfd, net->request, (SockOps) FD_READ,
324: HTDNS_closeSocket, net->priority);
2.24 frystyk 325: }
2.23 frystyk 326: }
327: if (net->isoc)
328: HTInputSocket_free(net->isoc);
329: if (net->request)
330: net->request->net = NULL; /* Break link to request */
331: free(net);
332: return status ? NO : YES;
333: }
334: return NO;
335: }
336:
337: /* HTNet_delete
338: ** ------------
339: ** Deletes the HTNet object from the list of active requests and calls
340: ** any registered call back functions IF not the status is HT_IGNORE.
341: ** This is used if we have internal requests that the app doesn't know
342: ** about. We also see if we have pending requests that can be started
343: ** up now when we have a socket free.
344: ** The callback functions are called in the reverse order of which they
345: ** were registered (last one first)
346: */
347: PUBLIC BOOL HTNet_delete (HTNet * net, int status)
348: {
349: if (THD_TRACE)
350: fprintf(TDEST,"HTNetDelete. Net Object and call callback functions\n");
351: if (HTNetActive && net) {
2.25 frystyk 352: SOCKFD cs = net->sockfd; /* Current sockfd */
2.23 frystyk 353:
354: /* Remove object and call callback functions */
355: HTRequest *request = net->request;
356: HTList_removeObject(HTNetActive, (void *) net);
357: delete_object(net, status);
358: HTNet_callback(request, status);
359:
2.25 frystyk 360: /*
361: ** See first if we have a persistent request queued up for this socket
362: ** If not then see if there is a pending request
363: */
364: if (HTNetPersistent) {
365: HTList *cur = HTNetPersistent;
366: HTNet *next;
367: while ((next = (HTNet *) HTList_nextObject(cur))) {
368: if (next->sockfd == cs) {
369: if (THD_TRACE)
370: fprintf(TDEST, "HTNet delete launch WARM request %p\n",
371: next->request);
2.28 ! frystyk 372: HTList_addObject(HTNetActive, (void *) next);
! 373: HTList_removeObject(HTNetPersistent, (void *) next);
2.25 frystyk 374: (*(next->cbf))(next->sockfd, next->request, FD_NONE);
375: break;
376: }
377: }
378: } else if (HTList_count(HTNetActive) < HTMaxActive &&
379: HTList_count(HTNetPending)) {
2.23 frystyk 380: HTNet *next = (HTNet *) HTList_removeFirstObject(HTNetPending);
381: if (next) {
382: HTList_addObject(HTNetActive, (void *) next);
383: if (THD_TRACE)
2.25 frystyk 384: fprintf(TDEST,"HTNet delete launch PENDING request %p\n",
2.23 frystyk 385: next->request);
386: (*(next->cbf))(INVSOC, next->request, FD_NONE);
387: }
388: }
389: return YES;
390: }
391: return NO;
392: }
393:
394: /* HTNet_deleteAll
395: ** ---------------
396: ** Deletes all HTNet object that might either be active or pending
2.25 frystyk 397: ** We DO NOT call the call back functions - A crude way of saying goodbye!
2.23 frystyk 398: */
399: PUBLIC BOOL HTNet_deleteAll (void)
400: {
401: if (THD_TRACE)
2.25 frystyk 402: fprintf(TDEST, "HTNetDelete. Remove all Net objects, NO callback\n");
403: if (HTNetPersistent) {
404: HTList *cur = HTNetPersistent;
405: HTNet *pres;
406: while ((pres = (HTNet *) HTList_nextObject(cur))) {
407: pres->sockfd = INVSOC; /* Don't close it more than once */
408: delete_object(pres, HT_INTERRUPTED);
409: }
410: HTList_delete(HTNetPersistent);
411: HTNetPersistent = NULL;
412: }
2.23 frystyk 413: if (HTNetPending) {
414: HTList *cur = HTNetPending;
415: HTNet *pres;
416: while ((pres = (HTNet *) HTList_nextObject(cur)))
417: delete_object(pres, HT_INTERRUPTED);
418: HTList_delete(HTNetPending);
419: HTNetPending = NULL;
420: }
421: if (HTNetActive) {
422: HTList *cur = HTNetActive;
423: HTNet *pres;
424: while ((pres = (HTNet *) HTList_nextObject(cur)))
425: delete_object(pres, HT_INTERRUPTED);
426: HTList_delete(HTNetActive);
427: HTNetActive = NULL;
428: }
429: return NO;
2.15 frystyk 430: }
431:
2.25 frystyk 432: /* HTNet_wait
433: ** ----------
434: ** Let a net object wait for a persistent socket. It will be launched
435: ** from the HTNet_delete() function
436: */
437: PUBLIC BOOL HTNet_wait (HTNet *net)
438: {
439: if (net) {
440: if (THD_TRACE)
441: fprintf(TDEST,"HTNet_wait.. request %p is waiting for socket %d\n",
442: net->request, net->sockfd);
443: if (!HTNetPersistent) HTNetPersistent = HTList_new();
444: HTList_addObject(HTNetPersistent, (void *) net);
445: return YES;
446: }
447: return NO;
448: }
449:
2.23 frystyk 450: /* ------------------------------------------------------------------------- */
451: /* Killing requests */
452: /* ------------------------------------------------------------------------- */
453:
454: /* HTNet_kill
455: ** ----------
456: ** Kill the request by calling the call back function with a request for
457: ** closing the connection. Does not remove the object. This is done by
458: ** HTNet_delete() function which is called by the load routine.
459: ** Returns OK if success, NO on error
460: */
461: PUBLIC BOOL HTNet_kill (HTNet * me)
462: {
463: if (HTNetActive && me) {
2.25 frystyk 464: HTList *cur = HTNetActive;
2.23 frystyk 465: HTNet *pres;
2.25 frystyk 466: while ((pres = (HTNet *) HTList_nextObject(cur))) {
2.23 frystyk 467: if (pres == me) {
2.25 frystyk 468: (*(pres->cbf))(pres->sockfd, pres->request, FD_CLOSE);
2.23 frystyk 469: return YES;
470: }
471: }
472: }
473: if (THD_TRACE)
2.25 frystyk 474: fprintf(TDEST, "HTNet_kill.. object %p is not registered\n", me);
2.23 frystyk 475: return NO;
476: }
477:
478: /* HTNet_killAll
479: ** -------------
480: ** Kills all registered (active+pending) requests by calling the call
481: ** back function with a request for closing the connection. We do not
482: ** remove the HTNet object as it is done by HTNet_delete().
483: ** Returns OK if success, NO on error
484: */
485: PUBLIC BOOL HTNet_killAll (void)
486: {
487: HTNet *pres;
488: if (THD_TRACE)
489: fprintf(TDEST, "HTNet_kill.. ALL registered requests!!!\n");
490:
2.25 frystyk 491: /* We start off in persistent queue so we avoid racing */
492: if (HTNetPersistent) {
493: while ((pres = (HTNet *) HTList_lastObject(HTNetPersistent)) != NULL) {
494: pres->sockfd = INVSOC;
495: (*(pres->cbf))(pres->sockfd, pres->request, FD_CLOSE);
496: HTList_removeObject(HTNetPersistent, pres);
497: }
498: }
2.23 frystyk 499: if (HTNetPending) {
500: while ((pres = (HTNet *) HTList_lastObject(HTNetPending)) != NULL) {
2.25 frystyk 501: (*(pres->cbf))(pres->sockfd, pres->request, FD_CLOSE);
2.23 frystyk 502: HTList_removeObject(HTNetPending, pres);
503: }
504: }
505: if (HTNetActive) {
506: while ((pres = (HTNet *) HTList_lastObject(HTNetActive)) != NULL)
2.25 frystyk 507: (*(pres->cbf))(pres->sockfd, pres->request, FD_CLOSE);
2.23 frystyk 508: }
509: return YES;
510: }
Webmaster