]> git.ipfire.org Git - thirdparty/squid.git/blame - src/icp_v2.cc
Needs #include "comm.h" for comm_udp_recvfrom()
[thirdparty/squid.git] / src / icp_v2.cc
CommitLineData
194dd3b8 1
9cef6668 2/*
0013f3a6 3 * $Id: icp_v2.cc,v 1.71 2002/10/21 09:18:40 adrian 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"
e6ccf245 37#include "Store.h"
063dc1eb 38#include "comm.h"
e6ccf245 39#include "ICP.h"
7a2f978b 40
17b6e784 41static void icpLogIcp(struct in_addr, log_type, int, const char *, int);
7a2f978b 42static void icpHandleIcpV2(int, struct sockaddr_in, char *, int);
071a3ae7 43static void icpCount(void *, int, size_t, int);
17b6e784 44
48382032 45/*
46 * IcpQueueHead is global so comm_incoming() knows whether or not
47 * to call icpUdpSendQueue.
48 */
49static icpUdpData *IcpQueueTail = NULL;
7a2f978b 50
e6ccf245 51/* icp_common_t */
52_icp_common_t::_icp_common_t() : opcode(ICP_INVALID), version(0), length(0), reqnum(0), flags(0), pad(0), shostid(0)
53{
54}
55
56_icp_common_t::_icp_common_t(char *buf, unsigned int len)
57{
58 if (len < sizeof(_icp_common_t)) {
59 /* mark as invalid */
60 length = len + 1;
61 return;
62 }
63 xmemcpy(this, buf, sizeof(icp_common_t));
64 /*
65 * Convert network order sensitive fields
66 */
67 length = ntohs(length);
68 reqnum = ntohl(reqnum);
69 flags = ntohl(flags);
70 pad = ntohl(pad);
71}
72
73icp_opcode
74_icp_common_t::getOpCode() const
75{
76 if (opcode > (char)ICP_END)
77 return ICP_INVALID;
78 return (icp_opcode)opcode;
79}
80
81/* ICPState */
82
83ICPState:: ICPState(icp_common_t & aHeader):header(aHeader)
84{
85}
86
87ICPState::~ICPState()
88{
89 safe_free(url);
90 if (request)
91 requestDestroy(request);
92}
93
94
95/* End ICPState */
96
97/* ICP2State */
98class ICP2State:public ICPState, public StoreClient {
99 public:
100 ICP2State(icp_common_t & aHeader):ICPState(aHeader),rtt(0),src_rtt(0),flags(0) {
101 } ~ICP2State();
102 void created(StoreEntry * newEntry);
103
104 int rtt;
105 int src_rtt;
106 u_int32_t flags;
107};
108
109ICP2State::~ICP2State ()
110{
111}
112
113void
114ICP2State::created (StoreEntry *newEntry)
115{
116 StoreEntry *entry = newEntry->isNull () ? NULL : newEntry;
117 debug(12, 5) ("icpHandleIcpV2: OPCODE %s\n", icp_opcode_str[header.opcode]);
118 icp_opcode codeToSend;
119 if (icpCheckUdpHit(entry, request)) {
120 codeToSend = ICP_HIT;
121 } else {
122 if (Config.onoff.test_reachability && rtt == 0) {
123 if ((rtt = netdbHostRtt(request->host)) == 0)
124 netdbPingSite(request->host);
125 }
126 if (icpGetCommonOpcode() != ICP_ERR)
127 codeToSend = icpGetCommonOpcode();
128 else if (Config.onoff.test_reachability && rtt == 0)
129 codeToSend = ICP_MISS_NOFETCH;
130 else
131 codeToSend = ICP_MISS;
132 }
133 icpCreateAndSend(codeToSend, flags, url, header.reqnum, src_rtt, fd, &from);
134 delete this;
135}
136
137/* End ICP2State */
138
7a2f978b 139static void
17b6e784 140icpLogIcp(struct in_addr caddr, log_type logcode, int len, const char *url, int delay)
7a2f978b 141{
7a2f978b 142 AccessLogEntry al;
96c617da 143 if (LOG_TAG_NONE == logcode)
144 return;
071a3ae7 145 if (LOG_ICP_QUERY == logcode)
146 return;
17b6e784 147 clientdbUpdate(caddr, logcode, PROTO_ICP, len);
7a2f978b 148 if (!Config.onoff.log_udp)
149 return;
17b6e784 150 memset(&al, '\0', sizeof(al));
27cd7235 151 al.icp.opcode = ICP_QUERY;
7a2f978b 152 al.url = url;
17b6e784 153 al.cache.caddr = caddr;
154 al.cache.size = len;
155 al.cache.code = logcode;
156 al.cache.msec = delay;
7a2f978b 157 accessLogLog(&al);
158}
159
48382032 160void
17b6e784 161icpUdpSendQueue(int fd, void *unused)
7a2f978b 162{
17b6e784 163 icpUdpData *q;
7a2f978b 164 int x;
17b6e784 165 int delay;
48382032 166 while ((q = IcpQueueHead) != NULL) {
17b6e784 167 delay = tvSubUsec(q->queue_time, current_time);
168 /* increment delay to prevent looping */
e6ccf245 169 x = icpUdpSend(fd, &q->address, (icp_common_t *) q->msg, q->logcode, ++delay);
48382032 170 IcpQueueHead = q->next;
17b6e784 171 safe_free(q);
172 if (x < 0)
173 break;
7a2f978b 174 }
175}
176
e6ccf245 177_icp_common_t *
178_icp_common_t::createMessage(
7a2f978b 179 icp_opcode opcode,
180 int flags,
181 const char *url,
182 int reqnum,
183 int pad)
184{
185 char *buf = NULL;
186 icp_common_t *headerp = NULL;
187 char *urloffset = NULL;
188 int buf_len;
189 buf_len = sizeof(icp_common_t) + strlen(url) + 1;
27cd7235 190 if (opcode == ICP_QUERY)
a9245686 191 buf_len += sizeof(u_int32_t);
e6ccf245 192 buf = (char *) xcalloc(buf_len, 1);
7a2f978b 193 headerp = (icp_common_t *) (void *) buf;
79d39a72 194 headerp->opcode = (char) opcode;
7a2f978b 195 headerp->version = ICP_VERSION_CURRENT;
a9245686 196 headerp->length = (u_int16_t) htons(buf_len);
7a2f978b 197 headerp->reqnum = htonl(reqnum);
198 headerp->flags = htonl(flags);
199 headerp->pad = htonl(pad);
67129385 200 headerp->shostid = theOutICPAddr.s_addr;
7a2f978b 201 urloffset = buf + sizeof(icp_common_t);
27cd7235 202 if (opcode == ICP_QUERY)
a9245686 203 urloffset += sizeof(u_int32_t);
7a2f978b 204 xmemcpy(urloffset, url, strlen(url));
e6ccf245 205 return (icp_common_t *)buf;
7a2f978b 206}
207
17b6e784 208int
7a2f978b 209icpUdpSend(int fd,
210 const struct sockaddr_in *to,
211 icp_common_t * msg,
212 log_type logcode,
17b6e784 213 int delay)
7a2f978b 214{
17b6e784 215 icpUdpData *queue;
8e68922c 216 int x;
17b6e784 217 int len;
218 len = (int) ntohs(msg->length);
219 debug(12, 5) ("icpUdpSend: FD %d sending %s, %d bytes to %s:%d\n",
8e68922c 220 fd,
17b6e784 221 icp_opcode_str[msg->opcode],
222 len,
223 inet_ntoa(to->sin_addr),
224 ntohs(to->sin_port));
225 x = comm_udp_sendto(fd, to, sizeof(*to), msg, len);
9f80ddf1 226 if (x >= 0) {
17b6e784 227 /* successfully written */
228 icpLogIcp(to->sin_addr, logcode, len, (char *) (msg + 1), delay);
071a3ae7 229 icpCount(msg, SENT, (size_t) len, delay);
17b6e784 230 safe_free(msg);
231 } else if (0 == delay) {
232 /* send failed, but queue it */
e6ccf245 233 queue = (icpUdpData *) xcalloc(1, sizeof(icpUdpData));
17b6e784 234 queue->address = *to;
235 queue->msg = msg;
236 queue->len = (int) ntohs(msg->length);
237 queue->queue_time = current_time;
238 queue->logcode = logcode;
48382032 239 if (IcpQueueHead == NULL) {
240 IcpQueueHead = queue;
241 IcpQueueTail = queue;
242 } else if (IcpQueueTail == IcpQueueHead) {
243 IcpQueueTail = queue;
244 IcpQueueHead->next = queue;
17b6e784 245 } else {
48382032 246 IcpQueueTail->next = queue;
247 IcpQueueTail = queue;
17b6e784 248 }
249 commSetSelect(fd, COMM_SELECT_WRITE, icpUdpSendQueue, NULL, 0);
83704487 250 statCounter.icp.replies_queued++;
8e68922c 251 } else {
17b6e784 252 /* don't queue it */
83704487 253 statCounter.icp.replies_dropped++;
8e68922c 254 }
17b6e784 255 return x;
7a2f978b 256}
257
258int
259icpCheckUdpHit(StoreEntry * e, request_t * request)
260{
261 if (e == NULL)
262 return 0;
263 if (!storeEntryValidToSend(e))
264 return 0;
265 if (Config.onoff.icp_hit_stale)
266 return 1;
829a9357 267 if (refreshCheckICP(e, request))
7a2f978b 268 return 0;
7a2f978b 269 return 1;
270}
7a2f978b 271
e6ccf245 272/* ICP_ERR means no opcode selected here */
273icp_opcode
274icpGetCommonOpcode()
275{
276 /* if store is rebuilding, return a UDP_HIT, but not a MISS */
277 if (store_dirs_rebuilding && opt_reload_hit_only ||
278 hit_only_mode_until > squid_curtime) {
279 return ICP_MISS_NOFETCH;
280 }
281 return ICP_ERR;
282}
283
284log_type
285icpLogFromICPCode(icp_opcode opcode)
286{
287 if (opcode == ICP_ERR)
288 return LOG_UDP_INVALID;
289 if (opcode == ICP_DENIED)
290 return LOG_UDP_DENIED;
291 if (opcode == ICP_HIT)
292 return LOG_UDP_HIT;
293 if (opcode == ICP_MISS)
294 return LOG_UDP_MISS;
295 if (opcode == ICP_MISS_NOFETCH)
296 return LOG_UDP_MISS_NOFETCH;
297 fatal("expected ICP opcode\n");
298 return LOG_UDP_INVALID;
299}
300
301void
302icpCreateAndSend(icp_opcode opcode, int flags, char const *url, int reqnum, int pad, int fd, const struct sockaddr_in *from)
303{
304 icp_common_t *reply = _icp_common_t::createMessage(opcode, flags, url, reqnum, pad);
305 icpUdpSend(fd, from, reply, icpLogFromICPCode(opcode), 0);
306}
307
308void
309icpDenyAccess(struct sockaddr_in *from, char *url, int reqnum, int fd)
310{
311 debug(12, 2) ("icpDenyAccess: Access Denied for %s by %s.\n",
312 inet_ntoa(from->sin_addr), AclMatchedName);
313 if (clientdbCutoffDenied(from->sin_addr)) {
314 /*
315 * count this DENIED query in the clientdb, even though
316 * we're not sending an ICP reply...
317 */
318 clientdbUpdate(from->sin_addr, LOG_UDP_DENIED, PROTO_ICP, 0);
319 } else {
320 icpCreateAndSend(ICP_DENIED, 0, url, reqnum, 0, fd, from);
321 }
322}
323
324int
325icpAccessAllowed(struct sockaddr_in *from, request_t * icp_request)
7a2f978b 326{
7a2f978b 327 aclCheck_t checklist;
e6ccf245 328 memset(&checklist, '\0', sizeof(checklist));
329 checklist.src_addr = from->sin_addr;
330 checklist.my_addr = no_addr;
331 checklist.request = icp_request;
332 return aclCheckFast(Config.accessList.icp, &checklist);
333}
334
335char const *
336icpGetUrlToSend(char *url)
337{
338 if (strpbrk(url, w_space))
339 return rfc1738_escape(url);
340 else
341 return url;
342}
343
344request_t *
345icpGetRequest(char *url, int reqnum, int fd, struct sockaddr_in * from)
346{
347 if (strpbrk(url, w_space)) {
348 url = rfc1738_escape(url);
349 icpCreateAndSend(ICP_ERR, 0, rfc1738_escape(url), reqnum, 0, fd, from);
350 return NULL;
351 }
352 request_t *result;
353 if ((result = urlParse(METHOD_GET, url)) == NULL)
354 icpCreateAndSend(ICP_ERR, 0, url, reqnum, 0, fd, from);
355 return result;
356
357}
358
359static void
360doV2Query(int fd, struct sockaddr_in from, char *buf, icp_common_t header)
361{
362 int rtt = 0;
7a2f978b 363 int src_rtt = 0;
a9245686 364 u_int32_t flags = 0;
e6ccf245 365 /* We have a valid packet */
366 char *url = buf + sizeof(icp_common_t) + sizeof(u_int32_t);
367 request_t *icp_request = icpGetRequest(url, header.reqnum, fd, &from);
368 if (!icp_request)
369 return;
370 if (!icpAccessAllowed(&from, icp_request)) {
371 icpDenyAccess(&from, url, header.reqnum, fd);
372 requestDestroy(icp_request);
373 return;
374 }
375 if (header.flags & ICP_FLAG_SRC_RTT) {
376 rtt = netdbHostRtt(icp_request->host);
377 int hops = netdbHostHops(icp_request->host);
378 src_rtt = ((hops & 0xFFFF) << 16) | (rtt & 0xFFFF);
379 if (rtt)
380 flags |= ICP_FLAG_SRC_RTT;
381 }
382 /* The peer is allowed to use this cache */
383 ICP2State *state = new ICP2State (header);
384 state->fd = fd;
385 state->from = from;
386 state->url = xstrdup (url);
387 state->flags = flags;
388 state->rtt = rtt;
389 state->src_rtt = src_rtt;
390 _StoreEntry::getPublic (state, url, METHOD_GET);
391}
392
393void
394_icp_common_t::handleReply(char *buf, struct sockaddr_in *from)
395{
396 if (neighbors_do_private_keys && reqnum == 0) {
397 debug(12, 0) ("icpHandleIcpV2: Neighbor %s returned reqnum = 0\n",
398 inet_ntoa(from->sin_addr));
399 debug(12, 0) ("icpHandleIcpV2: Disabling use of private keys\n");
400 neighbors_do_private_keys = 0;
401 }
402 char *url = buf + sizeof(icp_common_t);
403 debug(12, 3) ("icpHandleIcpV2: %s from %s for '%s'\n",
404 icp_opcode_str[opcode],
405 inet_ntoa(from->sin_addr),
406 url);
407 const cache_key *key = icpGetCacheKey(url, (int) reqnum);
408 /* call neighborsUdpAck even if ping_status != PING_WAITING */
409 neighborsUdpAck(key, this, from);
410}
411
412static void
413icpHandleIcpV2(int fd, struct sockaddr_in from, char *buf, int len)
414{
415 if (len <= 0) {
416 debug(12, 3) ("icpHandleIcpV2: ICP message is too small\n");
417 return;
418 }
419 icp_common_t header(buf, len);
7b83b3d9 420 /*
421 * Length field should match the number of bytes read
422 */
423 if (len != header.length) {
424 debug(12, 3) ("icpHandleIcpV2: ICP message is too small\n");
425 return;
426 }
7a2f978b 427 switch (header.opcode) {
27cd7235 428 case ICP_QUERY:
7a2f978b 429 /* We have a valid packet */
e6ccf245 430 doV2Query(fd, from, buf, header);
7a2f978b 431 break;
432
27cd7235 433 case ICP_HIT:
db1cd23c 434#if ALLOW_SOURCE_PING
27cd7235 435 case ICP_SECHO:
db1cd23c 436#endif
27cd7235 437 case ICP_DECHO:
438 case ICP_MISS:
439 case ICP_DENIED:
440 case ICP_MISS_NOFETCH:
e6ccf245 441 header.handleReply(buf, &from);
7a2f978b 442 break;
443
27cd7235 444 case ICP_INVALID:
445 case ICP_ERR:
7a2f978b 446 break;
447
448 default:
449 debug(12, 0) ("icpHandleIcpV2: UNKNOWN OPCODE: %d from %s\n",
450 header.opcode, inet_ntoa(from.sin_addr));
451 break;
452 }
7a2f978b 453}
454
455#ifdef ICP_PKT_DUMP
456static void
457icpPktDump(icp_common_t * pkt)
458{
459 struct in_addr a;
460
461 debug(12, 9) ("opcode: %3d %s\n",
462 (int) pkt->opcode,
27cd7235 463 icp_opcode_str[pkt->opcode]);
7a2f978b 464 debug(12, 9) ("version: %-8d\n", (int) pkt->version);
465 debug(12, 9) ("length: %-8d\n", (int) ntohs(pkt->length));
466 debug(12, 9) ("reqnum: %-8d\n", ntohl(pkt->reqnum));
467 debug(12, 9) ("flags: %-8x\n", ntohl(pkt->flags));
67129385 468 a.s_addr = pkt->shostid;
7a2f978b 469 debug(12, 9) ("shostid: %s\n", inet_ntoa(a));
470 debug(12, 9) ("payload: %s\n", (char *) pkt + sizeof(icp_common_t));
471}
472#endif
473
474void
ba4f8e5a 475icpHandleUdp(int sock, void *data)
7a2f978b 476{
d193a436 477 int *N = &incoming_sockets_accepted;
7a2f978b 478 struct sockaddr_in from;
6637e3a5 479 socklen_t from_len;
7a2f978b 480 LOCAL_ARRAY(char, buf, SQUID_UDP_SO_RCVBUF);
e6ccf245 481 size_t len;
7a2f978b 482 int icp_version;
309ad3b6 483 int max = INCOMING_ICP_MAX;
7a2f978b 484 commSetSelect(sock, COMM_SELECT_READ, icpHandleUdp, NULL, 0);
5b0aaa58 485 while (max--) {
486 from_len = sizeof(from);
487 memset(&from, '\0', from_len);
0013f3a6 488 len = comm_udp_recvfrom(sock,
5b0aaa58 489 buf,
490 SQUID_UDP_SO_RCVBUF - 1,
491 0,
492 (struct sockaddr *) &from,
493 &from_len);
494 if (len == 0)
495 break;
496 if (len < 0) {
497 if (ignoreErrno(errno))
498 break;
7a2f978b 499#ifdef _SQUID_LINUX_
5b0aaa58 500 /* Some Linux systems seem to set the FD for reading and then
501 * return ECONNREFUSED when sendto() fails and generates an ICMP
502 * port unreachable message. */
503 /* or maybe an EHOSTUNREACH "No route to host" message */
504 if (errno != ECONNREFUSED && errno != EHOSTUNREACH)
7a2f978b 505#endif
5b0aaa58 506 debug(50, 1) ("icpHandleUdp: FD %d recvfrom: %s\n",
507 sock, xstrerror());
508 break;
509 }
ba4f8e5a 510 (*N)++;
5b0aaa58 511 icpCount(buf, RECV, (size_t) len, 0);
512 buf[len] = '\0';
85f5fd11 513 debug(12, 4) ("icpHandleUdp: FD %d: received %lu bytes from %s.\n",
5b0aaa58 514 sock,
85f5fd11 515 (unsigned long int)len,
5b0aaa58 516 inet_ntoa(from.sin_addr));
7a2f978b 517#ifdef ICP_PACKET_DUMP
5b0aaa58 518 icpPktDump(buf);
7a2f978b 519#endif
5b0aaa58 520 if (len < sizeof(icp_common_t)) {
521 debug(12, 4) ("icpHandleUdp: Ignoring too-small UDP packet\n");
522 break;
523 }
524 icp_version = (int) buf[1]; /* cheat! */
525 if (icp_version == ICP_VERSION_2)
526 icpHandleIcpV2(sock, from, buf, len);
527 else if (icp_version == ICP_VERSION_3)
528 icpHandleIcpV3(sock, from, buf, len);
529 else
edc182e2 530 debug(12, 1) ("WARNING: Unused ICP version %d received from %s:%d\n",
5b0aaa58 531 icp_version,
532 inet_ntoa(from.sin_addr),
533 ntohs(from.sin_port));
7a2f978b 534 }
7a2f978b 535}
15df8349 536
537void
538icpConnectionsOpen(void)
539{
a9245686 540 u_int16_t port;
15df8349 541 struct in_addr addr;
542 struct sockaddr_in xaddr;
543 int x;
6637e3a5 544 socklen_t len;
15df8349 545 wordlist *s;
546 if (Config2.Accel.on && !Config.onoff.accel_with_proxy)
547 return;
548 if ((port = Config.Port.icp) <= 0)
549 return;
550 enter_suid();
551 theInIcpConnection = comm_open(SOCK_DGRAM,
552 0,
553 Config.Addrs.udp_incoming,
554 port,
555 COMM_NONBLOCKING,
de0df6f5 556 "ICP Socket");
15df8349 557 leave_suid();
558 if (theInIcpConnection < 0)
559 fatal("Cannot open ICP Port");
15df8349 560 commSetSelect(theInIcpConnection,
eeb423fb 561 COMM_SELECT_READ,
562 icpHandleUdp,
563 NULL,
564 0);
15df8349 565 for (s = Config.mcast_group_list; s; s = s->next)
566 ipcache_nbgethostbyname(s->key, mcastJoinGroups, NULL);
7e3ce7b9 567 debug(12, 1) ("Accepting ICP messages at %s, port %d, FD %d.\n",
568 inet_ntoa(Config.Addrs.udp_incoming),
15df8349 569 (int) port, theInIcpConnection);
570 if ((addr = Config.Addrs.udp_outgoing).s_addr != no_addr.s_addr) {
571 enter_suid();
572 theOutIcpConnection = comm_open(SOCK_DGRAM,
573 0,
574 addr,
575 port,
576 COMM_NONBLOCKING,
577 "ICP Port");
578 leave_suid();
579 if (theOutIcpConnection < 0)
580 fatal("Cannot open Outgoing ICP Port");
581 commSetSelect(theOutIcpConnection,
582 COMM_SELECT_READ,
583 icpHandleUdp,
ba4f8e5a 584 NULL,
585 0);
17e6c0a1 586 debug(12, 1) ("Outgoing ICP messages on port %d, FD %d.\n",
1e948d78 587 (int) port, theOutIcpConnection);
15df8349 588 fd_note(theOutIcpConnection, "Outgoing ICP socket");
589 fd_note(theInIcpConnection, "Incoming ICP socket");
590 } else {
591 theOutIcpConnection = theInIcpConnection;
592 }
593 memset(&theOutICPAddr, '\0', sizeof(struct in_addr));
594 len = sizeof(struct sockaddr_in);
595 memset(&xaddr, '\0', len);
596 x = getsockname(theOutIcpConnection,
597 (struct sockaddr *) &xaddr, &len);
598 if (x < 0)
599 debug(50, 1) ("theOutIcpConnection FD %d: getsockname: %s\n",
600 theOutIcpConnection, xstrerror());
601 else
602 theOutICPAddr = xaddr.sin_addr;
603}
c0fbae16 604
17e6c0a1 605/*
606 * icpConnectionShutdown only closes the 'in' socket if it is
607 * different than the 'out' socket.
608 */
c0fbae16 609void
17e6c0a1 610icpConnectionShutdown(void)
c0fbae16 611{
612 if (theInIcpConnection < 0)
613 return;
17e6c0a1 614 if (theInIcpConnection != theOutIcpConnection) {
c7863c6f 615 debug(12, 1) ("FD %d Closing ICP connection\n", theInIcpConnection);
c0fbae16 616 comm_close(theInIcpConnection);
17e6c0a1 617 }
c0fbae16 618 /*
619 * Here we set 'theInIcpConnection' to -1 even though the ICP 'in'
620 * and 'out' sockets might be just one FD. This prevents this
621 * function from executing repeatedly. When we are really ready to
622 * exit or restart, main will comm_close the 'out' descriptor.
623 */
624 theInIcpConnection = -1;
625 /*
626 * Normally we only write to the outgoing ICP socket, but
627 * we also have a read handler there to catch messages sent
628 * to that specific interface. During shutdown, we must
629 * disable reading on the outgoing socket.
630 */
631 assert(theOutIcpConnection > -1);
632 commSetSelect(theOutIcpConnection, COMM_SELECT_READ, NULL, NULL, 0);
633}
17e6c0a1 634
635void
636icpConnectionClose(void)
637{
638 icpConnectionShutdown();
639 if (theOutIcpConnection > -1) {
c7863c6f 640 debug(12, 1) ("FD %d Closing ICP connection\n", theOutIcpConnection);
17e6c0a1 641 comm_close(theOutIcpConnection);
05b744f3 642 theOutIcpConnection = -1;
17e6c0a1 643 }
644}
071a3ae7 645
646static void
647icpCount(void *buf, int which, size_t len, int delay)
648{
e6ccf245 649 icp_common_t *icp = (icp_common_t *) buf;
071a3ae7 650 if (len < sizeof(*icp))
651 return;
652 if (SENT == which) {
83704487 653 statCounter.icp.pkts_sent++;
654 kb_incr(&statCounter.icp.kbytes_sent, len);
071a3ae7 655 if (ICP_QUERY == icp->opcode) {
83704487 656 statCounter.icp.queries_sent++;
657 kb_incr(&statCounter.icp.q_kbytes_sent, len);
071a3ae7 658 } else {
83704487 659 statCounter.icp.replies_sent++;
660 kb_incr(&statCounter.icp.r_kbytes_sent, len);
071a3ae7 661 /* this is the sent-reply service time */
83704487 662 statHistCount(&statCounter.icp.reply_svc_time, delay);
071a3ae7 663 }
4b4cd312 664 if (ICP_HIT == icp->opcode)
83704487 665 statCounter.icp.hits_sent++;
071a3ae7 666 } else if (RECV == which) {
83704487 667 statCounter.icp.pkts_recv++;
668 kb_incr(&statCounter.icp.kbytes_recv, len);
071a3ae7 669 if (ICP_QUERY == icp->opcode) {
83704487 670 statCounter.icp.queries_recv++;
671 kb_incr(&statCounter.icp.q_kbytes_recv, len);
071a3ae7 672 } else {
83704487 673 statCounter.icp.replies_recv++;
674 kb_incr(&statCounter.icp.r_kbytes_recv, len);
675 /* statCounter.icp.query_svc_time set in clientUpdateCounters */
071a3ae7 676 }
4b4cd312 677 if (ICP_HIT == icp->opcode)
83704487 678 statCounter.icp.hits_recv++;
071a3ae7 679 }
680}
007b8be4 681
682#define N_QUERIED_KEYS 8192
683#define N_QUERIED_KEYS_MASK 8191
684static cache_key queried_keys[N_QUERIED_KEYS][MD5_DIGEST_CHARS];
685
686int
5942e8d4 687icpSetCacheKey(const cache_key * key)
007b8be4 688{
689 static int reqnum = 0;
690 if (++reqnum < 0)
691 reqnum = 1;
692 storeKeyCopy(queried_keys[reqnum & N_QUERIED_KEYS_MASK], key);
693 return reqnum;
694}
695
696const cache_key *
697icpGetCacheKey(const char *url, int reqnum)
698{
699 if (neighbors_do_private_keys && reqnum)
700 return queried_keys[reqnum & N_QUERIED_KEYS_MASK];
701 return storeKeyPublic(url, METHOD_GET);
702}