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