📄 hthost.c
字号:
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 + -