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