📄 hthost.c
字号:
/* HTHost.c** REMOTE HOST INFORMATION**** (c) COPYRIGHT MIT 1995.** Please first read the full copyright statement in the file COPYRIGH.** @(#) $Id: HTHost.c,v 2.72 2000/07/28 13:56:08 kahan Exp $**** This object manages the information that we know about a remote host.** This can for example be what type of host it is, and what version** it is using. We also keep track of persistent connections**** April 96 HFN Written*//* Library include files */#include "wwwsys.h"#include "WWWUtil.h"#include "HTParse.h"#include "HTAlert.h"#include "HTError.h"#include "HTNetMan.h"#include "HTTrans.h"#include "HTTPUtil.h"#include "HTTCP.h"#include "HTHost.h" /* Implemented here */#include "HTHstMan.h"#define HOST_OBJECT_TTL 43200L /* Default host timeout is 12 h */#define TCP_IDLE_PASSIVE 120L /* Passive TTL in s on an idle connection */#define TCP_IDLE_ACTIVE 60000L /* Active TTL in ms on an idle connection */#define MAX_PIPES 50 /* maximum number of pipelined requests */#define MAX_HOST_RECOVER 1 /* Max number of auto recovery */#define DEFAULT_DELAY 30 /* Default write flush delay in ms */struct _HTInputStream { const HTInputStreamClass * isa;};PRIVATE int HostEvent(SOCKET soc, void * pVoid, HTEventType type);/* Type definitions and global variables etc. local to this module */PRIVATE time_t HostTimeout = HOST_OBJECT_TTL; /* Timeout for host objects */PRIVATE time_t HTPassiveTimeout = TCP_IDLE_PASSIVE; /* Passive timeout in s */PRIVATE ms_t HTActiveTimeout = TCP_IDLE_ACTIVE; /* Active timeout in ms */PRIVATE HTList ** HostTable = NULL;PRIVATE HTList * PendHost = NULL; /* List of pending host elements *//* JK: New functions for interruption the automatic pending request activation */PRIVATE HTHost_ActivateRequestCallback * ActivateReqCBF = NULL;PRIVATE int HTHost_ActivateRequest (HTNet *net);PRIVATE BOOL DoPendingReqLaunch = YES; /* controls automatic activation of pending requests */PRIVATE int EventTimeout = -1; /* Global Host event timeout */PRIVATE ms_t WriteDelay = DEFAULT_DELAY; /* Delay in ms */PRIVATE int MaxPipelinedRequests = MAX_PIPES;/* ------------------------------------------------------------------------- */PRIVATE void free_object (HTHost * me){ if (me) { int i; HT_FREE(me->hostname); HT_FREE(me->type); HT_FREE(me->server); HT_FREE(me->user_agent); HT_FREE(me->range_units); /* Delete the channel (if any) */ if (me->channel) { HTChannel_delete(me->channel, HT_OK); me->channel = NULL; } /* Unregister the events */ for (i = 0; i < HTEvent_TYPES; i++) HTEvent_delete(me->events[i]); /* Delete the timer (if any) */ if (me->timer) HTTimer_delete(me->timer); /* Delete the queues */ HTList_delete(me->pipeline); HTList_delete(me->pending); HT_FREE(me); }}PRIVATE BOOL delete_object (HTList * list, HTHost * me){ HTTRACE(CORE_TRACE, "Host info... object %p from list %p\n" _ me _ list); HTList_removeObject(list, (void *) me); free_object(me); return YES;}PRIVATE BOOL isLastInPipe (HTHost * host, HTNet * net){ return HTList_lastObject(host->pipeline) == net;}PRIVATE BOOL killPipeline (HTHost * host, HTEventType type){ if (host) { int piped = HTList_count(host->pipeline); int pending = HTList_count(host->pending); int cnt; HTTRACE(CORE_TRACE, "Host kill... Pipeline due to %s event\n" _ HTEvent_type2str(type)); /* Terminate all net objects in pending queue */ for (cnt=0; cnt<pending; cnt++) { HTNet * net = HTList_removeLastObject(host->pending); if (net) { HTTRACE(CORE_TRACE, "Host kill... Terminating net object %p from pending queue\n" _ net); net->registeredFor = 0; (*net->event.cbf)(HTChannel_socket(host->channel), net->event.param, type); if (host->lock == net) host->lock = NULL; } } /* Terminate all net objects in pipeline */ if (piped >= 1) { /* ** Terminte all net objects in the pipeline */ for (cnt=0; cnt<piped; cnt++) { HTNet * net = HTList_firstObject(host->pipeline); if (net) { HTTRACE(CORE_TRACE, "Host kill... Terminating net object %p from pipe line\n" _ net); net->registeredFor = 0; (*net->event.cbf)(HTChannel_socket(host->channel), net->event.param, type); } } } return YES; } return NO;}/*** Silently close an idle persistent connection after ** HTActiveTimeout secs*/PRIVATE int IdleTimeoutEvent (HTTimer * timer, void * param, HTEventType type){ HTHost * host = (HTHost *) param; SOCKET sockfd = HTChannel_socket(host->channel); HTTimer_delete(timer); host->timer = NULL; return HostEvent (sockfd, host, HTEvent_CLOSE);}/*** HostEvent - host event manager - recieves events from the event ** manager and dispatches them to the client net objects by calling the ** net object's cbf.***/PRIVATE int HostEvent (SOCKET soc, void * pVoid, HTEventType type){ HTHost * host = (HTHost *)pVoid; if (type == HTEvent_READ || type == HTEvent_CLOSE || type == HTEvent_ACCEPT) { HTNet * targetNet; /* call the first net object */ do { int ret; /* netscape and apache servers can do a lazy close well after usage * of previous socket has been dispensed by the library, * the section below makes sure the event does not get miss attributed */ if (HTChannel_socket(host->channel) != soc && type != HTEvent_ACCEPT && !host->listening) { HTTRACE(CORE_TRACE, "Host Event.. wild socket %d type = %s real socket is %d\n" _ soc _ type == HTEvent_CLOSE ? "Event_Close" : "Event_Read" _ HTChannel_socket(host->channel)); return HT_OK; } targetNet = (HTNet *)HTList_firstObject(host->pipeline); if (targetNet) { HTTRACE(CORE_TRACE, "Host Event.. READ passed to `%s\'\n" _ HTAnchor_physical(HTRequest_anchor(HTNet_request(targetNet)))); if ((ret = (*targetNet->event.cbf)(HTChannel_socket(host->channel), targetNet->event.param, type)) != HT_OK) return ret; } if (targetNet == NULL && host->remainingRead > 0) { HTTRACE(CORE_TRACE, "HostEvent... Error: %d bytes left to read and nowhere to put them\n" _ host->remainingRead); host->remainingRead = 0; /* ** Fall through to close the channel */ } /* call pipelined net object to eat all the data in the channel */ } while (host->remainingRead > 0); /* last target net should have set remainingRead to 0 */ if (targetNet) return HT_OK; /* If there was notargetNet, it should be a close */ HTTRACE(CORE_TRACE, "Host Event.. host %p `%s\' closed connection.\n" _ host _ host->hostname); /* Is there garbage in the channel? Let's check: */ { char buf[256]; int ret; memset(buf, '\0', sizeof(buf)); if (HTChannel_socket(host->channel) != INVSOC) { while ((ret = NETREAD(HTChannel_socket(host->channel), buf, sizeof(buf)-1)) > 0) { HTTRACE(CORE_TRACE, "Host Event.. Host %p `%s\' had %d extraneous bytes: `%s\'\n" _ host _ host->hostname _ ret _ buf); memset(buf, '\0', sizeof(buf)); } } } HTHost_clearChannel(host, HT_OK); return HT_OK; /* extra garbage does not constitute an application error */ } else if (type == HTEvent_WRITE || type == HTEvent_CONNECT) { HTNet * targetNet = (HTNet *)HTList_lastObject(host->pipeline); if (targetNet) { HTTRACE(CORE_TRACE, "Host Event.. WRITE passed to `%s\'\n" _ HTAnchor_physical(HTRequest_anchor(HTNet_request(targetNet)))); return (*targetNet->event.cbf)(HTChannel_socket(host->channel), targetNet->event.param, type); } HTTRACE(CORE_TRACE, "Host Event Host %p (`%s\') dispatched with event %s but doesn't have a target - %d requests made, %d requests in pipe, %d pending\n" _ host _ host ? host->hostname : "<null>" _ HTEvent_type2str(type) _ host ? host->reqsMade : -1 _ HTList_count(host->pipeline) _ HTList_count(host->pending));#if 0 HTDEBUGBREAK("Host Event.. Host %p (`%s\') dispatched with event %d\n" _ host _ host ? host->hostname : "<null>" _ type); return HT_ERROR;#else return HT_OK;#endif } else if (type == HTEvent_TIMEOUT) { killPipeline(host, HTEvent_TIMEOUT); } else { HTTRACE(CORE_TRACE, "Don't know how to handle OOB data from `%s\'?\n" _ host->hostname); } return HT_OK;}/*** Search the host info cache for a host object or create a new one** and add it. Examples of host names are**** www.w3.org** www.foo.com:8000** 18.52.0.18**** Returns Host object or NULL if error. You may get back an already** existing host object - you're not guaranteed a new one each time.*/PUBLIC HTHost * HTHost_new (char * host, u_short u_port){ HTList * list = NULL; /* Current list in cache */ HTHost * pres = NULL; int hash = 0; if (!host) { HTTRACE(CORE_TRACE, "Host info... Bad argument\n"); return NULL; } /* Find a hash for this host */ { char *ptr; for (ptr=host; *ptr; ptr++) hash = (int) ((hash * 3 + (*(unsigned char *) ptr)) % HOST_HASH_SIZE); if (!HostTable) { if ((HostTable = (HTList **) HT_CALLOC(HOST_HASH_SIZE, sizeof(HTList *))) == NULL) HT_OUTOFMEM("HTHost_find"); } if (!HostTable[hash]) HostTable[hash] = HTList_new(); list = HostTable[hash]; } /* Search the cache */ { HTList * cur = list; while ((pres = (HTHost *) HTList_nextObject(cur))) { if (!strcmp(pres->hostname, host) && u_port == pres->u_port) { if (HTHost_isIdle(pres) && time(NULL)>pres->ntime+HostTimeout){ HTTRACE(CORE_TRACE, "Host info... Collecting host info %p\n" _ pres); delete_object(list, pres); pres = NULL; } break; } } } /* If not found then create new Host object, else use existing one */ if (pres) { if (pres->channel) { /* ** If we have a TTL for this TCP connection then ** check that we haven't passed it. */ if (pres->expires > 0) { time_t t = time(NULL); if (HTHost_isIdle(pres) && pres->expires < t) { HTTRACE(CORE_TRACE, "Host info... Persistent channel %p gotten cold\n" _ pres->channel); HTHost_clearChannel(pres, HT_OK); } else { pres->expires = t + HTPassiveTimeout; HTTRACE(CORE_TRACE, "Host info... REUSING CHANNEL %p\n" _ pres->channel); } } } else { HTTRACE(CORE_TRACE, "Host info... Found Host %p with no active channel\n" _ pres); } } else { if ((pres = (HTHost *) HT_CALLOC(1, sizeof(HTHost))) == NULL) HT_OUTOFMEM("HTHost_add"); pres->hash = hash; StrAllocCopy(pres->hostname, host); pres->u_port = u_port; pres->ntime = time(NULL); pres->mode = HT_TP_SINGLE; pres->delay = WriteDelay; pres->inFlush = NO; { int i; for (i = 0; i < HTEvent_TYPES; i++) pres->events[i]= HTEvent_new(HostEvent, pres, HT_PRIORITY_MAX, EventTimeout); } HTTRACE(CORE_TRACE, "Host info... added `%s\' with host %p to list %p\n" _ host _ pres _ list); HTList_addObject(list, (void *) pres); } return pres;}PUBLIC HTHost * HTHost_newWParse (HTRequest * request, char * url, u_short u_port){ char * port; char * fullhost = NULL; char * parsedHost = NULL; SockA * sin; HTHost * me; char * proxy = HTRequest_proxy(request); fullhost = HTParse(proxy ? proxy : url, "", PARSE_HOST); /* If there's an @ then use the stuff after it as a hostname */ if (fullhost) { char * at_sign; if ((at_sign = strchr(fullhost, '@')) != NULL) parsedHost = at_sign+1; else parsedHost = fullhost; } if (!parsedHost || !*parsedHost) { HTRequest_addError(request, ERR_FATAL, NO, HTERR_NO_HOST, NULL, 0, "HTHost_newWParse"); HT_FREE(fullhost); return NULL; } /* See if the default port should be overridden */ if ((port = strchr(parsedHost, ':')) != NULL) { *port++ = '\0'; if (*port && isdigit((int) *port)) u_port = (u_short) atol(port); } HTTRACE(PROT_TRACE, "HTHost parse Looking up `%s\' on port %u\n" _ parsedHost _ u_port); /* Find information about this host */ if ((me = HTHost_new(parsedHost, u_port)) == NULL) { HTTRACE(PROT_TRACE, "HTHost parse Can't get host info\n"); me->tcpstate = TCP_ERROR; return NULL; } sin = &me->sock_addr; memset((void *) sin, '\0', sizeof(SockA));#ifdef DECNET sin->sdn_family = AF_DECnet; net->sock_addr.sdn_objnum = port ? (unsigned char)(strtol(port, (char **) 0, 10)) : DNP_OBJ;#else /* Internet */ sin->sin_family = AF_INET; sin->sin_port = htons(u_port);#endif HT_FREE(fullhost); /* parsedHost points into fullhost */ return me;}/*** Search the host info cache for a host object. Examples of host names:**** www.w3.org** www.foo.com:8000** 18.52.0.18**** Returns Host object or NULL if not found.*/PUBLIC HTHost * HTHost_find (char * host){ HTList * list = NULL; /* Current list in cache */ HTHost * pres = NULL; HTTRACE(CORE_TRACE, "Host info... Looking for `%s\'\n" _ host ? host : "<null>"); /* Find a hash for this host */ if (host && HostTable) { int hash = 0; char *ptr; for (ptr=host; *ptr; ptr++) hash = (int) ((hash * 3 + (*(unsigned char *) ptr)) % HOST_HASH_SIZE); if (!HostTable[hash]) return NULL; list = HostTable[hash]; /* Search the cache */ { HTList * cur = list; while ((pres = (HTHost *) HTList_nextObject(cur))) { if (!strcmp(pres->hostname, host)) { if (time(NULL) > pres->ntime + HostTimeout) { HTTRACE(CORE_TRACE, "Host info... Collecting host %p\n" _ pres); delete_object(list, pres); pres = NULL; } else { HTTRACE(CORE_TRACE, "Host info... Found `%s\'\n" _ host); } return pres; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -