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