⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hthost.c

📁 www工具包. 这是W3C官方支持的www支撑库. 其中提供通用目的的客户端的WebAPI: complete HTTP/1.1 (with caching, pipelining, PUT, POS
💻 C
📖 第 1 页 / 共 4 页
字号:
PUBLIC BOOL HTHost_setMode (HTHost * host, HTTransportMode mode){    if (host) {	/*	**  Check the new mode and see if we must adjust the queues.	*/	if (mode == HT_TP_SINGLE && host->mode > mode) {	    int piped = HTList_count(host->pipeline);	    if (piped > 0) {		int cnt;		HTTRACE(CORE_TRACE, "Host info... Moving %d Net objects from pipe line to pending queue\n" _ piped);		if (!host->pending) host->pending = HTList_new();		for (cnt=0; cnt<piped; cnt++) {		    HTNet * net = HTList_removeLastObject(host->pipeline);		    HTTRACE(CORE_TRACE, "Host info... Resetting net object %p\n" _ net);		    (*net->event.cbf)(HTChannel_socket(host->channel), net->event.param, HTEvent_RESET);		    HTList_appendObject(host->pending, net);		}		HTChannel_setSemaphore(host->channel, 0);		HTHost_clearChannel(host, HT_INTERRUPTED);	    }	}	/*	**  If we know that this host is bad then we don't allow anything than	**  single mode. We can't recover connections for the rest of our life	*/	if (mode == HT_TP_PIPELINE && host->recovered > MAX_HOST_RECOVER) {	    HTTRACE(PROT_TRACE, "Host info... %p is bad for pipelining so we won't do it!!!\n" _ 			host);	} else {	    host->mode = mode;	    HTTRACE(PROT_TRACE, "Host info... New mode is %d for host %p\n" _ host->mode _ host);	}    }    return NO;}/***	Check whether a host is idle meaning if it is ready for a new**	request which depends on the mode of the host. If the host is **	idle, i.e. ready for use then return YES else NO. If the host supports**	persistent connections then still only return idle if no requests are**	ongoing. */PUBLIC BOOL HTHost_isIdle (HTHost * host){    return (host && HTList_isEmpty(host->pipeline));}PRIVATE BOOL _roomInPipe (HTHost * host){    int count;    if (!host ||	(host->reqsPerConnection && host->reqsMade >= host->reqsPerConnection) ||	HTHost_closeNotification(host) || host->broken_pipe)	return NO;    count = HTList_count(host->pipeline);    switch (host->mode) {    case HT_TP_SINGLE:	return count <= 0;    case HT_TP_PIPELINE:	return (host->recovered < MAX_HOST_RECOVER) ?	    (count < MaxPipelinedRequests) : (count <= 0);    case HT_TP_INTERLEAVE:	return YES;    }    return NO;}/***	Add a net object to the host object. If the host**	is idle then add to active list (pipeline) else add**	it to the pending list**	Return HT_PENDING if we must pend, HT_OK, or HT_ERROR*/PUBLIC int HTHost_addNet (HTHost * host, HTNet * net){    if (host && net) {	int status = HT_OK;	BOOL doit = (host->doit==net);	/*	**  If we don't have a socket already then check to see if we can get	**  one. Otherwise we put the host object into our pending queue.	*/	if (!host->channel && HTNet_availableSockets() <= 0) {	    /* Create list for pending Host objects */	    if (!PendHost) PendHost = HTList_new();	    /* Add the host object ad pending if not already */	    if (HTList_indexOf(PendHost, host) < 0) HTList_addObject(PendHost, host);	    /* 	    ** Add the Net object to the Host object. If it is the current Net	    ** obejct holding the lock then add it to the beginning of the list.	    ** Otherwise add it to the end	    */	    if (!host->pending) host->pending = HTList_new();	    if (host->lock == net)		HTList_appendObject(host->pending, net);	    else		HTList_addObject(host->pending, net); 	    HTTRACE(CORE_TRACE, "Host info... Added Net %p (request %p) as pending on pending Host %p, %d requests made, %d requests in pipe, %d pending\n" _ 			net _ net->request _ host _ host->reqsMade _ 			HTList_count(host->pipeline) _ HTList_count(host->pending));	    return HT_PENDING;	}#if 0	/*	** First check whether the net object is already on either queue.	** Do NOT add extra copies of the HTNet object to	** the pipeline or pending list (if it's already on the list).	*/	if (HTList_indexOf(host->pipeline, net) >= 0) {	    HTTRACE(CORE_TRACE, "Host info... The Net %p (request %p) is already in pipe,"			" %d requests made, %d requests in pipe, %d pending\n" _ 			net _ net->request _ host->reqsMade _ 			HTList_count(host->pipeline) _ 			HTList_count(host->pending));	    HTDEBUGBREAK("Net object %p registered multiple times in pipeline\n" _ 			 net);	    return HT_OK;	}	if (HTList_indexOf(host->pending,  net) >= 0) {	    HTTRACE(CORE_TRACE, "Host info... The Net %p (request %p) already pending,"			" %d requests made, %d requests in pipe, %d pending\n" _ 			net _ net->request _ host->reqsMade _ 			HTList_count(host->pipeline) _ 			HTList_count(host->pending));	    HTDEBUGBREAK("Net object %p registered multiple times in pending queue\n" _ 			 net);	    return HT_PENDING;	}#endif	/*	**  Add net object to either active or pending queue.	*/	if (_roomInPipe(host) && (HTList_isEmpty(host->pending) || doit)) {	    if (doit) host->doit = NULL;	    if (!host->pipeline) host->pipeline = HTList_new();	    HTList_addObject(host->pipeline, net);	    host->reqsMade++;            HTTRACE(CORE_TRACE, "Host info... Added Net %p (request %p) to pipe on Host %p, %d requests made, %d requests in pipe, %d pending\n" _ 			net _ net->request _ host _ host->reqsMade _ 			HTList_count(host->pipeline) _ HTList_count(host->pending));	    /*	    **  If we have been idle then make sure we delete the timer	    */	    if (host->timer) {		HTTimer_delete(host->timer);		host->timer = NULL;	    }                       /*JK: New CBF function	    ** Call any user-defined callback to say the request will            ** be processed.            */            HTHost_ActivateRequest (net);	} else {	    if (!host->pending) host->pending = HTList_new();	    HTList_addObject(host->pending, net);	    	    HTTRACE(CORE_TRACE, "Host info... Added Net %p (request %p) as pending on Host %p, %d requests made, %d requests in pipe, %d pending\n" _ 			net _ net->request _ 			host _ host->reqsMade _ 			HTList_count(host->pipeline) _ HTList_count(host->pending));	    status = HT_PENDING;	}	return status;    }    return HT_ERROR;}PRIVATE BOOL HTHost_free (HTHost * host, int status){    if (host->channel) {	/* Check if we should keep the socket open */        if (HTHost_isPersistent(host)) {	    int piped = HTList_count(host->pipeline);            if (HTHost_closeNotification(host)) {		HTTRACE(CORE_TRACE, "Host Object. got close notifiation on socket %d\n" _ 			    HTChannel_socket(host->channel));                		/*		**  If more than a single element (this one) in the pipe		**  then we have to recover gracefully		*/		if (piped > 1) {		    host->reqsPerConnection = host->reqsMade - piped;		    HTTRACE(CORE_TRACE, "%d requests made, %d in pipe, max %d requests pr connection\n" _ 				host->reqsMade _ piped _ host->reqsPerConnection);		    host->do_recover = YES;		    /* @@ JK: not clear yet if I need or not to set the channel to NULL. I think not */		    /* HTChannel_delete(host->channel, status);  */		    if (HTChannel_delete(host->channel, status)) {			HTTRACE(CORE_TRACE, "Host Event.. clearing channel on host %p (%s)\n" _ host _ host->hostname);			host->channel = NULL;		    }		} else {		    HTChannel_setSemaphore(host->channel, 0);		    HTHost_clearChannel(host, status);		}	    } else if (piped<=1 && host->reqsMade==host->reqsPerConnection) {                HTTRACE(CORE_TRACE, "Host Object. closing persistent socket %d\n" _ 			HTChannel_socket(host->channel));                                /*                 **  By lowering the semaphore we make sure that the channel                **  is gonna be deleted                */                HTChannel_setSemaphore(host->channel, 0);                HTHost_clearChannel(host, status);            } else {                HTTRACE(CORE_TRACE, "Host Object. keeping persistent socket %d\n" _ 			HTChannel_socket(host->channel));                if (HTChannel_delete(host->channel, status)) {		    HTDEBUGBREAK("Host Event.. Channel unexpected deleted from host %p (%s)\n" _ host _ host->hostname);		    host->channel = NULL;                }                /*                **  If connection is idle then set a timer so that we close the                 **  connection if idle too long                */                if (piped<=1 && HTList_isEmpty(host->pending) && !host->timer) {                    host->timer = HTTimer_new(NULL, IdleTimeoutEvent,					      host, HTActiveTimeout, YES, NO);                    HTTRACE(PROT_TRACE, "Host........ Object %p going idle...\n" _ host);                }            }            return YES;        } else {            HTTRACE(CORE_TRACE, "Host Object. closing socket %d\n" _ HTChannel_socket(host->channel));	    HTChannel_setSemaphore(host->channel, 0);	    HTHost_clearChannel(host, status);        }    }    return NO;}PUBLIC BOOL HTHost_deleteNet (HTHost * host, HTNet * net, int status){    if (host && net) {        HTTRACE(CORE_TRACE, "Host info... Remove %p from pipe\n" _ net);	/* If the Net object is in the pipeline then also update the channel */	if (host->pipeline && HTList_indexOf(host->pipeline, net) >= 0) {	    HTHost_free(host, status);	    HTList_removeObjectAll(host->pipeline, net);	}	HTList_removeObjectAll(host->pending, net); /* just to make sure */	host->lock = HTList_firstObject(host->pending);	return YES;    }    return NO;}/***	Handle pending host objects.**	There are two ways we can end up with pending reqyests:**	 1) If we are out of sockets then register new host objects as pending.**	 2) If we are pending on a connection then register new net objects as**	    pending**	This set of functions handles pending host objects and can start new**	requests as resources get available*//***	Check this host object for any pending requests and return the next**	registered Net object.*/PUBLIC HTNet * HTHost_nextPendingNet (HTHost * host){    HTNet * net = NULL;    if (host && host->pending) {	/*JK 23/Sep/96 Bug correction. Associated the following lines to the	**above if. There was a missing pair of brackets. 	*/	if ((net = (HTNet *) HTList_removeFirstObject(host->pending)) != NULL) {	    HTTRACE(CORE_TRACE, "Host info... Popping %p from pending net queue on host %p\n" _ 			net _ host);#if 0	    {		HTRequest * request = HTNet_request(net);		char * uri = HTAnchor_address((HTAnchor *) HTRequest_anchor(request));		fprintf(stderr, "Popping '%s'\n", uri);	    }#endif	    host->doit = net;	}    }    return net;}/***	Return the current list of pending host objects waiting for a socket*/PUBLIC HTHost * HTHost_nextPendingHost (void){    HTHost * host = NULL;    if (PendHost) {	if ((host = (HTHost *) HTList_removeFirstObject(PendHost)) != NULL)	    HTTRACE(PROT_TRACE, "Host info... Popping %p from pending host queue\n" _ 			host);    }    return host;}/***	Start the next pending request if any. First we look for pending**	requests for the same host and then we check for any other pending**	hosts*/PUBLIC BOOL HTHost_launchPending (HTHost * host){    HTNet * net = NULL;    if (!host) {	HTTRACE(PROT_TRACE, "Host info... Bad arguments\n");	return NO;    }    /*    **  In pipeline we can only have one doing writing at a time.    **  We therefore check that there are no other Net object    **  registered for write    */    if (host->mode == HT_TP_PIPELINE) {	net = (HTNet *) HTList_lastObject(host->pipeline);	if (net && net->registeredFor == HTEvent_WRITE)	    return NO;    }    /*    **  Check the current Host object for pending Net objects    */    if (_roomInPipe(host) && DoPendingReqLaunch &&	   (net = HTHost_nextPendingNet(host))) {	HTHost_ActivateRequest(net);	HTTRACE(CORE_TRACE, "Launch pending net object %p with %d reqs in pipe (%d reqs made)\n" _ 		    net _ HTList_count(host->pipeline) _ host->reqsMade);	return HTNet_execute(net, HTEvent_WRITE);    }    /*    **  Check for other pending Host objects    */    if (DoPendingReqLaunch && HTNet_availableSockets() > 0) {	HTHost * pending = HTHost_nextPendingHost();	if (pending && (net = HTHost_nextPendingNet(pending))) {	    if (!pending->pipeline) pending->pipeline = HTList_new();	    HTList_addObject(pending->pipeline, net);	    host->reqsMade++;	    HTTRACE(CORE_TRACE, "Launch pending host object %p, net %p with %d reqs in pipe (%d reqs made)\n" _ 			pending _ net _ HTList_count(pending->pipeline) _ pending->reqsMade);	    HTHost_ActivateRequest(net);	    return HTNet_execute(net, HTEvent_WRITE);	}    }    return YES;}PUBLIC HTNet * HTHost_firstNet (HTHost * host){    return (HTNet *) HTList_firstObject(host->pipeline);}PUBLIC int HTHost_numberOfOutstandingNetObjects (HTHost * host){    return host ? HTList_count(host->pipeline) : -1;}PUBLIC int HTHost_numberOfPendingNetObjects (HTHost * host){    return host ? HTList_count(host->pending) : -1;}/***	The host event manager keeps track of the state of it's client engines**	(typically HTTPEvent), accepting multiple blocks on read or write from**	multiple pipelined engines. It then registers its own engine **	(HostEvent) with the event manager.*/PUBLIC int HTHost_connect (HTHost * host, HTNet * net, char * url){    HTRequest * request = HTNet_request(net);    int status = HT_OK;    if (!host) {	HTProtocol * protocol = HTNet_protocol(net);	if ((host = HTHost_newWParse(request, url, HTProtocol_id(protocol))) == NULL)	    return HT_ERROR;	/*	** If not already locked and without a channel	** then lock the darn thing with the first Net object	** pending.	*/	if (!host->lock && !host->channel) {	    HTNet * next_pending = NULL;	    host->forceWriteFlush = YES;	    host->lock = (next_pending = HTList_firstObject(host->pending)) ?		next_pending : net;	    HTTRACE(CORE_TRACE, "Host connect Grabbing lock on Host %p with %p\n" _ host _ host->lock);	}	HTNet_setHost(net, host);    }    if (!host->lock || (host->lock && host->lock == net)) {	status = HTDoConnect(net);	if (status == HT_PENDING)	    return HT_WOULD_BLOCK;	else if (status == HT_WOULD_BLOCK) {	    host->lock = net;	    return status;	} else {	    /*	    **  See if there is already a new pending request that should	    **  take over the current lock	    */	    HTNet * next_pending = NULL;	    if ((next_pending = HTList_firstObject(host->pending))) {		HTTRACE(CORE_TRACE, "Host connect Changing lock on Host %p to %p\n" _ 			host _ next_pending);		host->lock = next_pending;	    	    } else {		HTTRACE(CORE_TRACE, "Host connect Unlocking Host %p\n" _ host);		host->lock = NULL;	    	    }	    return status;	}    } else {	HTTRACE(CORE_TRACE, "Host connect Host %p already locked with %p\n" _ host _ host->lock);	if ((status = HTHost_addNet(host, net)) == HT_PENDING) {	    return HT_PENDING;	}    }    return HT_ERROR; /* @@@ - some more deletion and stuff here? */}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -