]> git.ipfire.org Git - thirdparty/squid.git/blame - src/neighbors.cc
fix strftime() to use RFC1123 format
[thirdparty/squid.git] / src / neighbors.cc
CommitLineData
30a4f2a8 1/*
ceb8994e 2 * $Id: neighbors.cc,v 1.72 1996/10/24 06:12:46 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 *));
090089c4 112
30a4f2a8 113static neighbors *friends = NULL;
090089c4 114static struct neighbor_cf *Neighbor_cf = NULL;
090089c4 115static icp_common_t echo_hdr;
30a4f2a8 116static u_short echo_port;
30a4f2a8 117
30a4f2a8 118char *hier_strings[] =
090089c4 119{
120 "NONE",
121 "DIRECT",
a99f5332 122 "SIBLING_HIT",
090089c4 123 "PARENT_HIT",
124 "SINGLE_PARENT",
30a4f2a8 125 "FIRST_UP_PARENT",
090089c4 126 "NO_PARENT_DIRECT",
127 "FIRST_PARENT_MISS",
128 "LOCAL_IP_DIRECT",
30a4f2a8 129 "FIREWALL_IP_DIRECT",
090089c4 130 "NO_DIRECT_FAIL",
131 "SOURCE_FASTEST",
a99f5332 132 "SIBLING_UDP_HIT_OBJ",
133 "PARENT_UDP_HIT_OBJ",
090089c4 134 "INVALID CODE"
135};
136
137
b8d8561b 138static edge *
4eda6afe 139whichEdge(struct sockaddr_in *from)
090089c4 140{
22e4fa85 141 int j;
4eda6afe 142 u_short port = ntohs(from->sin_port);
143 struct in_addr ip = from->sin_addr;
090089c4 144 edge *e = NULL;
019dd986 145 debug(15, 3, "whichEdge: from %s port %d\n", inet_ntoa(ip), port);
090089c4 146 for (e = friends->edges_head; e; e = e->next) {
147 for (j = 0; j < e->n_addresses; j++) {
30a4f2a8 148 if (ip.s_addr == e->addresses[j].s_addr && port == e->icp_port) {
090089c4 149 return e;
150 }
151 }
152 }
4eda6afe 153 return NULL;
090089c4 154}
155
b8d8561b 156void
157hierarchyNote(request_t * request, hier_code code, int timeout, char *cache_host)
090089c4 158{
eaa77841 159 if (request) {
160 request->hierarchy.code = code;
161 request->hierarchy.timeout = timeout;
162 request->hierarchy.host = xstrdup(cache_host);
090089c4 163 }
090089c4 164}
165
24a1003d 166static neighbor_t
167neighborType(edge * e, request_t * request)
168{
169 dom_list *d = NULL;
170 for (d = e->domains; d; d = d->next) {
171 if (matchDomainName(d->domain, request->host))
172 if (d->neighbor_type != EDGE_NONE)
24382924 173 return d->neighbor_type;
24a1003d 174 }
175 return e->type;
176}
177
b8d8561b 178static int
179edgeWouldBePinged(edge * e, request_t * request)
090089c4 180{
090089c4 181 dom_list *d = NULL;
182 int do_ping = 1;
30a4f2a8 183 struct _acl_list *a = NULL;
f88bb09c 184 aclCheck_t checklist;
090089c4 185
24a1003d 186 if (BIT_TEST(request->flags, REQ_NOCACHE))
24382924 187 if (neighborType(e, request) == EDGE_SIBLING)
24a1003d 188 return 0;
30a4f2a8 189 if (e->domains == NULL && e->acls == NULL)
090089c4 190 return do_ping;
090089c4 191 do_ping = 0;
192 for (d = e->domains; d; d = d->next) {
30a4f2a8 193 if (matchDomainName(d->domain, request->host))
194 return d->do_ping;
195 do_ping = !d->do_ping;
196 }
f88bb09c 197 checklist.src_addr = any_addr; /* XXX bogus! */
198 checklist.request = request;
30a4f2a8 199 for (a = e->acls; a; a = a->next) {
f88bb09c 200 if (aclMatchAcl(a->acl, &checklist))
30a4f2a8 201 return a->op;
202 do_ping = !a->op;
090089c4 203 }
204 return do_ping;
205}
206
b8d8561b 207edge *
208getSingleParent(request_t * request, int *n)
090089c4 209{
210 edge *p = NULL;
211 edge *e = NULL;
090089c4 212 int count = 0;
213
214 if (n == NULL && friends->n_parent < 1)
215 return NULL;
216 for (e = friends->edges_head; e; e = e->next) {
caebbe00 217 if (!edgeWouldBePinged(e, request))
218 continue;
219 count++;
24a1003d 220 if (neighborType(e, request) != EDGE_PARENT) {
caebbe00 221 /* we matched a neighbor, not a parent. There
222 * can be no single parent */
223 if (n == NULL)
224 return NULL;
225 continue;
090089c4 226 }
caebbe00 227 if (p) {
228 /* already have a parent, this makes the second,
229 * so there can be no single parent */
230 if (n == NULL)
231 return NULL;
232 continue;
233 }
234 p = e;
090089c4 235 }
236 /* Ok, all done checking the edges. If only one parent matched, then
237 * p will already point to it */
238 if (n)
239 *n = count;
240 if (count == 1)
241 return p;
242 return NULL;
243}
244
b8d8561b 245edge *
246getFirstUpParent(request_t * request)
090089c4 247{
248 edge *e = NULL;
090089c4 249 if (friends->n_parent < 1)
250 return NULL;
251 for (e = friends->edges_head; e; e = e->next) {
30a4f2a8 252 if (!e->neighbor_up)
253 continue;
24a1003d 254 if (neighborType(e, request) != EDGE_PARENT)
090089c4 255 continue;
30a4f2a8 256 if (edgeWouldBePinged(e, request))
090089c4 257 return e;
258 }
259 return NULL;
260}
261
b8d8561b 262edge *
263getNextEdge(edge * e)
090089c4 264{
265 return e->next;
266}
267
b8d8561b 268edge *
269getFirstEdge(void)
090089c4 270{
271 return friends->edges_head;
272}
273
b8d8561b 274static void
275neighborRemove(edge * target)
30a4f2a8 276{
277 edge *e = NULL;
278 edge **E = NULL;
279 e = friends->edges_head;
280 E = &friends->edges_head;
281 while (e) {
282 if (target == e)
283 break;
284 E = &e->next;
285 e = e->next;
286 }
287 if (e) {
288 *E = e->next;
5560c2ae 289 safe_free(e->host);
30a4f2a8 290 safe_free(e);
6e1788b9 291 friends->n--;
30a4f2a8 292 }
293}
294
b8d8561b 295void
0673c0ba 296neighborsDestroy(void)
4d64d74a 297{
298 edge *e = NULL;
299 edge *next = NULL;
300
0ffd22bc 301 debug(15, 3, "neighborsDestroy: called\n");
4d64d74a 302
303 for (e = friends->edges_head; e; e = next) {
304 next = e->next;
305 safe_free(e->host);
306 safe_free(e);
071764d1 307 friends->n--;
4d64d74a 308 }
0ffd22bc 309 safe_free(friends);
310 friends = NULL;
4d64d74a 311}
312
b8d8561b 313void
314neighbors_open(int fd)
090089c4 315{
22e4fa85 316 int j;
30a4f2a8 317 struct sockaddr_in name;
090089c4 318 struct sockaddr_in *ap;
30a4f2a8 319 int len = sizeof(struct sockaddr_in);
e5f6c5c2 320 ipcache_addrs *ia = NULL;
090089c4 321 edge *e = NULL;
30a4f2a8 322 edge *next = NULL;
323 edge **E = NULL;
30a4f2a8 324 struct servent *sep = NULL;
090089c4 325
30a4f2a8 326 memset(&name, '\0', sizeof(struct sockaddr_in));
327 if (getsockname(fd, (struct sockaddr *) &name, &len) < 0)
328 debug(15, 1, "getsockname(%d,%p,%p) failed.\n", fd, &name, &len);
090089c4 329
090089c4 330 /* Prepare neighbor connections, one at a time */
30a4f2a8 331 E = &friends->edges_head;
332 next = friends->edges_head;
333 while ((e = next)) {
c021888f 334 getCurrentTime();
30a4f2a8 335 next = e->next;
019dd986 336 debug(15, 2, "Finding IP addresses for '%s'\n", e->host);
e5f6c5c2 337 if ((ia = ipcache_gethostbyname(e->host, IP_BLOCKING_LOOKUP)) == NULL) {
30a4f2a8 338 debug(0, 0, "WARNING!!: DNS lookup for '%s' failed!\n", e->host);
339 debug(0, 0, "THIS NEIGHBOR WILL BE IGNORED.\n");
340 *E = next; /* skip */
341 safe_free(e);
342 continue;
090089c4 343 }
344 e->n_addresses = 0;
e5f6c5c2 345 for (j = 0; j < (int) ia->count && j < EDGE_MAX_ADDRESSES; j++) {
346 e->addresses[j] = ia->in_addrs[j];
090089c4 347 e->n_addresses++;
348 }
349 if (e->n_addresses < 1) {
30a4f2a8 350 debug(0, 0, "WARNING!!: No IP address found for '%s'!\n", e->host);
351 debug(0, 0, "THIS NEIGHBOR WILL BE IGNORED.\n");
352 *E = next; /* skip */
353 safe_free(e);
354 continue;
090089c4 355 }
356 for (j = 0; j < e->n_addresses; j++) {
30a4f2a8 357 debug(15, 2, "--> IP address #%d: %s\n",
358 j, inet_ntoa(e->addresses[j]));
090089c4 359 }
30a4f2a8 360 e->stats.rtt = 0;
090089c4 361
090089c4 362 ap = &e->in_addr;
363 memset(ap, '\0', sizeof(struct sockaddr_in));
364 ap->sin_family = AF_INET;
365 ap->sin_addr = e->addresses[0];
30a4f2a8 366 ap->sin_port = htons(e->icp_port);
090089c4 367
24a1003d 368 e->neighbor_up = 1;
30a4f2a8 369 E = &e->next;
370 }
090089c4 371
30a4f2a8 372 if (0 == echo_hdr.opcode) {
373 echo_hdr.opcode = ICP_OP_SECHO;
374 echo_hdr.version = ICP_VERSION_CURRENT;
375 echo_hdr.length = 0;
376 echo_hdr.reqnum = 0;
377 echo_hdr.flags = 0;
378 echo_hdr.pad = 0;
379 /* memset(echo_hdr.auth, '\0', sizeof(u_num32) * ICP_AUTH_SIZE); */
380 echo_hdr.shostid = name.sin_addr.s_addr;
381 sep = getservbyname("echo", "udp");
382 echo_port = sep ? ntohs((u_short) sep->s_port) : 7;
090089c4 383 }
384}
385
090089c4 386
b8d8561b 387int
388neighborsUdpPing(protodispatch_data * proto)
090089c4 389{
7111c86a 390 char *host = proto->request->host;
090089c4 391 char *url = proto->url;
392 StoreEntry *entry = proto->entry;
e5f6c5c2 393 ipcache_addrs *ia = NULL;
090089c4 394 struct sockaddr_in to_addr;
395 edge *e = NULL;
396 int i;
30a4f2a8 397 MemObject *mem = entry->mem_obj;
1061b406 398 int reqnum = 0;
6d2296d4 399 int flags;
090089c4 400
30a4f2a8 401 mem->e_pings_n_pings = 0;
402 mem->e_pings_n_acks = 0;
403 mem->e_pings_first_miss = NULL;
404 mem->w_rtt = 0;
405 mem->start_ping = current_time;
090089c4 406
95d659f0 407 if (friends->edges_head == NULL)
090089c4 408 return 0;
af00901c 409 if (theOutIcpConnection < 0) {
410 debug(15, 0, "neighborsUdpPing: There is no ICP socket!\n");
411 debug(15, 0, "Cannot query neighbors for '%s'.\n", url);
412 debug(15, 0, "Check 'icp_port' in your config file\n");
413 fatal_dump(NULL);
414 }
090089c4 415 for (i = 0, e = friends->first_ping; i++ < friends->n; e = e->next) {
a11fc0d2 416 if (entry->swap_status != NO_SWAP)
d556a268 417 fatal_dump("neighborsUdpPing: bad swap_status");
090089c4 418 if (e == (edge *) NULL)
419 e = friends->edges_head;
019dd986 420 debug(15, 5, "neighborsUdpPing: Edge %s\n", e->host);
090089c4 421
30a4f2a8 422 /* skip any cache where we failed to connect() w/in the last 60s */
423 if (squid_curtime - e->last_fail_time < 60)
090089c4 424 continue;
425
30a4f2a8 426 if (!edgeWouldBePinged(e, proto->request))
090089c4 427 continue; /* next edge */
30a4f2a8 428 if (e->options & NEIGHBOR_NO_QUERY)
429 continue;
090089c4 430
019dd986 431 debug(15, 4, "neighborsUdpPing: pinging cache %s for <URL:%s>\n",
090089c4 432 e->host, url);
433
2d25dc1a 434 if (BIT_TEST(entry->flag, KEY_PRIVATE))
1061b406 435 reqnum = atoi(entry->key);
9151555a 436 else
1061b406 437 reqnum = getKeyCounter();
0ffd22bc 438 debug(15, 3, "neighborsUdpPing: key = '%s'\n", entry->key);
1061b406 439 debug(15, 3, "neighborsUdpPing: reqnum = %d\n", reqnum);
090089c4 440
30a4f2a8 441 if (e->icp_port == echo_port) {
019dd986 442 debug(15, 4, "neighborsUdpPing: Looks like a dumb cache, send DECHO ping\n");
1061b406 443 echo_hdr.reqnum = reqnum;
af00901c 444 icpUdpSend(theOutIcpConnection,
95d659f0 445 url,
6d2296d4 446 reqnum,
95d659f0 447 &e->in_addr,
6d2296d4 448 0,
95d659f0 449 ICP_OP_DECHO,
a528eb87 450 LOG_TAG_NONE,
451 PROTO_NONE);
090089c4 452 } else {
6d2296d4 453 flags = 0;
454 /* check if we should set ICP_FLAG_HIT_OBJ */
455 if (opt_udp_hit_obj)
456 if (!BIT_TEST(proto->request->flags, REQ_NOCACHE))
457 if (e->icp_version == ICP_VERSION_2)
458 flags |= ICP_FLAG_HIT_OBJ;
af00901c 459 icpUdpSend(theOutIcpConnection,
95d659f0 460 url,
6d2296d4 461 reqnum,
95d659f0 462 &e->in_addr,
6d2296d4 463 flags,
95d659f0 464 ICP_OP_QUERY,
a528eb87 465 LOG_TAG_NONE,
466 PROTO_NONE);
090089c4 467 }
468
e90100aa 469 if (e->mcast_ttl > 0) {
470 /* XXX kill us off, so Squid won't expect a reply */
471 e->stats.ack_deficit = HIER_MAX_DEFICIT;
472 } else {
473 e->stats.ack_deficit++;
474 }
30a4f2a8 475 e->stats.pings_sent++;
090089c4 476
457bedbd 477 debug(15, 3, "neighborsUdpPing: %s: ack_deficit = %d\n",
478 e->host, e->stats.ack_deficit);
4aa84b41 479
30a4f2a8 480 if (e->stats.ack_deficit < HIER_MAX_DEFICIT) {
1061b406 481 /* its alive, expect a reply from it */
090089c4 482 e->neighbor_up = 1;
30a4f2a8 483 mem->e_pings_n_pings++;
090089c4 484 } else {
1061b406 485 /* Neighbor is dead; ping it anyway, but don't expect a reply */
090089c4 486 e->neighbor_up = 0;
090089c4 487 /* log it once at the threshold */
30a4f2a8 488 if ((e->stats.ack_deficit == HIER_MAX_DEFICIT)) {
3fc6cf44 489 debug(15, 0, "Detected DEAD %s: %s/%d/%d\n",
d2af9477 490 e->type == EDGE_SIBLING ? "SIBLING" : "PARENT",
3fc6cf44 491 e->host, e->http_port, e->icp_port);
090089c4 492 }
493 }
494 friends->first_ping = e->next;
495 }
496
497 /* only do source_ping if we have neighbors */
1061b406 498 if (friends->n) {
499 if (!proto->source_ping) {
500 debug(15, 6, "neighborsUdpPing: Source Ping is disabled.\n");
e5f6c5c2 501 } else if ((ia = ipcache_gethostbyname(host, IP_BLOCKING_LOOKUP))) {
1061b406 502 debug(15, 6, "neighborsUdpPing: Source Ping: to %s for '%s'\n",
503 host, url);
1061b406 504 echo_hdr.reqnum = reqnum;
16b204c4 505 if (icmp_sock != -1) {
e5f6c5c2 506 icmpSourcePing(ia->in_addrs[ia->cur], &echo_hdr, url);
16b204c4 507 } else {
508 to_addr.sin_family = AF_INET;
e5f6c5c2 509 to_addr.sin_addr = ia->in_addrs[ia->cur];
16b204c4 510 to_addr.sin_port = htons(echo_port);
511 icpUdpSend(theOutIcpConnection,
512 url,
6d2296d4 513 reqnum,
16b204c4 514 &to_addr,
515 entry->flag,
516 ICP_OP_SECHO,
517 LOG_TAG_NONE,
518 PROTO_NONE);
519 }
090089c4 520 } else {
1061b406 521 debug(15, 6, "neighborsUdpPing: Source Ping: unknown host: %s\n",
522 host);
090089c4 523 }
524 }
1061b406 525 return mem->e_pings_n_pings;
090089c4 526}
527
d73844ca 528static void
4eda6afe 529neighborAlive(edge * e, MemObject * mem, icp_common_t * header)
530{
531 int rtt;
532 int n;
533 /* Neighbor is alive, reset the ack deficit */
534 if (e->stats.ack_deficit >= HIER_MAX_DEFICIT) {
535 debug(15, 0, "Detected REVIVED %s: %s/%d/%d\n",
536 e->type == EDGE_PARENT ? "PARENT" : "SIBLING",
537 e->host, e->http_port, e->icp_port);
538 }
539 e->neighbor_up = 1;
540 e->stats.ack_deficit = 0;
541 n = ++e->stats.pings_acked;
542 if ((icp_opcode) header->opcode <= ICP_OP_END)
543 e->stats.counts[header->opcode]++;
544 if (n > RTT_AV_FACTOR)
545 n = RTT_AV_FACTOR;
546 if (mem) {
547 rtt = tvSubMsec(mem->start_ping, current_time);
548 e->stats.rtt = (e->stats.rtt * (n - 1) + rtt) / n;
549 e->icp_version = (int) header->version;
550 }
551}
090089c4 552
553/* I should attach these records to the entry. We take the first
554 * hit we get our wait until everyone misses. The timeout handler
555 * call needs to nip this shopping list or call one of the misses.
556 *
557 * If a hit process is already started, then sobeit
558 */
b8d8561b 559void
560neighborsUdpAck(int fd, char *url, icp_common_t * header, struct sockaddr_in *from, StoreEntry * entry, char *data, int data_sz)
090089c4 561{
562 edge *e = NULL;
30a4f2a8 563 MemObject *mem = entry->mem_obj;
fe113054 564 int w_rtt;
30a4f2a8 565 HttpStateData *httpState = NULL;
24a1003d 566 neighbor_t ntype = EDGE_NONE;
5e5126cc 567 char *opcode_d;
090089c4 568
d2af9477 569 debug(15, 6, "neighborsUdpAck: opcode %d '%s'\n",
570 (int) header->opcode, url);
4eda6afe 571 if ((e = whichEdge(from)))
572 neighborAlive(e, mem, header);
0084c600 573 if ((icp_opcode) header->opcode > ICP_OP_END)
d2af9477 574 return;
5e5126cc 575 opcode_d = IcpOpcodeStr[header->opcode];
d2af9477 576 if (mem == NULL) {
5e5126cc 577 debug(15, 1, "Ignoring %s for missing mem_obj: %s\n", opcode_d, url);
d2af9477 578 return;
579 }
8de2f7ad 580 /* check if someone is already fetching it */
581 if (BIT_TEST(entry->flag, ENTRY_DISPATCHED)) {
582 debug(15, 5, "neighborsUdpAck: '%s' already being fetched.\n", url);
583 return;
584 }
585 if (entry->ping_status != PING_WAITING) {
5e5126cc 586 debug(15, 5, "neighborsUdpAck: Unexpected %s for %s\n", opcode_d, url);
8de2f7ad 587 return;
588 }
4eda6afe 589 if (entry->lock_count == 0) {
5e5126cc 590 debug(12, 3, "neighborsUdpAck: '%s' has no locks\n", url);
4eda6afe 591 return;
090089c4 592 }
d2af9477 593 debug(15, 3, "neighborsUdpAck: %s for '%s' from %s \n",
5e5126cc 594 opcode_d, url, e ? e->host : "source");
d2af9477 595 mem->e_pings_n_acks++;
5e5126cc 596 if (e)
ceb8994e 597 ntype = neighborType(e, mem->request);
090089c4 598 if (header->opcode == ICP_OP_SECHO) {
d2af9477 599 /* Received source-ping reply */
090089c4 600 if (e) {
004b3381 601 debug(15, 1, "Ignoring SECHO from neighbor %s\n", e->host);
090089c4 602 } else {
d2af9477 603 /* if we reach here, source-ping reply is the first 'parent',
604 * so fetch directly from the source */
019dd986 605 debug(15, 6, "Source is the first to respond.\n");
eaa77841 606 hierarchyNote(entry->mem_obj->request,
090089c4 607 HIER_SOURCE_FASTEST,
608 0,
1061b406 609 fqdnFromAddr(from->sin_addr));
30a4f2a8 610 entry->ping_status = PING_DONE;
457bedbd 611 protoStart(0, entry, NULL, entry->mem_obj->request);
d2af9477 612 return;
090089c4 613 }
30a4f2a8 614 } else if (header->opcode == ICP_OP_HIT_OBJ) {
a99f5332 615 if (e == NULL) {
616 debug(15, 0, "Ignoring ICP_OP_HIT_OBJ from non-neighbor %s\n",
617 inet_ntoa(from->sin_addr));
618 } else if (entry->object_len != 0) {
d2af9477 619 debug(15, 1, "Too late UDP_HIT_OBJ '%s'?\n", entry->url);
620 } else {
b8d8561b 621 if (e->options & NEIGHBOR_PROXY_ONLY)
622 storeReleaseRequest(entry);
d2af9477 623 protoCancelTimeout(0, entry);
624 entry->ping_status = PING_DONE;
625 httpState = xcalloc(1, sizeof(HttpStateData));
626 httpState->entry = entry;
627 httpProcessReplyHeader(httpState, data, data_sz);
628 storeAppend(entry, data, data_sz);
eaa77841 629 hierarchyNote(entry->mem_obj->request,
24a1003d 630 ntype == EDGE_PARENT ? HIER_PARENT_UDP_HIT_OBJ : HIER_SIBLING_UDP_HIT_OBJ,
d2af9477 631 0,
a99f5332 632 e->host);
37bcb332 633 storeComplete(entry); /* This might release entry! */
d2af9477 634 if (httpState->reply_hdr)
635 put_free_8k_page(httpState->reply_hdr);
636 safe_free(httpState);
30a4f2a8 637 return;
638 }
30a4f2a8 639 } else if (header->opcode == ICP_OP_HIT) {
d2af9477 640 if (e == NULL) {
004b3381 641 debug(15, 1, "Ignoring HIT from non-neighbor %s\n",
642 inet_ntoa(from->sin_addr));
d2af9477 643 } else {
eaa77841 644 hierarchyNote(entry->mem_obj->request,
24a1003d 645 ntype == EDGE_PARENT ? HIER_PARENT_HIT : HIER_SIBLING_HIT,
d2af9477 646 0,
647 e->host);
d2af9477 648 entry->ping_status = PING_DONE;
457bedbd 649 protoStart(0, entry, e, entry->mem_obj->request);
090089c4 650 return;
651 }
d2af9477 652 } else if (header->opcode == ICP_OP_DECHO) {
653 if (e == NULL) {
004b3381 654 debug(15, 1, "Ignoring DECHO from non-neighbor %s\n",
655 inet_ntoa(from->sin_addr));
24a1003d 656 } else if (ntype == EDGE_SIBLING) {
5e604a0e 657 debug_trap("neighborsUdpAck: Found non-ICP cache as SIBLING\n");
658 debug_trap("neighborsUdpAck: non-ICP neighbors must be a PARENT\n");
090089c4 659 } else {
30a4f2a8 660 w_rtt = tvSubMsec(mem->start_ping, current_time) / e->weight;
661 if (mem->w_rtt == 0 || w_rtt < mem->w_rtt) {
662 mem->e_pings_first_miss = e;
663 mem->w_rtt = w_rtt;
090089c4 664 }
665 }
d2af9477 666 } else if (header->opcode == ICP_OP_MISS) {
667 if (e == NULL) {
004b3381 668 debug(15, 1, "Ignoring MISS from non-neighbor %s\n",
669 inet_ntoa(from->sin_addr));
24a1003d 670 } else if (ntype == EDGE_PARENT) {
d2af9477 671 w_rtt = tvSubMsec(mem->start_ping, current_time) / e->weight;
672 if (mem->w_rtt == 0 || w_rtt < mem->w_rtt) {
673 mem->e_pings_first_miss = e;
674 mem->w_rtt = w_rtt;
675 }
090089c4 676 }
30a4f2a8 677 } else if (header->opcode == ICP_OP_DENIED) {
d2af9477 678 if (e == NULL) {
004b3381 679 debug(15, 1, "Ignoring DENIED from non-neighbor %s\n",
680 inet_ntoa(from->sin_addr));
d2af9477 681 } else if (e->stats.pings_acked > 100) {
30a4f2a8 682 if (100 * e->stats.counts[ICP_OP_DENIED] / e->stats.pings_acked > 95) {
683 debug(15, 0, "95%% of replies from '%s' are UDP_DENIED\n", e->host);
684 debug(15, 0, "Disabling '%s', please check your configuration.\n", e->host);
685 neighborRemove(e);
686 }
687 }
1061b406 688 } else if (header->opcode == ICP_OP_RELOADING) {
689 if (e)
690 debug(15, 3, "neighborsUdpAck: %s is RELOADING\n", e->host);
090089c4 691 } else {
5e5126cc 692 debug(15, 0, "neighborsUdpAck: Unexpected ICP reply: %s\n", opcode_d);
d2af9477 693 }
694 if (mem->e_pings_n_acks == mem->e_pings_n_pings) {
d2af9477 695 entry->ping_status = PING_DONE;
696 debug(15, 6, "neighborsUdpAck: All replies received.\n");
457bedbd 697 /* pass in fd=0 here so protoStart() looks up the real FD
d2af9477 698 * and resets the timeout handler */
699 getFromDefaultSource(0, entry);
700 return;
090089c4 701 }
702}
703
b8d8561b 704void
e90100aa 705neighbors_cf_add(char *host, char *type, int http_port, int icp_port, int options, int weight, int mcast_ttl)
090089c4 706{
707 struct neighbor_cf *t, *u;
708
30a4f2a8 709 t = xcalloc(1, sizeof(struct neighbor_cf));
090089c4 710 t->host = xstrdup(host);
711 t->type = xstrdup(type);
30a4f2a8 712 t->http_port = http_port;
713 t->icp_port = icp_port;
714 t->options = options;
fe113054 715 t->weight = weight;
e90100aa 716 t->mcast_ttl = mcast_ttl;
090089c4 717 t->next = (struct neighbor_cf *) NULL;
718
719 if (Neighbor_cf == (struct neighbor_cf *) NULL) {
720 Neighbor_cf = t;
721 } else {
722 for (u = Neighbor_cf; u->next; u = u->next);
723 u->next = t;
724 }
725}
726
b8d8561b 727void
24a1003d 728neighbors_cf_domain(char *host, char *domain, neighbor_t type)
090089c4 729{
30a4f2a8 730 struct neighbor_cf *t = NULL;
731 dom_list *l = NULL;
732 dom_list **L = NULL;
090089c4 733
734 for (t = Neighbor_cf; t; t = t->next) {
735 if (strcmp(t->host, host) == 0)
736 break;
737 }
30a4f2a8 738 if (t == NULL) {
739 debug(15, 0, "%s, line %d: No cache_host '%s'\n",
740 cfg_filename, config_lineno, host);
741 return;
742 }
743 l = xmalloc(sizeof(dom_list));
090089c4 744 l->do_ping = 1;
745 if (*domain == '!') { /* check for !.edu */
746 l->do_ping = 0;
747 domain++;
748 }
749 l->domain = xstrdup(domain);
24a1003d 750 l->neighbor_type = type;
090089c4 751 l->next = NULL;
752 for (L = &(t->domains); *L; L = &((*L)->next));
753 *L = l;
30a4f2a8 754}
755
b8d8561b 756void
757neighbors_cf_acl(char *host, char *aclname)
30a4f2a8 758{
759 struct neighbor_cf *t = NULL;
760 struct _acl_list *L = NULL;
761 struct _acl_list **Tail = NULL;
762 struct _acl *a = NULL;
090089c4 763
30a4f2a8 764 for (t = Neighbor_cf; t; t = t->next) {
765 if (strcmp(t->host, host) == 0)
766 break;
767 }
768 if (t == NULL) {
769 debug(15, 0, "%s, line %d: No cache_host '%s'\n",
770 cfg_filename, config_lineno, host);
771 return;
772 }
773 L = xcalloc(1, sizeof(struct _acl_list));
774 L->op = 1;
775 if (*aclname == '!') {
776 L->op = 0;
777 aclname++;
778 }
779 debug(15, 3, "neighbors_cf_acl: looking for ACL name '%s'\n", aclname);
780 a = aclFindByName(aclname);
781 if (a == NULL) {
782 debug(15, 0, "%s line %d: %s\n",
783 cfg_filename, config_lineno, config_input_line);
784 debug(15, 0, "neighbors_cf_acl: ACL name '%s' not found.\n", aclname);
785 xfree(L);
786 return;
787 }
788 if (a->type == ACL_SRC_IP) {
789 debug(15, 0, "%s line %d: %s\n",
790 cfg_filename, config_lineno, config_input_line);
791 debug(15, 0, "neighbors_cf_acl: 'src' ALC's not supported for 'cache_host_acl'\n");
792 xfree(L);
793 return;
794 }
795 L->acl = a;
796 for (Tail = &(t->acls); *Tail; Tail = &((*Tail)->next));
797 *Tail = L;
090089c4 798}
799
b8d8561b 800void
0673c0ba 801neighbors_init(void)
090089c4 802{
c62e9195 803 struct neighbor_cf *t = NULL;
804 struct neighbor_cf *next = NULL;
805 char *me = getMyHostname();
806 edge *e = NULL;
c62e9195 807
808 debug(15, 1, "neighbors_init: Initializing Neighbors...\n");
809
810 if (friends == NULL)
30a4f2a8 811 friends = xcalloc(1, sizeof(neighbors));
c62e9195 812
090089c4 813 for (t = Neighbor_cf; t; t = next) {
814 next = t->next;
b6f794d6 815 if (!strcmp(t->host, me) && t->http_port == Config.Port.http) {
019dd986 816 debug(15, 0, "neighbors_init: skipping cache_host %s %s %d %d\n",
30a4f2a8 817 t->type, t->host, t->http_port, t->icp_port);
c62e9195 818 continue;
819 }
30a4f2a8 820 debug(15, 1, "Adding a %s: %s/%d/%d\n",
821 t->type, t->host, t->http_port, t->icp_port);
c62e9195 822
30a4f2a8 823 e = xcalloc(1, sizeof(edge));
824 e->http_port = t->http_port;
825 e->icp_port = t->icp_port;
e90100aa 826 e->mcast_ttl = t->mcast_ttl;
30a4f2a8 827 e->options = t->options;
fe113054 828 e->weight = t->weight;
c62e9195 829 e->host = t->host;
830 e->domains = t->domains;
30a4f2a8 831 e->acls = t->acls;
c62e9195 832 e->neighbor_up = 1;
6d2296d4 833 e->icp_version = ICP_VERSION_CURRENT;
c62e9195 834 if (!strcmp(t->type, "parent")) {
835 friends->n_parent++;
6e77be39 836 e->type = EDGE_PARENT;
c62e9195 837 } else {
838 friends->n_neighbor++;
6e77be39 839 e->type = EDGE_SIBLING;
090089c4 840 }
30a4f2a8 841 safe_free(t->type);
c62e9195 842
843 /* Append edge */
844 if (!friends->edges_head)
845 friends->edges_head = e;
846 if (friends->edges_tail)
847 friends->edges_tail->next = e;
848 friends->edges_tail = e;
849 friends->n++;
850
0ffd22bc 851 safe_free(t);
090089c4 852 }
0ffd22bc 853 Neighbor_cf = NULL;
30a4f2a8 854 any_addr.s_addr = inet_addr("0.0.0.0");
090089c4 855}
856
b8d8561b 857edge *
858neighborFindByName(char *name)
98ffb7e4 859{
860 edge *e = NULL;
861 for (e = friends->edges_head; e; e = e->next) {
862 if (!strcasecmp(name, e->host))
863 break;
864 }
865 return e;
866}