Annotation of libwww/Library/src/HTNet.c, revision 2.42
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.37 frystyk 24: #include "HTParse.h"
2.23 frystyk 25: #include "HTReqMan.h"
2.17 frystyk 26: #include "HTEvntrg.h"
2.23 frystyk 27: #include "HTStream.h"
2.24 frystyk 28: #include "HTNetMan.h" /* Implemented here */
2.1 frystyk 29:
2.9 frystyk 30: #ifdef WIN32
31: #include <io.h>
32: #endif
33:
2.23 frystyk 34: #ifndef HT_MAX_SOCKETS
35: #define HT_MAX_SOCKETS 6
36: #endif
37:
2.33 frystyk 38: typedef struct _NetCall {
2.30 frystyk 39: HTNetCallback * cbf;
2.23 frystyk 40: int status; /* Status associated with this callback */
2.33 frystyk 41: } NetCall;
2.23 frystyk 42:
43: struct _HTStream {
44: CONST HTStreamClass * isa;
45: /* ... */
46: };
47:
48: PRIVATE int HTMaxActive = HT_MAX_SOCKETS; /* Max active requests */
2.33 frystyk 49: PRIVATE HTList *HTBefore = NULL; /* List of call back functions */
50: PRIVATE HTList *HTAfter = NULL; /* List of call back functions */
2.24 frystyk 51:
2.23 frystyk 52: PRIVATE HTList *HTNetActive = NULL; /* List of active requests */
53: PRIVATE HTList *HTNetPending = NULL; /* List of pending requests */
2.24 frystyk 54: PRIVATE HTList *HTNetPersistent = NULL; /* List of persistent connections */
2.1 frystyk 55:
56: /* ------------------------------------------------------------------------- */
57:
2.23 frystyk 58: /*
59: ** Set the max number of simultanous sockets. Default is HT_MAX_SOCKETS
2.1 frystyk 60: */
2.23 frystyk 61: PUBLIC BOOL HTNet_setMaxSocket (int newmax)
62: {
63: if (newmax > 0) {
64: HTMaxActive = newmax;
65: return YES;
66: }
67: return NO;
68: }
69:
70: PUBLIC int HTNet_maxSocket (void)
2.1 frystyk 71: {
2.23 frystyk 72: return HTMaxActive;
73: }
74:
75: /* ------------------------------------------------------------------------- */
2.33 frystyk 76: /* Call Back Functions */
2.23 frystyk 77: /* ------------------------------------------------------------------------- */
78:
2.33 frystyk 79: /* HTNetCall_add
80: ** -------------
81: ** Register a call back function that is to be called on every request.
82: ** Several call back functions can be registered
2.23 frystyk 83: ** in which case all of them are called in the order of which they
84: ** were registered.
85: **
86: ** The status signifies which call back function to call depending of the
87: ** result of the request. This can be
88: **
89: ** HT_ERROR An error occured
90: ** HT_LOADED The document was loaded
91: ** HT_NO_DATA OK, but no data
2.33 frystyk 92: ** HT_REDIRECT If we received a redirection
2.23 frystyk 93: ** HT_RETRY Retry request after at a later time
94: ** HT_ALL All of above
95: */
2.33 frystyk 96: PUBLIC BOOL HTNetCall_add (HTList * list, HTNetCallback *cbf, int status)
2.23 frystyk 97: {
2.33 frystyk 98: if (WWWTRACE)
99: TTYPrint(TDEST, "Call Add.... HTNetCallback %p\n", (void *) cbf);
100: if (list && cbf) {
101: NetCall *me = (NetCall *) calloc(1, sizeof(NetCall));
2.40 frystyk 102: if (!me) outofmem(__FILE__, "HTNetCall_add");
2.33 frystyk 103: me->cbf = cbf;
104: me->status = status;
105: return HTList_addObject(list, (void *) me);
2.23 frystyk 106: }
107: return NO;
108: }
109:
2.33 frystyk 110: /* HTNetCall_delete
111: ** ----------------
112: ** Unregister a call back function from a list
2.23 frystyk 113: */
2.33 frystyk 114: PUBLIC BOOL HTNetCall_delete (HTList * list, HTNetCallback *cbf)
2.23 frystyk 115: {
2.33 frystyk 116: if (WWWTRACE)
117: TTYPrint(TDEST, "Call delete HTNetCallback %p\n", (void *) cbf);
118: if (list && cbf) {
119: HTList *cur = list;
120: NetCall *pres;
121: while ((pres = (NetCall *) HTList_nextObject(cur))) {
2.23 frystyk 122: if (pres->cbf == cbf) {
2.33 frystyk 123: HTList_removeObject(list, (void *) pres);
2.23 frystyk 124: free(pres);
125: return YES;
126: }
127: }
128: }
129: return NO;
130: }
2.1 frystyk 131:
2.33 frystyk 132: /* HTNetCall_deleteAll
2.23 frystyk 133: ** -------------------
134: ** Unregisters all call back functions
135: */
2.33 frystyk 136: PUBLIC BOOL HTNetCall_deleteAll (HTList * list)
2.23 frystyk 137: {
2.33 frystyk 138: if (WWWTRACE)
139: TTYPrint(TDEST, "Call delete All callback functions\n");
140: if (list) {
141: HTList *cur = list;
142: NetCall *pres;
143: while ((pres = (NetCall *) HTList_nextObject(cur))) {
144: HTList_removeObject(list, (void *) pres);
2.23 frystyk 145: free(pres);
146: }
2.33 frystyk 147: HTList_delete(list);
2.23 frystyk 148: return YES;
149: }
150: return NO;
151: }
152:
2.33 frystyk 153: /* HTNetCall_execute
154: ** -----------------
2.23 frystyk 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.
2.33 frystyk 161: ** Returns what the last callback function returns
2.23 frystyk 162: */
2.33 frystyk 163: PUBLIC int HTNetCall_execute (HTList * list, HTRequest * request, int status)
2.23 frystyk 164: {
2.33 frystyk 165: int ret = HT_OK;
166: if (list && request && status != HT_IGNORE) {
167: int cnt = HTList_count(list);
2.23 frystyk 168: while (--cnt >= 0) {
2.33 frystyk 169: NetCall *pres = (NetCall *) HTList_objectAt(list, cnt);
2.23 frystyk 170: if (pres && (pres->status == status || pres->status == HT_ALL)) {
2.33 frystyk 171: if (WWWTRACE)
172: TTYPrint(TDEST,"Net callback %p (request=%p, status=%d)\n",
2.23 frystyk 173: (void *) pres->cbf, request, status);
2.33 frystyk 174: if ((ret = (*(pres->cbf))(request, status)) != HT_OK) break;
2.23 frystyk 175: }
176: }
2.1 frystyk 177: }
2.33 frystyk 178: return ret;
179: }
180:
181: /*
182: ** Global set of callback functions BEFORE the request is issued
183: ** list can be NULL
184: */
185: PUBLIC BOOL HTNet_setBefore (HTList *list)
186: {
187: if (HTBefore) HTNetCall_deleteAll(HTBefore);
188: HTBefore = list;
189: return YES;
190: }
191:
192: PUBLIC HTList * HTNet_before (void)
193: {
194: return HTBefore;
195: }
196:
197: PUBLIC int HTNet_callBefore (HTRequest *request, int status)
198: {
199: return HTNetCall_execute(HTBefore, request, status);
200: }
201:
202: PUBLIC BOOL HTNetCall_addBefore (HTNetCallback *cbf, int status)
203: {
204: if (!HTBefore) HTBefore = HTList_new();
205: return HTNetCall_add(HTBefore, cbf, status);
206: }
207:
208: /*
209: ** Global set of callback functions AFTER the request is issued
210: ** list can be NULL
211: */
212: PUBLIC BOOL HTNet_setAfter (HTList *list)
213: {
214: if (HTAfter) HTNetCall_deleteAll(HTAfter);
215: HTAfter = list;
216: return YES;
217: }
218:
219: PUBLIC HTList * HTNet_after (void)
220: {
221: return HTAfter;
222: }
223:
224: PUBLIC int HTNet_callAfter (HTRequest *request, int status)
225: {
226: return HTNetCall_execute(HTAfter, request, status);
227: }
228:
229: PUBLIC BOOL HTNetCall_addAfter (HTNetCallback *cbf, int status)
230: {
231: if (!HTAfter) HTAfter = HTList_new();
232: return HTNetCall_add(HTAfter, cbf, status);
2.1 frystyk 233: }
234:
2.23 frystyk 235: /* ------------------------------------------------------------------------- */
236: /* Request Queue */
237: /* ------------------------------------------------------------------------- */
2.1 frystyk 238:
2.23 frystyk 239: /* HTNet_activeQueue
240: ** -----------------
241: ** Returns the list of active requests that are currently having an open
242: ** connection.
243: ** Returns list of HTNet objects or NULL if error
2.1 frystyk 244: */
2.23 frystyk 245: PUBLIC HTList *HTNet_activeQueue (void)
246: {
247: return HTNetActive;
248: }
2.17 frystyk 249:
2.40 frystyk 250: /* HTNet_idle
251: ** ----------
252: ** Returns whether there are active requests
2.28 frystyk 253: */
2.29 frystyk 254: PUBLIC BOOL HTNet_idle (void)
2.28 frystyk 255: {
2.29 frystyk 256: return HTList_isEmpty(HTNetActive);
2.28 frystyk 257: }
258:
2.40 frystyk 259: /* HTNet_empty
260: ** -----------
261: ** Returns whether there are requests registered or not
262: */
263: PUBLIC BOOL HTNet_isEmpty (void)
264: {
265: return (HTList_isEmpty(HTNetActive) && HTList_isEmpty(HTNetPersistent) &&
266: HTList_isEmpty(HTNetPending));
267: }
268:
2.23 frystyk 269: /* HTNet_pendingQueue
270: ** ------------------
271: ** Returns the list of pending requests that are waiting to become active
272: ** Returns list of HTNet objects or NULL if error
273: */
274: PUBLIC HTList *HTNet_pendingQueue (void)
2.1 frystyk 275: {
2.23 frystyk 276: return HTNetPending;
2.1 frystyk 277: }
278:
2.23 frystyk 279: /* ------------------------------------------------------------------------- */
280: /* Creation and deletion methods */
281: /* ------------------------------------------------------------------------- */
282:
2.27 frystyk 283: /* HTNet_duplicate
284: ** ---------------
285: ** Creates a new HTNet object as a duplicate of the same request.
286: ** Returns YES if OK, else NO
287: ** BUG: We do not check if we have a socket free!
288: */
289: PUBLIC BOOL HTNet_dup (HTNet *src, HTNet **dest)
290: {
291: *dest = NULL;
292: if (!src) return NO;
2.42 ! frystyk 293: if ((*dest = (HTNet *) malloc(sizeof(HTNet))) == NULL)
2.27 frystyk 294: outofmem(__FILE__, "HTNet_dup");
295: memcpy(*dest, src, sizeof(HTNet));
296: return YES;
297: }
298:
2.30 frystyk 299: /* HTNet_priority
300: ** --------------
301: ** Get the current priority of the Net object
302: */
303: PUBLIC HTPriority HTNet_priority (HTNet * net)
304: {
305: return (net ? net->priority : -1);
306: }
307:
308: /* HTNet_setPriority
309: ** -----------------
310: ** Set the current priority of the Net object
311: ** This will change the priority next time the thread is blocked
312: */
313: PUBLIC BOOL HTNet_setPriority (HTNet * net, HTPriority priority)
314: {
315: if (net) {
316: net->priority = priority;
317: return YES;
318: }
319: return NO;
320: }
321:
2.36 frystyk 322: /* create_object
323: ** -------------
324: ** Creates an HTNet object
325: */
326: PRIVATE HTNet * create_object (HTRequest * request)
327: {
328: HTNet * me;
329: if ((me = (HTNet *) calloc(1, sizeof(HTNet))) == NULL)
330: outofmem(__FILE__, "HTNet_new");
331: me->request = request;
332: request->net = me;
2.37 frystyk 333: me->tcpstate = TCP_BEGIN;
2.36 frystyk 334: return me;
335: }
336:
2.37 frystyk 337: /* HTNet_new
338: ** ---------
339: ** This function creates a new HTNet object and assigns the socket number
340: ** to it. This is intended to be used when you are going to listen on a
341: ** socket using the HTDoListen() function in HTTCP.c. The function do NOT
342: ** call any of the callback functions.
343: ** Returns new object or NULL on error
344: */
345: PUBLIC HTNet * HTNet_new (HTRequest * request, SOCKET sockfd)
346: {
347: HTNet * me;
348: if (WWWTRACE) TTYPrint(TDEST, "HTNet_new... Create empty Net object\n");
349: if (!request || sockfd==INVSOC) return NULL;
350: if ((me = create_object(request)) == NULL) return NULL;
351: me->preemtive = request->preemtive;
352: me->priority = request->priority;
353: me->sockfd = sockfd;
354: return me;
355: }
356:
357: /* HTNet_newServer
358: ** ---------------
359: ** Create a new HTNet object as a new request to be handled. If we have
360: ** more than HTMaxActive connections already then return NO.
361: ** Returns YES if OK, else NO
362: */
2.38 frystyk 363: PUBLIC BOOL HTNet_newServer (HTRequest * request, SOCKET sockfd)
2.37 frystyk 364: {
365: HTNet * me;
366: HTProtocol * protocol;
367: if (!request) return NO;
368:
369: /* Check if we can start the request, else return immediately */
370: if (!HTNetActive) HTNetActive = HTList_new();
371: if (HTList_count(HTNetActive) > HTMaxActive) {
372: if (PROT_TRACE) TTYPrint(TDEST, "HTNet new... NO SOCKET AVAILABLE\n");
373: HTNetCall_execute(HTAfter, request, HT_RETRY);
374: return YES;
375: }
376:
377: /* Find a protocol object for this access scheme */
378: protocol = HTProtocol_find(request, HTRequest_access(request));
379:
380: /* Create new net object and bind it to the request object */
381: if ((me = create_object(request)) == NULL) return NO;
382: me->preemtive = (HTProtocol_preemtive(protocol) || request->preemtive);
383: me->priority = request->priority;
2.38 frystyk 384: me->sockfd = sockfd;
2.37 frystyk 385: if (!(me->cbf = HTProtocol_server(protocol))) {
386: if (WWWTRACE) TTYPrint(TDEST, "HTNet_new... NO CALL BACK FUNCTION!\n");
387: free(me);
388: return NO;
389: }
390: request->retrys++;
391:
392: /* Start the server request */
393: HTList_addObject(HTNetActive, (void *) me);
394: if (WWWTRACE)
395: TTYPrint(TDEST, "HTNet_new... starting SERVER request %p\n", request);
396: (*(me->cbf))(me->sockfd, request, FD_NONE);
397: return YES;
398: }
2.36 frystyk 399:
2.30 frystyk 400: /* HTNet_new
401: ** ---------
2.23 frystyk 402: ** Create a new HTNet object as a new request to be handled. If we have
403: ** more than HTMaxActive connections already then put this into the
404: ** pending queue, else start the request by calling the call back
405: ** function registered with this access method.
406: ** Returns YES if OK, else NO
407: */
2.37 frystyk 408: PUBLIC BOOL HTNet_newClient (HTRequest * request)
2.23 frystyk 409: {
2.33 frystyk 410: int status;
411: HTNet * me;
2.37 frystyk 412: HTProtocol * protocol;
413: char * physical = NULL;
2.27 frystyk 414: if (!request) return NO;
2.33 frystyk 415: /*
416: ** First we do all the "BEFORE" callbacks in order to see if we are to
417: ** continue with this request or not. If we receive a callback status
418: ** that is NOT HT_OK then jump directly to the after callbacks and return
419: */
2.34 frystyk 420: if ((status = HTNetCall_execute(HTBefore, request, HT_OK)) != HT_OK) {
2.33 frystyk 421: HTNetCall_execute(HTAfter, request, status);
422: return YES;
423: }
424:
2.36 frystyk 425: /*
426: ** If no translation was provided by the application then use the anchor
427: ** address directly
428: */
2.37 frystyk 429: if (!HTNetActive) HTNetActive = HTList_new();
2.33 frystyk 430: if (!(physical = HTAnchor_physical(request->anchor)) || !*physical) {
2.36 frystyk 431: char * addr = HTAnchor_address((HTAnchor *) request->anchor);
2.37 frystyk 432: if (WWWTRACE) TTYPrint(TDEST, "HTNet New... Using default address\n");
2.36 frystyk 433: HTAnchor_setPhysical(request->anchor, addr);
2.37 frystyk 434: physical = HTAnchor_physical(request->anchor);
2.36 frystyk 435: FREE(addr);
2.33 frystyk 436: }
437:
2.37 frystyk 438: /* Find a protocol object for this access scheme */
439: {
440: char * access = HTParse(physical, "", PARSE_ACCESS);
441: if ((protocol = HTProtocol_find(request, access)) == NULL) {
442: if (WWWTRACE) TTYPrint(TDEST, "HTNet_new... NO PROTOCOL OBJECT\n");
443: free(access);
444: return NO;
445: }
446: free(access);
447: }
448:
2.23 frystyk 449: /* Create new net object and bind it to the request object */
2.36 frystyk 450: if ((me = create_object(request)) == NULL) return NO;
2.37 frystyk 451: me->preemtive = (HTProtocol_preemtive(protocol) || request->preemtive);
2.30 frystyk 452: me->priority = request->priority;
2.23 frystyk 453: me->sockfd = INVSOC;
2.37 frystyk 454: if (!(me->cbf = HTProtocol_client(protocol))) {
2.36 frystyk 455: if (WWWTRACE) TTYPrint(TDEST, "HTNet_new... NO CALL BACK FUNCTION!\n");
2.23 frystyk 456: free(me);
457: return NO;
458: }
2.25 frystyk 459: request->retrys++;
2.23 frystyk 460:
461: /*
462: ** Check if we can start the request, else put it into pending queue
463: ** If so then call the call back function associated with the anchor.
464: ** We use the INVSOC as we don't have a valid socket yet!
465: */
466: if (HTList_count(HTNetActive) < HTMaxActive) {
467: HTList_addObject(HTNetActive, (void *) me);
2.33 frystyk 468: if (WWWTRACE)
2.31 frystyk 469: TTYPrint(TDEST, "HTNet_new... starting request %p (retry=%d)\n",
2.25 frystyk 470: request, request->retrys);
471: (*(me->cbf))(me->sockfd, request, FD_NONE);
2.23 frystyk 472: } else {
2.35 frystyk 473: HTAlertCallback *cbf = HTAlert_find(HT_PROG_WAIT);
2.23 frystyk 474: if (!HTNetPending) HTNetPending = HTList_new();
2.33 frystyk 475: if (WWWTRACE)
2.31 frystyk 476: TTYPrint(TDEST, "HTNet_new... request %p registered as pending\n",
2.25 frystyk 477: request);
2.35 frystyk 478: if (cbf) (*cbf)(request, HT_PROG_WAIT, HT_MSG_NULL, NULL, NULL, NULL);
2.25 frystyk 479: HTList_addObject(HTNetPending, (void *) me);
2.23 frystyk 480: }
2.36 frystyk 481: return YES;
482: }
483:
2.23 frystyk 484: /* delete_object
485: ** -------------
486: ** Deletes an HTNet object
2.40 frystyk 487: ** Return YES if OK, else NO
2.15 frystyk 488: */
2.23 frystyk 489: PRIVATE BOOL delete_object (HTNet *net, int status)
2.15 frystyk 490: {
2.33 frystyk 491: if (WWWTRACE)
2.31 frystyk 492: TTYPrint(TDEST, "HTNet_delete Remove net object %p\n", net);
2.23 frystyk 493: if (net) {
494: int status = 0;
495:
496: /* Free stream with data FROM network to application */
497: if (net->target) {
498: if (status == HT_INTERRUPTED)
499: (*net->target->isa->abort)(net->target, NULL);
500: else
501: (*net->target->isa->_free)(net->target);
502: }
503:
504: /* Close socket */
505: if (net->sockfd != INVSOC) {
2.24 frystyk 506: if (HTDNS_socket(net->dns) == INVSOC) {
507: if ((status = NETCLOSE(net->sockfd)) < 0)
2.33 frystyk 508: HTRequest_addSystemError(net->request, ERR_FATAL,
509: socerrno, NO, "NETCLOSE");
510: if (WWWTRACE)
2.31 frystyk 511: TTYPrint(TDEST, "HTNet_delete closing %d\n", net->sockfd);
2.25 frystyk 512: HTEvent_UnRegister(net->sockfd, (SockOps) FD_ALL);
2.24 frystyk 513: } else {
2.33 frystyk 514: if (WWWTRACE)
2.31 frystyk 515: TTYPrint(TDEST, "HTNet_delete keeping %d\n", net->sockfd);
2.25 frystyk 516: HTDNS_clearActive(net->dns);
517: /* Here we should probably use a low priority */
2.27 frystyk 518: HTEvent_UnRegister(net->sockfd, (SockOps) FD_ALL);
2.25 frystyk 519: HTEvent_Register(net->sockfd, net->request, (SockOps) FD_READ,
520: HTDNS_closeSocket, net->priority);
2.24 frystyk 521: }
2.23 frystyk 522: }
523: if (net->isoc)
524: HTInputSocket_free(net->isoc);
525: if (net->request)
526: net->request->net = NULL; /* Break link to request */
527: free(net);
528: return status ? NO : YES;
529: }
530: return NO;
531: }
532:
533: /* HTNet_delete
534: ** ------------
535: ** Deletes the HTNet object from the list of active requests and calls
536: ** any registered call back functions IF not the status is HT_IGNORE.
537: ** This is used if we have internal requests that the app doesn't know
538: ** about. We also see if we have pending requests that can be started
539: ** up now when we have a socket free.
540: ** The callback functions are called in the reverse order of which they
541: ** were registered (last one first)
2.40 frystyk 542: ** Return YES if OK, else NO
2.23 frystyk 543: */
544: PUBLIC BOOL HTNet_delete (HTNet * net, int status)
545: {
2.33 frystyk 546: if (WWWTRACE)
547: TTYPrint(TDEST,"HTNetDelete. Object and call callback functions\n");
2.23 frystyk 548: if (HTNetActive && net) {
2.36 frystyk 549: SOCKET cs = net->sockfd; /* Current sockfd */
2.23 frystyk 550:
551: /* Remove object and call callback functions */
552: HTRequest *request = net->request;
2.42 ! frystyk 553: if (HTList_removeObject(HTNetActive, (void *) net) != YES)
2.40 frystyk 554: if (WWWTRACE)
2.42 ! frystyk 555: TTYPrint(TDEST, "HTNetDelete. %p not registered!\n", net);
2.23 frystyk 556: delete_object(net, status);
2.33 frystyk 557: HTNetCall_execute(HTAfter, request, status);
2.23 frystyk 558:
2.25 frystyk 559: /*
560: ** See first if we have a persistent request queued up for this socket
561: ** If not then see if there is a pending request
562: */
563: if (HTNetPersistent) {
564: HTList *cur = HTNetPersistent;
565: HTNet *next;
566: while ((next = (HTNet *) HTList_nextObject(cur))) {
567: if (next->sockfd == cs) {
2.33 frystyk 568: if (WWWTRACE)
2.39 frystyk 569: TTYPrint(TDEST, "HTNet delete Launch request %p on WARM socket %d (net object %p)\n",
570: next->request, next->sockfd, next);
2.28 frystyk 571: HTList_addObject(HTNetActive, (void *) next);
572: HTList_removeObject(HTNetPersistent, (void *) next);
2.41 frystyk 573: (*(next->cbf))(next->sockfd, next->request, FD_WRITE);
2.25 frystyk 574: break;
575: }
576: }
577: } else if (HTList_count(HTNetActive) < HTMaxActive &&
578: HTList_count(HTNetPending)) {
2.23 frystyk 579: HTNet *next = (HTNet *) HTList_removeFirstObject(HTNetPending);
580: if (next) {
581: HTList_addObject(HTNetActive, (void *) next);
2.33 frystyk 582: if (WWWTRACE)
2.31 frystyk 583: TTYPrint(TDEST,"HTNet delete launch PENDING request %p\n",
2.23 frystyk 584: next->request);
585: (*(next->cbf))(INVSOC, next->request, FD_NONE);
586: }
587: }
588: return YES;
589: }
590: return NO;
591: }
592:
593: /* HTNet_deleteAll
594: ** ---------------
595: ** Deletes all HTNet object that might either be active or pending
2.25 frystyk 596: ** We DO NOT call the call back functions - A crude way of saying goodbye!
2.23 frystyk 597: */
598: PUBLIC BOOL HTNet_deleteAll (void)
599: {
2.33 frystyk 600: if (WWWTRACE)
2.31 frystyk 601: TTYPrint(TDEST, "HTNetDelete. Remove all Net objects, NO callback\n");
2.25 frystyk 602: if (HTNetPersistent) {
603: HTList *cur = HTNetPersistent;
604: HTNet *pres;
605: while ((pres = (HTNet *) HTList_nextObject(cur))) {
606: pres->sockfd = INVSOC; /* Don't close it more than once */
607: delete_object(pres, HT_INTERRUPTED);
608: }
609: HTList_delete(HTNetPersistent);
610: HTNetPersistent = NULL;
611: }
2.23 frystyk 612: if (HTNetPending) {
613: HTList *cur = HTNetPending;
614: HTNet *pres;
615: while ((pres = (HTNet *) HTList_nextObject(cur)))
616: delete_object(pres, HT_INTERRUPTED);
617: HTList_delete(HTNetPending);
618: HTNetPending = NULL;
619: }
620: if (HTNetActive) {
621: HTList *cur = HTNetActive;
622: HTNet *pres;
623: while ((pres = (HTNet *) HTList_nextObject(cur)))
624: delete_object(pres, HT_INTERRUPTED);
625: HTList_delete(HTNetActive);
626: HTNetActive = NULL;
627: }
628: return NO;
2.15 frystyk 629: }
630:
2.25 frystyk 631: /* HTNet_wait
632: ** ----------
633: ** Let a net object wait for a persistent socket. It will be launched
634: ** from the HTNet_delete() function
2.40 frystyk 635: ** Return YES if OK, else NO
2.25 frystyk 636: */
637: PUBLIC BOOL HTNet_wait (HTNet *net)
638: {
639: if (net) {
2.33 frystyk 640: if (WWWTRACE)
2.40 frystyk 641: TTYPrint(TDEST,"HTNet_wait.. request %p is waiting for presistent socket %d\n",
642: net->request, net->sockfd);
643:
644: /* Take it out of the active queue and add it to persistent queue */
645: if (HTList_removeObject(HTNetActive, (void *) net) != YES) {
646: if (WWWTRACE) TTYPrint(TDEST, "HTNet_wait.. not registered!\n");
647: return NO;
648: }
2.25 frystyk 649: if (!HTNetPersistent) HTNetPersistent = HTList_new();
2.40 frystyk 650: return HTList_addObject(HTNetPersistent, (void *) net);
2.25 frystyk 651: }
652: return NO;
653: }
654:
2.23 frystyk 655: /* ------------------------------------------------------------------------- */
656: /* Killing requests */
657: /* ------------------------------------------------------------------------- */
658:
659: /* HTNet_kill
660: ** ----------
661: ** Kill the request by calling the call back function with a request for
662: ** closing the connection. Does not remove the object. This is done by
663: ** HTNet_delete() function which is called by the load routine.
664: ** Returns OK if success, NO on error
665: */
666: PUBLIC BOOL HTNet_kill (HTNet * me)
667: {
668: if (HTNetActive && me) {
2.25 frystyk 669: HTList *cur = HTNetActive;
2.23 frystyk 670: HTNet *pres;
2.25 frystyk 671: while ((pres = (HTNet *) HTList_nextObject(cur))) {
2.23 frystyk 672: if (pres == me) {
2.25 frystyk 673: (*(pres->cbf))(pres->sockfd, pres->request, FD_CLOSE);
2.23 frystyk 674: return YES;
675: }
676: }
677: }
2.33 frystyk 678: if (WWWTRACE)
2.31 frystyk 679: TTYPrint(TDEST, "HTNet_kill.. object %p is not registered\n", me);
2.23 frystyk 680: return NO;
681: }
682:
683: /* HTNet_killAll
684: ** -------------
685: ** Kills all registered (active+pending) requests by calling the call
686: ** back function with a request for closing the connection. We do not
687: ** remove the HTNet object as it is done by HTNet_delete().
688: ** Returns OK if success, NO on error
689: */
690: PUBLIC BOOL HTNet_killAll (void)
691: {
692: HTNet *pres;
2.33 frystyk 693: if (WWWTRACE)
2.31 frystyk 694: TTYPrint(TDEST, "HTNet_kill.. ALL registered requests!!!\n");
2.23 frystyk 695:
2.25 frystyk 696: /* We start off in persistent queue so we avoid racing */
697: if (HTNetPersistent) {
698: while ((pres = (HTNet *) HTList_lastObject(HTNetPersistent)) != NULL) {
699: pres->sockfd = INVSOC;
700: (*(pres->cbf))(pres->sockfd, pres->request, FD_CLOSE);
701: HTList_removeObject(HTNetPersistent, pres);
702: }
703: }
2.23 frystyk 704: if (HTNetPending) {
705: while ((pres = (HTNet *) HTList_lastObject(HTNetPending)) != NULL) {
2.25 frystyk 706: (*(pres->cbf))(pres->sockfd, pres->request, FD_CLOSE);
2.23 frystyk 707: HTList_removeObject(HTNetPending, pres);
708: }
709: }
710: if (HTNetActive) {
711: while ((pres = (HTNet *) HTList_lastObject(HTNetActive)) != NULL)
2.25 frystyk 712: (*(pres->cbf))(pres->sockfd, pres->request, FD_CLOSE);
2.23 frystyk 713: }
714: return YES;
715: }
2.38 frystyk 716:
717: /* ------------------------------------------------------------------------- */
718: /* Data Access Methods */
719: /* ------------------------------------------------------------------------- */
720:
721: /*
722: ** Get and set the socket number
723: */
724: PUBLIC BOOL HTNet_setSocket (HTNet * net, SOCKET sockfd)
725: {
726: if (net) {
727: net->sockfd = sockfd;
728: return YES;
729: }
730: return NO;
731: }
732:
733: PUBLIC SOCKET HTNet_socket (HTNet * net)
734: {
735: return (net ? net->sockfd : INVSOC);
736: }
737:
Webmaster