2 * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
9 /* DEBUG: section 12 Internet Cache Protocol (ICP) */
12 \defgroup ServerProtocolICPInternal2 ICPv2 Internals
13 \ingroup ServerProtocolICPAPI
17 #include "AccessLogEntry.h"
19 #include "acl/FilledChecklist.h"
20 #include "client_db.h"
22 #include "comm/Connection.h"
23 #include "comm/Loops.h"
24 #include "comm/UdpOpenDialer.h"
26 #include "HttpRequest.h"
27 #include "icmp/net_db.h"
29 #include "ip/Address.h"
33 #include "multicast.h"
34 #include "neighbors.h"
37 #include "SquidConfig.h"
38 #include "SquidTime.h"
39 #include "StatCounters.h"
41 #include "store_key_md5.h"
45 // for tvSubUsec() which should be in SquidTime.h
50 /// a delayed icpUdpSend() call
51 class DelayedUdpSend
{
53 Ip::Address address
; ///< remote peer (which may not be a cache_peer)
54 icp_common_t
*msg
= nullptr; ///< ICP message with network byte order fields
55 DelayedUdpSend
*next
= nullptr; ///< invasive FIFO queue of delayed ICP messages
56 AccessLogEntryPointer ale
; ///< sender's master transaction summary
57 struct timeval queue_time
= {0, 0}; ///< queuing timestamp
60 static void icpIncomingConnectionOpened(const Comm::ConnectionPointer
&conn
, int errNo
);
62 /// \ingroup ServerProtocolICPInternal2
63 static void icpLogIcp(const Ip::Address
&, const LogTags_ot
, int, const char *, const int, AccessLogEntryPointer
&);
65 /// \ingroup ServerProtocolICPInternal2
66 static void icpHandleIcpV2(int, Ip::Address
&, char *, int);
68 /// \ingroup ServerProtocolICPInternal2
69 static void icpCount(void *, int, size_t, int);
71 static LogTags_ot
icpLogFromICPCode(icp_opcode
);
73 static int icpUdpSend(int fd
, const Ip::Address
&to
, icp_common_t
* msg
, int delay
, AccessLogEntryPointer al
);
76 icpSyncAle(AccessLogEntryPointer
&al
, const Ip::Address
&caddr
, const char *url
, int len
, int delay
)
79 al
= new AccessLogEntry();
80 al
->icp
.opcode
= ICP_QUERY
;
81 al
->cache
.caddr
= caddr
;
83 al
->setVirginUrlForMissingRequest(al
->url
);
84 // XXX: move to use icp.clientReply instead
85 al
->http
.clientReplySz
.payloadData
= len
;
86 al
->cache
.start_time
= current_time
;
87 al
->cache
.start_time
.tv_sec
-= delay
;
88 al
->cache
.trTime
.tv_sec
= delay
;
89 al
->cache
.trTime
.tv_usec
= 0;
93 \ingroup ServerProtocolICPInternal2
94 * IcpQueueHead is global so comm_incoming() knows whether or not
95 * to call icpUdpSendQueue.
97 static DelayedUdpSend
*IcpQueueHead
= NULL
;
98 /// \ingroup ServerProtocolICPInternal2
99 static DelayedUdpSend
*IcpQueueTail
= NULL
;
101 /// \ingroup ServerProtocolICPInternal2
102 Comm::ConnectionPointer icpIncomingConn
= NULL
;
103 /// \ingroup ServerProtocolICPInternal2
104 Comm::ConnectionPointer icpOutgoingConn
= NULL
;
107 icp_common_t::icp_common_t() :
108 opcode(ICP_INVALID
), version(0), length(0), reqnum(0),
109 flags(0), pad(0), shostid(0)
112 icp_common_t::icp_common_t(char *buf
, unsigned int len
) :
113 opcode(ICP_INVALID
), version(0), reqnum(0), flags(0), pad(0), shostid(0)
115 if (len
< sizeof(icp_common_t
)) {
116 /* mark as invalid */
121 memcpy(this, buf
, sizeof(icp_common_t
));
123 * Convert network order sensitive fields
125 length
= ntohs(length
);
126 reqnum
= ntohl(reqnum
);
127 flags
= ntohl(flags
);
132 icp_common_t::getOpCode() const
134 if (opcode
> static_cast<char>(icp_opcode::ICP_END
))
137 return static_cast<icp_opcode
>(opcode
);
142 ICPState::ICPState(icp_common_t
&aHeader
, HttpRequest
*aRequest
):
148 HTTPMSGLOCK(request
);
151 ICPState::~ICPState()
154 HTTPMSGUNLOCK(request
);
158 ICPState::isHit() const
160 const auto e
= storeGetPublic(url
, Http::METHOD_GET
);
162 const auto hit
= e
&& confirmAndPrepHit(*e
);
165 e
->abandon(__FUNCTION__
);
171 ICPState::confirmAndPrepHit(const StoreEntry
&e
) const
173 if (!e
.validToSend())
176 if (!Config
.onoff
.icp_hit_stale
&& refreshCheckICP(&e
, request
))
179 if (e
.hittingRequiresCollapsing() && !startCollapsingOn(e
, false))
186 ICPState::loggingTags() const
188 // calling icpSyncAle(LOG_TAG_NONE) here would not change cache.code
190 al
= new AccessLogEntry();
191 return &al
->cache
.code
;
195 ICPState::fillChecklist(ACLFilledChecklist
&checklist
) const
197 checklist
.setRequest(request
);
198 icpSyncAle(al
, from
, url
, 0, 0);
206 /// \ingroup ServerProtocolICPInternal2
207 class ICP2State
: public ICPState
211 ICP2State(icp_common_t
& aHeader
, HttpRequest
*aRequest
):
212 ICPState(aHeader
, aRequest
),rtt(0),src_rtt(0),flags(0) {}
221 ICP2State::~ICP2State()
226 /// updates ALE (if any) and logs the transaction (if needed)
228 icpLogIcp(const Ip::Address
&caddr
, const LogTags_ot logcode
, const int len
, const char *url
, int delay
, AccessLogEntry::Pointer
&al
)
230 assert(logcode
!= LOG_TAG_NONE
);
232 // Optimization: No premature (ALE creation in) icpSyncAle().
234 icpSyncAle(al
, caddr
, url
, len
, delay
);
235 al
->cache
.code
.update(logcode
);
238 if (logcode
== LOG_ICP_QUERY
)
239 return; // we never log queries
241 if (!Config
.onoff
.log_udp
) {
242 clientdbUpdate(caddr
, al
? al
->cache
.code
: LogTags(logcode
), AnyP::PROTO_ICP
, len
);
247 // The above attempt to optimize ALE creation has failed. We do need it.
248 icpSyncAle(al
, caddr
, url
, len
, delay
);
249 al
->cache
.code
.update(logcode
);
251 clientdbUpdate(caddr
, al
->cache
.code
, AnyP::PROTO_ICP
, len
);
252 accessLogLog(al
, NULL
);
255 /// \ingroup ServerProtocolICPInternal2
257 icpUdpSendQueue(int fd
, void *)
261 while ((q
= IcpQueueHead
) != NULL
) {
262 int delay
= tvSubUsec(q
->queue_time
, current_time
);
263 /* increment delay to prevent looping */
264 const int x
= icpUdpSend(fd
, q
->address
, q
->msg
, ++delay
, q
->ale
);
265 IcpQueueHead
= q
->next
;
274 icp_common_t::CreateMessage(
282 icp_common_t
*headerp
= NULL
;
283 char *urloffset
= NULL
;
285 buf_len
= sizeof(icp_common_t
) + strlen(url
) + 1;
287 if (opcode
== ICP_QUERY
)
288 buf_len
+= sizeof(uint32_t);
290 buf
= (char *) xcalloc(buf_len
, 1);
292 headerp
= (icp_common_t
*) (void *) buf
;
294 headerp
->opcode
= (char) opcode
;
296 headerp
->version
= ICP_VERSION_CURRENT
;
298 headerp
->length
= (uint16_t) htons(buf_len
);
300 headerp
->reqnum
= htonl(reqnum
);
302 headerp
->flags
= htonl(flags
);
304 headerp
->pad
= htonl(pad
);
306 headerp
->shostid
= 0;
308 urloffset
= buf
+ sizeof(icp_common_t
);
310 if (opcode
== ICP_QUERY
)
311 urloffset
+= sizeof(uint32_t);
313 memcpy(urloffset
, url
, strlen(url
));
315 return (icp_common_t
*)buf
;
318 // TODO: Move retries to icpCreateAndSend(); the other caller does not retry.
319 /// writes the given UDP msg to the socket; queues a retry on the first failure
320 /// \returns a negative number on failures
323 const Ip::Address
&to
,
326 AccessLogEntryPointer al
)
330 len
= (int) ntohs(msg
->length
);
331 debugs(12, 5, "icpUdpSend: FD " << fd
<< " sending " <<
332 icp_opcode_str
[msg
->opcode
] << ", " << len
<< " bytes to " << to
);
334 x
= comm_udp_sendto(fd
, to
, msg
, len
);
337 /* successfully written */
338 const auto logcode
= icpLogFromICPCode(static_cast<icp_opcode
>(msg
->opcode
));
339 icpLogIcp(to
, logcode
, len
, (char *) (msg
+ 1), delay
, al
);
340 icpCount(msg
, SENT
, (size_t) len
, delay
);
342 } else if (0 == delay
) {
343 /* send failed, but queue it */
344 const auto queue
= new DelayedUdpSend();
347 queue
->queue_time
= current_time
;
350 if (IcpQueueHead
== NULL
) {
351 IcpQueueHead
= queue
;
352 IcpQueueTail
= queue
;
353 } else if (IcpQueueTail
== IcpQueueHead
) {
354 IcpQueueTail
= queue
;
355 IcpQueueHead
->next
= queue
;
357 IcpQueueTail
->next
= queue
;
358 IcpQueueTail
= queue
;
361 Comm::SetSelect(fd
, COMM_SELECT_WRITE
, icpUdpSendQueue
, NULL
, 0);
362 ++statCounter
.icp
.replies_queued
;
365 // XXX: safe_free(msg)
366 ++statCounter
.icp
.replies_dropped
;
373 * This routine selects an ICP opcode for ICP misses.
375 \retval ICP_ERR no opcode selected here
376 \retval ICP_MISS_NOFETCH store is rebuilding, no fetch is possible yet
381 /* if store is rebuilding, return a UDP_MISS_NOFETCH */
383 if ((StoreController::store_dirs_rebuilding
&& opt_reload_hit_only
) ||
384 hit_only_mode_until
> squid_curtime
) {
385 return ICP_MISS_NOFETCH
;
392 icpLogFromICPCode(icp_opcode opcode
)
394 if (opcode
== ICP_ERR
)
395 return LOG_UDP_INVALID
;
397 if (opcode
== ICP_DENIED
)
398 return LOG_UDP_DENIED
;
400 if (opcode
== ICP_HIT
)
403 if (opcode
== ICP_MISS
)
406 if (opcode
== ICP_MISS_NOFETCH
)
407 return LOG_UDP_MISS_NOFETCH
;
409 if (opcode
== ICP_DECHO
)
410 return LOG_ICP_QUERY
;
412 if (opcode
== ICP_QUERY
)
413 return LOG_ICP_QUERY
;
415 fatal("expected ICP opcode\n");
417 return LOG_UDP_INVALID
;
421 icpCreateAndSend(icp_opcode opcode
, int flags
, char const *url
, int reqnum
, int pad
, int fd
, const Ip::Address
&from
, AccessLogEntry::Pointer al
)
423 // update potentially shared ALE ASAP; the ICP query itself may be delayed
425 al
->cache
.code
.update(icpLogFromICPCode(opcode
));
426 icp_common_t
*reply
= icp_common_t::CreateMessage(opcode
, flags
, url
, reqnum
, pad
);
427 icpUdpSend(fd
, from
, reply
, 0, al
);
431 icpDenyAccess(Ip::Address
&from
, char *url
, int reqnum
, int fd
)
433 debugs(12, 2, "icpDenyAccess: Access Denied for " << from
<< " by " << AclMatchedName
<< ".");
435 if (clientdbCutoffDenied(from
)) {
437 * count this DENIED query in the clientdb, even though
438 * we're not sending an ICP reply...
440 clientdbUpdate(from
, LogTags(LOG_UDP_DENIED
), AnyP::PROTO_ICP
, 0);
442 icpCreateAndSend(ICP_DENIED
, 0, url
, reqnum
, 0, fd
, from
, nullptr);
447 icpAccessAllowed(Ip::Address
&from
, HttpRequest
* icp_request
)
449 /* absent any explicit rules, we deny all */
450 if (!Config
.accessList
.icp
)
453 ACLFilledChecklist
checklist(Config
.accessList
.icp
, icp_request
, NULL
);
454 checklist
.src_addr
= from
;
455 checklist
.my_addr
.setNoAddr();
456 return checklist
.fastCheck().allowed();
460 icpGetUrlToSend(char *url
)
462 if (strpbrk(url
, w_space
))
463 return rfc1738_escape(url
);
469 icpGetRequest(char *url
, int reqnum
, int fd
, Ip::Address
&from
)
471 if (strpbrk(url
, w_space
)) {
472 url
= rfc1738_escape(url
);
473 icpCreateAndSend(ICP_ERR
, 0, rfc1738_escape(url
), reqnum
, 0, fd
, from
, nullptr);
477 const MasterXaction::Pointer mx
= new MasterXaction(XactionInitiator::initIcp
);
478 auto *result
= HttpRequest::FromUrlXXX(url
, mx
);
480 icpCreateAndSend(ICP_ERR
, 0, url
, reqnum
, 0, fd
, from
, nullptr);
487 doV2Query(int fd
, Ip::Address
&from
, char *buf
, icp_common_t header
)
492 /* We have a valid packet */
493 char *url
= buf
+ sizeof(icp_common_t
) + sizeof(uint32_t);
494 HttpRequest
*icp_request
= icpGetRequest(url
, header
.reqnum
, fd
, from
);
499 HTTPMSGLOCK(icp_request
);
501 if (!icpAccessAllowed(from
, icp_request
)) {
502 icpDenyAccess(from
, url
, header
.reqnum
, fd
);
503 HTTPMSGUNLOCK(icp_request
);
507 if (header
.flags
& ICP_FLAG_SRC_RTT
) {
508 rtt
= netdbHostRtt(icp_request
->url
.host());
509 int hops
= netdbHostHops(icp_request
->url
.host());
510 src_rtt
= ((hops
& 0xFFFF) << 16) | (rtt
& 0xFFFF);
513 flags
|= ICP_FLAG_SRC_RTT
;
515 #endif /* USE_ICMP */
517 /* The peer is allowed to use this cache */
518 ICP2State
state(header
, icp_request
);
521 state
.url
= xstrdup(url
);
524 state
.src_rtt
= src_rtt
;
526 icp_opcode codeToSend
;
529 codeToSend
= ICP_HIT
;
532 if (Config
.onoff
.test_reachability
&& state
.rtt
== 0) {
533 if ((state
.rtt
= netdbHostRtt(state
.request
->url
.host())) == 0)
534 netdbPingSite(state
.request
->url
.host());
536 #endif /* USE_ICMP */
538 if (icpGetCommonOpcode() != ICP_ERR
)
539 codeToSend
= icpGetCommonOpcode();
540 else if (Config
.onoff
.test_reachability
&& rtt
== 0)
541 codeToSend
= ICP_MISS_NOFETCH
;
543 codeToSend
= ICP_MISS
;
546 icpCreateAndSend(codeToSend
, flags
, url
, header
.reqnum
, src_rtt
, fd
, from
, state
.al
);
548 HTTPMSGUNLOCK(icp_request
);
552 icp_common_t::handleReply(char *buf
, Ip::Address
&from
)
554 if (neighbors_do_private_keys
&& reqnum
== 0) {
555 debugs(12, DBG_CRITICAL
, "icpHandleIcpV2: Neighbor " << from
<< " returned reqnum = 0");
556 debugs(12, DBG_CRITICAL
, "icpHandleIcpV2: Disabling use of private keys");
557 neighbors_do_private_keys
= 0;
560 char *url
= buf
+ sizeof(icp_common_t
);
561 debugs(12, 3, "icpHandleIcpV2: " << icp_opcode_str
[opcode
] << " from " << from
<< " for '" << url
<< "'");
563 const cache_key
*key
= icpGetCacheKey(url
, (int) reqnum
);
564 /* call neighborsUdpAck even if ping_status != PING_WAITING */
565 neighborsUdpAck(key
, this, from
);
569 icpHandleIcpV2(int fd
, Ip::Address
&from
, char *buf
, int len
)
572 debugs(12, 3, "icpHandleIcpV2: ICP message is too small");
576 icp_common_t
header(buf
, len
);
578 * Length field should match the number of bytes read
581 if (len
!= header
.length
) {
582 debugs(12, 3, "icpHandleIcpV2: ICP message is too small");
586 debugs(12, 5, "OPCODE " << icp_opcode_str
[header
.getOpCode()] << '=' << uint8_t(header
.opcode
));
588 switch (header
.opcode
) {
591 /* We have a valid packet */
592 doV2Query(fd
, from
, buf
, header
);
603 case ICP_MISS_NOFETCH
:
604 header
.handleReply(buf
, from
);
613 debugs(12, DBG_CRITICAL
, "icpHandleIcpV2: UNKNOWN OPCODE: " << header
.opcode
<< " from " << from
);
621 icpPktDump(icp_common_t
* pkt
)
625 debugs(12, 9, "opcode: " << std::setw(3) << pkt
->opcode
<< " " << icp_opcode_str
[pkt
->opcode
]);
626 debugs(12, 9, "version: "<< std::left
<< std::setw(8) << pkt
->version
);
627 debugs(12, 9, "length: "<< std::left
<< std::setw(8) << ntohs(pkt
->length
));
628 debugs(12, 9, "reqnum: "<< std::left
<< std::setw(8) << ntohl(pkt
->reqnum
));
629 debugs(12, 9, "flags: "<< std::left
<< std::hex
<< std::setw(8) << ntohl(pkt
->flags
));
630 a
= (struct in_addr
)pkt
->shostid
;
631 debugs(12, 9, "shostid: " << a
);
632 debugs(12, 9, "payload: " << (char *) pkt
+ sizeof(icp_common_t
));
638 icpHandleUdp(int sock
, void *)
640 int *N
= &incoming_sockets_accepted
;
643 LOCAL_ARRAY(char, buf
, SQUID_UDP_SO_RCVBUF
);
646 int max
= INCOMING_UDP_MAX
;
647 Comm::SetSelect(sock
, COMM_SELECT_READ
, icpHandleUdp
, NULL
, 0);
651 len
= comm_udp_recvfrom(sock
,
653 SQUID_UDP_SO_RCVBUF
- 1,
662 if (ignoreErrno(xerrno
))
666 /* Some Linux systems seem to set the FD for reading and then
667 * return ECONNREFUSED when sendto() fails and generates an ICMP
668 * port unreachable message. */
669 /* or maybe an EHOSTUNREACH "No route to host" message */
670 if (xerrno
!= ECONNREFUSED
&& xerrno
!= EHOSTUNREACH
)
672 debugs(50, DBG_IMPORTANT
, "icpHandleUdp: FD " << sock
<< " recvfrom: " << xstrerr(xerrno
));
678 icpCount(buf
, RECV
, (size_t) len
, 0);
680 debugs(12, 4, "icpHandleUdp: FD " << sock
<< ": received " <<
681 (unsigned long int)len
<< " bytes from " << from
);
683 #ifdef ICP_PACKET_DUMP
688 if ((size_t) len
< sizeof(icp_common_t
)) {
689 debugs(12, 4, "icpHandleUdp: Ignoring too-small UDP packet");
693 icp_version
= (int) buf
[1]; /* cheat! */
695 if (icpOutgoingConn
->local
== from
)
696 // ignore ICP packets which loop back (multicast usually)
697 debugs(12, 4, "icpHandleUdp: Ignoring UDP packet sent by myself");
698 else if (icp_version
== ICP_VERSION_2
)
699 icpHandleIcpV2(sock
, from
, buf
, len
);
700 else if (icp_version
== ICP_VERSION_3
)
701 icpHandleIcpV3(sock
, from
, buf
, len
);
703 debugs(12, DBG_IMPORTANT
, "WARNING: Unused ICP version " << icp_version
<<
704 " received from " << from
);
713 if ((port
= Config
.Port
.icp
) <= 0)
716 icpIncomingConn
= new Comm::Connection
;
717 icpIncomingConn
->local
= Config
.Addrs
.udp_incoming
;
718 icpIncomingConn
->local
.port(port
);
720 if (!Ip::EnableIpv6
&& !icpIncomingConn
->local
.setIPv4()) {
721 debugs(12, DBG_CRITICAL
, "ERROR: IPv6 is disabled. " << icpIncomingConn
->local
<< " is not an IPv4 address.");
722 fatal("ICP port cannot be opened.");
724 /* split-stack for now requires default IPv4-only ICP */
725 if (Ip::EnableIpv6
&IPV6_SPECIAL_SPLITSTACK
&& icpIncomingConn
->local
.isAnyAddr()) {
726 icpIncomingConn
->local
.setIPv4();
729 AsyncCall::Pointer call
= asyncCall(12, 2,
730 "icpIncomingConnectionOpened",
731 Comm::UdpOpenDialer(&icpIncomingConnectionOpened
));
733 Ipc::StartListening(SOCK_DGRAM
,
736 Ipc::fdnInIcpSocket
, call
);
738 if ( !Config
.Addrs
.udp_outgoing
.isNoAddr() ) {
739 icpOutgoingConn
= new Comm::Connection
;
740 icpOutgoingConn
->local
= Config
.Addrs
.udp_outgoing
;
741 icpOutgoingConn
->local
.port(port
);
743 if (!Ip::EnableIpv6
&& !icpOutgoingConn
->local
.setIPv4()) {
744 debugs(49, DBG_CRITICAL
, "ERROR: IPv6 is disabled. " << icpOutgoingConn
->local
<< " is not an IPv4 address.");
745 fatal("ICP port cannot be opened.");
747 /* split-stack for now requires default IPv4-only ICP */
748 if (Ip::EnableIpv6
&IPV6_SPECIAL_SPLITSTACK
&& icpOutgoingConn
->local
.isAnyAddr()) {
749 icpOutgoingConn
->local
.setIPv4();
753 comm_open_listener(SOCK_DGRAM
, IPPROTO_UDP
, icpOutgoingConn
, "Outgoing ICP Port");
756 if (!Comm::IsConnOpen(icpOutgoingConn
))
757 fatal("Cannot open Outgoing ICP Port");
759 debugs(12, DBG_CRITICAL
, "Sending ICP messages from " << icpOutgoingConn
->local
);
761 Comm::SetSelect(icpOutgoingConn
->fd
, COMM_SELECT_READ
, icpHandleUdp
, NULL
, 0);
762 fd_note(icpOutgoingConn
->fd
, "Outgoing ICP socket");
767 icpIncomingConnectionOpened(const Comm::ConnectionPointer
&conn
, int)
769 if (!Comm::IsConnOpen(conn
))
770 fatal("Cannot open ICP Port");
772 Comm::SetSelect(conn
->fd
, COMM_SELECT_READ
, icpHandleUdp
, NULL
, 0);
774 for (const wordlist
*s
= Config
.mcast_group_list
; s
; s
= s
->next
)
775 ipcache_nbgethostbyname(s
->key
, mcastJoinGroups
, NULL
); // XXX: pass the conn for mcastJoinGroups usage.
777 debugs(12, DBG_IMPORTANT
, "Accepting ICP messages on " << conn
->local
);
779 fd_note(conn
->fd
, "Incoming ICP port");
781 if (Config
.Addrs
.udp_outgoing
.isNoAddr()) {
782 icpOutgoingConn
= conn
;
783 debugs(12, DBG_IMPORTANT
, "Sending ICP messages from " << icpOutgoingConn
->local
);
788 * icpConnectionShutdown only closes the 'in' socket if it is
789 * different than the 'out' socket.
792 icpConnectionShutdown(void)
794 if (!Comm::IsConnOpen(icpIncomingConn
))
797 debugs(12, DBG_IMPORTANT
, "Stop receiving ICP on " << icpIncomingConn
->local
);
799 /** Release the 'in' socket for lazy closure.
800 * in and out sockets may be sharing one same FD.
801 * This prevents this function from executing repeatedly.
803 icpIncomingConn
= NULL
;
806 * Normally we only write to the outgoing ICP socket, but
807 * we also have a read handler there to catch messages sent
808 * to that specific interface. During shutdown, we must
809 * disable reading on the outgoing socket.
811 assert(Comm::IsConnOpen(icpOutgoingConn
));
813 Comm::SetSelect(icpOutgoingConn
->fd
, COMM_SELECT_READ
, NULL
, NULL
, 0);
819 icpConnectionShutdown();
821 if (icpOutgoingConn
!= NULL
) {
822 debugs(12, DBG_IMPORTANT
, "Stop sending ICP from " << icpOutgoingConn
->local
);
823 icpOutgoingConn
= NULL
;
828 icpCount(void *buf
, int which
, size_t len
, int delay
)
830 icp_common_t
*icp
= (icp_common_t
*) buf
;
832 if (len
< sizeof(*icp
))
836 ++statCounter
.icp
.pkts_sent
;
837 statCounter
.icp
.kbytes_sent
+= len
;
839 if (ICP_QUERY
== icp
->opcode
) {
840 ++statCounter
.icp
.queries_sent
;
841 statCounter
.icp
.q_kbytes_sent
+= len
;
843 ++statCounter
.icp
.replies_sent
;
844 statCounter
.icp
.r_kbytes_sent
+= len
;
845 /* this is the sent-reply service time */
846 statCounter
.icp
.replySvcTime
.count(delay
);
849 if (ICP_HIT
== icp
->opcode
)
850 ++statCounter
.icp
.hits_sent
;
851 } else if (RECV
== which
) {
852 ++statCounter
.icp
.pkts_recv
;
853 statCounter
.icp
.kbytes_recv
+= len
;
855 if (ICP_QUERY
== icp
->opcode
) {
856 ++statCounter
.icp
.queries_recv
;
857 statCounter
.icp
.q_kbytes_recv
+= len
;
859 ++statCounter
.icp
.replies_recv
;
860 statCounter
.icp
.r_kbytes_recv
+= len
;
861 /* statCounter.icp.querySvcTime set in clientUpdateCounters */
864 if (ICP_HIT
== icp
->opcode
)
865 ++statCounter
.icp
.hits_recv
;
869 #define N_QUERIED_KEYS 8192
870 #define N_QUERIED_KEYS_MASK 8191
871 static cache_key queried_keys
[N_QUERIED_KEYS
][SQUID_MD5_DIGEST_LENGTH
];
874 icpSetCacheKey(const cache_key
* key
)
876 static int reqnum
= 0;
881 storeKeyCopy(queried_keys
[reqnum
& N_QUERIED_KEYS_MASK
], key
);
887 icpGetCacheKey(const char *url
, int reqnum
)
889 if (neighbors_do_private_keys
&& reqnum
)
890 return queried_keys
[reqnum
& N_QUERIED_KEYS_MASK
];
892 return storeKeyPublic(url
, Http::METHOD_GET
);