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