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