Annotation of libwww/Library/src/HTHost.c, revision 2.54
2.1 frystyk 1: /* HTHost.c
2: ** REMOTE HOST INFORMATION
3: **
4: ** (c) COPYRIGHT MIT 1995.
5: ** Please first read the full copyright statement in the file COPYRIGH.
2.54 ! frystyk 6: ** @(#) $Id: HTHost.c,v 2.53 1998/11/29 20:03:05 frystyk Exp $
2.1 frystyk 7: **
8: ** This object manages the information that we know about a remote host.
9: ** This can for example be what type of host it is, and what version
10: ** it is using. We also keep track of persistent connections
11: **
12: ** April 96 HFN Written
13: */
14:
15: /* Library include files */
2.44 frystyk 16: #include "wwwsys.h"
2.1 frystyk 17: #include "WWWUtil.h"
18: #include "HTParse.h"
19: #include "HTAlert.h"
20: #include "HTError.h"
21: #include "HTNetMan.h"
22: #include "HTTrans.h"
2.13 frystyk 23: #include "HTTPUtil.h"
24: #include "HTTCP.h"
2.1 frystyk 25: #include "HTHost.h" /* Implemented here */
2.13 frystyk 26: #include "HTHstMan.h"
2.1 frystyk 27:
2.48 frystyk 28: #define HOST_OBJECT_TTL 43200L /* Default host timeout is 12 h */
2.29 frystyk 29:
2.48 frystyk 30: #define TCP_IDLE_PASSIVE 120L /* Passive TTL in s on an idle connection */
31: #define TCP_IDLE_ACTIVE 60000L /* Active TTL in ms on an idle connection */
2.29 frystyk 32:
2.45 frystyk 33: #define MAX_PIPES 50 /* maximum number of pipelined requests */
2.50 frystyk 34: #define MAX_HOST_RECOVER 1 /* Max number of auto recovery */
2.32 frystyk 35: #define DEFAULT_DELAY 30 /* Default write flush delay in ms */
2.1 frystyk 36:
2.13 frystyk 37: struct _HTInputStream {
38: const HTInputStreamClass * isa;
2.1 frystyk 39: };
40:
2.13 frystyk 41: PRIVATE int HostEvent(SOCKET soc, void * pVoid, HTEventType type);
42:
43: /* Type definitions and global variables etc. local to this module */
2.48 frystyk 44: PRIVATE time_t HostTimeout = HOST_OBJECT_TTL; /* Timeout for host objects */
2.53 frystyk 45: PRIVATE time_t HTPassiveTimeout = TCP_IDLE_PASSIVE; /* Passive timeout in s */
46: PRIVATE ms_t HTActiveTimeout = TCP_IDLE_ACTIVE; /* Active timeout in ms */
2.1 frystyk 47:
2.8 frystyk 48: PRIVATE HTList ** HostTable = NULL;
49: PRIVATE HTList * PendHost = NULL; /* List of pending host elements */
2.1 frystyk 50:
2.40 kahan 51: /* JK: New functions for interruption the automatic pending request
52: activation */
53: PRIVATE HTHost_ActivateRequestCallback * ActivateReqCBF = NULL;
54: PRIVATE int HTHost_ActivateRequest (HTNet *net);
55: PRIVATE BOOL DoPendingReqLaunch = YES; /* controls automatic activation
56: of pending requests */
57:
2.13 frystyk 58: PRIVATE int EventTimeout = -1; /* Global Host event timeout */
59:
2.36 frystyk 60: PRIVATE ms_t WriteDelay = DEFAULT_DELAY; /* Delay in ms */
2.26 frystyk 61:
2.45 frystyk 62: PRIVATE int MaxPipelinedRequests = MAX_PIPES;
63:
2.1 frystyk 64: /* ------------------------------------------------------------------------- */
65:
66: PRIVATE void free_object (HTHost * me)
67: {
68: if (me) {
2.30 frystyk 69: int i;
2.1 frystyk 70: HT_FREE(me->hostname);
71: HT_FREE(me->type);
2.12 frystyk 72: HT_FREE(me->server);
73: HT_FREE(me->user_agent);
74: HT_FREE(me->range_units);
2.30 frystyk 75:
76: /* Delete the channel (if any) */
2.3 eric 77: if (me->channel) {
2.5 eric 78: HTChannel_delete(me->channel, HT_OK);
2.3 eric 79: me->channel = NULL;
80: }
2.30 frystyk 81:
82: /* Unregister the events */
2.18 eric 83: for (i = 0; i < HTEvent_TYPES; i++)
84: HTEvent_delete(me->events[i]);
2.30 frystyk 85:
86: /* Delete the timer (if any) */
87: if (me->timer) HTTimer_delete(me->timer);
88:
89: /* Delete the queues */
2.8 frystyk 90: HTList_delete(me->pipeline);
91: HTList_delete(me->pending);
2.1 frystyk 92: HT_FREE(me);
93: }
94: }
95:
96: PRIVATE BOOL delete_object (HTList * list, HTHost * me)
97: {
2.2 frystyk 98: if (CORE_TRACE) HTTrace("Host info... object %p from list %p\n", me, list);
2.1 frystyk 99: HTList_removeObject(list, (void *) me);
100: free_object(me);
101: return YES;
102: }
103:
2.13 frystyk 104: PRIVATE BOOL isLastInPipe (HTHost * host, HTNet * net)
105: {
106: return HTList_lastObject(host->pipeline) == net;
107: }
108:
2.51 frystyk 109: PRIVATE BOOL killPipeline (HTHost * host, HTEventType type)
2.48 frystyk 110: {
111: if (host) {
112: int piped = HTList_count(host->pipeline);
113: int pending = HTList_count(host->pending);
114: int cnt;
115:
2.51 frystyk 116: if (CORE_TRACE)
117: HTTrace("Host kill... Pipeline due to %s event\n", HTEvent_type2str(type));
118:
2.48 frystyk 119: /* Terminate all net objects in pending queue */
120: for (cnt=0; cnt<pending; cnt++) {
121: HTNet * net = HTList_removeLastObject(host->pending);
2.51 frystyk 122: if (CORE_TRACE) HTTrace("Host kill... Terminating net object %p from pending queue\n", net);
2.48 frystyk 123: net->registeredFor = 0;
2.51 frystyk 124: (*net->event.cbf)(HTChannel_socket(host->channel), net->event.param, type);
2.48 frystyk 125: }
126:
127: /* Terminate all net objects in pipeline */
128: if (piped >= 1) {
129:
2.51 frystyk 130: #if 0
2.48 frystyk 131: /*
132: ** Unregister this host for all events
133: */
134: HTEvent_unregister(HTChannel_socket(host->channel), HTEvent_READ);
135: HTEvent_unregister(HTChannel_socket(host->channel), HTEvent_WRITE);
136: host->registeredFor = 0;
137:
138: /*
139: ** Set new mode to single until we know what is going on
140: */
141: host->mode = HT_TP_SINGLE;
2.51 frystyk 142: #endif
2.48 frystyk 143: /*
144: ** Terminte all net objects in the pipeline
145: */
146: for (cnt=0; cnt<piped; cnt++) {
147: HTNet * net = HTList_firstObject(host->pipeline);
2.51 frystyk 148: if (CORE_TRACE) HTTrace("Host kill... Terminating net object %p from pipe line\n", net);
2.48 frystyk 149: net->registeredFor = 0;
2.51 frystyk 150: (*net->event.cbf)(HTChannel_socket(host->channel), net->event.param, type);
2.48 frystyk 151: }
152:
2.51 frystyk 153: #if 0
2.48 frystyk 154: HTChannel_setSemaphore(host->channel, 0);
155: HTHost_clearChannel(host, HT_INTERRUPTED);
2.51 frystyk 156: #endif
2.48 frystyk 157:
158: }
159: return YES;
160: }
161: return NO;
162: }
163:
164: /*
2.51 frystyk 165: ** Silently close an idle persistent connection after
2.53 frystyk 166: ** HTActiveTimeout secs
2.51 frystyk 167: */
168: PRIVATE int IdleTimeoutEvent (HTTimer * timer, void * param, HTEventType type)
169: {
170: HTHost * host = (HTHost *) param;
171: SOCKET sockfd = HTChannel_socket(host->channel);
172: int result = HostEvent (sockfd, host, HTEvent_CLOSE);
173: HTTimer_delete(timer);
174: host->timer = NULL;
175: return result;
176: }
177:
178: /*
2.13 frystyk 179: ** HostEvent - host event manager - recieves events from the event
180: ** manager and dispatches them to the client net objects by calling the
181: ** net object's cbf.
182: **
183: */
184: PRIVATE int HostEvent (SOCKET soc, void * pVoid, HTEventType type)
185: {
186: HTHost * host = (HTHost *)pVoid;
187:
2.18 eric 188: if (type == HTEvent_READ || type == HTEvent_CLOSE) {
2.13 frystyk 189: HTNet * targetNet;
190:
191: /* call the first net object */
192: do {
193: int ret;
2.49 frystyk 194:
195: /* netscape and apache servers can do a lazy close well after usage
196: * of previous socket has been dispensed by the library,
197: * the section below makes sure the event does not get miss attributed
198: */
199: if (HTChannel_socket(host->channel) != soc) {
200: if (CORE_TRACE)
201: HTTrace("Host Event.. wild socket %d type = %s real socket is %d\n", soc,
202: type == HTEvent_CLOSE ? "Event_Close" : "Event_Read",
203: HTChannel_socket(host->channel));
204: return HT_OK;
205: }
206:
2.13 frystyk 207: targetNet = (HTNet *)HTList_firstObject(host->pipeline);
208: if (targetNet) {
209: if (CORE_TRACE)
2.28 frystyk 210: HTTrace("Host Event.. READ passed to `%s\'\n",
211: HTAnchor_physical(HTRequest_anchor(HTNet_request(targetNet))));
2.13 frystyk 212: if ((ret = (*targetNet->event.cbf)(HTChannel_socket(host->channel),
213: targetNet->event.param, type)) != HT_OK)
214: return ret;
215: }
216: if (targetNet == NULL && host->remainingRead > 0) {
2.31 frystyk 217: if (CORE_TRACE)
218: HTTrace("HostEvent... Error: %d bytes left to read and nowhere to put them\n",
219: host->remainingRead);
2.13 frystyk 220: host->remainingRead = 0;
221: /*
222: ** Fall through to close the channel
223: */
224: }
225: /* call pipelined net object to eat all the data in the channel */
226: } while (host->remainingRead > 0);
227:
228: /* last target net should have set remainingRead to 0 */
229: if (targetNet)
230: return HT_OK;
231:
232: /* If there was notargetNet, it should be a close */
2.28 frystyk 233: if (CORE_TRACE)
234: HTTrace("Host Event.. host %p `%s\' closed connection.\n",
235: host, host->hostname);
2.13 frystyk 236:
237: /* Is there garbage in the channel? Let's check: */
238: {
239: char buf[256];
240: int ret;
2.28 frystyk 241: memset(buf, '\0', sizeof(buf));
2.48 frystyk 242: while ((ret = NETREAD(HTChannel_socket(host->channel), buf, sizeof(buf)-1)) > 0) {
2.28 frystyk 243: if (CORE_TRACE)
244: HTTrace("Host Event.. Host %p `%s\' had %d extraneous bytes: `%s\'\n",
245: host, host->hostname, ret, buf);
246: memset(buf, '\0', sizeof(buf));
247: }
2.13 frystyk 248: }
249: HTHost_clearChannel(host, HT_OK);
2.28 frystyk 250: return HT_OK; /* extra garbage does not constitute an application error */
2.13 frystyk 251:
2.18 eric 252: } else if (type == HTEvent_WRITE || type == HTEvent_CONNECT) {
2.13 frystyk 253: HTNet * targetNet = (HTNet *)HTList_lastObject(host->pipeline);
254: if (targetNet) {
255: if (CORE_TRACE)
2.28 frystyk 256: HTTrace("Host Event.. WRITE passed to `%s\'\n",
257: HTAnchor_physical(HTRequest_anchor(HTNet_request(targetNet))));
2.13 frystyk 258: return (*targetNet->event.cbf)(HTChannel_socket(host->channel), targetNet->event.param, type);
259: }
2.44 frystyk 260: HTTrace("Host Event.. Who wants to write to `%s\'?\n", host->hostname);
2.13 frystyk 261: return HT_ERROR;
2.14 frystyk 262: } else if (type == HTEvent_TIMEOUT) {
2.51 frystyk 263: killPipeline(host, HTEvent_TIMEOUT);
2.14 frystyk 264: } else {
2.44 frystyk 265: HTTrace("Don't know how to handle OOB data from `%s\'?\n",
266: host->hostname);
2.14 frystyk 267: }
2.13 frystyk 268: return HT_OK;
269: }
270:
2.1 frystyk 271: /*
272: ** Search the host info cache for a host object or create a new one
273: ** and add it. Examples of host names are
274: **
275: ** www.w3.org
276: ** www.foo.com:8000
277: ** 18.52.0.18
278: **
279: ** Returns Host object or NULL if error. You may get back an already
280: ** existing host object - you're not guaranteed a new one each time.
281: */
2.15 eric 282: PUBLIC HTHost * HTHost_new (char * host, u_short u_port)
2.1 frystyk 283: {
284: HTList * list = NULL; /* Current list in cache */
285: HTHost * pres = NULL;
2.13 frystyk 286: int hash = 0;
2.1 frystyk 287: if (!host) {
2.2 frystyk 288: if (CORE_TRACE) HTTrace("Host info... Bad argument\n");
2.1 frystyk 289: return NULL;
290: }
291:
292: /* Find a hash for this host */
293: {
294: char *ptr;
295: for (ptr=host; *ptr; ptr++)
2.13 frystyk 296: hash = (int) ((hash * 3 + (*(unsigned char *) ptr)) % HOST_HASH_SIZE);
2.1 frystyk 297: if (!HostTable) {
2.13 frystyk 298: if ((HostTable = (HTList **) HT_CALLOC(HOST_HASH_SIZE,
2.1 frystyk 299: sizeof(HTList *))) == NULL)
300: HT_OUTOFMEM("HTHost_find");
301: }
302: if (!HostTable[hash]) HostTable[hash] = HTList_new();
303: list = HostTable[hash];
304: }
305:
306: /* Search the cache */
307: {
308: HTList * cur = list;
309: while ((pres = (HTHost *) HTList_nextObject(cur))) {
2.15 eric 310: if (!strcmp(pres->hostname, host) && u_port == pres->u_port) {
2.8 frystyk 311: if (HTHost_isIdle(pres) && time(NULL)>pres->ntime+HostTimeout){
2.2 frystyk 312: if (CORE_TRACE)
2.1 frystyk 313: HTTrace("Host info... Collecting host info %p\n",pres);
314: delete_object(list, pres);
315: pres = NULL;
316: }
317: break;
318: }
319: }
320: }
321:
2.8 frystyk 322: /* If not found then create new Host object, else use existing one */
2.1 frystyk 323: if (pres) {
324: if (pres->channel) {
2.32 frystyk 325:
326: /*
327: ** If we have a TTL for this TCP connection then
328: ** check that we haven't passed it.
329: */
330: if (pres->expires > 0) {
331: time_t t = time(NULL);
2.51 frystyk 332: if (HTHost_isIdle(pres) && pres->expires < t) {
2.32 frystyk 333: if (CORE_TRACE)
334: HTTrace("Host info... Persistent channel %p gotten cold\n",
335: pres->channel);
2.48 frystyk 336: HTHost_clearChannel(pres, HT_OK);
2.32 frystyk 337: } else {
2.53 frystyk 338: pres->expires = t + HTPassiveTimeout;
2.32 frystyk 339: if (CORE_TRACE)
340: HTTrace("Host info... REUSING CHANNEL %p\n",pres->channel);
341: }
342: }
2.1 frystyk 343: }
344: } else {
345: if ((pres = (HTHost *) HT_CALLOC(1, sizeof(HTHost))) == NULL)
346: HT_OUTOFMEM("HTHost_add");
2.13 frystyk 347: pres->hash = hash;
2.1 frystyk 348: StrAllocCopy(pres->hostname, host);
2.15 eric 349: pres->u_port = u_port;
2.1 frystyk 350: pres->ntime = time(NULL);
2.8 frystyk 351: pres->mode = HT_TP_SINGLE;
2.26 frystyk 352: pres->delay = WriteDelay;
2.18 eric 353: {
2.26 frystyk 354: int i;
355: for (i = 0; i < HTEvent_TYPES; i++)
356: pres->events[i]= HTEvent_new(HostEvent, pres, HT_PRIORITY_MAX, EventTimeout);
2.18 eric 357: }
2.2 frystyk 358: if (CORE_TRACE)
2.24 frystyk 359: HTTrace("Host info... added `%s\' with host %p to list %p\n",
360: host, pres, list);
2.1 frystyk 361: HTList_addObject(list, (void *) pres);
362: }
363: return pres;
2.9 frystyk 364: }
365:
2.15 eric 366: PUBLIC HTHost * HTHost_newWParse (HTRequest * request, char * url, u_short u_port)
2.13 frystyk 367: {
2.32 frystyk 368: char * port;
369: char * fullhost = NULL;
370: char * parsedHost = NULL;
371: SockA * sin;
372: HTHost * me;
373: char * proxy = HTRequest_proxy(request);
2.13 frystyk 374:
2.32 frystyk 375: fullhost = HTParse(proxy ? proxy : url, "", PARSE_HOST);
2.13 frystyk 376:
377: /* If there's an @ then use the stuff after it as a hostname */
2.32 frystyk 378: if (fullhost) {
379: char * at_sign;
380: if ((at_sign = strchr(fullhost, '@')) != NULL)
381: parsedHost = at_sign+1;
382: else
383: parsedHost = fullhost;
384: }
385: if (!parsedHost || !*parsedHost) {
386: HTRequest_addError(request, ERR_FATAL, NO, HTERR_NO_HOST,
2.52 frystyk 387: NULL, 0, "HTHost_newWParse");
2.32 frystyk 388: HT_FREE(fullhost);
389: return NULL;
390: }
391: port = strchr(parsedHost, ':');
392: if (PROT_TRACE)
2.52 frystyk 393: HTTrace("HTHost parse Looking up `%s\'\n", parsedHost);
2.32 frystyk 394: if (port) {
395: *port++ = '\0';
2.36 frystyk 396: if (!*port || !isdigit((int) *port))
2.32 frystyk 397: port = 0;
398: u_port = (u_short) atol(port);
399: }
400: /* Find information about this host */
401: if ((me = HTHost_new(parsedHost, u_port)) == NULL) {
2.52 frystyk 402: if (PROT_TRACE)HTTrace("HTHost parse Can't get host info\n");
2.32 frystyk 403: me->tcpstate = TCP_ERROR;
404: return NULL;
405: }
406: sin = &me->sock_addr;
407: memset((void *) sin, '\0', sizeof(SockA));
2.13 frystyk 408: #ifdef DECNET
2.32 frystyk 409: sin->sdn_family = AF_DECnet;
410: net->sock_addr.sdn_objnum = port ? (unsigned char)(strtol(port, (char **) 0, 10)) : DNP_OBJ;
2.13 frystyk 411: #else /* Internet */
2.32 frystyk 412: sin->sin_family = AF_INET;
413: sin->sin_port = htons(u_port);
2.13 frystyk 414: #endif
2.32 frystyk 415: HT_FREE(fullhost); /* parsedHost points into fullhost */
416: return me;
2.13 frystyk 417: }
418:
2.9 frystyk 419: /*
420: ** Search the host info cache for a host object. Examples of host names:
421: **
422: ** www.w3.org
423: ** www.foo.com:8000
424: ** 18.52.0.18
425: **
426: ** Returns Host object or NULL if not found.
427: */
428: PUBLIC HTHost * HTHost_find (char * host)
429: {
430: HTList * list = NULL; /* Current list in cache */
431: HTHost * pres = NULL;
432: if (CORE_TRACE)
433: HTTrace("Host info... Looking for `%s\'\n", host ? host : "<null>");
434:
435: /* Find a hash for this host */
436: if (host && HostTable) {
437: int hash = 0;
438: char *ptr;
439: for (ptr=host; *ptr; ptr++)
2.13 frystyk 440: hash = (int) ((hash * 3 + (*(unsigned char *) ptr)) % HOST_HASH_SIZE);
2.9 frystyk 441: if (!HostTable[hash]) return NULL;
442: list = HostTable[hash];
443:
444: /* Search the cache */
445: {
446: HTList * cur = list;
447: while ((pres = (HTHost *) HTList_nextObject(cur))) {
448: if (!strcmp(pres->hostname, host)) {
449: if (time(NULL) > pres->ntime + HostTimeout) {
450: if (CORE_TRACE)
451: HTTrace("Host info... Collecting host %p\n", pres);
452: delete_object(list, pres);
453: pres = NULL;
454: } else {
455: if (CORE_TRACE)
456: HTTrace("Host info... Found `%s\'\n", host);
457: }
458: return pres;
459: }
460: }
461: }
462: }
463: return NULL;
2.1 frystyk 464: }
465:
466: /*
2.8 frystyk 467: ** Get and set the hostname of the remote host
468: */
469: PUBLIC char * HTHost_name (HTHost * host)
470: {
471: return host ? host->hostname : NULL;
472: }
473:
474: /*
2.1 frystyk 475: ** Get and set the type class of the remote host
476: */
477: PUBLIC char * HTHost_class (HTHost * host)
478: {
479: return host ? host->type : NULL;
480: }
481:
482: PUBLIC void HTHost_setClass (HTHost * host, char * s_class)
483: {
484: if (host && s_class) StrAllocCopy(host->type, s_class);
485: }
486:
487: /*
488: ** Get and set the version of the remote host
489: */
490: PUBLIC int HTHost_version (HTHost *host)
491: {
492: return host ? host->version : 0;
493: }
494:
495: PUBLIC void HTHost_setVersion (HTHost * host, int version)
496: {
497: if (host) host->version = version;
498: }
499:
500: /*
2.53 frystyk 501: ** Get and set the passive timeout for persistent entries.
2.1 frystyk 502: */
2.53 frystyk 503: PUBLIC BOOL HTHost_setPersistTimeout (time_t timeout)
2.1 frystyk 504: {
2.53 frystyk 505: if (timeout > 0) {
506: HTPassiveTimeout = timeout;
507: return YES;
508: }
509: return NO;
510: }
511:
512: PUBLIC time_t HTHost_persistTimeout (void)
513: {
514: return HTPassiveTimeout;
515: }
516:
517: /*
518: ** Get and set the active timeout for persistent entries.
519: */
520: PUBLIC BOOL HTHost_setActiveTimeout (ms_t timeout)
521: {
522: if (timeout > 1000) {
523: HTActiveTimeout = timeout;
524: return YES;
525: }
526: return NO;
2.1 frystyk 527: }
528:
2.53 frystyk 529: PUBLIC ms_t HTHost_activeTimeout (void)
2.1 frystyk 530: {
2.53 frystyk 531: return HTActiveTimeout;
2.1 frystyk 532: }
533:
534: /* Persistent Connection Expiration
535: ** --------------------------------
536: ** Should normally not be used. If, then use calendar time.
537: */
538: PUBLIC void HTHost_setPersistExpires (HTHost * host, time_t expires)
539: {
540: if (host) host->expires = expires;
541: }
542:
543: PUBLIC time_t HTHost_persistExpires (HTHost * host)
544: {
545: return host ? host->expires : -1;
546: }
547:
2.22 eric 548: PUBLIC void HTHost_setReqsPerConnection (HTHost * host, int reqs)
549: {
550: if (host) host->reqsPerConnection = reqs;
551: }
552:
553: PUBLIC int HTHost_reqsPerConnection (HTHost * host)
554: {
555: return host ? host->reqsPerConnection : -1;
556: }
557:
558: PUBLIC void HTHost_setReqsMade (HTHost * host, int reqs)
559: {
560: if (host) host->reqsMade = reqs;
561: }
562:
563: PUBLIC int HTHost_reqsMade (HTHost * host)
564: {
565: return host ? host->reqsMade : -1;
566: }
567:
2.1 frystyk 568: /*
2.6 frystyk 569: ** Public methods for this host
570: */
571: PUBLIC HTMethod HTHost_publicMethods (HTHost * me)
572: {
573: return me ? me->methods : METHOD_INVALID;
574: }
575:
576: PUBLIC void HTHost_setPublicMethods (HTHost * me, HTMethod methodset)
577: {
578: if (me) me->methods = methodset;
579: }
580:
581: PUBLIC void HTHost_appendPublicMethods (HTHost * me, HTMethod methodset)
582: {
583: if (me) me->methods |= methodset;
584: }
585:
586: /*
587: ** Get and set the server name of the remote host
588: */
589: PUBLIC char * HTHost_server (HTHost * host)
590: {
591: return host ? host->server : NULL;
592: }
593:
594: PUBLIC BOOL HTHost_setServer (HTHost * host, const char * server)
595: {
596: if (host && server) {
597: StrAllocCopy(host->server, server);
598: return YES;
599: }
600: return NO;
601: }
602:
603: /*
604: ** Get and set the userAgent name of the remote host
605: */
606: PUBLIC char * HTHost_userAgent (HTHost * host)
607: {
608: return host ? host->user_agent : NULL;
609: }
610:
611: PUBLIC BOOL HTHost_setUserAgent (HTHost * host, const char * userAgent)
612: {
613: if (host && userAgent) {
614: StrAllocCopy(host->user_agent, userAgent);
615: return YES;
2.12 frystyk 616: }
617: return NO;
618: }
619:
620: /*
621: ** Get and set acceptable range units
622: */
623: PUBLIC char * HTHost_rangeUnits (HTHost * host)
624: {
625: return host ? host->range_units : NULL;
626: }
627:
628: PUBLIC BOOL HTHost_setRangeUnits (HTHost * host, const char * units)
629: {
630: if (host && units) {
631: StrAllocCopy(host->range_units, units);
632: return YES;
633: }
634: return NO;
635: }
636:
637: /*
638: ** Checks whether a specific range unit is OK. We always say
639: ** YES except if we have a specific statement from the server that
640: ** it doesn't understand byte ranges - that is - it has sent "none"
641: ** in a "Accept-Range" response header
642: */
643: PUBLIC BOOL HTHost_isRangeUnitAcceptable (HTHost * host, const char * unit)
644: {
645: if (host && unit) {
646: #if 0
647: if (host->range_units) {
648: char * start = strcasestr(host->range_units, "none");
649:
650: /*
651: ** Check that "none" is infact a token. It could be part of some
652: ** other valid string, so we'd better check for it.
653: */
654: if (start) {
655:
656:
657: }
658: return NO;
659: }
660: #endif
661: return strcasecomp(unit, "bytes") ? NO : YES;
2.6 frystyk 662: }
663: return NO;
664: }
665:
2.1 frystyk 666: /*
667: ** As soon as we know that this host accepts persistent connections,
668: ** we associated the channel with the host.
669: ** We don't want more than MaxSockets-2 connections to be persistent in
670: ** order to avoid deadlock.
671: */
2.13 frystyk 672: PUBLIC BOOL HTHost_setPersistent (HTHost * host,
673: BOOL persistent,
674: HTTransportMode mode)
2.1 frystyk 675: {
2.13 frystyk 676: if (!host) return NO;
677:
678: if (!persistent) {
679: /*
680: ** We use the HT_IGNORE status code as we don't want to free
681: ** the stream at this point in time. The situation we want to
682: ** avoid is that we free the channel from within the stream pipe.
683: ** This will lead to an infinite look having the stream freing
684: ** itself.
685: */
2.30 frystyk 686: host->persistent = NO;
2.13 frystyk 687: return HTHost_clearChannel(host, HT_IGNORE);
688: }
689:
2.18 eric 690: /*
691: ** Set the host persistent if not already. Also update the mode to
692: ** the new one - it may have changed
693: */
694: HTHost_setMode(host, mode);
695: if (!host->persistent) {
2.13 frystyk 696: SOCKET sockfd = HTChannel_socket(host->channel);
2.8 frystyk 697: if (sockfd != INVSOC && HTNet_availablePersistentSockets() > 0) {
2.13 frystyk 698: host->persistent = YES;
2.53 frystyk 699: host->expires = time(NULL) + HTPassiveTimeout; /* Default timeout */
2.13 frystyk 700: HTChannel_setHost(host->channel, host);
2.8 frystyk 701: HTNet_increasePersistentSocket();
2.2 frystyk 702: if (CORE_TRACE)
2.1 frystyk 703: HTTrace("Host info... added host %p as persistent\n", host);
704: return YES;
705: } else {
2.2 frystyk 706: if (CORE_TRACE)
707: HTTrace("Host info... no room for persistent socket %d\n",
2.7 frystyk 708: sockfd);
2.18 eric 709: return NO;
2.1 frystyk 710: }
2.18 eric 711: } else {
712: if (CORE_TRACE) HTTrace("Host info... %p already persistent\n", host);
713: return YES;
2.1 frystyk 714: }
715: return NO;
716: }
717:
718: /*
2.13 frystyk 719: ** Check whether we have a persistent channel or not
720: */
721: PUBLIC BOOL HTHost_isPersistent (HTHost * host)
722: {
723: return host && host->persistent;
724: }
725:
726: /*
2.1 frystyk 727: ** Find persistent channel associated with this host.
728: */
729: PUBLIC HTChannel * HTHost_channel (HTHost * host)
730: {
731: return host ? host->channel : NULL;
732: }
733:
2.30 frystyk 734:
2.1 frystyk 735: /*
2.30 frystyk 736: ** Check whether we have got a "close" notification, for example in the
737: ** connection header
738: */
739: PUBLIC BOOL HTHost_setCloseNotification (HTHost * host, BOOL mode)
740: {
741: if (host) {
742: host->close_notification = mode;
2.37 frystyk 743: return YES;
2.30 frystyk 744: }
745: return NO;
746: }
747:
748: PUBLIC BOOL HTHost_closeNotification (HTHost * host)
749: {
750: return host && host->close_notification;
751: }
752:
753: /*
2.1 frystyk 754: ** Clear the persistent entry by deleting the channel object. Note that
755: ** the channel object is only deleted if it's not used anymore.
756: */
2.8 frystyk 757: PUBLIC BOOL HTHost_clearChannel (HTHost * host, int status)
2.1 frystyk 758: {
759: if (host && host->channel) {
2.8 frystyk 760: HTChannel_setHost(host->channel, NULL);
2.10 frystyk 761:
2.13 frystyk 762: HTEvent_unregister(HTChannel_socket(host->channel), HTEvent_READ);
763: HTEvent_unregister(HTChannel_socket(host->channel), HTEvent_WRITE);
2.18 eric 764: host->registeredFor = 0;
2.13 frystyk 765:
2.10 frystyk 766: /*
767: ** We don't want to recursively delete ourselves so if we are
768: ** called from within the stream pipe then don't delete the channel
769: ** at this point
770: */
2.8 frystyk 771: HTChannel_delete(host->channel, status);
2.18 eric 772: host->expires = 0;
2.1 frystyk 773: host->channel = NULL;
2.22 eric 774: host->tcpstate = TCP_BEGIN;
775: host->reqsMade = 0;
2.32 frystyk 776: if (HTHost_isPersistent(host)) {
777: HTNet_decreasePersistentSocket();
778: host->persistent = NO;
779: }
780: host->close_notification = NO;
2.45 frystyk 781: host->broken_pipe = NO;
2.32 frystyk 782: host->mode = HT_TP_SINGLE;
783:
2.28 frystyk 784: if (CORE_TRACE) HTTrace("Host info... removed host %p as persistent\n", host);
2.32 frystyk 785:
786: if (!HTList_isEmpty(host->pending)) {
787: if (CORE_TRACE)
2.45 frystyk 788: HTTrace("Host has %d object(s) pending - attempting launch\n", HTList_count(host->pending));
2.32 frystyk 789: HTHost_launchPending(host);
790: }
2.1 frystyk 791: return YES;
792: }
793: return NO;
794: }
795:
2.37 frystyk 796: PUBLIC BOOL HTHost_doRecover (HTHost * host)
797: {
798: return host ? host->do_recover : NO;
799: }
800:
2.1 frystyk 801: /*
2.18 eric 802: ** Move all entries in the pipeline and move the rest to the pending
803: ** queue. They will get launched at a later point in time.
804: */
805: PUBLIC BOOL HTHost_recoverPipe (HTHost * host)
806: {
807: if (host) {
808: int piped = HTList_count(host->pipeline);
809: if (piped > 0) {
810: int cnt;
2.24 frystyk 811: host->recovered++;
2.18 eric 812: if (CORE_TRACE)
2.24 frystyk 813: HTTrace("Host recovered %d times. Moving %d Net objects from pipe line to pending queue\n",
814: host->recovered, piped);
2.18 eric 815:
816: /*
817: ** Unregister this host for all events
818: */
819: HTEvent_unregister(HTChannel_socket(host->channel), HTEvent_READ);
820: HTEvent_unregister(HTChannel_socket(host->channel), HTEvent_WRITE);
821: host->registeredFor = 0;
822:
823: /*
824: ** Set new mode to single until we know what is going on
825: */
826: host->mode = HT_TP_SINGLE;
827:
828: /*
829: ** Move all net objects from the net object to the pending queue.
830: */
831: if (!host->pending) host->pending = HTList_new();
832: for (cnt=0; cnt<piped; cnt++) {
833: HTNet * net = HTList_removeLastObject(host->pipeline);
834: if (CORE_TRACE) HTTrace("Host recover Resetting net object %p\n", net);
835: net->registeredFor = 0;
836: (*net->event.cbf)(HTChannel_socket(host->channel), net->event.param, HTEvent_RESET);
837: HTList_appendObject(host->pending, net);
838: }
2.37 frystyk 839:
2.18 eric 840: HTChannel_setSemaphore(host->channel, 0);
841: HTHost_clearChannel(host, HT_INTERRUPTED);
2.37 frystyk 842: host->do_recover = NO;
2.18 eric 843: }
2.24 frystyk 844: return YES;
2.18 eric 845: }
846: return NO;
847: }
848:
849: /*
2.51 frystyk 850: ** Terminate a pipeline prematurely, for example because of timeout,
851: ** interruption, etc.
852: */
853: PUBLIC BOOL HTHost_killPipe (HTHost * host)
854: {
855: return killPipeline(host, HTEvent_CLOSE);
856: }
857:
858: /*
2.8 frystyk 859: ** Handle the connection mode. The mode may change mode in the
860: ** middle of a connection.
861: */
862: PUBLIC HTTransportMode HTHost_mode (HTHost * host, BOOL * active)
863: {
864: return host ? host->mode : HT_TP_SINGLE;
865: }
866:
867: /*
868: ** If the new mode is lower than the old mode then adjust the pipeline
869: ** accordingly. That is, if we are going into single mode then move
870: ** all entries in the pipeline and move the rest to the pending
871: ** queue. They will get launched at a later point in time.
872: */
873: PUBLIC BOOL HTHost_setMode (HTHost * host, HTTransportMode mode)
874: {
875: if (host) {
876: /*
877: ** Check the new mode and see if we must adjust the queues.
878: */
879: if (mode == HT_TP_SINGLE && host->mode > mode) {
880: int piped = HTList_count(host->pipeline);
881: if (piped > 0) {
882: int cnt;
883: if (CORE_TRACE)
884: HTTrace("Host info... Moving %d Net objects from pipe line to pending queue\n", piped);
885: if (!host->pending) host->pending = HTList_new();
886: for (cnt=0; cnt<piped; cnt++) {
2.18 eric 887: HTNet * net = HTList_removeLastObject(host->pipeline);
888: if (CORE_TRACE) HTTrace("Host info... Resetting net object %p\n", net);
2.13 frystyk 889: (*net->event.cbf)(HTChannel_socket(host->channel), net->event.param, HTEvent_RESET);
2.8 frystyk 890: HTList_appendObject(host->pending, net);
891: }
2.18 eric 892: HTChannel_setSemaphore(host->channel, 0);
893: HTHost_clearChannel(host, HT_INTERRUPTED);
2.8 frystyk 894: }
2.24 frystyk 895: }
896:
897: /*
898: ** If we know that this host is bad then we don't allow anything than
899: ** single mode. We can't recover connections for the rest of our life
900: */
901: if (mode == HT_TP_PIPELINE && host->recovered > MAX_HOST_RECOVER) {
902: if (PROT_TRACE)
903: HTTrace("Host info... %p is bad for pipelining so we won't do it!!!\n",
904: host);
905: } else {
906: host->mode = mode;
907: if (PROT_TRACE)
908: HTTrace("Host info... New mode is %d for host %p\n", host->mode, host);
909: }
2.8 frystyk 910: }
911: return NO;
912: }
913:
914: /*
915: ** Check whether a host is idle meaning if it is ready for a new
916: ** request which depends on the mode of the host. If the host is
917: ** idle, i.e. ready for use then return YES else NO. If the host supports
918: ** persistent connections then still only return idle if no requests are
919: ** ongoing.
920: */
921: PUBLIC BOOL HTHost_isIdle (HTHost * host)
922: {
2.32 frystyk 923: return (host && HTList_isEmpty(host->pipeline));
2.8 frystyk 924: }
925:
2.13 frystyk 926: PRIVATE BOOL _roomInPipe (HTHost * host)
927: {
928: int count;
2.34 frystyk 929: if (!host ||
930: (host->reqsPerConnection && host->reqsMade >= host->reqsPerConnection) ||
2.45 frystyk 931: HTHost_closeNotification(host) || host->broken_pipe)
2.32 frystyk 932: return NO;
2.13 frystyk 933: count = HTList_count(host->pipeline);
934: switch (host->mode) {
935: case HT_TP_SINGLE:
936: return count <= 0;
937: case HT_TP_PIPELINE:
2.51 frystyk 938: return (host->recovered < MAX_HOST_RECOVER) ?
939: (count < MaxPipelinedRequests) : (count <= 0);
2.13 frystyk 940: case HT_TP_INTERLEAVE:
941: return YES;
942: }
943: return NO;
944: }
945:
2.8 frystyk 946: /*
947: ** Add a net object to the host object. If the host
948: ** is idle then add to active list (pipeline) else add
949: ** it to the pending list
950: ** Return HT_PENDING if we must pend, HT_OK, or HT_ERROR
951: */
952: PUBLIC int HTHost_addNet (HTHost * host, HTNet * net)
953: {
954: if (host && net) {
955: int status = HT_OK;
2.32 frystyk 956: BOOL doit = (host->doit==net);
2.8 frystyk 957:
2.18 eric 958: /*
959: ** If we don't have a socket already then check to see if we can get
960: ** one. Otherwise we put the host object into our pending queue.
2.52 frystyk 961: */
2.18 eric 962: if (!host->channel && HTNet_availableSockets() <= 0) {
2.8 frystyk 963: if (!PendHost) PendHost = HTList_new();
964: HTList_addObject(PendHost, host);
2.52 frystyk 965: if (!host->pending) host->pending = HTList_new();
966: HTList_addObject(host->pending, net);
967: if (CORE_TRACE)
968: HTTrace("Host info... Added Host %p with Net %p (request %p) as pending, %d requests made, %d requests in pipe, %d pending\n",
969: host, net, net->request, host->reqsMade, HTList_count(host->pipeline), HTList_count(host->pending));
970: return HT_PENDING;
2.8 frystyk 971: }
972:
2.45 frystyk 973: #if 0
2.18 eric 974: /*
2.45 frystyk 975: ** First check whether the net object is already on either queue.
976: ** Do NOT add extra copies of the HTNet object to
977: ** the pipeline or pending list (if it's already on the list).
978: */
979: if (HTList_indexOf(host->pipeline, net) >= 0) {
980: if (CORE_TRACE)
981: HTTrace("Host info... The Net %p (request %p) is already in pipe,"
982: " %d requests made, %d requests in pipe, %d pending\n",
983: net, net->request, host->reqsMade,
984: HTList_count(host->pipeline),
985: HTList_count(host->pending));
986: HTDebugBreak(__FILE__, __LINE__,
987: "Net object %p registered multiple times in pipeline\n",
988: net);
989: return HT_OK;
990: }
2.44 frystyk 991:
2.45 frystyk 992: if (HTList_indexOf(host->pending, net) >= 0) {
993: if (CORE_TRACE)
994: HTTrace("Host info... The Net %p (request %p) already pending,"
995: " %d requests made, %d requests in pipe, %d pending\n",
996: net, net->request, host->reqsMade,
997: HTList_count(host->pipeline),
998: HTList_count(host->pending));
999: HTDebugBreak(__FILE__, __LINE__,
1000: "Net object %p registered multiple times in pending queue\n",
1001: net);
1002:
1003: return HT_PENDING;
1004: }
1005: #endif
2.44 frystyk 1006:
1007: /*
2.18 eric 1008: ** Add net object to either active or pending queue.
1009: */
2.44 frystyk 1010: if (_roomInPipe(host) && (HTList_isEmpty(host->pending) || doit)) {
2.32 frystyk 1011: if (doit) host->doit = NULL;
2.8 frystyk 1012: if (!host->pipeline) host->pipeline = HTList_new();
1013: HTList_addObject(host->pipeline, net);
2.32 frystyk 1014: host->reqsMade++;
1015: if (CORE_TRACE)
1016: HTTrace("Host info... Add Net %p (request %p) to pipe, %d requests made, %d requests in pipe, %d pending\n",
1017: net, net->request, host->reqsMade, HTList_count(host->pipeline), HTList_count(host->pending));
2.18 eric 1018:
2.13 frystyk 1019: /*
2.30 frystyk 1020: ** If we have been idle then make sure we delete the timer
2.13 frystyk 1021: */
2.30 frystyk 1022: if (host->timer) {
1023: HTTimer_delete(host->timer);
1024: host->timer = NULL;
1025: }
2.40 kahan 1026:
1027: /*JK: New CBF function
1028: ** Call any user-defined callback to say the request will
1029: ** be processed.
1030: */
1031: HTHost_ActivateRequest (net);
2.30 frystyk 1032:
2.8 frystyk 1033: } else {
1034: if (!host->pending) host->pending = HTList_new();
2.44 frystyk 1035: HTList_addObject(host->pending, net);
2.32 frystyk 1036: if (CORE_TRACE)
1037: HTTrace("Host info... Add Net %p (request %p) to pending, %d requests made, %d requests in pipe, %d pending\n",
1038: net, net->request, host->reqsMade, HTList_count(host->pipeline), HTList_count(host->pending));
2.8 frystyk 1039: status = HT_PENDING;
1040: }
1041: return status;
1042: }
1043: return HT_ERROR;
1044: }
1045:
2.51 frystyk 1046: PRIVATE BOOL HTHost_free (HTHost * host, int status)
2.13 frystyk 1047: {
2.32 frystyk 1048: if (host->channel) {
2.13 frystyk 1049:
2.32 frystyk 1050: /* Check if we should keep the socket open */
1051: if (HTHost_isPersistent(host)) {
2.48 frystyk 1052: int piped = HTList_count(host->pipeline);
2.37 frystyk 1053: if (HTHost_closeNotification(host)) {
1054: if (CORE_TRACE)
1055: HTTrace("Host Object. got close notifiation on socket %d\n",
1056: HTChannel_socket(host->channel));
1057:
1058: /*
1059: ** If more than a single element (this one) in the pipe
1060: ** then we have to recover gracefully
1061: */
1062: if (piped > 1) {
1063: host->reqsPerConnection = host->reqsMade - piped;
1064: if (CORE_TRACE)
1065: HTTrace("%d requests made, %d in pipe, max %d requests pr connection\n",
1066: host->reqsMade, piped, host->reqsPerConnection);
1067: host->do_recover = YES;
2.38 frystyk 1068: HTChannel_delete(host->channel, status);
1069: } else {
1070: HTChannel_setSemaphore(host->channel, 0);
1071: HTHost_clearChannel(host, status);
2.37 frystyk 1072: }
2.48 frystyk 1073: } else if (piped<=1 && host->reqsMade==host->reqsPerConnection) {
2.37 frystyk 1074: if (CORE_TRACE) HTTrace("Host Object. closing persistent socket %d\n",
1075: HTChannel_socket(host->channel));
2.32 frystyk 1076:
1077: /*
1078: ** By lowering the semaphore we make sure that the channel
1079: ** is gonna be deleted
1080: */
1081: HTChannel_setSemaphore(host->channel, 0);
1082: HTHost_clearChannel(host, status);
1083:
1084: } else {
1085: if (CORE_TRACE) HTTrace("Host Object. keeping persistent socket %d\n", HTChannel_socket(host->channel));
1086: HTChannel_delete(host->channel, status);
1087:
1088: /*
1089: ** If connection is idle then set a timer so that we close the
1090: ** connection if idle too long
1091: */
2.48 frystyk 1092: if (piped<=1 && HTList_isEmpty(host->pending) && !host->timer) {
1093: host->timer = HTTimer_new(NULL, IdleTimeoutEvent,
2.53 frystyk 1094: host, HTActiveTimeout, YES, NO);
2.32 frystyk 1095: if (PROT_TRACE) HTTrace("Host........ Object %p going idle...\n", host);
1096: }
1097: }
1098: return YES;
1099: } else {
2.33 frystyk 1100: if (CORE_TRACE) HTTrace("Host Object. closing socket %d\n", HTChannel_socket(host->channel));
2.47 frystyk 1101: HTChannel_setSemaphore(host->channel, 0);
2.41 frystyk 1102: HTHost_clearChannel(host, status);
2.32 frystyk 1103: }
2.13 frystyk 1104: }
2.32 frystyk 1105: return NO;
2.13 frystyk 1106: }
1107:
2.51 frystyk 1108: PUBLIC BOOL HTHost_deleteNet (HTHost * host, HTNet * net, int status)
2.8 frystyk 1109: {
1110: if (host && net) {
2.44 frystyk 1111: if (CORE_TRACE) HTTrace("Host info... Remove %p from pipe\n", net);
2.51 frystyk 1112:
1113: /* If the Net object is in the pipeline then also update the channel */
1114: if (host->pipeline && HTList_indexOf(host->pipeline, net) >= 0) {
1115: HTHost_free(host, status);
1116: HTList_removeObjectAll(host->pipeline, net);
1117: }
1118:
2.44 frystyk 1119: HTList_removeObjectAll(host->pending, net); /* just to make sure */
2.8 frystyk 1120: return YES;
1121: }
1122: return NO;
1123: }
1124:
1125: /*
1126: ** Handle pending host objects.
1127: ** There are two ways we can end up with pending reqyests:
1128: ** 1) If we are out of sockets then register new host objects as pending.
1129: ** 2) If we are pending on a connection then register new net objects as
1130: ** pending
1131: ** This set of functions handles pending host objects and can start new
1132: ** requests as resources get available
1133: */
1134:
1135: /*
1136: ** Check this host object for any pending requests and return the next
1137: ** registered Net object.
1138: */
1139: PUBLIC HTNet * HTHost_nextPendingNet (HTHost * host)
1140: {
1141: HTNet * net = NULL;
2.32 frystyk 1142: if (host && host->pending) {
2.18 eric 1143: /*JK 23/Sep/96 Bug correction. Associated the following lines to the
1144: **above if. There was a missing pair of brackets.
1145: */
1146: if ((net = (HTNet *) HTList_removeFirstObject(host->pending)) != NULL) {
2.32 frystyk 1147: if (CORE_TRACE)
1148: HTTrace("Host info... Popping %p from pending net queue\n", net);
2.33 frystyk 1149: #if 0
1150: {
1151: HTRequest * request = HTNet_request(net);
1152: char * uri = HTAnchor_address((HTAnchor *) HTRequest_anchor(request));
1153: fprintf(stderr, "Popping '%s'\n", uri);
1154: }
1155: #endif
2.32 frystyk 1156: host->doit = net;
2.18 eric 1157: }
2.8 frystyk 1158: }
1159: return net;
1160: }
1161:
1162: /*
2.13 frystyk 1163: ** Return the current list of pending host objects waiting for a socket
2.8 frystyk 1164: */
1165: PUBLIC HTHost * HTHost_nextPendingHost (void)
1166: {
1167: HTHost * host = NULL;
1168: if (PendHost) {
1169: if ((host = (HTHost *) HTList_removeFirstObject(PendHost)) != NULL)
1170: if (PROT_TRACE)
2.32 frystyk 1171: HTTrace("Host info... Popping %p from pending host queue\n",
2.8 frystyk 1172: host);
1173: }
1174: return host;
1175: }
1176:
1177: /*
1178: ** Start the next pending request if any. First we look for pending
1179: ** requests for the same host and then we check for any other pending
1180: ** hosts
1181: */
1182: PUBLIC BOOL HTHost_launchPending (HTHost * host)
1183: {
2.52 frystyk 1184: HTNet * net = NULL;
2.8 frystyk 1185: if (!host) {
1186: if (PROT_TRACE) HTTrace("Host info... Bad arguments\n");
1187: return NO;
1188: }
1189:
1190: /*
2.52 frystyk 1191: ** In pipeline we can only have one doing writing at a time.
1192: ** We therefore check that there are no other Net object
1193: ** registered for write
2.8 frystyk 1194: */
2.52 frystyk 1195: if (host->mode == HT_TP_PIPELINE) {
1196: net = (HTNet *) HTList_lastObject(host->pipeline);
1197: if (net && net->registeredFor == HTEvent_WRITE)
1198: return NO;
1199: }
2.8 frystyk 1200:
2.52 frystyk 1201: /*
1202: ** Check the current Host object for pending Net objects
1203: */
1204: if (_roomInPipe(host) && DoPendingReqLaunch &&
1205: (net = HTHost_nextPendingNet(host))) {
1206: HTHost_ActivateRequest(net);
1207: if (CORE_TRACE)
1208: HTTrace("Launch pending net object %p with %d reqs in pipe (%d reqs made)\n",
1209: net, HTList_count(host->pipeline), host->reqsMade);
1210: return HTNet_execute(net, HTEvent_WRITE);
1211: }
2.13 frystyk 1212:
2.52 frystyk 1213: /*
1214: ** Check for other pending Host objects
1215: */
1216: if (DoPendingReqLaunch && HTNet_availableSockets() > 0) {
1217: HTHost * pending = HTHost_nextPendingHost();
1218: if (pending && (net = HTHost_nextPendingNet(pending))) {
1219: if (!pending->pipeline) pending->pipeline = HTList_new();
1220: HTList_addObject(pending->pipeline, net);
1221: host->reqsMade++;
1222: if (CORE_TRACE)
1223: HTTrace("Launch pending host object %p, net %p with %d reqs in pipe (%d reqs made)\n",
1224: pending, net, HTList_count(pending->pipeline), pending->reqsMade);
1225: HTHost_ActivateRequest(net);
1226: return HTNet_execute(net, HTEvent_WRITE);
2.8 frystyk 1227: }
2.52 frystyk 1228: }
1229: return YES;
2.13 frystyk 1230: }
1231:
1232: PUBLIC HTNet * HTHost_firstNet (HTHost * host)
1233: {
1234: return (HTNet *) HTList_firstObject(host->pipeline);
1235: }
1236:
1237: /*
1238: ** The host event manager keeps track of the state of it's client engines
1239: ** (typically HTTPEvent), accepting multiple blocks on read or write from
1240: ** multiple pipelined engines. It then registers its own engine
1241: ** (HostEvent) with the event manager.
1242: */
1243: PUBLIC int HTHost_connect (HTHost * host, HTNet * net, char * url, HTProtocolId port)
1244: {
2.42 frystyk 1245: HTRequest * request = HTNet_request(net);
2.52 frystyk 1246: int status = HT_OK;
2.42 frystyk 1247: if (!host) {
1248: HTProtocol * protocol = HTNet_protocol(net);
1249: if ((host = HTHost_newWParse(request, url, HTProtocol_id(protocol))) == NULL)
2.45 frystyk 1250: return HT_ERROR;
2.52 frystyk 1251:
1252: /*
1253: ** If not already locked and without a channel
1254: ** then lock the darn thing
1255: */
1256: if (!host->lock && !host->channel) {
2.42 frystyk 1257: host->forceWriteFlush = YES;
1258: host->lock = net;
1259: }
1260: HTNet_setHost(net, host);
1261: }
1262:
1263: if (!host->lock || (host->lock && host->lock == net)) {
1264: status = HTDoConnect(net, url, port);
1265: if (status == HT_OK) {
1266: host->lock = NULL;
1267: return HT_OK;
1268: }
1269: if (status == HT_WOULD_BLOCK) {
1270: host->lock = net;
2.52 frystyk 1271: return status;
2.42 frystyk 1272: }
1273: if (status == HT_PENDING) return HT_WOULD_BLOCK;
1274: } else {
1275: if ((status = HTHost_addNet(host, net)) == HT_PENDING) {
1276: return HT_PENDING;
1277: }
2.54 ! frystyk 1278: }
! 1279: return HT_ERROR; /* @@@ - some more deletion and stuff here? */
! 1280: }
! 1281:
! 1282: PUBLIC int HTHost_accept (HTHost * host, HTNet * net, HTNet ** accepted,
! 1283: char * url, HTProtocolId port)
! 1284: {
! 1285: HTRequest * request = HTNet_request(net);
! 1286: int status = HT_OK;
! 1287: if (!host) {
! 1288: HTProtocol * protocol = HTNet_protocol(net);
! 1289: if ((host = HTHost_newWParse(request, url, HTProtocol_id(protocol))) == NULL)
! 1290: return HT_ERROR;
! 1291: else {
! 1292: SockA *sin = &host->sock_addr;
! 1293: sin->sin_addr.s_addr = INADDR_ANY;
! 1294: }
! 1295:
! 1296: /*
! 1297: ** If not already locked and without a channel
! 1298: ** then lock the darn thing
! 1299: */
! 1300: if (!host->lock && !host->channel) {
! 1301: host->forceWriteFlush = YES;
! 1302: host->lock = net;
! 1303: }
! 1304: HTNet_setHost(net, host);
! 1305:
! 1306: /*
! 1307: ** Start listening on the socket
! 1308: */
! 1309: {
! 1310: status = HTDoListen(net, port, INVSOC, HT_BACKLOG);
! 1311: if (status != HT_OK) {
! 1312: if (CORE_TRACE) HTTrace("Listen...... On Host %p resulted in %d\n", host, status);
! 1313: return HT_ERROR;
! 1314: }
! 1315: }
! 1316: }
! 1317:
! 1318: if (!host->lock || (host->lock && host->lock == net)) {
! 1319: status = HTDoAccept(net, accepted);
! 1320: if (status == HT_OK) {
! 1321:
! 1322: /* Add the new accepted Net object to the pipeline */
! 1323: HTList_appendObject(host->pipeline, *accepted);
! 1324:
! 1325: /* Unlock the accept object */
! 1326: host->lock = NULL;
! 1327:
! 1328: return HT_OK;
! 1329: }
! 1330: if (status == HT_WOULD_BLOCK) {
! 1331: host->lock = net;
! 1332: return status;
! 1333: }
! 1334: if (status == HT_PENDING) return HT_WOULD_BLOCK;
2.42 frystyk 1335: }
2.13 frystyk 1336: return HT_ERROR; /* @@@ - some more deletion and stuff here? */
1337: }
1338:
1339: /*
1340: ** Rules: SINGLE: one element in pipe, either reading or writing
1341: ** PIPE: n element in pipe, n-1 reading, 1 writing
1342: */
1343: PUBLIC int HTHost_register (HTHost * host, HTNet * net, HTEventType type)
1344: {
2.40 kahan 1345: HTEvent *event;
1346:
2.13 frystyk 1347: if (host && net) {
1348:
2.28 frystyk 1349: if (type == HTEvent_CLOSE) {
2.13 frystyk 1350:
2.28 frystyk 1351: /*
1352: ** Unregister this host for all events
1353: */
1354: HTEvent_unregister(HTChannel_socket(host->channel), HTEvent_READ);
1355: HTEvent_unregister(HTChannel_socket(host->channel), HTEvent_WRITE);
1356: host->registeredFor = 0;
2.13 frystyk 1357: return YES;
2.28 frystyk 1358:
1359: } else {
1360:
1361: /* net object may already be registered */
1362: if (HTEvent_BITS(type) & net->registeredFor)
1363: return NO;
1364: net->registeredFor ^= HTEvent_BITS(type);
1365:
1366: /* host object may already be registered */
1367: if (host->registeredFor & HTEvent_BITS(type))
1368: return YES;
1369: host->registeredFor ^= HTEvent_BITS(type);
2.46 frystyk 1370:
1371: #ifdef WWW_WIN_ASYNC
1372: /* Make sure we are registered for CLOSE on windows */
1373: event = *(host->events+HTEvent_INDEX(HTEvent_CLOSE));
1374: HTEvent_register(HTChannel_socket(host->channel), HTEvent_CLOSE, event);
1375: #endif /* WWW_WIN_ASYNC */
1376:
1377: /* JK: register a request in the event structure */
2.40 kahan 1378: event = *(host->events+HTEvent_INDEX(type));
1379: event->request = HTNet_request (net);
2.28 frystyk 1380: return HTEvent_register(HTChannel_socket(host->channel),
2.40 kahan 1381: type, event);
2.28 frystyk 1382: }
2.52 frystyk 1383:
1384: return YES;
2.13 frystyk 1385: }
2.52 frystyk 1386: if ("HTHost req.. Bad arguments\n");
2.13 frystyk 1387: return NO;
1388: }
1389:
1390: PUBLIC int HTHost_unregister (HTHost * host, HTNet * net, HTEventType type)
1391: {
1392: if (host && net) {
1393:
2.28 frystyk 1394: /* net object may not be registered */
2.13 frystyk 1395: if (!(HTEvent_BITS(type) & net->registeredFor))
1396: return NO;
1397: net->registeredFor ^= HTEvent_BITS(type);
1398:
2.28 frystyk 1399: /* host object may not be registered */
2.13 frystyk 1400: if (!(host->registeredFor & HTEvent_BITS(type)))
1401: return YES;
1402: host->registeredFor ^= HTEvent_BITS(type);
1403:
1404: /* stay registered for READ to catch a socket close */
1405: /* WRITE and CONNECT can be unregistered, though */
1406: if ((type == HTEvent_WRITE && isLastInPipe(host, net)) ||
1407: type == HTEvent_CONNECT)
1408: /* if we are blocked downstream, shut down the whole pipe */
1409: HTEvent_unregister(HTChannel_socket(host->channel), type);
1410: return YES;
1411: }
1412: return NO;
1413: }
1414:
1415: /*
1416: ** The reader tells HostEvent that it's stream did not finish the data
1417: */
1418: PUBLIC BOOL HTHost_setRemainingRead (HTHost * host, size_t remaining)
1419: {
1420: if (host == NULL) return NO;
1421: host->remainingRead = remaining;
2.20 frystyk 1422: if (PROT_TRACE) HTTrace("Host........ %d bytes remaining \n", remaining);
2.45 frystyk 1423: if (host->broken_pipe && remaining == 0) {
1424: if (PROT_TRACE) HTTrace("Host........ Emtied out connection\n");
1425: }
2.13 frystyk 1426: return YES;
1427: }
1428:
2.32 frystyk 1429: PUBLIC size_t HTHost_remainingRead (HTHost * host)
1430: {
1431: return host ? host->remainingRead : -1;
1432: }
1433:
2.13 frystyk 1434: PUBLIC SockA * HTHost_getSockAddr (HTHost * host)
1435: {
1436: if (!host) return NULL;
1437: return &host->sock_addr;
1438: }
1439:
1440: PUBLIC BOOL HTHost_setHome (HTHost * host, int home)
1441: {
1442: if (!host) return NO;
1443: host->home = home;
1444: return YES;
1445: }
1446:
1447: PUBLIC int HTHost_home (HTHost * host)
1448: {
1449: if (!host) return 0;
1450: return host->home;
1451: }
1452:
2.27 frystyk 1453: PUBLIC BOOL HTHost_setRetry (HTHost * host, int retry)
1454: {
1455: if (!host) return NO;
1456: host->retry = retry;
1457: return YES;
1458: }
1459:
1460: PUBLIC BOOL HTHost_decreaseRetry (HTHost * host)
1461: {
2.44 frystyk 1462: if (!host) return NO;
1463:
1464: if (host->retry > 0) host->retry--;
1465: return YES;
1466:
2.27 frystyk 1467: }
1468:
1469: PUBLIC int HTHost_retry (HTHost * host)
1470: {
1471: if (!host) return 0;
1472: return host->retry;
1473: }
1474:
2.13 frystyk 1475: #if 0 /* Is a macro right now */
2.21 frystyk 1476: PRIVATE BOOL HTHost_setDNS5 (HTHost * host, HTdns * dns)
2.13 frystyk 1477: {
1478: if (!host) return NO;
1479: host->dns = dns;
1480: return YES;
1481: }
1482: #endif
1483:
1484: PUBLIC BOOL HTHost_setChannel (HTHost * host, HTChannel * channel)
1485: {
1486: if (!host) return NO;
1487: host->channel = channel;
1488: return YES;
1489: }
1490:
1491: PUBLIC HTNet * HTHost_getReadNet(HTHost * host)
1492: {
2.38 frystyk 1493: return host ? (HTNet *) HTList_firstObject(host->pipeline) : NULL;
2.13 frystyk 1494: }
1495:
1496: PUBLIC HTNet * HTHost_getWriteNet(HTHost * host)
1497: {
1498: return host ? (HTNet *) HTList_lastObject(host->pipeline) : NULL;
1499: }
1500:
1501: /*
1502: ** Create the input stream and bind it to the channel
1503: ** Please read the description in the HTIOStream module for the parameters
1504: */
1505: PUBLIC HTInputStream * HTHost_getInput (HTHost * host, HTTransport * tp,
1506: void * param, int mode)
1507: {
1508: if (host && host->channel && tp) {
1509: HTChannel * ch = host->channel;
1510: HTInputStream * input = (*tp->input_new)(host, ch, param, mode);
1511: HTChannel_setInput(ch, input);
1512: return HTChannel_getChannelIStream(ch);
1513: }
2.24 frystyk 1514: if (CORE_TRACE) HTTrace("Host Object. Can't create input stream\n");
2.13 frystyk 1515: return NULL;
1516: }
1517:
1518: PUBLIC HTOutputStream * HTHost_getOutput (HTHost * host, HTTransport * tp,
1519: void * param, int mode)
1520: {
1521: if (host && host->channel && tp) {
1522: HTChannel * ch = host->channel;
1523: HTOutputStream * output = (*tp->output_new)(host, ch, param, mode);
1524: HTChannel_setOutput(ch, output);
1525: return output;
1526: }
2.24 frystyk 1527: if (CORE_TRACE) HTTrace("Host Object. Can't create output stream\n");
2.13 frystyk 1528: return NULL;
1529: }
1530:
1531: PUBLIC HTOutputStream * HTHost_output (HTHost * host, HTNet * net)
1532: {
1533: if (host && host->channel && net) {
1534: HTOutputStream * output = HTChannel_output(host->channel);
1535: return output;
1536: }
1537: return NULL;
1538: }
1539:
1540: PUBLIC int HTHost_read(HTHost * host, HTNet * net)
1541: {
1542: HTInputStream * input = HTChannel_input(host->channel);
1543: if (net != HTHost_getReadNet(host)) {
1544: HTHost_register(host, net, HTEvent_READ);
1545: return HT_WOULD_BLOCK;
1546: }
2.17 frystyk 1547:
1548: /*
1549: ** If there is no input channel then this can either mean that
1550: ** we have lost the channel or an error occurred. We return
1551: ** HT_CLOSED as this is a sign to the caller that we don't
1552: ** have a channel
1553: */
1554: return input ? (*input->isa->read)(input) : HT_CLOSED;
2.13 frystyk 1555: }
1556:
1557: PUBLIC BOOL HTHost_setConsumed(HTHost * host, size_t bytes)
1558: {
1559: HTInputStream * input;
1560: if (!host || !host->channel) return NO;
1561: if ((input = HTChannel_input(host->channel)) == NULL)
1562: return NO;
2.32 frystyk 1563: if (CORE_TRACE)
2.20 frystyk 1564: HTTrace("Host........ passing %d bytes as consumed to %p\n", bytes, input);
2.13 frystyk 1565: return (*input->isa->consumed)(input, bytes);
1566: }
1567:
1568: PUBLIC int HTHost_hash (HTHost * host)
1569: {
1570: return host ? host->hash : -1;
1571: }
1572:
2.26 frystyk 1573: PUBLIC BOOL HTHost_setWriteDelay (HTHost * host, ms_t delay)
2.13 frystyk 1574: {
2.26 frystyk 1575: if (host && delay >= 0) {
1576: host->delay = delay;
1577: return YES;
1578: }
1579: return NO;
1580: }
1581:
1582: PUBLIC ms_t HTHost_writeDelay (HTHost * host)
1583: {
1584: return host ? host->delay : 0;
1585: }
1586:
1587: PUBLIC int HTHost_findWriteDelay (HTHost * host, ms_t lastFlushTime, int buffSize)
1588: {
2.35 frystyk 1589: #if 0
2.15 eric 1590: unsigned short mtu;
2.18 eric 1591: int ret = -1;
2.15 eric 1592: int socket = HTChannel_socket(host->channel);
2.18 eric 1593: #ifndef WWW_MSWINDOWS
2.15 eric 1594: ret = ioctl(socket, 666, (unsigned long)&mtu);
2.18 eric 1595: #endif /* WWW_MSWINDOWS */
2.15 eric 1596: if ((ret == 0 && buffSize >= mtu) || host->forceWriteFlush)
2.13 frystyk 1597: return 0;
2.26 frystyk 1598: return host->delay;
2.35 frystyk 1599: #else
1600: return host->forceWriteFlush ? 0 : host->delay;
1601: #endif
2.13 frystyk 1602: }
1603:
2.26 frystyk 1604: PUBLIC BOOL HTHost_setDefaultWriteDelay (ms_t delay)
1605: {
1606: if (delay >= 0) {
1607: WriteDelay = delay;
1608: if (CORE_TRACE) HTTrace("Host........ Default write delay is %d ms\n", delay);
1609: return YES;
1610: }
1611: return NO;
1612: }
1613:
1614: PUBLIC ms_t HTHost_defaultWriteDelay (void)
1615: {
1616: return WriteDelay;
1617: }
1618:
2.13 frystyk 1619: PUBLIC int HTHost_forceFlush(HTHost * host)
1620: {
2.35 frystyk 1621: HTNet * targetNet = (HTNet *) HTList_lastObject(host->pipeline);
2.13 frystyk 1622: int ret;
2.35 frystyk 1623: if (targetNet == NULL) return HT_ERROR;
2.13 frystyk 1624: if (CORE_TRACE)
2.28 frystyk 1625: HTTrace("Host Event.. FLUSH passed to `%s\'\n",
1626: HTAnchor_physical(HTRequest_anchor(HTNet_request(targetNet))));
2.13 frystyk 1627: host->forceWriteFlush = YES;
1628: ret = (*targetNet->event.cbf)(HTChannel_socket(host->channel), targetNet->event.param, HTEvent_FLUSH);
2.35 frystyk 1629: host->forceWriteFlush = NO;
2.13 frystyk 1630: return ret;
2.39 frystyk 1631: }
1632:
1633: /*
1634: ** Context pointer to be used as a user defined context
1635: */
1636: PUBLIC void HTHost_setContext (HTHost * me, void * context)
1637: {
2.40 kahan 1638: if (me) me->context = context;
2.39 frystyk 1639: }
1640:
1641: PUBLIC void * HTHost_context (HTHost * me)
1642: {
2.40 kahan 1643: return me ? me->context : NULL;
2.1 frystyk 1644: }
2.11 kahan 1645:
2.13 frystyk 1646: PUBLIC int HTHost_eventTimeout (void)
1647: {
1648: return EventTimeout;
1649: }
2.11 kahan 1650:
2.13 frystyk 1651: PUBLIC void HTHost_setEventTimeout (int millis)
1652: {
1653: EventTimeout = millis;
1654: if (CORE_TRACE) HTTrace("Host........ Setting event timeout to %d ms\n", millis);
1655: }
2.40 kahan 1656:
2.45 frystyk 1657: PUBLIC BOOL HTHost_setMaxPipelinedRequests (int max)
1658: {
1659: if (max > 1) {
1660: MaxPipelinedRequests = max;
1661: return YES;
1662: }
1663: return NO;
1664: }
2.40 kahan 1665:
2.45 frystyk 1666: PUBLIC int HTHost_maxPipelinedRequests (void)
2.40 kahan 1667: {
2.45 frystyk 1668: return MaxPipelinedRequests;
1669: }
1670:
1671: PUBLIC void HTHost_setActivateRequestCallback (HTHost_ActivateRequestCallback * cbf)
1672: {
1673: if (CORE_TRACE) HTTrace("HTHost...... Registering %p\n", cbf);
2.40 kahan 1674: ActivateReqCBF = cbf;
1675: }
1676:
2.45 frystyk 1677: PRIVATE int HTHost_ActivateRequest (HTNet * net)
2.40 kahan 1678: {
2.45 frystyk 1679: HTRequest * request = NULL;
1680: if (!ActivateReqCBF) {
1681: if (CORE_TRACE)
1682: HTTrace("HTHost...... No ActivateRequest callback handler registered\n");
1683: return HT_ERROR;
1684: }
1685: request = HTNet_request(net);
1686: return (*ActivateReqCBF)(request);
2.40 kahan 1687: }
1688:
1689: PUBLIC void HTHost_disable_PendingReqLaunch (void)
1690: {
2.45 frystyk 1691: DoPendingReqLaunch = NO;
2.40 kahan 1692: }
1693:
1694: PUBLIC void HTHost_enable_PendingReqLaunch (void)
1695: {
2.45 frystyk 1696: DoPendingReqLaunch = YES;
2.40 kahan 1697: }
1698:
Webmaster