1 /* HTNet.c
2 ** HTNet Class
3 **
4 ** (c) COPYRIGHT MIT 1995.
5 ** Please first read the full copyright statement in the file COPYRIGH.
6 ** @(#) $Id$
7 **
8 ** This is the implementation of the internal library multithreading
9 ** functions. This includes an interrupt handler and a event loop.
10 **
11 ** History:
12 ** 12 June 94 Written by Henrik Frystyk, frystyk@w3.org
13 ** 31 May 95 Charlie Brooks cbrooks@osf.org
14 **
15 */
16
17 /* Implemention dependent include files */
18 #include "wwwsys.h"
19
20 /* Library include files */
21 #include "WWWUtil.h"
22 #include "HTProt.h"
23 #include "HTError.h"
24 #include "HTAlert.h"
25 #include "HTParse.h"
26 #include "HTTrans.h"
27 #include "HTHost.h"
28 #include "HTReq.h"
29 #include "HTEvent.h"
30 #include "HTStream.h"
31 #include "HTHstMan.h"
32 #include "HTIOStream.h"
33 #include "HTNetMan.h" /* Implemented here */
34
35 #ifndef HT_MAX_SOCKETS
36 #define HT_MAX_SOCKETS 25
37 #endif
38
39 typedef struct _BeforeFilter {
40 HTNetBefore * before; /* Filter function */
41 char * tmplate; /* URL template for when to call filter */
42 int order; /* Relative execution order */
43 void * param; /* Local context */
44 } BeforeFilter;
45
46 typedef struct _AfterFilter {
47 HTNetAfter * after; /* Filter function */
48 char * tmplate; /* URL template for when to call filter */
49 int order; /* Relative execution order */
50 void * param; /* Local context */
51 int status; /* Status of load for when to call filter */
52 } AfterFilter;
53
54 struct _HTStream {
55 const HTStreamClass * isa;
56 /* ... */
57 };
58
59 struct _HTInputStream {
60 const HTInputStreamClass * isa;
61 /* ... */
62 };
63
64 typedef struct _HTFilterEvent {
65 HTRequest * request;
66 int status;
67 HTTimer * timer;
68 } HTFilterEvent;
69
70 PRIVATE HTList * HTBefore = NULL; /* List of global BEFORE filters */
71 PRIVATE HTList * HTAfter = NULL; /* List of global AFTER filters */
72
73 PRIVATE int MaxActive = HT_MAX_SOCKETS; /* Max active requests */
74 PRIVATE int Active = 0; /* Counts open sockets */
75 PRIVATE int Persistent = 0; /* Counts persistent sockets */
76
77 PRIVATE HTList ** NetTable = NULL; /* List of net objects */
78 PRIVATE int HTNetCount = 0; /* Counting elements in table */
79
80 /* ------------------------------------------------------------------------- */
81 /* GENERIC BEFORE and AFTER filter Management */
82 /* ------------------------------------------------------------------------- */
83
HTBeforeOrder(const void * a,const void * b)84 PRIVATE int HTBeforeOrder (const void * a, const void * b)
85 {
86 return ((BeforeFilter *) b)->order - ((BeforeFilter *) a)->order;
87 }
88
HTAfterOrder(const void * a,const void * b)89 PRIVATE int HTAfterOrder (const void * a, const void * b)
90 {
91 return ((AfterFilter *) b)->order - ((AfterFilter *) a)->order;
92 }
93
check_order(HTFilterOrder order)94 PRIVATE int check_order (HTFilterOrder order)
95 {
96 return (order<HT_FILTER_FIRST) ? HT_FILTER_FIRST :
97 (order>HT_FILTER_LAST) ? HT_FILTER_LAST : order;
98 }
99
100 /*
101 ** Register a BEFORE filter in the list provided by the caller.
102 ** Several filters can be registered in which case they are called
103 ** with the filter ordering in mind.
104 */
HTNetCall_addBefore(HTList * list,HTNetBefore * before,const char * tmplate,void * param,HTFilterOrder order)105 PUBLIC BOOL HTNetCall_addBefore (HTList * list, HTNetBefore * before,
106 const char * tmplate, void * param,
107 HTFilterOrder order)
108 {
109 if (list && before) {
110 BeforeFilter * me;
111 if ((me = (BeforeFilter *) HT_CALLOC(1, sizeof(BeforeFilter)))==NULL)
112 HT_OUTOFMEM("HTNetCall_addBefore");
113 me->before = before;
114 if (tmplate) StrAllocCopy(me->tmplate, tmplate);
115 me->order = check_order(order);
116 me->param = param;
117 HTTRACE(CORE_TRACE, "Net Before.. Add %p with order %d tmplate `%s\' context %p\n" _
118 before _ me->order _ tmplate ? tmplate : "<null>" _ param);
119 return (HTList_addObject(list, me) &&
120 HTList_insertionSort(list, HTBeforeOrder));
121 }
122 return NO;
123 }
124
125 /*
126 ** Unregister all instances of a BEFORE filter from a list.
127 */
HTNetCall_deleteBefore(HTList * list,HTNetBefore * before)128 PUBLIC BOOL HTNetCall_deleteBefore (HTList * list, HTNetBefore * before)
129 {
130 HTTRACE(CORE_TRACE, "Net Before.. Delete %p\n" _ before);
131 if (list && before) {
132 HTList * cur = list;
133 BeforeFilter * pres;
134 while ((pres = (BeforeFilter *) HTList_nextObject(cur))) {
135 if (pres->before == before) {
136 HTList_removeObject(list, (void *) pres);
137 HT_FREE(pres->tmplate);
138 HT_FREE(pres);
139 cur = list;
140 }
141 }
142 }
143 return NO;
144 }
145
146 /*
147 ** Deletes all BEFORE filters in list
148 */
HTNetCall_deleteBeforeAll(HTList * list)149 PUBLIC BOOL HTNetCall_deleteBeforeAll (HTList * list)
150 {
151 HTTRACE(CORE_TRACE, "Net Before. Delete All filters\n");
152 if (list) {
153 HTList * cur = list;
154 BeforeFilter * pres;
155 while ((pres = (BeforeFilter *) HTList_nextObject(cur))) {
156 HT_FREE(pres->tmplate);
157 HT_FREE(pres);
158 }
159 HTList_delete(list);
160 return YES;
161 }
162 return NO;
163 }
164
165 /*
166 ** Call all the BEFORE filters in the order specified at registration
167 ** time. We also check for any template and whether it matches or not.
168 ** If a filter returns other than HT_OK then stop and return immediately.
169 ** Otherwise return what the last filter returns.
170 */
HTNetCall_executeBefore(HTList * list,HTRequest * request)171 PUBLIC int HTNetCall_executeBefore (HTList * list, HTRequest * request)
172 {
173 HTParentAnchor * anchor = HTRequest_anchor(request);
174 char * url = HTAnchor_physical(anchor);
175 char * addr = url ? url : HTAnchor_address((HTAnchor *) anchor);
176 int ret = HT_OK;
177 int mode = 0;
178 if (list && request && addr) {
179 BeforeFilter * pres;
180 while ((pres = (BeforeFilter *) HTList_nextObject(list))) {
181 if (!pres->tmplate ||
182 (pres->tmplate && HTStrMatch(pres->tmplate, addr))) {
183 HTTRACE(CORE_TRACE, "Net Before.. calling %p (request %p, context %p)\n" _
184 pres->before _
185 request _ pres->param);
186 ret = (*pres->before)(request, pres->param, mode);
187 if (ret != HT_OK) break;
188
189 /*
190 ** Update the address to match against if the filter changed
191 ** the physical address.
192 */
193 if ((url = HTAnchor_physical(anchor))) addr = url;
194 }
195 }
196 }
197 if (!url) HT_FREE(addr);
198 return ret;
199 }
200
201 /*
202 ** Register an AFTER filter in the list provided by the caller.
203 ** Several filters can be registered in which case they are called
204 ** with the filter ordering in mind.
205 */
HTNetCall_addAfter(HTList * list,HTNetAfter * after,const char * tmplate,void * param,int status,HTFilterOrder order)206 PUBLIC BOOL HTNetCall_addAfter (HTList * list, HTNetAfter * after,
207 const char * tmplate, void * param,
208 int status, HTFilterOrder order)
209 {
210 if (list && after) {
211 AfterFilter * me;
212 if ((me = (AfterFilter *) HT_CALLOC(1, sizeof(AfterFilter)))==NULL)
213 HT_OUTOFMEM("HTNetCall_addAfter");
214 me->after = after;
215 if (tmplate) StrAllocCopy(me->tmplate, tmplate);
216 me->order = check_order(order);
217 me->param = param;
218 me->status = status;
219 HTTRACE(CORE_TRACE, "Net After... Add %p with order %d tmplate `%s\' code %d context %p\n" _
220 after _ me->order _ tmplate ? tmplate : "<null>" _ status _ param);
221 return (HTList_addObject(list, me) &&
222 HTList_insertionSort(list, HTAfterOrder));
223 }
224 return NO;
225 }
226
227 /*
228 ** Unregister all instances of an AFTER filter from a list.
229 */
HTNetCall_deleteAfter(HTList * list,HTNetAfter * after)230 PUBLIC BOOL HTNetCall_deleteAfter (HTList * list, HTNetAfter * after)
231 {
232 HTTRACE(CORE_TRACE, "Net After... Delete %p\n" _ after);
233 if (list && after) {
234 HTList * cur = list;
235 AfterFilter * pres;
236 while ((pres = (AfterFilter *) HTList_nextObject(cur))) {
237 if (pres->after == after) {
238 HTList_removeObject(list, (void *) pres);
239 HT_FREE(pres->tmplate);
240 HT_FREE(pres);
241 cur = list;
242 }
243 }
244 }
245 return NO;
246 }
247
248 /*
249 ** Unregister all filters registered for a given status.
250 */
HTNetCall_deleteAfterStatus(HTList * list,int status)251 PUBLIC BOOL HTNetCall_deleteAfterStatus (HTList * list, int status)
252 {
253 HTTRACE(CORE_TRACE, "Net After... Delete all with status %d\n" _ status);
254 if (list) {
255 HTList * cur = list;
256 AfterFilter * pres;
257 while ((pres = (AfterFilter *) HTList_nextObject(cur))) {
258 if (pres->status == status) {
259 HTList_removeObject(list, (void *) pres);
260 HT_FREE(pres->tmplate);
261 HT_FREE(pres);
262 cur = list;
263 }
264 }
265 return YES;
266 }
267 return NO;
268 }
269
270 /*
271 ** Deletes all AFTER filters in list
272 */
HTNetCall_deleteAfterAll(HTList * list)273 PUBLIC BOOL HTNetCall_deleteAfterAll (HTList * list)
274 {
275 HTTRACE(CORE_TRACE, "Net After. Delete All filters\n");
276 if (list) {
277 HTList * cur = list;
278 AfterFilter * pres;
279 while ((pres = (AfterFilter *) HTList_nextObject(cur))) {
280 HT_FREE(pres->tmplate);
281 HT_FREE(pres);
282 }
283 HTList_delete(list);
284 return YES;
285 }
286 return NO;
287 }
288
289 /*
290 ** Call all the AFTER filters in the order specified at registration
291 ** time and if it has the right status code and it's not HT_IGNORE.
292 ** We also check for any template and whether it matches or not.
293 ** If a filter returns other than HT_OK then stop and return immediately.
294 ** Otherwise return what the last filter returns.
295 */
HTNetCall_executeAfter(HTList * list,HTRequest * request,int status)296 PUBLIC int HTNetCall_executeAfter (HTList * list, HTRequest * request,
297 int status)
298 {
299 int ret = HT_OK;
300 if (status != HT_IGNORE) {
301 HTParentAnchor * anchor = HTRequest_anchor(request);
302 char * url = HTAnchor_physical(anchor);
303 char * addr = url ? url : HTAnchor_address((HTAnchor *) anchor);
304 HTResponse * response = HTRequest_response(request);
305 if (list && request && addr) {
306 AfterFilter * pres;
307 while ((pres = (AfterFilter *) HTList_nextObject(list))) {
308 if ((pres->status == status || pres->status == HT_ALL) &&
309 (!pres->tmplate ||
310 (pres->tmplate && HTStrMatch(pres->tmplate, addr)))) {
311 HTTRACE(CORE_TRACE, "Net After... calling %p (request %p, response %p, status %d, context %p)\n" _
312 pres->after _ request _ response _
313 status _ pres->param);
314 ret = (*pres->after)(request, response, pres->param, status);
315 if (ret != HT_OK) break;
316
317 /*
318 ** Update the address to match against if the filter changed
319 ** the physical address.
320 */
321 if ((url = HTAnchor_physical(anchor))) addr = url;
322 }
323 }
324 }
325 if (!url) HT_FREE(addr);
326 }
327 return ret;
328 }
329
330 /* ------------------------------------------------------------------------- */
331 /* GLOBAL BEFORE and AFTER filter Management */
332 /* ------------------------------------------------------------------------- */
333
334 /*
335 ** Global set of callback functions BEFORE the request is issued
336 ** list can be NULL
337 */
HTNet_setBefore(HTList * list)338 PUBLIC BOOL HTNet_setBefore (HTList *list)
339 {
340 HTBefore = list;
341 return YES;
342 }
343
HTNet_before(void)344 PUBLIC HTList * HTNet_before (void)
345 {
346 return HTBefore;
347 }
348
HTNet_addBefore(HTNetBefore * before,const char * tmplate,void * param,HTFilterOrder order)349 PUBLIC BOOL HTNet_addBefore (HTNetBefore * before, const char * tmplate,
350 void * param, HTFilterOrder order)
351 {
352 if (!HTBefore) HTBefore = HTList_new();
353 else HTNet_deleteBefore(before); /* Ensure not listed twice */
354 return HTNetCall_addBefore(HTBefore, before, tmplate, param, order);
355 }
356
HTNet_deleteBefore(HTNetBefore * cbf)357 PUBLIC BOOL HTNet_deleteBefore (HTNetBefore * cbf)
358 {
359 return HTNetCall_deleteBefore(HTBefore, cbf);
360 }
361
362 /*
363 ** Call both the local and the global BEFORE filters (if any)
364 */
HTNet_executeBeforeAll(HTRequest * request)365 PUBLIC int HTNet_executeBeforeAll (HTRequest * request)
366 {
367 int ret;
368 BOOL override = NO;
369 HTList * befores;
370 if ((befores = HTRequest_before(request, &override))) {
371 if ((ret = HTNetCall_executeBefore(befores, request)) != HT_OK)
372 return ret;
373 }
374 return override ? HT_OK : HTNetCall_executeBefore(HTBefore, request);
375 }
376
377 /*
378 ** Global set of callback functions AFTER the request is issued
379 ** list can be NULL
380 */
HTNet_setAfter(HTList * list)381 PUBLIC BOOL HTNet_setAfter (HTList *list)
382 {
383 HTAfter = list;
384 return YES;
385 }
386
HTNet_after(void)387 PUBLIC HTList * HTNet_after (void)
388 {
389 return HTAfter;
390 }
391
HTNet_addAfter(HTNetAfter * after,const char * tmplate,void * param,int status,HTFilterOrder order)392 PUBLIC BOOL HTNet_addAfter (HTNetAfter * after, const char * tmplate,
393 void * param, int status, HTFilterOrder order)
394 {
395 if (!HTAfter) HTAfter = HTList_new();
396 else HTNet_deleteAfter(after); /* Ensure not listed twice */
397 return HTNetCall_addAfter(HTAfter, after, tmplate, param, status, order);
398 }
399
HTNet_deleteAfter(HTNetAfter * cbf)400 PUBLIC BOOL HTNet_deleteAfter (HTNetAfter * cbf)
401 {
402 return HTNetCall_deleteAfter(HTAfter, cbf);
403 }
404
HTNet_deleteAfterStatus(int status)405 PUBLIC BOOL HTNet_deleteAfterStatus (int status)
406 {
407 return HTNetCall_deleteAfterStatus(HTAfter, status);
408 }
409
410 /*
411 ** Call both the local and the global AFTER filters (if any)
412 */
HTNet_executeAfterAll(HTRequest * request,int status)413 PUBLIC int HTNet_executeAfterAll (HTRequest * request, int status)
414 {
415 int ret;
416 BOOL override = NO;
417 HTList * afters;
418 if ((afters = HTRequest_after(request, &override))) {
419 if ((ret = HTNetCall_executeAfter(afters, request, status)) != HT_OK)
420 return ret;
421 }
422 return override ? HT_OK : HTNetCall_executeAfter(HTAfter, request, status);
423 }
424
425 /* ------------------------------------------------------------------------- */
426 /* Socket Management */
427 /* ------------------------------------------------------------------------- */
428
HTNet_maxSocket(void)429 PUBLIC int HTNet_maxSocket (void)
430 {
431 return MaxActive;
432 }
433
HTNet_setMaxSocket(int newmax)434 PUBLIC BOOL HTNet_setMaxSocket (int newmax)
435 {
436 if (newmax > 0) {
437 MaxActive = newmax;
438 return YES;
439 }
440 return NO;
441 }
442
HTNet_increaseSocket(void)443 PUBLIC void HTNet_increaseSocket (void)
444 {
445 Active++;
446 HTTRACE(CORE_TRACE, "Net Manager. Increasing active sockets to %d, %d persistent sockets\n" _
447 Active _ Persistent);
448 }
449
HTNet_decreaseSocket(void)450 PUBLIC void HTNet_decreaseSocket (void)
451 {
452 if (--Active < 0) Active = 0;
453 HTTRACE(CORE_TRACE, "Net Manager. Decreasing active sockets to %d, %d persistent sockets\n" _
454 Active _ Persistent);
455 }
456
HTNet_availableSockets(void)457 PUBLIC int HTNet_availableSockets (void)
458 {
459 int available = MaxActive - Active;
460 return available > 0 ? available : 0;
461 }
462
HTNet_increasePersistentSocket(void)463 PUBLIC void HTNet_increasePersistentSocket (void)
464 {
465 Persistent++;
466 HTTRACE(CORE_TRACE, "Net Manager. %d active sockets, increasing persistent sockets to %d\n" _
467 Active _ Persistent);
468 }
469
HTNet_decreasePersistentSocket(void)470 PUBLIC void HTNet_decreasePersistentSocket (void)
471 {
472 if (--Persistent < 0) Persistent = 0;
473 HTTRACE(CORE_TRACE, "Net Manager. %d active sockets, decreasing persistent sockets to %d\n" _
474 Active _ Persistent);
475 }
476
HTNet_availablePersistentSockets(void)477 PUBLIC int HTNet_availablePersistentSockets (void)
478 {
479 int available = MaxActive - 2 - Persistent;
480 return available > 0 ? available : 0;
481 }
482
483 /*
484 ** Returns whether there are any Net objects pending or active
485 */
HTNet_isIdle(void)486 PUBLIC BOOL HTNet_isIdle (void)
487 {
488 return (HTNetCount > 0);
489 }
490
HTNet_isEmpty(void)491 PUBLIC BOOL HTNet_isEmpty (void)
492 {
493 return (HTNetCount <= 0);
494 }
495
HTNet_count(void)496 PUBLIC int HTNet_count (void)
497 {
498 return HTNetCount;
499 }
500
501 /* ------------------------------------------------------------------------- */
502 /* Creation and deletion methods */
503 /* ------------------------------------------------------------------------- */
504
AfterFilterEvent(HTTimer * timer,void * param,HTEventType type)505 PRIVATE int AfterFilterEvent (HTTimer * timer, void * param, HTEventType type)
506 {
507 HTFilterEvent * fe = (HTFilterEvent *) param;
508 if (fe) {
509 HTRequest * request = fe->request;
510 int status = fe->status;
511 if (timer != fe->timer)
512 HTDEBUGBREAK("Net timer. %p not in sync\n" _ timer);
513 HTTRACE(CORE_TRACE, "HTNet....... Continuing calling AFTER filters %p with timer %p\n" _
514 fe _ timer);
515
516 /* Delete the event context */
517 HT_FREE(fe);
518
519 /* Now call the remaining AFTER filters */
520 return HTNet_executeAfterAll(request, status);
521 }
522 return HT_ERROR;
523 }
524
createAfterFilterEvent(HTRequest * request,int status)525 PRIVATE BOOL createAfterFilterEvent (HTRequest * request, int status)
526 {
527 HTFilterEvent * me = NULL;
528 if ((me = (HTFilterEvent *) HT_CALLOC(1, sizeof(HTFilterEvent))) == NULL)
529 HT_OUTOFMEM("createAfterFilterEvent");
530 me->request = request;
531 me->status = status;
532 me->timer = HTTimer_new(NULL, AfterFilterEvent, me, 1, YES, NO);
533 return YES;
534 }
535
create_object(void)536 PRIVATE HTNet * create_object (void)
537 {
538 static int net_hash = 0;
539 HTNet * me = NULL;
540
541 /* Create new object */
542 if ((me = (HTNet *) HT_CALLOC(1, sizeof(HTNet))) == NULL)
543 HT_OUTOFMEM("HTNet_new");
544 me->hash = net_hash++ % HT_XL_HASH_SIZE;
545
546 /* Insert into hash table */
547 if (!NetTable) {
548 if ((NetTable = (HTList **) HT_CALLOC(HT_XL_HASH_SIZE, sizeof(HTList *))) == NULL)
549 HT_OUTOFMEM("create_object");
550 }
551 if (!NetTable[me->hash]) NetTable[me->hash] = HTList_new();
552 HTList_addObject(NetTable[me->hash], (void *) me);
553 HTNetCount++;
554 HTTRACE(CORE_TRACE, "Net Object.. %p created with hash %d\n" _ me _ me->hash);
555 return me;
556 }
557
558 /* HTNet_duplicate
559 ** ---------------
560 ** Creates a new HTNet object as a duplicate of the same request.
561 ** Returns YES if OK, else NO
562 ** BUG: We do not check if we have a socket free!
563 */
HTNet_dup(HTNet * src)564 PUBLIC HTNet * HTNet_dup (HTNet * src)
565 {
566 if (src) {
567 HTNet * me;
568 int hash;
569 if ((me = create_object()) == NULL) return NULL;
570 hash = me->hash;
571 HTTRACE(CORE_TRACE, "Net Object.. Duplicated %p\n" _ src);
572 memcpy((void *) me, src, sizeof(HTNet));
573 me->hash = hash; /* Carry over hash entry */
574 return me;
575 }
576 return NULL;
577 }
578
HTNet_execute(HTNet * net,HTEventType type)579 PUBLIC BOOL HTNet_execute (HTNet * net, HTEventType type)
580 {
581 if (net && net->event.cbf && net->request) {
582 HTTRACE(CORE_TRACE, "Net Object.. %p calling %p with event type %d and context %p\n" _
583 net _ net->event.cbf _ type _ net->event.param);
584 (*(net->event.cbf))(HTNet_socket(net), net->event.param, type);
585 return YES;
586 }
587 return NO;
588 }
589
590 /*
591 ** Start a Net obejct by calling the protocol module.
592 */
HTNet_start(HTNet * net)593 PUBLIC BOOL HTNet_start (HTNet * net)
594 {
595 if (net && net->event.cbf && net->request) {
596 HTTRACE(CORE_TRACE, "Net Object.. Launching %p\n" _ net);
597 (*(net->event.cbf))(HTNet_socket(net), net->event.param, HTEvent_BEGIN);
598 return YES;
599 }
600 return NO;
601 }
602
603 /* HTNet_new
604 ** ---------
605 ** This function creates a new HTNet object and assigns the socket number
606 ** to it. This is intended to be used when you are going to listen on a
607 ** socket using the HTDoListen() function in HTTCP.c. The function do NOT
608 ** call any of the before or after filter functions.
609 ** Returns new object or NULL on error
610 */
HTNet_new(HTHost * host)611 PUBLIC HTNet * HTNet_new (HTHost * host)
612 {
613 if (host) {
614 HTNet * me;
615 HTTRACE(CORE_TRACE, "Net Object.. Creating listen object for host %p\n" _ host);
616 me = create_object();
617 me->host = host;
618 return me;
619 }
620 return NULL;
621 }
622
623 /* HTNet_newServer
624 ** ---------------
625 ** Create a new HTNet object as a new request to be handled. If we have
626 ** more than MaxActive connections already then return NO.
627 ** Returns YES if OK, else NO
628 */
HTNet_newServer(HTRequest * request)629 PUBLIC BOOL HTNet_newServer (HTRequest * request)
630 {
631 HTParentAnchor * anchor = HTRequest_anchor(request);
632 HTNet * me = NULL;
633 HTProtocol * protocol;
634 HTTransport * tp = NULL; /* added JTD:5/28/96 */
635 char * physical = NULL;
636 int status;
637 HTProtCallback * cbf;
638
639 if (!request) return NO;
640
641 /*
642 ** First we do all the "BEFORE" callbacks in order to see if we are to
643 ** continue with this request or not. If we receive a callback status
644 ** that is NOT HT_OK then jump directly to the after callbacks and return
645 */
646 if ((status = HTNet_executeBeforeAll(request)) != HT_OK) {
647
648 /*
649 ** If in non-blocking mode then return here and call AFTER
650 ** filters from a timer event handler. As Olga Antropova
651 ** points out, otherwise, the stack can grow if new requests
652 ** are started directly from the after filters
653 */
654 if (HTEvent_isCallbacksRegistered() && !HTRequest_preemptive(request))
655 createAfterFilterEvent(request, status);
656 else
657 HTNet_executeAfterAll(request, status);
658 return YES;
659 }
660
661 /*
662 ** If no translation was provided by the filters then use the anchor
663 ** address directly
664 */
665 if (!(physical = HTAnchor_physical(anchor))) {
666 char * addr = HTAnchor_address((HTAnchor *) anchor);
667 HTTRACE(CORE_TRACE, "Net Object.. Using default address\n");
668 HTAnchor_setPhysical(anchor, addr);
669 physical = HTAnchor_physical(anchor);
670 HT_FREE(addr);
671 }
672
673 /* Find a protocol object for this access scheme */
674 {
675 char * access = HTParse(physical, "", PARSE_ACCESS);
676 if ((protocol = HTProtocol_find(request, access)) == NULL) {
677 HTTRACE(CORE_TRACE, "Net Object.. NO PROTOCOL Object found for URI scheme `%s\'\n" _ access);
678 HT_FREE(access);
679 return NO;
680 }
681 if (!(cbf = HTProtocol_server(protocol))) {
682 HTTRACE(CORE_TRACE, "Net Object.. NO SERVER HANDLER for URI scheme `%s\'\n" _ access);
683 HT_FREE(access);
684 HT_FREE(me);
685 return NO;
686 }
687 HT_FREE(access);
688 }
689
690 /* Find a transport object for this protocol */
691 if ((tp = HTTransport_find(request, HTProtocol_transport(protocol))) == NULL) {
692 HTTRACE(CORE_TRACE, "Net Object.. NO TRANSPORT found for protocol `%s\'\n" _ HTProtocol_name(protocol));
693 return NO;
694 }
695
696 /* Create new net object and bind to request object */
697 if ((me = create_object()) == NULL) return NO;
698 me->preemptive = (HTProtocol_preemptive(protocol) || HTRequest_preemptive(request));
699 HTNet_setEventPriority(me, HTRequest_priority(request));
700 me->protocol = protocol;
701 me->transport = tp; /* added - JTD:5/28/96 */
702 me->request = request;
703 HTRequest_setNet(request, me);
704
705 /* Start the server request */
706 HTTRACE(CORE_TRACE, "Net Object.. starting SERVER request %p and net object %p\n" _ request _ me);
707 (*(cbf))(INVSOC, request);
708 return YES;
709 }
710
711 /* HTNet_newClient
712 ** ---------------
713 ** Create a new HTNet object as a new request to be handled. If we have
714 ** more than MaxActive connections already then put this into the
715 ** pending queue, else start the request by calling the call back
716 ** function registered with this access method.
717 ** Returns YES if OK, else NO
718 */
HTNet_newClient(HTRequest * request)719 PUBLIC BOOL HTNet_newClient (HTRequest * request)
720 {
721 HTParentAnchor * anchor = HTRequest_anchor(request);
722 HTNet * me = NULL;
723 HTProtocol * protocol = NULL;
724 HTTransport * tp = NULL;
725 char * physical = NULL;
726 int status;
727 HTProtCallback * cbf;
728
729 if (!request) return NO;
730
731 /*
732 ** First we do all the "BEFORE" callbacks in order to see if we are to
733 ** continue with this request or not. If we receive a callback status
734 ** that is NOT HT_OK then jump directly to the after callbacks and return
735 */
736 if ((status = HTNet_executeBeforeAll(request)) != HT_OK) {
737
738 /*
739 ** If in non-blocking mode then return here and call AFTER
740 ** filters from a timer event handler. As Olga Antropova
741 ** points out, otherwise, the stack can grow if new requests
742 ** are started directly from the after filters
743 */
744 if (HTEvent_isCallbacksRegistered() && !HTRequest_preemptive(request))
745 createAfterFilterEvent(request, status);
746 else
747 HTNet_executeAfterAll(request, status);
748 return YES;
749 }
750
751 /*
752 ** If no translation was provided by the filters then use the anchor
753 ** address directly
754 */
755 if (!(physical = HTAnchor_physical(anchor))) {
756 char * addr = HTAnchor_address((HTAnchor *) anchor);
757 HTTRACE(CORE_TRACE, "Net Object.. Using default address\n");
758 HTAnchor_setPhysical(anchor, addr);
759 physical = HTAnchor_physical(anchor);
760 HT_FREE(addr);
761 }
762
763 /* Find a protocol object for this access scheme */
764 {
765 char * proxy = HTRequest_proxy(request);
766 char * access = HTParse(proxy ? proxy : physical, "", PARSE_ACCESS);
767 if ((protocol = HTProtocol_find(request, access)) == NULL) {
768 HTTRACE(CORE_TRACE, "Net Object.. NO PROTOCOL Object found for URI scheme `%s\'\n" _ access);
769 HT_FREE(access);
770 return NO;
771 }
772 if (!(cbf = HTProtocol_client(protocol))) {
773 HTTRACE(CORE_TRACE, "Net Object.. NO CLIENT HANDLER for URI scheme `%s\'\n" _ access);
774 HT_FREE(access);
775 HT_FREE(me);
776 return NO;
777 }
778 HT_FREE(access);
779 }
780
781 /* Find a transport object for this protocol */
782 tp = HTTransport_find(request, HTProtocol_transport(protocol));
783 if (tp == NULL) {
784 HTTRACE(CORE_TRACE, "Net Object.. NO TRANSPORT found for protocol `%s\'\n" _ HTProtocol_name(protocol));
785 return NO;
786 }
787
788 /* Create new net object and bind it to the request object */
789 if ((me = create_object()) == NULL) return NO;
790 me->preemptive = (HTProtocol_preemptive(protocol) || HTRequest_preemptive(request));
791 #if 0
792 me->priority = HTRequest_priority(request);
793 #endif
794 HTNet_setEventPriority(me, HTRequest_priority(request));
795 me->protocol = protocol;
796 me->transport = tp;
797 me->request = request;
798 HTRequest_setNet(request, me);
799
800 /* Increase the number of retrys for this download */
801 HTRequest_addRetry(request);
802
803 /*
804 ** Check if we can start the request, else put it into pending queue
805 ** If so then call the call back function associated with the anchor.
806 ** We use the INVSOC as we don't have a valid socket yet!
807 */
808 HTTRACE(CORE_TRACE, "Net Object.. starting request %p (retry=%d) with net object %p\n" _
809 request _ HTRequest_retrys(request) _ me);
810 (*(cbf))(INVSOC, request);
811 return YES;
812 }
813
814 /*
815 ** Check whether we have any pending HTNet objects and if so
816 ** then start the next one.
817 ** Return YES if OK, else NO
818 */
check_pending(HTNet * net)819 PRIVATE BOOL check_pending (HTNet * net)
820 {
821 HTTRACE(CORE_TRACE, "Net Object.. Check for pending Net objects\n");
822 if (net) {
823
824 /*
825 ** As we may have a socket available we check for whether
826 ** we can start any pending requests. We do this by asking for
827 ** pending Host objects. If none then use the current object
828 */
829 HTHost_launchPending(net->host);
830
831 return YES;
832 }
833 return NO;
834 }
835
free_net(HTNet * net)836 PRIVATE BOOL free_net (HTNet * net)
837 {
838 HTTRACE(CORE_TRACE, "Net Object.. Freeing object %p\n" _ net);
839 if (net) {
840 if (net == HTRequest_net(net->request)) HTRequest_setNet(net->request, NULL);
841 HT_FREE(net);
842 return YES;
843 }
844 return NO;
845 }
846
847 /*
848 ** Unregister the net object from the global list
849 ** and see if we can start a new pending request.
850 */
unregister_net(HTNet * net)851 PRIVATE BOOL unregister_net (HTNet * net)
852 {
853 if (net && NetTable) {
854 HTList * list = NetTable[net->hash];
855 if (list) {
856 HTList_removeObject(list, (void *) net);
857 check_pending(net);
858 HTNetCount--;
859 return YES;
860 }
861 }
862 return NO;
863 }
864
865 /*
866 ** Clears the contents of the Net object so that we can use it again.
867 */
HTNet_clear(HTNet * net)868 PUBLIC BOOL HTNet_clear (HTNet * net)
869 {
870 if (net) {
871 net->host->channel = NULL;
872 net->readStream = NULL;
873 net->bytesRead = 0;
874 net->headerBytesRead = 0;
875 net->bytesWritten = 0;
876 net->headerBytesWritten = 0;
877 return YES;
878 }
879 return NO;
880 }
881
882 /* HTNet_delete
883 ** ------------
884 ** Deletes the HTNet object from the list of active requests and calls
885 ** any registered call back functions IF not the status is HT_IGNORE.
886 ** This is used if we have internal requests that the app doesn't know
887 ** about. We also see if we have pending requests that can be started
888 ** up now when we have a socket free.
889 ** The callback functions are called in the reverse order of which they
890 ** were registered (last one first)
891 ** Return YES if OK, else NO
892 */
HTNet_delete(HTNet * net,int status)893 PUBLIC BOOL HTNet_delete (HTNet * net, int status)
894 {
895 HTTRACE(CORE_TRACE, "Net Object.. Delete %p and call AFTER filters\n" _ net);
896 if (net) {
897 HTRequest * request = net->request;
898
899 /*
900 ** If we have a premature close then recover the request. Otherwise
901 ** break the link to the Host object and continue deleting the net
902 ** object
903 */
904 if (net->host) {
905 HTHost_unregister (net->host, net, HTEvent_READ);
906 HTHost_unregister (net->host, net, HTEvent_WRITE);
907 if (status == HT_RECOVER_PIPE) {
908 HTNet_clear(net);
909 HTTRACE(CORE_TRACE, "Net Object.. Restarting request %p (retry=%d) with net object %p\n" _
910 request _ HTRequest_retrys(request) _ net);
911 return YES;
912 }
913 HTHost_deleteNet(net->host, net, status);
914 if (HTHost_doRecover(net->host)) HTHost_recoverPipe(net->host);
915 }
916
917 /* Remove object from the table of Net Objects */
918 unregister_net(net);
919 free_net(net);
920
921 /* Call AFTER filters */
922 if (status != HT_IGNORE) HTNet_executeAfterAll(request, status);
923
924 /*
925 ** Truely delete the HTNet object. Thanks to Mikhail Grouchinski
926 ** we now do this after having called the after filters so that
927 ** these filters can use the information in the Net object
928 */
929
930 return YES;
931 }
932 return NO;
933 }
934
HTNet_deleteDup(HTNet * dup)935 PUBLIC BOOL HTNet_deleteDup (HTNet * dup)
936 {
937 return dup ? (unregister_net(dup) && free_net(dup)) : NO;
938 }
939
940 /* HTNet_deleteAll
941 ** ---------------
942 ** Deletes all HTNet object that might either be active or pending
943 ** We DO NOT call the AFTER filters - A crude way of saying goodbye!
944 */
HTNet_deleteAll(void)945 PUBLIC BOOL HTNet_deleteAll (void)
946 {
947 HTTRACE(CORE_TRACE, "Net Object.. Remove all Net objects, NO filters\n");
948 if (NetTable) {
949 HTList * cur = NULL;
950 HTNet * pres = NULL;
951 int cnt;
952 for (cnt=0; cnt<HT_XL_HASH_SIZE; cnt++) {
953 if ((cur = NetTable[cnt])) {
954 while ((pres = (HTNet *) HTList_nextObject(cur)) != NULL) {
955 check_pending(pres);
956 free_net(pres);
957 }
958 }
959 HTList_delete(NetTable[cnt]);
960 }
961 HT_FREE(NetTable);
962 HTNetCount = 0;
963 return YES;
964 }
965 return NO;
966 }
967
968 /*
969 ** When pipelining, it is not possible to kill a single request
970 ** as we then loose track of where we are in the pipe. It is
971 ** therefore necessary to kill the whole pipeline.
972 */
HTNet_killPipe(HTNet * net)973 PUBLIC BOOL HTNet_killPipe (HTNet * net)
974 {
975 return (net && net->host) ? HTHost_killPipe(net->host) : NO;
976 }
977
978 /* HTNet_kill
979 ** ----------
980 ** Kill the request by calling the call back function with a request for
981 ** closing the connection. Does not remove the object. This is done by
982 ** HTNet_delete() function which is called by the load routine.
983 ** Returns OK if success, NO on error
984 */
HTNet_kill(HTNet * net)985 PUBLIC BOOL HTNet_kill (HTNet * net)
986 {
987 if (net) {
988 HTAlertCallback * cbf = HTAlert_find(HT_PROG_INTERRUPT);
989 if (cbf) (*cbf)(net->request, HT_PROG_INTERRUPT, HT_MSG_NULL, NULL, NULL, NULL);
990 HTTRACE(CORE_TRACE, "Net Object.. Killing %p\n" _ net);
991 if (net->event.cbf) {
992 (*(net->event.cbf))(HTNet_socket(net), net->event.param, HTEvent_CLOSE);
993 return YES;
994 }
995 return unregister_net(net) && free_net(net);
996 }
997 HTTRACE(CORE_TRACE, "Net Object.. No object to kill\n");
998 return NO;
999 }
1000
1001 /* HTNet_killAll
1002 ** -------------
1003 ** Kills all registered net objects by calling the call
1004 ** back function with a request for closing the connection. We do not
1005 ** remove the HTNet object as it is done by HTNet_delete().
1006 ** Returns OK if success, NO on error
1007 */
HTNet_killAll(void)1008 PUBLIC BOOL HTNet_killAll (void)
1009 {
1010 HTTRACE(CORE_TRACE, "Net Object.. Kill ALL Net objects!!!\n");
1011 if (NetTable) {
1012 HTList * cur = NULL;
1013 HTNet * pres = NULL;
1014 int cnt;
1015 for (cnt=0; cnt<HT_XL_HASH_SIZE; cnt++) {
1016 if ((cur = NetTable[cnt])) {
1017 while ((pres = (HTNet *) HTList_lastObject(cur)) != NULL) {
1018 HTNet_kill(pres);
1019 cur = NetTable[cnt];
1020 }
1021 }
1022 }
1023 return YES;
1024 }
1025 HTTRACE(CORE_TRACE, "Net Object.. No objects to kill\n");
1026 return NO;
1027 }
1028
1029 /* ------------------------------------------------------------------------- */
1030 /* Connection Specifics */
1031 /* ------------------------------------------------------------------------- */
1032
1033 /* HTNet_priority
1034 ** --------------
1035 ** Get the current priority of the Net object
1036 */
HTNet_priority(HTNet * net)1037 PUBLIC HTPriority HTNet_priority (HTNet * net)
1038 {
1039 return (net ? net->event.priority : HT_PRIORITY_INV);
1040 }
1041
1042 /* HTNet_setPriority
1043 ** -----------------
1044 ** Set the current priority of the Net object
1045 ** This will change the priority next time the thread is blocked
1046 */
HTNet_setPriority(HTNet * net,HTPriority priority)1047 PUBLIC BOOL HTNet_setPriority (HTNet * net, HTPriority priority)
1048 {
1049 if (net) {
1050 net->event.priority = priority;
1051 return YES;
1052 }
1053 return NO;
1054 }
1055
1056 /* HTNet_Persistent
1057 ** ----------------
1058 ** Check whether the net object handles persistent connections
1059 ** If we have a DNS entry then check that as well.
1060 */
HTNet_persistent(HTNet * net)1061 PUBLIC BOOL HTNet_persistent (HTNet * net)
1062 {
1063 return (net && HTHost_isPersistent(net->host));
1064 }
1065
1066 /* HTNet_persistent
1067 ** ----------------
1068 ** Set the net object to handle persistent connections
1069 ** If we also have a DNS entry then update that as well
1070 */
HTNet_setPersistent(HTNet * net,BOOL persistent,HTTransportMode mode)1071 PUBLIC BOOL HTNet_setPersistent (HTNet * net,
1072 BOOL persistent,
1073 HTTransportMode mode)
1074 {
1075 if (net) {
1076 BOOL result = HTHost_setPersistent(net->host, persistent, mode);
1077 HTTRACE(CORE_TRACE, "Net Object.. Persistent connection set %s %s\n" _
1078 persistent ? "ON" : "OFF" _
1079 result ? "succeeded" : "failed");
1080 return result;
1081 }
1082 return NO;
1083 }
1084
1085 /*
1086 ** Context pointer to be used in context call back function
1087 */
HTNet_setContext(HTNet * net,void * context)1088 PUBLIC BOOL HTNet_setContext (HTNet * net, void * context)
1089 {
1090 if (net) {
1091 net->context = context;
1092 return YES;
1093 }
1094 return NO;
1095 }
1096
HTNet_context(HTNet * net)1097 PUBLIC void * HTNet_context (HTNet * net)
1098 {
1099 return net ? net->context : NULL;
1100 }
1101
1102 /*
1103 ** Get and set the socket number
1104 */
HTNet_setSocket(HTNet * net,SOCKET sockfd)1105 PUBLIC BOOL HTNet_setSocket (HTNet * net, SOCKET sockfd)
1106 {
1107 if (net && net->host && net->host->channel) {
1108 HTChannel_setSocket(net->host->channel, sockfd);
1109 return YES;
1110 }
1111 return NO;
1112 }
1113
HTNet_socket(HTNet * net)1114 PUBLIC SOCKET HTNet_socket (HTNet * net)
1115 {
1116 return (net && net->host && net->host->channel ? HTChannel_socket(net->host->channel) : INVSOC);
1117 }
1118
1119 /*
1120 ** Get and set the HTRequest object
1121 */
HTNet_setRequest(HTNet * net,HTRequest * request)1122 PUBLIC BOOL HTNet_setRequest (HTNet * net, HTRequest * request)
1123 {
1124 if (net && request) {
1125 net->request = request;
1126 return YES;
1127 }
1128 return NO;
1129 }
1130
HTNet_request(HTNet * net)1131 PUBLIC HTRequest * HTNet_request (HTNet * net)
1132 {
1133 return (net ? net->request : NULL);
1134 }
1135
1136 /*
1137 ** Get and set the HTChannel object
1138 */
HTNet_setChannel(HTNet * net,HTChannel * channel)1139 PUBLIC BOOL HTNet_setChannel (HTNet * net, HTChannel * channel)
1140 {
1141 return (net && channel) ? HTHost_setChannel(net->host, channel) : NO;
1142 }
1143
HTNet_channel(HTNet * net)1144 PUBLIC HTChannel * HTNet_channel (HTNet * net)
1145 {
1146 return net ? HTHost_channel(net->host) : NULL;
1147 }
1148
1149 /*
1150 ** Get and set the HTHost object
1151 */
HTNet_setHost(HTNet * net,HTHost * host)1152 PUBLIC BOOL HTNet_setHost (HTNet * net, HTHost * host)
1153 {
1154 if (net && host) {
1155 net->host = host;
1156 return YES;
1157 }
1158 return NO;
1159 }
1160
HTNet_host(HTNet * net)1161 PUBLIC HTHost * HTNet_host (HTNet * net)
1162 {
1163 return (net ? net->host : NULL);
1164 }
1165
1166 /*
1167 ** Get and set the HTdns object
1168 */
HTNet_setDns(HTNet * net,HTdns * dns)1169 PUBLIC BOOL HTNet_setDns (HTNet * net, HTdns * dns)
1170 {
1171 if (net && dns) {
1172 net->host->dns = dns;
1173 return YES;
1174 }
1175 return NO;
1176 }
1177
HTNet_dns(HTNet * net)1178 PUBLIC HTdns * HTNet_dns (HTNet * net)
1179 {
1180 return (net ? net->host->dns : NULL);
1181 }
1182
HTNet_setProtocol(HTNet * net,HTProtocol * protocol)1183 PUBLIC BOOL HTNet_setProtocol (HTNet * net, HTProtocol * protocol)
1184 {
1185 if (net && protocol) {
1186 net->protocol = protocol;
1187 return YES;
1188 }
1189 return NO;
1190 }
1191
HTNet_protocol(HTNet * net)1192 PUBLIC HTProtocol * HTNet_protocol (HTNet * net)
1193 {
1194 return (net ? net->protocol : NULL);
1195 }
1196
HTNet_setTransport(HTNet * net,HTTransport * tp)1197 PUBLIC BOOL HTNet_setTransport (HTNet * net, HTTransport * tp)
1198 {
1199 if (net && tp) {
1200 net->transport = tp;
1201 return YES;
1202 }
1203 return NO;
1204 }
1205
HTNet_transport(HTNet * net)1206 PUBLIC HTTransport * HTNet_transport (HTNet * net)
1207 {
1208 return (net ? net->transport : NULL);
1209 }
1210
HTNet_preemptive(HTNet * net)1211 PUBLIC BOOL HTNet_preemptive (HTNet * net)
1212 {
1213 return (net ? net->preemptive : NO);
1214 }
1215
1216 /*
1217 ** Create the output stream and bind it to the channel
1218 ** Please read the description in the HTIOStream module on the parameters
1219 */
HTNet_getOutput(HTNet * me,void * param,int mode)1220 PUBLIC HTOutputStream * HTNet_getOutput (HTNet * me, void * param, int mode)
1221 {
1222 if (me && me->host && me->host->channel && me->transport) {
1223 HTTransport * tp = me->transport;
1224 HTChannel * ch = me->host->channel;
1225 HTOutputStream * output = (*tp->output_new)(me->host, ch, param, mode);
1226 HTChannel_setOutput(ch, output);
1227 return output;
1228 }
1229 HTTRACE(CORE_TRACE, "Host Object.. Can't create output stream\n");
1230 return NULL;
1231 }
1232
HTNet_event(HTNet * net)1233 PUBLIC HTEvent * HTNet_event (HTNet * net)
1234 {
1235 return net ? &net->event : NULL;
1236 }
1237
HTNet_setEventParam(HTNet * net,void * eventParam)1238 PUBLIC BOOL HTNet_setEventParam (HTNet * net, void * eventParam)
1239 {
1240 if (net) return HTEvent_setParam(&net->event, eventParam);
1241 return NO;
1242 }
1243
HTNet_eventParam(HTNet * net)1244 PUBLIC void * HTNet_eventParam (HTNet * net)
1245 {
1246 return net ? net->event.param : NULL;
1247 }
1248
HTNet_setEventCallback(HTNet * net,HTEventCallback * cbf)1249 PUBLIC BOOL HTNet_setEventCallback(HTNet * net, HTEventCallback * cbf)
1250 {
1251 if (net) return HTEvent_setCallback(&net->event, cbf);
1252 return NO;
1253 }
1254
HTNet_eventCallback(HTNet * net)1255 PUBLIC HTEventCallback * HTNet_eventCallback(HTNet * net)
1256 {
1257 return net->event.cbf;
1258 }
1259
HTNet_setEventPriority(HTNet * net,HTPriority priority)1260 PUBLIC BOOL HTNet_setEventPriority(HTNet * net, HTPriority priority)
1261 {
1262 if (net) return HTEvent_setPriority(&net->event, priority);
1263 return NO;
1264 }
1265
HTNet_eventPriority(HTNet * net)1266 PUBLIC HTPriority HTNet_eventPriority(HTNet * net)
1267 {
1268 return net->event.priority;
1269 }
1270
HTNet_readStream(HTNet * net)1271 PUBLIC HTStream * HTNet_readStream(HTNet * net)
1272 {
1273 if (!net) return NULL;
1274 return net->readStream;
1275 }
1276
HTNet_setReadStream(HTNet * net,HTStream * stream)1277 PUBLIC BOOL HTNet_setReadStream (HTNet * net, HTStream * stream)
1278 {
1279 if (net) {
1280 net->readStream = stream;
1281 return YES;
1282 }
1283 return NO;
1284 }
1285
1286 /*
1287 ** Should we do raw byte count at the network or later?
1288 ** Normally it is later but in cases like FTP we need it
1289 ** in the raw form
1290 */
HTNet_setRawBytesCount(HTNet * net,BOOL mode)1291 PUBLIC BOOL HTNet_setRawBytesCount (HTNet * net, BOOL mode)
1292 {
1293 if (net) {
1294 net->countRawBytes = mode;
1295 return YES;
1296 }
1297 return NO;
1298 }
1299
HTNet_rawBytesCount(HTNet * net)1300 PUBLIC BOOL HTNet_rawBytesCount (HTNet * net)
1301 {
1302 return (net && net->countRawBytes);
1303 }
1304