]> git.ipfire.org Git - thirdparty/squid.git/blame - src/neighbors.cc
adding
[thirdparty/squid.git] / src / neighbors.cc
CommitLineData
30a4f2a8 1/*
a7e59001 2 * $Id: neighbors.cc,v 1.73 1996/10/27 07:11:58 wessels Exp $
30a4f2a8 3 *
4 * DEBUG: section 15 Neighbor Routines
5 * AUTHOR: Harvest Derived
6 *
7 * SQUID Internet Object Cache http://www.nlanr.net/Squid/
8 * --------------------------------------------------------
9 *
10 * Squid is the result of efforts by numerous individuals from the
11 * Internet community. Development is led by Duane Wessels of the
12 * National Laboratory for Applied Network Research and funded by
13 * the National Science Foundation.
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 *
4d64d74a 29 */
019dd986 30
31/*
30a4f2a8 32 * Copyright (c) 1994, 1995. All rights reserved.
33 *
34 * The Harvest software was developed by the Internet Research Task
35 * Force Research Group on Resource Discovery (IRTF-RD):
36 *
37 * Mic Bowman of Transarc Corporation.
38 * Peter Danzig of the University of Southern California.
39 * Darren R. Hardy of the University of Colorado at Boulder.
40 * Udi Manber of the University of Arizona.
41 * Michael F. Schwartz of the University of Colorado at Boulder.
42 * Duane Wessels of the University of Colorado at Boulder.
43 *
44 * This copyright notice applies to software in the Harvest
45 * ``src/'' directory only. Users should consult the individual
46 * copyright notices in the ``components/'' subdirectories for
47 * copyright information about other software bundled with the
48 * Harvest source code distribution.
49 *
50 * TERMS OF USE
51 *
52 * The Harvest software may be used and re-distributed without
53 * charge, provided that the software origin and research team are
54 * cited in any use of the system. Most commonly this is
55 * accomplished by including a link to the Harvest Home Page
56 * (http://harvest.cs.colorado.edu/) from the query page of any
57 * Broker you deploy, as well as in the query result pages. These
58 * links are generated automatically by the standard Broker
59 * software distribution.
60 *
61 * The Harvest software is provided ``as is'', without express or
62 * implied warranty, and with no support nor obligation to assist
63 * in its use, correction, modification or enhancement. We assume
64 * no liability with respect to the infringement of copyrights,
65 * trade secrets, or any patents, and are not responsible for
66 * consequential damages. Proper use of the Harvest software is
67 * entirely the responsibility of the user.
68 *
69 * DERIVATIVE WORKS
70 *
71 * Users may make derivative works from the Harvest software, subject
72 * to the following constraints:
73 *
74 * - You must include the above copyright notice and these
75 * accompanying paragraphs in all forms of derivative works,
76 * and any documentation and other materials related to such
77 * distribution and use acknowledge that the software was
78 * developed at the above institutions.
79 *
80 * - You must notify IRTF-RD regarding your distribution of
81 * the derivative work.
82 *
83 * - You must clearly notify users that your are distributing
84 * a modified version and not the original Harvest software.
85 *
86 * - Any derivative product is also subject to these copyright
87 * and use restrictions.
88 *
89 * Note that the Harvest software is NOT in the public domain. We
90 * retain copyright, as specified above.
91 *
92 * HISTORY OF FREE SOFTWARE STATUS
93 *
94 * Originally we required sites to license the software in cases
95 * where they were going to build commercial products/services
96 * around Harvest. In June 1995 we changed this policy. We now
97 * allow people to use the core Harvest software (the code found in
98 * the Harvest ``src/'' directory) for free. We made this change
99 * in the interest of encouraging the widest possible deployment of
100 * the technology. The Harvest software is really a reference
101 * implementation of a set of protocols and formats, some of which
102 * we intend to standardize. We encourage commercial
103 * re-implementations of code complying to this set of standards.
019dd986 104 */
090089c4 105
44a47c6e 106#include "squid.h"
090089c4 107
67508012 108static int edgeWouldBePinged _PARAMS((edge *, request_t *));
109static void neighborRemove _PARAMS((edge *));
d6a4502f 110static edge *whichEdge _PARAMS((struct sockaddr_in * from));
d73844ca 111static void neighborAlive _PARAMS((edge *, MemObject *, icp_common_t *));
a7e59001 112static void neighborCountIgnored _PARAMS((edge * e, icp_opcode op_unused));
090089c4 113
30a4f2a8 114static neighbors *friends = NULL;
090089c4 115static struct neighbor_cf *Neighbor_cf = NULL;
090089c4 116static icp_common_t echo_hdr;
30a4f2a8 117static u_short echo_port;
30a4f2a8 118
30a4f2a8 119char *hier_strings[] =
090089c4 120{
121 "NONE",
122 "DIRECT",
a99f5332 123 "SIBLING_HIT",
090089c4 124 "PARENT_HIT",
125 "SINGLE_PARENT",
30a4f2a8 126 "FIRST_UP_PARENT",
090089c4 127 "NO_PARENT_DIRECT",
128 "FIRST_PARENT_MISS",
129 "LOCAL_IP_DIRECT",
30a4f2a8 130 "FIREWALL_IP_DIRECT",
090089c4 131 "NO_DIRECT_FAIL",
132 "SOURCE_FASTEST",
a99f5332 133 "SIBLING_UDP_HIT_OBJ",
134 "PARENT_UDP_HIT_OBJ",
090089c4 135 "INVALID CODE"
136};
137
138
b8d8561b 139static edge *
4eda6afe 140whichEdge(struct sockaddr_in *from)
090089c4 141{
22e4fa85 142 int j;
4eda6afe 143 u_short port = ntohs(from->sin_port);
144 struct in_addr ip = from->sin_addr;
090089c4 145 edge *e = NULL;
019dd986 146 debug(15, 3, "whichEdge: from %s port %d\n", inet_ntoa(ip), port);
090089c4 147 for (e = friends->edges_head; e; e = e->next) {
148 for (j = 0; j < e->n_addresses; j++) {
30a4f2a8 149 if (ip.s_addr == e->addresses[j].s_addr && port == e->icp_port) {
090089c4 150 return e;
151 }
152 }
153 }
4eda6afe 154 return NULL;
090089c4 155}
156
b8d8561b 157void
158hierarchyNote(request_t * request, hier_code code, int timeout, char *cache_host)
090089c4 159{
eaa77841 160 if (request) {
161 request->hierarchy.code = code;
162 request->hierarchy.timeout = timeout;
163 request->hierarchy.host = xstrdup(cache_host);
090089c4 164 }
090089c4 165}
166
24a1003d 167static neighbor_t
168neighborType(edge * e, request_t * request)
169{
170 dom_list *d = NULL;
171 for (d = e->domains; d; d = d->next) {
172 if (matchDomainName(d->domain, request->host))
173 if (d->neighbor_type != EDGE_NONE)
24382924 174 return d->neighbor_type;
24a1003d 175 }
176 return e->type;
177}
178
b8d8561b 179static int
180edgeWouldBePinged(edge * e, request_t * request)
090089c4 181{
090089c4 182 dom_list *d = NULL;
183 int do_ping = 1;
30a4f2a8 184 struct _acl_list *a = NULL;
f88bb09c 185 aclCheck_t checklist;
090089c4 186
24a1003d 187 if (BIT_TEST(request->flags, REQ_NOCACHE))
24382924 188 if (neighborType(e, request) == EDGE_SIBLING)
24a1003d 189 return 0;
30a4f2a8 190 if (e->domains == NULL && e->acls == NULL)
090089c4 191 return do_ping;
090089c4 192 do_ping = 0;
193 for (d = e->domains; d; d = d->next) {
30a4f2a8 194 if (matchDomainName(d->domain, request->host))
195 return d->do_ping;
196 do_ping = !d->do_ping;
197 }
f88bb09c 198 checklist.src_addr = any_addr; /* XXX bogus! */
199 checklist.request = request;
30a4f2a8 200 for (a = e->acls; a; a = a->next) {
f88bb09c 201 if (aclMatchAcl(a->acl, &checklist))
30a4f2a8 202 return a->op;
203 do_ping = !a->op;
090089c4 204 }
205 return do_ping;
206}
207
b8d8561b 208edge *
209getSingleParent(request_t * request, int *n)
090089c4 210{
211 edge *p = NULL;
212 edge *e = NULL;
090089c4 213 int count = 0;
214
215 if (n == NULL && friends->n_parent < 1)
216 return NULL;
217 for (e = friends->edges_head; e; e = e->next) {
caebbe00 218 if (!edgeWouldBePinged(e, request))
219 continue;
220 count++;
24a1003d 221 if (neighborType(e, request) != EDGE_PARENT) {
caebbe00 222 /* we matched a neighbor, not a parent. There
223 * can be no single parent */
224 if (n == NULL)
225 return NULL;
226 continue;
090089c4 227 }
caebbe00 228 if (p) {
229 /* already have a parent, this makes the second,
230 * so there can be no single parent */
231 if (n == NULL)
232 return NULL;
233 continue;
234 }
235 p = e;
090089c4 236 }
237 /* Ok, all done checking the edges. If only one parent matched, then
238 * p will already point to it */
239 if (n)
240 *n = count;
241 if (count == 1)
242 return p;
243 return NULL;
244}
245
b8d8561b 246edge *
247getFirstUpParent(request_t * request)
090089c4 248{
249 edge *e = NULL;
090089c4 250 if (friends->n_parent < 1)
251 return NULL;
252 for (e = friends->edges_head; e; e = e->next) {
30a4f2a8 253 if (!e->neighbor_up)
254 continue;
24a1003d 255 if (neighborType(e, request) != EDGE_PARENT)
090089c4 256 continue;
30a4f2a8 257 if (edgeWouldBePinged(e, request))
090089c4 258 return e;
259 }
260 return NULL;
261}
262
b8d8561b 263edge *
264getNextEdge(edge * e)
090089c4 265{
266 return e->next;
267}
268
b8d8561b 269edge *
270getFirstEdge(void)
090089c4 271{
272 return friends->edges_head;
273}
274
b8d8561b 275static void
276neighborRemove(edge * target)
30a4f2a8 277{
278 edge *e = NULL;
279 edge **E = NULL;
280 e = friends->edges_head;
281 E = &friends->edges_head;
282 while (e) {
283 if (target == e)
284 break;
285 E = &e->next;
286 e = e->next;
287 }
288 if (e) {
289 *E = e->next;
5560c2ae 290 safe_free(e->host);
30a4f2a8 291 safe_free(e);
6e1788b9 292 friends->n--;
30a4f2a8 293 }
294}
295
b8d8561b 296void
0673c0ba 297neighborsDestroy(void)
4d64d74a 298{
299 edge *e = NULL;
300 edge *next = NULL;
301
0ffd22bc 302 debug(15, 3, "neighborsDestroy: called\n");
4d64d74a 303
304 for (e = friends->edges_head; e; e = next) {
305 next = e->next;
306 safe_free(e->host);
307 safe_free(e);
071764d1 308 friends->n--;
4d64d74a 309 }
0ffd22bc 310 safe_free(friends);
311 friends = NULL;
4d64d74a 312}
313
b8d8561b 314void
315neighbors_open(int fd)
090089c4 316{
22e4fa85 317 int j;
30a4f2a8 318 struct sockaddr_in name;
090089c4 319 struct sockaddr_in *ap;
30a4f2a8 320 int len = sizeof(struct sockaddr_in);
e5f6c5c2 321 ipcache_addrs *ia = NULL;
090089c4 322 edge *e = NULL;
30a4f2a8 323 edge *next = NULL;
324 edge **E = NULL;
30a4f2a8 325 struct servent *sep = NULL;
090089c4 326
30a4f2a8 327 memset(&name, '\0', sizeof(struct sockaddr_in));
328 if (getsockname(fd, (struct sockaddr *) &name, &len) < 0)
329 debug(15, 1, "getsockname(%d,%p,%p) failed.\n", fd, &name, &len);
090089c4 330
090089c4 331 /* Prepare neighbor connections, one at a time */
30a4f2a8 332 E = &friends->edges_head;
333 next = friends->edges_head;
334 while ((e = next)) {
c021888f 335 getCurrentTime();
30a4f2a8 336 next = e->next;
019dd986 337 debug(15, 2, "Finding IP addresses for '%s'\n", e->host);
e5f6c5c2 338 if ((ia = ipcache_gethostbyname(e->host, IP_BLOCKING_LOOKUP)) == NULL) {
30a4f2a8 339 debug(0, 0, "WARNING!!: DNS lookup for '%s' failed!\n", e->host);
340 debug(0, 0, "THIS NEIGHBOR WILL BE IGNORED.\n");
341 *E = next; /* skip */
342 safe_free(e);
343 continue;
090089c4 344 }
345 e->n_addresses = 0;
e5f6c5c2 346 for (j = 0; j < (int) ia->count && j < EDGE_MAX_ADDRESSES; j++) {
347 e->addresses[j] = ia->in_addrs[j];
090089c4 348 e->n_addresses++;
349 }
350 if (e->n_addresses < 1) {
30a4f2a8 351 debug(0, 0, "WARNING!!: No IP address found for '%s'!\n", e->host);
352 debug(0, 0, "THIS NEIGHBOR WILL BE IGNORED.\n");
353 *E = next; /* skip */
354 safe_free(e);
355 continue;
090089c4 356 }
357 for (j = 0; j < e->n_addresses; j++) {
30a4f2a8 358 debug(15, 2, "--> IP address #%d: %s\n",
359 j, inet_ntoa(e->addresses[j]));
090089c4 360 }
30a4f2a8 361 e->stats.rtt = 0;
090089c4 362
090089c4 363 ap = &e->in_addr;
364 memset(ap, '\0', sizeof(struct sockaddr_in));
365 ap->sin_family = AF_INET;
366 ap->sin_addr = e->addresses[0];
30a4f2a8 367 ap->sin_port = htons(e->icp_port);
090089c4 368
24a1003d 369 e->neighbor_up = 1;
30a4f2a8 370 E = &e->next;
371 }
090089c4 372
30a4f2a8 373 if (0 == echo_hdr.opcode) {
374 echo_hdr.opcode = ICP_OP_SECHO;
375 echo_hdr.version = ICP_VERSION_CURRENT;
376 echo_hdr.length = 0;
377 echo_hdr.reqnum = 0;
378 echo_hdr.flags = 0;
379 echo_hdr.pad = 0;
380 /* memset(echo_hdr.auth, '\0', sizeof(u_num32) * ICP_AUTH_SIZE); */
381 echo_hdr.shostid = name.sin_addr.s_addr;
382 sep = getservbyname("echo", "udp");
383 echo_port = sep ? ntohs((u_short) sep->s_port) : 7;
090089c4 384 }
385}
386
090089c4 387
b8d8561b 388int
389neighborsUdpPing(protodispatch_data * proto)
090089c4 390{
7111c86a 391 char *host = proto->request->host;
090089c4 392 char *url = proto->url;
393 StoreEntry *entry = proto->entry;
e5f6c5c2 394 ipcache_addrs *ia = NULL;
090089c4 395 struct sockaddr_in to_addr;
396 edge *e = NULL;
397 int i;
30a4f2a8 398 MemObject *mem = entry->mem_obj;
1061b406 399 int reqnum = 0;
6d2296d4 400 int flags;
090089c4 401
30a4f2a8 402 mem->e_pings_n_pings = 0;
403 mem->e_pings_n_acks = 0;
404 mem->e_pings_first_miss = NULL;
405 mem->w_rtt = 0;
406 mem->start_ping = current_time;
090089c4 407
95d659f0 408 if (friends->edges_head == NULL)
090089c4 409 return 0;
af00901c 410 if (theOutIcpConnection < 0) {
411 debug(15, 0, "neighborsUdpPing: There is no ICP socket!\n");
412 debug(15, 0, "Cannot query neighbors for '%s'.\n", url);
413 debug(15, 0, "Check 'icp_port' in your config file\n");
414 fatal_dump(NULL);
415 }
090089c4 416 for (i = 0, e = friends->first_ping; i++ < friends->n; e = e->next) {
a11fc0d2 417 if (entry->swap_status != NO_SWAP)
d556a268 418 fatal_dump("neighborsUdpPing: bad swap_status");
090089c4 419 if (e == (edge *) NULL)
420 e = friends->edges_head;
019dd986 421 debug(15, 5, "neighborsUdpPing: Edge %s\n", e->host);
090089c4 422
30a4f2a8 423 /* skip any cache where we failed to connect() w/in the last 60s */
424 if (squid_curtime - e->last_fail_time < 60)
090089c4 425 continue;
426
30a4f2a8 427 if (!edgeWouldBePinged(e, proto->request))
090089c4 428 continue; /* next edge */
30a4f2a8 429 if (e->options & NEIGHBOR_NO_QUERY)
430 continue;
090089c4 431
019dd986 432 debug(15, 4, "neighborsUdpPing: pinging cache %s for <URL:%s>\n",
090089c4 433 e->host, url);
434
2d25dc1a 435 if (BIT_TEST(entry->flag, KEY_PRIVATE))
1061b406 436 reqnum = atoi(entry->key);
9151555a 437 else
1061b406 438 reqnum = getKeyCounter();
0ffd22bc 439 debug(15, 3, "neighborsUdpPing: key = '%s'\n", entry->key);
1061b406 440 debug(15, 3, "neighborsUdpPing: reqnum = %d\n", reqnum);
090089c4 441
30a4f2a8 442 if (e->icp_port == echo_port) {
019dd986 443 debug(15, 4, "neighborsUdpPing: Looks like a dumb cache, send DECHO ping\n");
1061b406 444 echo_hdr.reqnum = reqnum;
af00901c 445 icpUdpSend(theOutIcpConnection,
95d659f0 446 url,
6d2296d4 447 reqnum,
95d659f0 448 &e->in_addr,
6d2296d4 449 0,
95d659f0 450 ICP_OP_DECHO,
a528eb87 451 LOG_TAG_NONE,
452 PROTO_NONE);
090089c4 453 } else {
6d2296d4 454 flags = 0;
455 /* check if we should set ICP_FLAG_HIT_OBJ */
456 if (opt_udp_hit_obj)
457 if (!BIT_TEST(proto->request->flags, REQ_NOCACHE))
458 if (e->icp_version == ICP_VERSION_2)
459 flags |= ICP_FLAG_HIT_OBJ;
af00901c 460 icpUdpSend(theOutIcpConnection,
95d659f0 461 url,
6d2296d4 462 reqnum,
95d659f0 463 &e->in_addr,
6d2296d4 464 flags,
95d659f0 465 ICP_OP_QUERY,
a528eb87 466 LOG_TAG_NONE,
467 PROTO_NONE);
090089c4 468 }
469
e90100aa 470 if (e->mcast_ttl > 0) {
471 /* XXX kill us off, so Squid won't expect a reply */
472 e->stats.ack_deficit = HIER_MAX_DEFICIT;
473 } else {
474 e->stats.ack_deficit++;
475 }
30a4f2a8 476 e->stats.pings_sent++;
090089c4 477
457bedbd 478 debug(15, 3, "neighborsUdpPing: %s: ack_deficit = %d\n",
479 e->host, e->stats.ack_deficit);
4aa84b41 480
30a4f2a8 481 if (e->stats.ack_deficit < HIER_MAX_DEFICIT) {
1061b406 482 /* its alive, expect a reply from it */
090089c4 483 e->neighbor_up = 1;
30a4f2a8 484 mem->e_pings_n_pings++;
090089c4 485 } else {
1061b406 486 /* Neighbor is dead; ping it anyway, but don't expect a reply */
090089c4 487 e->neighbor_up = 0;
090089c4 488 /* log it once at the threshold */
30a4f2a8 489 if ((e->stats.ack_deficit == HIER_MAX_DEFICIT)) {
3fc6cf44 490 debug(15, 0, "Detected DEAD %s: %s/%d/%d\n",
d2af9477 491 e->type == EDGE_SIBLING ? "SIBLING" : "PARENT",
3fc6cf44 492 e->host, e->http_port, e->icp_port);
090089c4 493 }
494 }
495 friends->first_ping = e->next;
496 }
497
498 /* only do source_ping if we have neighbors */
1061b406 499 if (friends->n) {
500 if (!proto->source_ping) {
501 debug(15, 6, "neighborsUdpPing: Source Ping is disabled.\n");
e5f6c5c2 502 } else if ((ia = ipcache_gethostbyname(host, IP_BLOCKING_LOOKUP))) {
1061b406 503 debug(15, 6, "neighborsUdpPing: Source Ping: to %s for '%s'\n",
504 host, url);
1061b406 505 echo_hdr.reqnum = reqnum;
16b204c4 506 if (icmp_sock != -1) {
e5f6c5c2 507 icmpSourcePing(ia->in_addrs[ia->cur], &echo_hdr, url);
16b204c4 508 } else {
509 to_addr.sin_family = AF_INET;
e5f6c5c2 510 to_addr.sin_addr = ia->in_addrs[ia->cur];
16b204c4 511 to_addr.sin_port = htons(echo_port);
512 icpUdpSend(theOutIcpConnection,
513 url,
6d2296d4 514 reqnum,
16b204c4 515 &to_addr,
516 entry->flag,
517 ICP_OP_SECHO,
518 LOG_TAG_NONE,
519 PROTO_NONE);
520 }
090089c4 521 } else {
1061b406 522 debug(15, 6, "neighborsUdpPing: Source Ping: unknown host: %s\n",
523 host);
090089c4 524 }
525 }
1061b406 526 return mem->e_pings_n_pings;
090089c4 527}
528
d73844ca 529static void
4eda6afe 530neighborAlive(edge * e, MemObject * mem, icp_common_t * header)
531{
532 int rtt;
533 int n;
534 /* Neighbor is alive, reset the ack deficit */
535 if (e->stats.ack_deficit >= HIER_MAX_DEFICIT) {
536 debug(15, 0, "Detected REVIVED %s: %s/%d/%d\n",
537 e->type == EDGE_PARENT ? "PARENT" : "SIBLING",
538 e->host, e->http_port, e->icp_port);
539 }
540 e->neighbor_up = 1;
541 e->stats.ack_deficit = 0;
542 n = ++e->stats.pings_acked;
543 if ((icp_opcode) header->opcode <= ICP_OP_END)
544 e->stats.counts[header->opcode]++;
545 if (n > RTT_AV_FACTOR)
546 n = RTT_AV_FACTOR;
547 if (mem) {
548 rtt = tvSubMsec(mem->start_ping, current_time);
549 e->stats.rtt = (e->stats.rtt * (n - 1) + rtt) / n;
550 e->icp_version = (int) header->version;
551 }
552}
090089c4 553
a7e59001 554static void
555neighborCountIgnored(edge * e, icp_opcode op_unused)
556{
557 if (e == NULL)
558 return;
559 e->stats.ignored_replies++;
560}
561
090089c4 562/* I should attach these records to the entry. We take the first
563 * hit we get our wait until everyone misses. The timeout handler
564 * call needs to nip this shopping list or call one of the misses.
565 *
566 * If a hit process is already started, then sobeit
567 */
b8d8561b 568void
569neighborsUdpAck(int fd, char *url, icp_common_t * header, struct sockaddr_in *from, StoreEntry * entry, char *data, int data_sz)
090089c4 570{
571 edge *e = NULL;
30a4f2a8 572 MemObject *mem = entry->mem_obj;
fe113054 573 int w_rtt;
30a4f2a8 574 HttpStateData *httpState = NULL;
24a1003d 575 neighbor_t ntype = EDGE_NONE;
5e5126cc 576 char *opcode_d;
a7e59001 577 icp_opcode opcode = (icp_opcode) header->opcode;
090089c4 578
a7e59001 579 debug(15, 6, "neighborsUdpAck: opcode %d '%s'\n", (int) opcode, url);
4eda6afe 580 if ((e = whichEdge(from)))
581 neighborAlive(e, mem, header);
a7e59001 582 if (opcode > ICP_OP_END)
d2af9477 583 return;
a7e59001 584 opcode_d = IcpOpcodeStr[opcode];
d2af9477 585 if (mem == NULL) {
5e5126cc 586 debug(15, 1, "Ignoring %s for missing mem_obj: %s\n", opcode_d, url);
a7e59001 587 neighborCountIgnored(e, opcode);
d2af9477 588 return;
589 }
8de2f7ad 590 /* check if someone is already fetching it */
591 if (BIT_TEST(entry->flag, ENTRY_DISPATCHED)) {
592 debug(15, 5, "neighborsUdpAck: '%s' already being fetched.\n", url);
a7e59001 593 neighborCountIgnored(e, opcode);
8de2f7ad 594 return;
595 }
596 if (entry->ping_status != PING_WAITING) {
5e5126cc 597 debug(15, 5, "neighborsUdpAck: Unexpected %s for %s\n", opcode_d, url);
a7e59001 598 neighborCountIgnored(e, opcode);
8de2f7ad 599 return;
600 }
4eda6afe 601 if (entry->lock_count == 0) {
5e5126cc 602 debug(12, 3, "neighborsUdpAck: '%s' has no locks\n", url);
a7e59001 603 neighborCountIgnored(e, opcode);
4eda6afe 604 return;
090089c4 605 }
d2af9477 606 debug(15, 3, "neighborsUdpAck: %s for '%s' from %s \n",
5e5126cc 607 opcode_d, url, e ? e->host : "source");
d2af9477 608 mem->e_pings_n_acks++;
5e5126cc 609 if (e)
ceb8994e 610 ntype = neighborType(e, mem->request);
a7e59001 611 if (opcode == ICP_OP_SECHO) {
d2af9477 612 /* Received source-ping reply */
090089c4 613 if (e) {
004b3381 614 debug(15, 1, "Ignoring SECHO from neighbor %s\n", e->host);
a7e59001 615 neighborCountIgnored(e, opcode);
090089c4 616 } else {
d2af9477 617 /* if we reach here, source-ping reply is the first 'parent',
618 * so fetch directly from the source */
019dd986 619 debug(15, 6, "Source is the first to respond.\n");
eaa77841 620 hierarchyNote(entry->mem_obj->request,
090089c4 621 HIER_SOURCE_FASTEST,
622 0,
1061b406 623 fqdnFromAddr(from->sin_addr));
30a4f2a8 624 entry->ping_status = PING_DONE;
457bedbd 625 protoStart(0, entry, NULL, entry->mem_obj->request);
d2af9477 626 return;
090089c4 627 }
a7e59001 628 } else if (opcode == ICP_OP_HIT_OBJ) {
a99f5332 629 if (e == NULL) {
630 debug(15, 0, "Ignoring ICP_OP_HIT_OBJ from non-neighbor %s\n",
631 inet_ntoa(from->sin_addr));
632 } else if (entry->object_len != 0) {
d2af9477 633 debug(15, 1, "Too late UDP_HIT_OBJ '%s'?\n", entry->url);
634 } else {
b8d8561b 635 if (e->options & NEIGHBOR_PROXY_ONLY)
636 storeReleaseRequest(entry);
d2af9477 637 protoCancelTimeout(0, entry);
638 entry->ping_status = PING_DONE;
639 httpState = xcalloc(1, sizeof(HttpStateData));
640 httpState->entry = entry;
641 httpProcessReplyHeader(httpState, data, data_sz);
642 storeAppend(entry, data, data_sz);
eaa77841 643 hierarchyNote(entry->mem_obj->request,
24a1003d 644 ntype == EDGE_PARENT ? HIER_PARENT_UDP_HIT_OBJ : HIER_SIBLING_UDP_HIT_OBJ,
d2af9477 645 0,
a99f5332 646 e->host);
37bcb332 647 storeComplete(entry); /* This might release entry! */
d2af9477 648 if (httpState->reply_hdr)
649 put_free_8k_page(httpState->reply_hdr);
650 safe_free(httpState);
30a4f2a8 651 return;
652 }
a7e59001 653 } else if (opcode == ICP_OP_HIT) {
d2af9477 654 if (e == NULL) {
004b3381 655 debug(15, 1, "Ignoring HIT from non-neighbor %s\n",
656 inet_ntoa(from->sin_addr));
d2af9477 657 } else {
eaa77841 658 hierarchyNote(entry->mem_obj->request,
24a1003d 659 ntype == EDGE_PARENT ? HIER_PARENT_HIT : HIER_SIBLING_HIT,
d2af9477 660 0,
661 e->host);
d2af9477 662 entry->ping_status = PING_DONE;
457bedbd 663 protoStart(0, entry, e, entry->mem_obj->request);
090089c4 664 return;
665 }
a7e59001 666 } else if (opcode == ICP_OP_DECHO) {
d2af9477 667 if (e == NULL) {
004b3381 668 debug(15, 1, "Ignoring DECHO from non-neighbor %s\n",
669 inet_ntoa(from->sin_addr));
24a1003d 670 } else if (ntype == EDGE_SIBLING) {
5e604a0e 671 debug_trap("neighborsUdpAck: Found non-ICP cache as SIBLING\n");
672 debug_trap("neighborsUdpAck: non-ICP neighbors must be a PARENT\n");
090089c4 673 } else {
30a4f2a8 674 w_rtt = tvSubMsec(mem->start_ping, current_time) / e->weight;
675 if (mem->w_rtt == 0 || w_rtt < mem->w_rtt) {
676 mem->e_pings_first_miss = e;
677 mem->w_rtt = w_rtt;
090089c4 678 }
679 }
a7e59001 680 } else if (opcode == ICP_OP_MISS) {
d2af9477 681 if (e == NULL) {
004b3381 682 debug(15, 1, "Ignoring MISS from non-neighbor %s\n",
683 inet_ntoa(from->sin_addr));
24a1003d 684 } else if (ntype == EDGE_PARENT) {
d2af9477 685 w_rtt = tvSubMsec(mem->start_ping, current_time) / e->weight;
686 if (mem->w_rtt == 0 || w_rtt < mem->w_rtt) {
687 mem->e_pings_first_miss = e;
688 mem->w_rtt = w_rtt;
689 }
090089c4 690 }
a7e59001 691 } else if (opcode == ICP_OP_DENIED) {
d2af9477 692 if (e == NULL) {
004b3381 693 debug(15, 1, "Ignoring DENIED from non-neighbor %s\n",
694 inet_ntoa(from->sin_addr));
d2af9477 695 } else if (e->stats.pings_acked > 100) {
30a4f2a8 696 if (100 * e->stats.counts[ICP_OP_DENIED] / e->stats.pings_acked > 95) {
697 debug(15, 0, "95%% of replies from '%s' are UDP_DENIED\n", e->host);
698 debug(15, 0, "Disabling '%s', please check your configuration.\n", e->host);
699 neighborRemove(e);
700 }
a7e59001 701 neighborCountIgnored(e, opcode);
30a4f2a8 702 }
a7e59001 703 } else if (opcode == ICP_OP_RELOADING) {
1061b406 704 if (e)
705 debug(15, 3, "neighborsUdpAck: %s is RELOADING\n", e->host);
090089c4 706 } else {
5e5126cc 707 debug(15, 0, "neighborsUdpAck: Unexpected ICP reply: %s\n", opcode_d);
d2af9477 708 }
709 if (mem->e_pings_n_acks == mem->e_pings_n_pings) {
d2af9477 710 entry->ping_status = PING_DONE;
711 debug(15, 6, "neighborsUdpAck: All replies received.\n");
457bedbd 712 /* pass in fd=0 here so protoStart() looks up the real FD
d2af9477 713 * and resets the timeout handler */
714 getFromDefaultSource(0, entry);
715 return;
090089c4 716 }
717}
718
b8d8561b 719void
e90100aa 720neighbors_cf_add(char *host, char *type, int http_port, int icp_port, int options, int weight, int mcast_ttl)
090089c4 721{
722 struct neighbor_cf *t, *u;
723
30a4f2a8 724 t = xcalloc(1, sizeof(struct neighbor_cf));
090089c4 725 t->host = xstrdup(host);
726 t->type = xstrdup(type);
30a4f2a8 727 t->http_port = http_port;
728 t->icp_port = icp_port;
729 t->options = options;
fe113054 730 t->weight = weight;
e90100aa 731 t->mcast_ttl = mcast_ttl;
090089c4 732 t->next = (struct neighbor_cf *) NULL;
733
734 if (Neighbor_cf == (struct neighbor_cf *) NULL) {
735 Neighbor_cf = t;
736 } else {
737 for (u = Neighbor_cf; u->next; u = u->next);
738 u->next = t;
739 }
740}
741
b8d8561b 742void
24a1003d 743neighbors_cf_domain(char *host, char *domain, neighbor_t type)
090089c4 744{
30a4f2a8 745 struct neighbor_cf *t = NULL;
746 dom_list *l = NULL;
747 dom_list **L = NULL;
090089c4 748
749 for (t = Neighbor_cf; t; t = t->next) {
750 if (strcmp(t->host, host) == 0)
751 break;
752 }
30a4f2a8 753 if (t == NULL) {
754 debug(15, 0, "%s, line %d: No cache_host '%s'\n",
755 cfg_filename, config_lineno, host);
756 return;
757 }
758 l = xmalloc(sizeof(dom_list));
090089c4 759 l->do_ping = 1;
760 if (*domain == '!') { /* check for !.edu */
761 l->do_ping = 0;
762 domain++;
763 }
764 l->domain = xstrdup(domain);
24a1003d 765 l->neighbor_type = type;
090089c4 766 l->next = NULL;
767 for (L = &(t->domains); *L; L = &((*L)->next));
768 *L = l;
30a4f2a8 769}
770
b8d8561b 771void
772neighbors_cf_acl(char *host, char *aclname)
30a4f2a8 773{
774 struct neighbor_cf *t = NULL;
775 struct _acl_list *L = NULL;
776 struct _acl_list **Tail = NULL;
777 struct _acl *a = NULL;
090089c4 778
30a4f2a8 779 for (t = Neighbor_cf; t; t = t->next) {
780 if (strcmp(t->host, host) == 0)
781 break;
782 }
783 if (t == NULL) {
784 debug(15, 0, "%s, line %d: No cache_host '%s'\n",
785 cfg_filename, config_lineno, host);
786 return;
787 }
788 L = xcalloc(1, sizeof(struct _acl_list));
789 L->op = 1;
790 if (*aclname == '!') {
791 L->op = 0;
792 aclname++;
793 }
794 debug(15, 3, "neighbors_cf_acl: looking for ACL name '%s'\n", aclname);
795 a = aclFindByName(aclname);
796 if (a == NULL) {
797 debug(15, 0, "%s line %d: %s\n",
798 cfg_filename, config_lineno, config_input_line);
799 debug(15, 0, "neighbors_cf_acl: ACL name '%s' not found.\n", aclname);
800 xfree(L);
801 return;
802 }
803 if (a->type == ACL_SRC_IP) {
804 debug(15, 0, "%s line %d: %s\n",
805 cfg_filename, config_lineno, config_input_line);
806 debug(15, 0, "neighbors_cf_acl: 'src' ALC's not supported for 'cache_host_acl'\n");
807 xfree(L);
808 return;
809 }
810 L->acl = a;
811 for (Tail = &(t->acls); *Tail; Tail = &((*Tail)->next));
812 *Tail = L;
090089c4 813}
814
b8d8561b 815void
0673c0ba 816neighbors_init(void)
090089c4 817{
c62e9195 818 struct neighbor_cf *t = NULL;
819 struct neighbor_cf *next = NULL;
820 char *me = getMyHostname();
821 edge *e = NULL;
c62e9195 822
823 debug(15, 1, "neighbors_init: Initializing Neighbors...\n");
824
825 if (friends == NULL)
30a4f2a8 826 friends = xcalloc(1, sizeof(neighbors));
c62e9195 827
090089c4 828 for (t = Neighbor_cf; t; t = next) {
829 next = t->next;
b6f794d6 830 if (!strcmp(t->host, me) && t->http_port == Config.Port.http) {
019dd986 831 debug(15, 0, "neighbors_init: skipping cache_host %s %s %d %d\n",
30a4f2a8 832 t->type, t->host, t->http_port, t->icp_port);
c62e9195 833 continue;
834 }
30a4f2a8 835 debug(15, 1, "Adding a %s: %s/%d/%d\n",
836 t->type, t->host, t->http_port, t->icp_port);
c62e9195 837
30a4f2a8 838 e = xcalloc(1, sizeof(edge));
839 e->http_port = t->http_port;
840 e->icp_port = t->icp_port;
e90100aa 841 e->mcast_ttl = t->mcast_ttl;
30a4f2a8 842 e->options = t->options;
fe113054 843 e->weight = t->weight;
c62e9195 844 e->host = t->host;
845 e->domains = t->domains;
30a4f2a8 846 e->acls = t->acls;
c62e9195 847 e->neighbor_up = 1;
6d2296d4 848 e->icp_version = ICP_VERSION_CURRENT;
c62e9195 849 if (!strcmp(t->type, "parent")) {
850 friends->n_parent++;
6e77be39 851 e->type = EDGE_PARENT;
c62e9195 852 } else {
853 friends->n_neighbor++;
6e77be39 854 e->type = EDGE_SIBLING;
090089c4 855 }
30a4f2a8 856 safe_free(t->type);
c62e9195 857
858 /* Append edge */
859 if (!friends->edges_head)
860 friends->edges_head = e;
861 if (friends->edges_tail)
862 friends->edges_tail->next = e;
863 friends->edges_tail = e;
864 friends->n++;
865
0ffd22bc 866 safe_free(t);
090089c4 867 }
0ffd22bc 868 Neighbor_cf = NULL;
30a4f2a8 869 any_addr.s_addr = inet_addr("0.0.0.0");
090089c4 870}
871
b8d8561b 872edge *
873neighborFindByName(char *name)
98ffb7e4 874{
875 edge *e = NULL;
876 for (e = friends->edges_head; e; e = e->next) {
877 if (!strcasecmp(name, e->host))
878 break;
879 }
880 return e;
881}