]> git.ipfire.org Git - thirdparty/squid.git/blame - src/icp_v2.cc
Updated copyright
[thirdparty/squid.git] / src / icp_v2.cc
CommitLineData
194dd3b8 1
9cef6668 2/*
2b6662ba 3 * $Id: icp_v2.cc,v 1.65 2001/01/12 00:37:18 wessels Exp $
9cef6668 4 *
5 * DEBUG: section 12 Internet Cache Protocol
6 * AUTHOR: Duane Wessels
7 *
2b6662ba 8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9cef6668 9 * ----------------------------------------------------------
10 *
2b6662ba 11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
9cef6668 19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 *
34 */
35
7a2f978b 36#include "squid.h"
37
17b6e784 38static void icpLogIcp(struct in_addr, log_type, int, const char *, int);
7a2f978b 39static void icpHandleIcpV2(int, struct sockaddr_in, char *, int);
071a3ae7 40static void icpCount(void *, int, size_t, int);
17b6e784 41
48382032 42/*
43 * IcpQueueHead is global so comm_incoming() knows whether or not
44 * to call icpUdpSendQueue.
45 */
46static icpUdpData *IcpQueueTail = NULL;
7a2f978b 47
48static void
17b6e784 49icpLogIcp(struct in_addr caddr, log_type logcode, int len, const char *url, int delay)
7a2f978b 50{
7a2f978b 51 AccessLogEntry al;
96c617da 52 if (LOG_TAG_NONE == logcode)
53 return;
071a3ae7 54 if (LOG_ICP_QUERY == logcode)
55 return;
17b6e784 56 clientdbUpdate(caddr, logcode, PROTO_ICP, len);
7a2f978b 57 if (!Config.onoff.log_udp)
58 return;
17b6e784 59 memset(&al, '\0', sizeof(al));
27cd7235 60 al.icp.opcode = ICP_QUERY;
7a2f978b 61 al.url = url;
17b6e784 62 al.cache.caddr = caddr;
63 al.cache.size = len;
64 al.cache.code = logcode;
65 al.cache.msec = delay;
7a2f978b 66 accessLogLog(&al);
67}
68
48382032 69void
17b6e784 70icpUdpSendQueue(int fd, void *unused)
7a2f978b 71{
17b6e784 72 icpUdpData *q;
7a2f978b 73 int x;
17b6e784 74 int delay;
48382032 75 while ((q = IcpQueueHead) != NULL) {
17b6e784 76 delay = tvSubUsec(q->queue_time, current_time);
77 /* increment delay to prevent looping */
78 x = icpUdpSend(fd, &q->address, q->msg, q->logcode, ++delay);
48382032 79 IcpQueueHead = q->next;
17b6e784 80 safe_free(q);
81 if (x < 0)
82 break;
7a2f978b 83 }
84}
85
86void *
87icpCreateMessage(
88 icp_opcode opcode,
89 int flags,
90 const char *url,
91 int reqnum,
92 int pad)
93{
94 char *buf = NULL;
95 icp_common_t *headerp = NULL;
96 char *urloffset = NULL;
97 int buf_len;
98 buf_len = sizeof(icp_common_t) + strlen(url) + 1;
27cd7235 99 if (opcode == ICP_QUERY)
7a2f978b 100 buf_len += sizeof(u_num32);
101 buf = xcalloc(buf_len, 1);
102 headerp = (icp_common_t *) (void *) buf;
79d39a72 103 headerp->opcode = (char) opcode;
7a2f978b 104 headerp->version = ICP_VERSION_CURRENT;
79d39a72 105 headerp->length = (u_short) htons(buf_len);
7a2f978b 106 headerp->reqnum = htonl(reqnum);
107 headerp->flags = htonl(flags);
108 headerp->pad = htonl(pad);
67129385 109 headerp->shostid = theOutICPAddr.s_addr;
7a2f978b 110 urloffset = buf + sizeof(icp_common_t);
27cd7235 111 if (opcode == ICP_QUERY)
7a2f978b 112 urloffset += sizeof(u_num32);
113 xmemcpy(urloffset, url, strlen(url));
114 return buf;
115}
116
17b6e784 117int
7a2f978b 118icpUdpSend(int fd,
119 const struct sockaddr_in *to,
120 icp_common_t * msg,
121 log_type logcode,
17b6e784 122 int delay)
7a2f978b 123{
17b6e784 124 icpUdpData *queue;
8e68922c 125 int x;
17b6e784 126 int len;
127 len = (int) ntohs(msg->length);
128 debug(12, 5) ("icpUdpSend: FD %d sending %s, %d bytes to %s:%d\n",
8e68922c 129 fd,
17b6e784 130 icp_opcode_str[msg->opcode],
131 len,
132 inet_ntoa(to->sin_addr),
133 ntohs(to->sin_port));
134 x = comm_udp_sendto(fd, to, sizeof(*to), msg, len);
9f80ddf1 135 if (x >= 0) {
17b6e784 136 /* successfully written */
137 icpLogIcp(to->sin_addr, logcode, len, (char *) (msg + 1), delay);
071a3ae7 138 icpCount(msg, SENT, (size_t) len, delay);
17b6e784 139 safe_free(msg);
140 } else if (0 == delay) {
141 /* send failed, but queue it */
142 queue = xcalloc(1, sizeof(icpUdpData));
143 queue->address = *to;
144 queue->msg = msg;
145 queue->len = (int) ntohs(msg->length);
146 queue->queue_time = current_time;
147 queue->logcode = logcode;
48382032 148 if (IcpQueueHead == NULL) {
149 IcpQueueHead = queue;
150 IcpQueueTail = queue;
151 } else if (IcpQueueTail == IcpQueueHead) {
152 IcpQueueTail = queue;
153 IcpQueueHead->next = queue;
17b6e784 154 } else {
48382032 155 IcpQueueTail->next = queue;
156 IcpQueueTail = queue;
17b6e784 157 }
158 commSetSelect(fd, COMM_SELECT_WRITE, icpUdpSendQueue, NULL, 0);
83704487 159 statCounter.icp.replies_queued++;
8e68922c 160 } else {
17b6e784 161 /* don't queue it */
83704487 162 statCounter.icp.replies_dropped++;
8e68922c 163 }
17b6e784 164 return x;
7a2f978b 165}
166
167int
168icpCheckUdpHit(StoreEntry * e, request_t * request)
169{
170 if (e == NULL)
171 return 0;
172 if (!storeEntryValidToSend(e))
173 return 0;
174 if (Config.onoff.icp_hit_stale)
175 return 1;
829a9357 176 if (refreshCheckICP(e, request))
7a2f978b 177 return 0;
7a2f978b 178 return 1;
179}
7a2f978b 180
181static void
182icpHandleIcpV2(int fd, struct sockaddr_in from, char *buf, int len)
183{
184 icp_common_t header;
7a2f978b 185 StoreEntry *entry = NULL;
186 char *url = NULL;
187 const cache_key *key;
188 request_t *icp_request = NULL;
189 int allow = 0;
7a2f978b 190 aclCheck_t checklist;
191 icp_common_t *reply;
192 int src_rtt = 0;
193 u_num32 flags = 0;
194dd3b8 194 int rtt = 0;
195 int hops = 0;
c8f6c9c7 196 xmemcpy(&header, buf, sizeof(icp_common_t));
197 /*
198 * Only these fields need to be converted
199 */
200 header.length = ntohs(header.length);
201 header.reqnum = ntohl(header.reqnum);
202 header.flags = ntohl(header.flags);
203 header.pad = ntohl(header.pad);
7b83b3d9 204 /*
205 * Length field should match the number of bytes read
206 */
207 if (len != header.length) {
208 debug(12, 3) ("icpHandleIcpV2: ICP message is too small\n");
209 return;
210 }
7a2f978b 211 switch (header.opcode) {
27cd7235 212 case ICP_QUERY:
7a2f978b 213 /* We have a valid packet */
c8f6c9c7 214 url = buf + sizeof(icp_common_t) + sizeof(u_num32);
a02d20d9 215 if (strpbrk(url, w_space)) {
216 url = rfc1738_escape(url);
217 reply = icpCreateMessage(ICP_ERR, 0, url, header.reqnum, 0);
218 icpUdpSend(fd, &from, reply, LOG_UDP_INVALID, 0);
219 break;
220 }
007b8be4 221 if ((icp_request = urlParse(METHOD_GET, url)) == NULL) {
27cd7235 222 reply = icpCreateMessage(ICP_ERR, 0, url, header.reqnum, 0);
17b6e784 223 icpUdpSend(fd, &from, reply, LOG_UDP_INVALID, 0);
7a2f978b 224 break;
225 }
d20b1cd0 226 memset(&checklist, '\0', sizeof(checklist));
7a2f978b 227 checklist.src_addr = from.sin_addr;
ae2c08a2 228 checklist.my_addr = no_addr;
7a2f978b 229 checklist.request = icp_request;
230 allow = aclCheckFast(Config.accessList.icp, &checklist);
231 if (!allow) {
232 debug(12, 2) ("icpHandleIcpV2: Access Denied for %s by %s.\n",
233 inet_ntoa(from.sin_addr), AclMatchedName);
e711a2ff 234 if (clientdbCutoffDenied(from.sin_addr)) {
1a47dc5a 235 /*
236 * count this DENIED query in the clientdb, even though
237 * we're not sending an ICP reply...
238 */
728da2ee 239 clientdbUpdate(from.sin_addr, LOG_UDP_DENIED, PROTO_ICP, 0);
e711a2ff 240 } else {
241 reply = icpCreateMessage(ICP_DENIED, 0, url, header.reqnum, 0);
17b6e784 242 icpUdpSend(fd, &from, reply, LOG_UDP_DENIED, 0);
7a2f978b 243 }
244 break;
245 }
246 if (header.flags & ICP_FLAG_SRC_RTT) {
194dd3b8 247 rtt = netdbHostRtt(icp_request->host);
248 hops = netdbHostHops(icp_request->host);
7a2f978b 249 src_rtt = ((hops & 0xFFFF) << 16) | (rtt & 0xFFFF);
250 if (rtt)
251 flags |= ICP_FLAG_SRC_RTT;
252 }
253 /* The peer is allowed to use this cache */
08e5d64f 254 entry = storeGetPublic(url, METHOD_GET);
27cd7235 255 debug(12, 5) ("icpHandleIcpV2: OPCODE %s\n", icp_opcode_str[header.opcode]);
7a2f978b 256 if (icpCheckUdpHit(entry, icp_request)) {
067bea91 257 reply = icpCreateMessage(ICP_HIT, flags, url, header.reqnum, src_rtt);
17b6e784 258 icpUdpSend(fd, &from, reply, LOG_UDP_HIT, 0);
067bea91 259 break;
7a2f978b 260 }
194dd3b8 261 if (Config.onoff.test_reachability && rtt == 0) {
262 if ((rtt = netdbHostRtt(icp_request->host)) == 0)
263 netdbPingSite(icp_request->host);
264 }
7a2f978b 265 /* if store is rebuilding, return a UDP_HIT, but not a MISS */
b2c141d4 266 if (store_dirs_rebuilding && opt_reload_hit_only) {
27cd7235 267 reply = icpCreateMessage(ICP_MISS_NOFETCH, flags, url, header.reqnum, src_rtt);
17b6e784 268 icpUdpSend(fd, &from, reply, LOG_UDP_MISS_NOFETCH, 0);
7a2f978b 269 } else if (hit_only_mode_until > squid_curtime) {
27cd7235 270 reply = icpCreateMessage(ICP_MISS_NOFETCH, flags, url, header.reqnum, src_rtt);
17b6e784 271 icpUdpSend(fd, &from, reply, LOG_UDP_MISS_NOFETCH, 0);
194dd3b8 272 } else if (Config.onoff.test_reachability && rtt == 0) {
273 reply = icpCreateMessage(ICP_MISS_NOFETCH, flags, url, header.reqnum, src_rtt);
17b6e784 274 icpUdpSend(fd, &from, reply, LOG_UDP_MISS_NOFETCH, 0);
7a2f978b 275 } else {
27cd7235 276 reply = icpCreateMessage(ICP_MISS, flags, url, header.reqnum, src_rtt);
17b6e784 277 icpUdpSend(fd, &from, reply, LOG_UDP_MISS, 0);
7a2f978b 278 }
279 break;
280
27cd7235 281 case ICP_HIT:
db1cd23c 282#if ALLOW_SOURCE_PING
27cd7235 283 case ICP_SECHO:
db1cd23c 284#endif
27cd7235 285 case ICP_DECHO:
286 case ICP_MISS:
287 case ICP_DENIED:
288 case ICP_MISS_NOFETCH:
7a2f978b 289 if (neighbors_do_private_keys && header.reqnum == 0) {
290 debug(12, 0) ("icpHandleIcpV2: Neighbor %s returned reqnum = 0\n",
291 inet_ntoa(from.sin_addr));
292 debug(12, 0) ("icpHandleIcpV2: Disabling use of private keys\n");
293 neighbors_do_private_keys = 0;
294 }
c8f6c9c7 295 url = buf + sizeof(icp_common_t);
7a2f978b 296 debug(12, 3) ("icpHandleIcpV2: %s from %s for '%s'\n",
27cd7235 297 icp_opcode_str[header.opcode],
7a2f978b 298 inet_ntoa(from.sin_addr),
299 url);
007b8be4 300 key = icpGetCacheKey(url, (int) header.reqnum);
5ad33356 301 /* call neighborsUdpAck even if ping_status != PING_WAITING */
302 neighborsUdpAck(key, &header, &from);
7a2f978b 303 break;
304
27cd7235 305 case ICP_INVALID:
306 case ICP_ERR:
7a2f978b 307 break;
308
309 default:
310 debug(12, 0) ("icpHandleIcpV2: UNKNOWN OPCODE: %d from %s\n",
311 header.opcode, inet_ntoa(from.sin_addr));
312 break;
313 }
98abae73 314 if (icp_request)
99edd1c3 315 requestDestroy(icp_request);
7a2f978b 316}
317
318#ifdef ICP_PKT_DUMP
319static void
320icpPktDump(icp_common_t * pkt)
321{
322 struct in_addr a;
323
324 debug(12, 9) ("opcode: %3d %s\n",
325 (int) pkt->opcode,
27cd7235 326 icp_opcode_str[pkt->opcode]);
7a2f978b 327 debug(12, 9) ("version: %-8d\n", (int) pkt->version);
328 debug(12, 9) ("length: %-8d\n", (int) ntohs(pkt->length));
329 debug(12, 9) ("reqnum: %-8d\n", ntohl(pkt->reqnum));
330 debug(12, 9) ("flags: %-8x\n", ntohl(pkt->flags));
67129385 331 a.s_addr = pkt->shostid;
7a2f978b 332 debug(12, 9) ("shostid: %s\n", inet_ntoa(a));
333 debug(12, 9) ("payload: %s\n", (char *) pkt + sizeof(icp_common_t));
334}
335#endif
336
337void
ba4f8e5a 338icpHandleUdp(int sock, void *data)
7a2f978b 339{
ba4f8e5a 340 int *N = data;
7a2f978b 341 struct sockaddr_in from;
6637e3a5 342 socklen_t from_len;
7a2f978b 343 LOCAL_ARRAY(char, buf, SQUID_UDP_SO_RCVBUF);
344 int len;
7a2f978b 345 int icp_version;
309ad3b6 346 int max = INCOMING_ICP_MAX;
7a2f978b 347 commSetSelect(sock, COMM_SELECT_READ, icpHandleUdp, NULL, 0);
5b0aaa58 348 while (max--) {
349 from_len = sizeof(from);
350 memset(&from, '\0', from_len);
83704487 351 statCounter.syscalls.sock.recvfroms++;
5b0aaa58 352 len = recvfrom(sock,
353 buf,
354 SQUID_UDP_SO_RCVBUF - 1,
355 0,
356 (struct sockaddr *) &from,
357 &from_len);
358 if (len == 0)
359 break;
360 if (len < 0) {
361 if (ignoreErrno(errno))
362 break;
7a2f978b 363#ifdef _SQUID_LINUX_
5b0aaa58 364 /* Some Linux systems seem to set the FD for reading and then
365 * return ECONNREFUSED when sendto() fails and generates an ICMP
366 * port unreachable message. */
367 /* or maybe an EHOSTUNREACH "No route to host" message */
368 if (errno != ECONNREFUSED && errno != EHOSTUNREACH)
7a2f978b 369#endif
5b0aaa58 370 debug(50, 1) ("icpHandleUdp: FD %d recvfrom: %s\n",
371 sock, xstrerror());
372 break;
373 }
ba4f8e5a 374 (*N)++;
5b0aaa58 375 icpCount(buf, RECV, (size_t) len, 0);
376 buf[len] = '\0';
377 debug(12, 4) ("icpHandleUdp: FD %d: received %d bytes from %s.\n",
378 sock,
379 len,
380 inet_ntoa(from.sin_addr));
7a2f978b 381#ifdef ICP_PACKET_DUMP
5b0aaa58 382 icpPktDump(buf);
7a2f978b 383#endif
5b0aaa58 384 if (len < sizeof(icp_common_t)) {
385 debug(12, 4) ("icpHandleUdp: Ignoring too-small UDP packet\n");
386 break;
387 }
388 icp_version = (int) buf[1]; /* cheat! */
389 if (icp_version == ICP_VERSION_2)
390 icpHandleIcpV2(sock, from, buf, len);
391 else if (icp_version == ICP_VERSION_3)
392 icpHandleIcpV3(sock, from, buf, len);
393 else
edc182e2 394 debug(12, 1) ("WARNING: Unused ICP version %d received from %s:%d\n",
5b0aaa58 395 icp_version,
396 inet_ntoa(from.sin_addr),
397 ntohs(from.sin_port));
7a2f978b 398 }
7a2f978b 399}
15df8349 400
401void
402icpConnectionsOpen(void)
403{
404 u_short port;
405 struct in_addr addr;
406 struct sockaddr_in xaddr;
407 int x;
6637e3a5 408 socklen_t len;
15df8349 409 wordlist *s;
410 if (Config2.Accel.on && !Config.onoff.accel_with_proxy)
411 return;
412 if ((port = Config.Port.icp) <= 0)
413 return;
414 enter_suid();
415 theInIcpConnection = comm_open(SOCK_DGRAM,
416 0,
417 Config.Addrs.udp_incoming,
418 port,
419 COMM_NONBLOCKING,
de0df6f5 420 "ICP Socket");
15df8349 421 leave_suid();
422 if (theInIcpConnection < 0)
423 fatal("Cannot open ICP Port");
15df8349 424 commSetSelect(theInIcpConnection,
eeb423fb 425 COMM_SELECT_READ,
426 icpHandleUdp,
427 NULL,
428 0);
15df8349 429 for (s = Config.mcast_group_list; s; s = s->next)
430 ipcache_nbgethostbyname(s->key, mcastJoinGroups, NULL);
7e3ce7b9 431 debug(12, 1) ("Accepting ICP messages at %s, port %d, FD %d.\n",
432 inet_ntoa(Config.Addrs.udp_incoming),
15df8349 433 (int) port, theInIcpConnection);
434 if ((addr = Config.Addrs.udp_outgoing).s_addr != no_addr.s_addr) {
435 enter_suid();
436 theOutIcpConnection = comm_open(SOCK_DGRAM,
437 0,
438 addr,
439 port,
440 COMM_NONBLOCKING,
441 "ICP Port");
442 leave_suid();
443 if (theOutIcpConnection < 0)
444 fatal("Cannot open Outgoing ICP Port");
445 commSetSelect(theOutIcpConnection,
446 COMM_SELECT_READ,
447 icpHandleUdp,
ba4f8e5a 448 NULL,
449 0);
17e6c0a1 450 debug(12, 1) ("Outgoing ICP messages on port %d, FD %d.\n",
1e948d78 451 (int) port, theOutIcpConnection);
15df8349 452 fd_note(theOutIcpConnection, "Outgoing ICP socket");
453 fd_note(theInIcpConnection, "Incoming ICP socket");
454 } else {
455 theOutIcpConnection = theInIcpConnection;
456 }
457 memset(&theOutICPAddr, '\0', sizeof(struct in_addr));
458 len = sizeof(struct sockaddr_in);
459 memset(&xaddr, '\0', len);
460 x = getsockname(theOutIcpConnection,
461 (struct sockaddr *) &xaddr, &len);
462 if (x < 0)
463 debug(50, 1) ("theOutIcpConnection FD %d: getsockname: %s\n",
464 theOutIcpConnection, xstrerror());
465 else
466 theOutICPAddr = xaddr.sin_addr;
467}
c0fbae16 468
17e6c0a1 469/*
470 * icpConnectionShutdown only closes the 'in' socket if it is
471 * different than the 'out' socket.
472 */
c0fbae16 473void
17e6c0a1 474icpConnectionShutdown(void)
c0fbae16 475{
476 if (theInIcpConnection < 0)
477 return;
17e6c0a1 478 if (theInIcpConnection != theOutIcpConnection) {
c7863c6f 479 debug(12, 1) ("FD %d Closing ICP connection\n", theInIcpConnection);
c0fbae16 480 comm_close(theInIcpConnection);
17e6c0a1 481 }
c0fbae16 482 /*
483 * Here we set 'theInIcpConnection' to -1 even though the ICP 'in'
484 * and 'out' sockets might be just one FD. This prevents this
485 * function from executing repeatedly. When we are really ready to
486 * exit or restart, main will comm_close the 'out' descriptor.
487 */
488 theInIcpConnection = -1;
489 /*
490 * Normally we only write to the outgoing ICP socket, but
491 * we also have a read handler there to catch messages sent
492 * to that specific interface. During shutdown, we must
493 * disable reading on the outgoing socket.
494 */
495 assert(theOutIcpConnection > -1);
496 commSetSelect(theOutIcpConnection, COMM_SELECT_READ, NULL, NULL, 0);
497}
17e6c0a1 498
499void
500icpConnectionClose(void)
501{
502 icpConnectionShutdown();
503 if (theOutIcpConnection > -1) {
c7863c6f 504 debug(12, 1) ("FD %d Closing ICP connection\n", theOutIcpConnection);
17e6c0a1 505 comm_close(theOutIcpConnection);
05b744f3 506 theOutIcpConnection = -1;
17e6c0a1 507 }
508}
071a3ae7 509
510static void
511icpCount(void *buf, int which, size_t len, int delay)
512{
513 icp_common_t *icp = buf;
514 if (len < sizeof(*icp))
515 return;
516 if (SENT == which) {
83704487 517 statCounter.icp.pkts_sent++;
518 kb_incr(&statCounter.icp.kbytes_sent, len);
071a3ae7 519 if (ICP_QUERY == icp->opcode) {
83704487 520 statCounter.icp.queries_sent++;
521 kb_incr(&statCounter.icp.q_kbytes_sent, len);
071a3ae7 522 } else {
83704487 523 statCounter.icp.replies_sent++;
524 kb_incr(&statCounter.icp.r_kbytes_sent, len);
071a3ae7 525 /* this is the sent-reply service time */
83704487 526 statHistCount(&statCounter.icp.reply_svc_time, delay);
071a3ae7 527 }
4b4cd312 528 if (ICP_HIT == icp->opcode)
83704487 529 statCounter.icp.hits_sent++;
071a3ae7 530 } else if (RECV == which) {
83704487 531 statCounter.icp.pkts_recv++;
532 kb_incr(&statCounter.icp.kbytes_recv, len);
071a3ae7 533 if (ICP_QUERY == icp->opcode) {
83704487 534 statCounter.icp.queries_recv++;
535 kb_incr(&statCounter.icp.q_kbytes_recv, len);
071a3ae7 536 } else {
83704487 537 statCounter.icp.replies_recv++;
538 kb_incr(&statCounter.icp.r_kbytes_recv, len);
539 /* statCounter.icp.query_svc_time set in clientUpdateCounters */
071a3ae7 540 }
4b4cd312 541 if (ICP_HIT == icp->opcode)
83704487 542 statCounter.icp.hits_recv++;
071a3ae7 543 }
544}
007b8be4 545
546#define N_QUERIED_KEYS 8192
547#define N_QUERIED_KEYS_MASK 8191
548static cache_key queried_keys[N_QUERIED_KEYS][MD5_DIGEST_CHARS];
549
550int
5942e8d4 551icpSetCacheKey(const cache_key * key)
007b8be4 552{
553 static int reqnum = 0;
554 if (++reqnum < 0)
555 reqnum = 1;
556 storeKeyCopy(queried_keys[reqnum & N_QUERIED_KEYS_MASK], key);
557 return reqnum;
558}
559
560const cache_key *
561icpGetCacheKey(const char *url, int reqnum)
562{
563 if (neighbors_do_private_keys && reqnum)
564 return queried_keys[reqnum & N_QUERIED_KEYS_MASK];
565 return storeKeyPublic(url, METHOD_GET);
566}