]>
Commit | Line | Data |
---|---|---|
641941c0 | 1 | |
062e2281 | 2 | /* |
d46a87a8 | 3 | * $Id: peer_select.cc,v 1.85 1998/09/19 17:06:08 wessels Exp $ |
062e2281 | 4 | * |
5 | * DEBUG: section 44 Peer Selection Algorithm | |
6 | * AUTHOR: Duane Wessels | |
7 | * | |
8 | * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ | |
e25c139f | 9 | * ---------------------------------------------------------- |
062e2281 | 10 | * |
11 | * Squid is the result of efforts by numerous individuals from the | |
12 | * Internet community. Development is led by Duane Wessels of the | |
e25c139f | 13 | * National Laboratory for Applied Network Research and funded by the |
14 | * National Science Foundation. Squid is Copyrighted (C) 1998 by | |
15 | * Duane Wessels and the University of California San Diego. Please | |
16 | * see the COPYRIGHT file for full details. Squid incorporates | |
17 | * software developed and/or copyrighted by other sources. Please see | |
18 | * the CREDITS file for full details. | |
062e2281 | 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 | |
cbdec147 | 32 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. |
e25c139f | 33 | * |
062e2281 | 34 | */ |
35 | ||
36 | #include "squid.h" | |
37 | ||
429fdbec | 38 | const char *hier_strings[] = |
39 | { | |
40 | "NONE", | |
41 | "DIRECT", | |
42 | "SIBLING_HIT", | |
43 | "PARENT_HIT", | |
44 | "DEFAULT_PARENT", | |
45 | "SINGLE_PARENT", | |
46 | "FIRST_UP_PARENT", | |
47 | "NO_PARENT_DIRECT", | |
48 | "FIRST_PARENT_MISS", | |
49 | "CLOSEST_PARENT_MISS", | |
69c95dd3 | 50 | "CLOSEST_PARENT", |
429fdbec | 51 | "CLOSEST_DIRECT", |
52 | "NO_DIRECT_FAIL", | |
53 | "SOURCE_FASTEST", | |
429fdbec | 54 | "ROUNDROBIN_PARENT", |
6cfa8966 | 55 | #if USE_CACHE_DIGESTS |
c127134a | 56 | "CACHE_DIGEST_HIT", |
285f75ea | 57 | "NO_CACHE_DIGEST_DIRECT", |
afd88fbe | 58 | #endif |
59 | #if USE_CARP | |
60 | "CARP", | |
c127134a | 61 | #endif |
429fdbec | 62 | "INVALID CODE" |
63 | }; | |
64 | ||
85034133 | 65 | static struct { |
75e88d56 | 66 | int timeouts; |
85034133 | 67 | } PeerStats; |
062e2281 | 68 | |
f9e5a344 | 69 | static char *DirectStr[] = |
70 | { | |
71 | "DIRECT_NO", | |
72 | "DIRECT_MAYBE", | |
73 | "DIRECT_YES" | |
7b665aeb | 74 | }; |
75e88d56 | 75 | |
f5b8bbc4 | 76 | static void peerSelectFoo(ps_state *); |
77 | static void peerPingTimeout(void *data); | |
78 | static void peerSelectCallbackFail(ps_state * psstate); | |
86aebcda | 79 | static IRCB peerHandlePingReply; |
f5b8bbc4 | 80 | static void peerSelectStateFree(ps_state * psstate); |
81 | static void peerIcpParentMiss(peer *, icp_common_t *, ps_state *); | |
44e237d0 | 82 | #if USE_HTCP |
83 | static void peerHtcpParentMiss(peer *, htcpReplyData *, ps_state *); | |
84 | static void peerHandleHtcpReply(peer *, peer_t, htcpReplyData *, void *); | |
85 | #endif | |
f5b8bbc4 | 86 | static int peerCheckNetdbDirect(ps_state * psstate); |
348b2031 | 87 | |
88 | static void | |
89 | peerSelectStateFree(ps_state * psstate) | |
90 | { | |
91 | if (psstate->acl_checklist) { | |
51fdcbd5 | 92 | debug(44, 1) ("calling aclChecklistFree() from peerSelectStateFree\n"); |
348b2031 | 93 | aclChecklistFree(psstate->acl_checklist); |
94 | } | |
95 | requestUnlink(psstate->request); | |
8407afee | 96 | psstate->request = NULL; |
73a201f8 | 97 | if (psstate->entry) { |
6898e7b0 | 98 | assert(psstate->entry->ping_status != PING_WAITING); |
0cdcddb9 | 99 | storeUnlockObject(psstate->entry); |
100 | psstate->entry = NULL; | |
73a201f8 | 101 | } |
8407afee | 102 | cbdataFree(psstate); |
348b2031 | 103 | } |
062e2281 | 104 | |
105 | int | |
106 | peerSelectIcpPing(request_t * request, int direct, StoreEntry * entry) | |
107 | { | |
7b665aeb | 108 | int n; |
93775f90 | 109 | if (entry == NULL) |
110 | return 0; | |
9fb13bb6 | 111 | debug(44, 3) ("peerSelectIcpPing: %s\n", storeUrl(entry)); |
062e2281 | 112 | if (entry->ping_status != PING_NONE) |
113 | return 0; | |
9bd6a36d | 114 | assert(direct != DIRECT_YES); |
92695e5e | 115 | if (!request->flags.hierarchical && direct != DIRECT_NO) |
062e2281 | 116 | return 0; |
d46a87a8 | 117 | if (EBIT_TEST(entry->flags, KEY_PRIVATE) && !neighbors_do_private_keys) |
062e2281 | 118 | if (direct != DIRECT_NO) |
119 | return 0; | |
7b665aeb | 120 | n = neighborsCount(request); |
f9e5a344 | 121 | debug(44, 3) ("peerSelectIcpPing: counted %d neighbors\n", n); |
7b665aeb | 122 | return n; |
062e2281 | 123 | } |
124 | ||
125 | ||
126 | peer * | |
127 | peerGetSomeParent(request_t * request, hier_code * code) | |
128 | { | |
129 | peer *p; | |
669fefd4 | 130 | debug(44, 3) ("peerGetSomeParent: %s %s\n", |
131 | RequestMethodStr[request->method], | |
132 | request->host); | |
062e2281 | 133 | if ((p = getDefaultParent(request))) { |
429fdbec | 134 | *code = DEFAULT_PARENT; |
062e2281 | 135 | return p; |
136 | } | |
062e2281 | 137 | if ((p = getRoundRobinParent(request))) { |
429fdbec | 138 | *code = ROUNDROBIN_PARENT; |
062e2281 | 139 | return p; |
140 | } | |
141 | if ((p = getFirstUpParent(request))) { | |
429fdbec | 142 | *code = FIRSTUP_PARENT; |
062e2281 | 143 | return p; |
144 | } | |
145 | return NULL; | |
146 | } | |
147 | ||
148 | void | |
93775f90 | 149 | peerSelect(request_t * request, |
b6c0e933 | 150 | StoreEntry * entry, |
582b6456 | 151 | PSC * callback, |
152 | PSC * fail_callback, | |
b6c0e933 | 153 | void *callback_data) |
75e88d56 | 154 | { |
b6c0e933 | 155 | ps_state *psstate = xcalloc(1, sizeof(ps_state)); |
86b389fc | 156 | if (entry) |
9fb13bb6 | 157 | debug(44, 3) ("peerSelect: %s\n", storeUrl(entry)); |
86b389fc | 158 | else |
f9e5a344 | 159 | debug(44, 3) ("peerSelect: %s\n", RequestMethodStr[request->method]); |
3f6c0fb2 | 160 | cbdataAdd(psstate, MEM_NONE); |
b6c0e933 | 161 | psstate->request = requestLink(request); |
162 | psstate->entry = entry; | |
163 | psstate->callback = callback; | |
164 | psstate->fail_callback = fail_callback; | |
165 | psstate->callback_data = callback_data; | |
6cfa8966 | 166 | #if USE_CACHE_DIGESTS |
39edba21 | 167 | request->hier.peer_select_start = current_time; |
168 | #endif | |
2395cb21 | 169 | if (psstate->entry) |
0cdcddb9 | 170 | storeLockObject(psstate->entry); |
395b813e | 171 | cbdataLock(callback_data); |
b6c0e933 | 172 | peerSelectFoo(psstate); |
75e88d56 | 173 | } |
174 | ||
175 | static void | |
176 | peerCheckNeverDirectDone(int answer, void *data) | |
177 | { | |
b6c0e933 | 178 | ps_state *psstate = data; |
348b2031 | 179 | psstate->acl_checklist = NULL; |
a3d5953d | 180 | debug(44, 3) ("peerCheckNeverDirectDone: %d\n", answer); |
b6c0e933 | 181 | psstate->never_direct = answer ? 1 : -1; |
182 | peerSelectFoo(psstate); | |
75e88d56 | 183 | } |
184 | ||
185 | static void | |
186 | peerCheckAlwaysDirectDone(int answer, void *data) | |
187 | { | |
b6c0e933 | 188 | ps_state *psstate = data; |
348b2031 | 189 | psstate->acl_checklist = NULL; |
a3d5953d | 190 | debug(44, 3) ("peerCheckAlwaysDirectDone: %d\n", answer); |
7b665aeb | 191 | psstate->always_direct = answer ? 1 : -1; |
b6c0e933 | 192 | peerSelectFoo(psstate); |
75e88d56 | 193 | } |
194 | ||
93775f90 | 195 | static void |
b6c0e933 | 196 | peerSelectCallback(ps_state * psstate, peer * p) |
93775f90 | 197 | { |
b6c0e933 | 198 | StoreEntry *entry = psstate->entry; |
8407afee | 199 | void *data = psstate->callback_data; |
b6c0e933 | 200 | if (entry) { |
9fb13bb6 | 201 | debug(44, 3) ("peerSelectCallback: %s\n", storeUrl(entry)); |
b6c0e933 | 202 | if (entry->ping_status == PING_WAITING) |
203 | eventDelete(peerPingTimeout, psstate); | |
204 | entry->ping_status = PING_DONE; | |
205 | } | |
44e237d0 | 206 | psstate->ping.stop = current_time; |
8407afee | 207 | if (cbdataValid(data)) |
365e5b34 | 208 | psstate->callback(p, data); |
8407afee | 209 | cbdataUnlock(data); |
348b2031 | 210 | peerSelectStateFree(psstate); |
93775f90 | 211 | } |
212 | ||
213 | static void | |
b6c0e933 | 214 | peerSelectCallbackFail(ps_state * psstate) |
93775f90 | 215 | { |
b6c0e933 | 216 | request_t *request = psstate->request; |
8407afee | 217 | void *data = psstate->callback_data; |
9b5d1d21 | 218 | const char *url = psstate->entry ? storeUrl(psstate->entry) : urlCanonical(request); |
6898e7b0 | 219 | if (psstate->entry) |
220 | psstate->entry->ping_status = PING_DONE; | |
a3d5953d | 221 | debug(44, 1) ("Failed to select source for '%s'\n", url); |
222 | debug(44, 1) (" always_direct = %d\n", psstate->always_direct); | |
223 | debug(44, 1) (" never_direct = %d\n", psstate->never_direct); | |
44e237d0 | 224 | debug(44, 1) (" timedout = %d\n", psstate->ping.timedout); |
8407afee | 225 | if (cbdataValid(data)) |
365e5b34 | 226 | psstate->fail_callback(NULL, data); |
8407afee | 227 | cbdataUnlock(data); |
348b2031 | 228 | peerSelectStateFree(psstate); |
93775f90 | 229 | } |
230 | ||
b3264694 | 231 | static int |
232 | peerCheckNetdbDirect(ps_state * psstate) | |
233 | { | |
85223cd7 | 234 | peer *p = whichPeer(&psstate->closest_parent_miss); |
b3264694 | 235 | int myrtt; |
236 | int myhops; | |
237 | if (p == NULL) | |
238 | return 0; | |
239 | myrtt = netdbHostRtt(psstate->request->host); | |
0f8df3b0 | 240 | debug(44, 3) ("peerCheckNetdbDirect: MY RTT = %d msec\n", myrtt); |
241 | debug(44, 3) ("peerCheckNetdbDirect: closest_parent_miss RTT = %d msec\n", | |
44e237d0 | 242 | psstate->ping.p_rtt); |
243 | if (myrtt && myrtt < psstate->ping.p_rtt) | |
b3264694 | 244 | return 1; |
245 | myhops = netdbHostHops(psstate->request->host); | |
437e2060 | 246 | debug(44, 3) ("peerCheckNetdbDirect: MY hops = %d\n", myhops); |
247 | debug(44, 3) ("peerCheckNetdbDirect: minimum_direct_hops = %d\n", | |
b3264694 | 248 | Config.minDirectHops); |
249 | if (myhops && myhops <= Config.minDirectHops) | |
250 | return 1; | |
251 | return 0; | |
252 | } | |
253 | ||
93775f90 | 254 | static void |
b6c0e933 | 255 | peerSelectFoo(ps_state * psstate) |
062e2281 | 256 | { |
257 | peer *p; | |
258 | hier_code code; | |
b6c0e933 | 259 | StoreEntry *entry = psstate->entry; |
260 | request_t *request = psstate->request; | |
75e88d56 | 261 | int direct; |
7b665aeb | 262 | debug(44, 3) ("peerSelectFoo: '%s %s'\n", |
b6c0e933 | 263 | RequestMethodStr[request->method], |
264 | request->host); | |
3445a83a | 265 | if (psstate->always_direct == 0 && Config.accessList.AlwaysDirect) { |
348b2031 | 266 | psstate->acl_checklist = aclChecklistCreate( |
3445a83a | 267 | Config.accessList.AlwaysDirect, |
75e88d56 | 268 | request, |
269 | request->client_addr, | |
270 | NULL, /* user agent */ | |
348b2031 | 271 | NULL); /* ident */ |
272 | aclNBCheck(psstate->acl_checklist, | |
3445a83a | 273 | peerCheckAlwaysDirectDone, |
b6c0e933 | 274 | psstate); |
75e88d56 | 275 | return; |
3445a83a | 276 | } else if (psstate->always_direct > 0) { |
277 | direct = DIRECT_YES; | |
278 | } else if (psstate->never_direct == 0 && Config.accessList.NeverDirect) { | |
348b2031 | 279 | psstate->acl_checklist = aclChecklistCreate( |
3445a83a | 280 | Config.accessList.NeverDirect, |
75e88d56 | 281 | request, |
282 | request->client_addr, | |
283 | NULL, /* user agent */ | |
348b2031 | 284 | NULL); /* ident */ |
285 | aclNBCheck(psstate->acl_checklist, | |
3445a83a | 286 | peerCheckNeverDirectDone, |
b6c0e933 | 287 | psstate); |
75e88d56 | 288 | return; |
3445a83a | 289 | } else if (psstate->never_direct > 0) { |
290 | direct = DIRECT_NO; | |
92695e5e | 291 | } else if (request->flags.loopdetect) { |
9945ba2e | 292 | direct = DIRECT_YES; |
75e88d56 | 293 | } else { |
294 | direct = DIRECT_MAYBE; | |
295 | } | |
7b665aeb | 296 | debug(44, 3) ("peerSelectFoo: direct = %s\n", DirectStr[direct]); |
062e2281 | 297 | if (direct == DIRECT_YES) { |
7b665aeb | 298 | debug(44, 3) ("peerSelectFoo: DIRECT\n"); |
44e237d0 | 299 | hierarchyNote(&request->hier, DIRECT, &psstate->ping, request->host); |
b6c0e933 | 300 | peerSelectCallback(psstate, NULL); |
062e2281 | 301 | return; |
302 | } | |
85223cd7 | 303 | if ((p = getSingleParent(request))) { |
e82d6d21 | 304 | psstate->single_parent = p->in_addr; |
a369131d | 305 | debug(44, 3) ("peerSelect: found single parent, skipping ICP query\n"); |
85223cd7 | 306 | } |
6cfa8966 | 307 | #if USE_CACHE_DIGESTS |
85223cd7 | 308 | else if ((p = neighborsDigestSelect(request, entry))) { |
69c95dd3 | 309 | debug(44, 2) ("peerSelect: Using Cache Digest\n"); |
310 | request->hier.alg = PEER_SA_DIGEST; | |
311 | code = CACHE_DIGEST_HIT; | |
312 | debug(44, 2) ("peerSelect: %s/%s\n", hier_strings[code], p->host); | |
44e237d0 | 313 | hierarchyNote(&request->hier, code, &psstate->ping, p->host); |
69c95dd3 | 314 | peerSelectCallback(psstate, p); |
315 | return; | |
85223cd7 | 316 | } |
afd88fbe | 317 | #endif |
318 | #if USE_CARP | |
85223cd7 | 319 | else if ((p = carpSelectParent(request))) { |
44e237d0 | 320 | hierarchyNote(&request->hier, CARP, &psstate->ping, p->host); |
0cdcddb9 | 321 | peerSelectCallback(psstate, p); |
322 | return; | |
85223cd7 | 323 | } |
c127134a | 324 | #endif |
85223cd7 | 325 | else if ((p = netdbClosestParent(request))) { |
69c95dd3 | 326 | request->hier.alg = PEER_SA_NETDB; |
327 | code = CLOSEST_PARENT; | |
328 | debug(44, 2) ("peerSelect: %s/%s\n", hier_strings[code], p->host); | |
44e237d0 | 329 | hierarchyNote(&request->hier, code, &psstate->ping, p->host); |
52040193 | 330 | peerSelectCallback(psstate, p); |
331 | return; | |
69c95dd3 | 332 | } else if (peerSelectIcpPing(request, direct, entry)) { |
333 | assert(entry->ping_status == PING_NONE); | |
334 | request->hier.alg = PEER_SA_ICP; | |
335 | debug(44, 3) ("peerSelect: Doing ICP pings\n"); | |
44e237d0 | 336 | psstate->ping.start = current_time; |
337 | psstate->ping.n_sent = neighborsUdpPing(request, | |
69c95dd3 | 338 | entry, |
86aebcda | 339 | peerHandlePingReply, |
69c95dd3 | 340 | psstate, |
44e237d0 | 341 | &psstate->ping.n_replies_expected, |
342 | &psstate->ping.timeout); | |
343 | if (psstate->ping.n_sent == 0) | |
69c95dd3 | 344 | debug(44, 0) ("WARNING: neighborsUdpPing returned 0\n"); |
70b768cd | 345 | debug(44, 3) ("peerSelectFoo: %d ICP replies expected, RTT %d msec\n", |
44e237d0 | 346 | psstate->ping.n_replies_expected, psstate->ping.timeout); |
347 | if (psstate->ping.n_replies_expected > 0) { | |
69c95dd3 | 348 | entry->ping_status = PING_WAITING; |
349 | eventAdd("peerPingTimeout", | |
350 | peerPingTimeout, | |
b6c0e933 | 351 | psstate, |
44e237d0 | 352 | 0.001 * psstate->ping.timeout, |
52040193 | 353 | 0); |
69c95dd3 | 354 | return; |
062e2281 | 355 | } |
062e2281 | 356 | } |
de7ba689 | 357 | debug(44, 3) ("peerSelectFoo: After peerSelectIcpPing.\n"); |
b3264694 | 358 | if (peerCheckNetdbDirect(psstate)) { |
359 | code = CLOSEST_DIRECT; | |
360 | debug(44, 3) ("peerSelect: %s/%s\n", hier_strings[code], request->host); | |
44e237d0 | 361 | hierarchyNote(&request->hier, code, &psstate->ping, request->host); |
b3264694 | 362 | peerSelectCallback(psstate, NULL); |
85223cd7 | 363 | } else if ((p = whichPeer(&psstate->closest_parent_miss))) { |
b3264694 | 364 | code = CLOSEST_PARENT_MISS; |
365 | debug(44, 3) ("peerSelect: %s/%s\n", hier_strings[code], p->host); | |
44e237d0 | 366 | hierarchyNote(&request->hier, code, &psstate->ping, p->host); |
b3264694 | 367 | peerSelectCallback(psstate, p); |
85223cd7 | 368 | } else if ((p = whichPeer(&psstate->first_parent_miss))) { |
429fdbec | 369 | code = FIRST_PARENT_MISS; |
a3d5953d | 370 | debug(44, 3) ("peerSelect: %s/%s\n", hier_strings[code], p->host); |
44e237d0 | 371 | hierarchyNote(&request->hier, code, &psstate->ping, p->host); |
b6c0e933 | 372 | peerSelectCallback(psstate, p); |
85223cd7 | 373 | } else if ((p = whichPeer(&psstate->single_parent))) { |
a369131d | 374 | code = SINGLE_PARENT; |
375 | debug(44, 3) ("peerSelect: %s/%s\n", hier_strings[code], p->host); | |
44e237d0 | 376 | hierarchyNote(&request->hier, code, &psstate->ping, p->host); |
a369131d | 377 | peerSelectCallback(psstate, p); |
93775f90 | 378 | } else if (direct != DIRECT_NO) { |
429fdbec | 379 | code = DIRECT; |
a3d5953d | 380 | debug(44, 3) ("peerSelect: %s/%s\n", hier_strings[code], request->host); |
44e237d0 | 381 | hierarchyNote(&request->hier, code, &psstate->ping, request->host); |
b6c0e933 | 382 | peerSelectCallback(psstate, NULL); |
93775f90 | 383 | } else if ((p = peerGetSomeParent(request, &code))) { |
a3d5953d | 384 | debug(44, 3) ("peerSelect: %s/%s\n", hier_strings[code], p->host); |
44e237d0 | 385 | hierarchyNote(&request->hier, code, &psstate->ping, p->host); |
b6c0e933 | 386 | peerSelectCallback(psstate, p); |
93775f90 | 387 | } else { |
429fdbec | 388 | code = NO_DIRECT_FAIL; |
44e237d0 | 389 | hierarchyNote(&request->hier, code, &psstate->ping, NULL); |
b6c0e933 | 390 | peerSelectCallbackFail(psstate); |
062e2281 | 391 | } |
392 | } | |
393 | ||
d9586c3c | 394 | static void |
93775f90 | 395 | peerPingTimeout(void *data) |
062e2281 | 396 | { |
b6c0e933 | 397 | ps_state *psstate = data; |
398 | StoreEntry *entry = psstate->entry; | |
fefb0227 | 399 | if (entry) |
400 | debug(44, 3) ("peerPingTimeout: '%s'\n", storeUrl(entry)); | |
401 | entry->ping_status = PING_TIMEOUT; | |
73a201f8 | 402 | if (!cbdataValid(psstate->callback_data)) { |
403 | /* request aborted */ | |
404 | cbdataUnlock(psstate->callback_data); | |
0cdcddb9 | 405 | peerSelectStateFree(psstate); |
73a201f8 | 406 | return; |
407 | } | |
75e88d56 | 408 | PeerStats.timeouts++; |
44e237d0 | 409 | psstate->ping.timedout = 1; |
b6c0e933 | 410 | peerSelectFoo(psstate); |
85034133 | 411 | } |
412 | ||
413 | void | |
414 | peerSelectInit(void) | |
415 | { | |
75e88d56 | 416 | memset(&PeerStats, '\0', sizeof(PeerStats)); |
9bdbfe33 | 417 | assert(sizeof(hier_strings) == (HIER_MAX + 1) * sizeof(char *)); |
062e2281 | 418 | } |
93775f90 | 419 | |
b3264694 | 420 | static void |
421 | peerIcpParentMiss(peer * p, icp_common_t * header, ps_state * ps) | |
422 | { | |
423 | int rtt; | |
424 | int hops; | |
425 | if (Config.onoff.query_icmp) { | |
79a15e0a | 426 | if (header->flags & ICP_FLAG_SRC_RTT) { |
b3264694 | 427 | rtt = header->pad & 0xFFFF; |
428 | hops = (header->pad >> 16) & 0xFFFF; | |
429 | if (rtt > 0 && rtt < 0xFFFF) | |
430 | netdbUpdatePeer(ps->request, p, rtt, hops); | |
44e237d0 | 431 | if (rtt && (ps->ping.p_rtt == 0 || rtt < ps->ping.p_rtt)) { |
85223cd7 | 432 | ps->closest_parent_miss = p->in_addr; |
44e237d0 | 433 | ps->ping.p_rtt = rtt; |
b3264694 | 434 | } |
435 | } | |
436 | } | |
18ec72b2 | 437 | /* if closest-only is set, then don't allow FIRST_PARENT_MISS */ |
cd196bc8 | 438 | if (p->options.closest_only) |
b3264694 | 439 | return; |
85223cd7 | 440 | /* set FIRST_MISS if there is no CLOSEST parent */ |
441 | if (ps->closest_parent_miss.sin_addr.s_addr != any_addr.s_addr) | |
b3264694 | 442 | return; |
44e237d0 | 443 | rtt = tvSubMsec(ps->ping.start, current_time) / p->weight; |
444 | if (ps->ping.w_rtt == 0 || rtt < ps->ping.w_rtt) { | |
85223cd7 | 445 | ps->first_parent_miss = p->in_addr; |
44e237d0 | 446 | ps->ping.w_rtt = rtt; |
b3264694 | 447 | } |
448 | } | |
93775f90 | 449 | |
b6c0e933 | 450 | static void |
b3264694 | 451 | peerHandleIcpReply(peer * p, peer_t type, icp_common_t * header, void *data) |
93775f90 | 452 | { |
b6c0e933 | 453 | ps_state *psstate = data; |
b3264694 | 454 | icp_opcode op = header->opcode; |
b6c0e933 | 455 | request_t *request = psstate->request; |
f9e5a344 | 456 | debug(44, 3) ("peerHandleIcpReply: %s %s\n", |
27cd7235 | 457 | icp_opcode_str[op], |
9fb13bb6 | 458 | storeUrl(psstate->entry)); |
69c95dd3 | 459 | #if USE_CACHE_DIGESTS && 0 |
26b164ac | 460 | /* do cd lookup to count false misses */ |
3ab66981 | 461 | if (p && request) |
4b4cd312 | 462 | peerNoteDigestLookup(request, p, |
3ab66981 | 463 | peerDigestLookup(p, request, psstate->entry)); |
26b164ac | 464 | #endif |
44e237d0 | 465 | psstate->ping.n_recv++; |
27cd7235 | 466 | if (op == ICP_MISS || op == ICP_DECHO) { |
b3264694 | 467 | if (type == PEER_PARENT) |
468 | peerIcpParentMiss(p, header, psstate); | |
a7c05555 | 469 | } else if (op == ICP_HIT) { |
a4394ebd | 470 | hierarchyNote(&request->hier, |
429fdbec | 471 | type == PEER_PARENT ? PARENT_HIT : SIBLING_HIT, |
44e237d0 | 472 | &psstate->ping, |
93775f90 | 473 | p->host); |
b6c0e933 | 474 | peerSelectCallback(psstate, p); |
93775f90 | 475 | return; |
27cd7235 | 476 | } else if (op == ICP_SECHO) { |
a4394ebd | 477 | hierarchyNote(&request->hier, |
429fdbec | 478 | SOURCE_FASTEST, |
44e237d0 | 479 | &psstate->ping, |
b6c0e933 | 480 | request->host); |
4f92c80c | 481 | peerSelectCallback(psstate, NULL); |
93775f90 | 482 | return; |
483 | } | |
44e237d0 | 484 | if (psstate->ping.n_recv < psstate->ping.n_replies_expected) |
93775f90 | 485 | return; |
b6c0e933 | 486 | peerSelectFoo(psstate); |
93775f90 | 487 | } |
86aebcda | 488 | |
489 | #if USE_HTCP | |
490 | static void | |
44e237d0 | 491 | peerHandleHtcpReply(peer * p, peer_t type, htcpReplyData * htcp, void *data) |
86aebcda | 492 | { |
493 | ps_state *psstate = data; | |
44e237d0 | 494 | request_t *request = psstate->request; |
495 | debug(44, 3) ("peerHandleIcpReply: %s %s\n", | |
496 | htcp->hit ? "HIT" : "MISS", | |
497 | storeUrl(psstate->entry)); | |
498 | psstate->ping.n_recv++; | |
499 | if (htcp->hit) { | |
500 | hierarchyNote(&request->hier, | |
501 | type == PEER_PARENT ? PARENT_HIT : SIBLING_HIT, | |
502 | &psstate->ping, | |
503 | p->host); | |
504 | peerSelectCallback(psstate, p); | |
505 | return; | |
506 | } | |
507 | if (type == PEER_PARENT) | |
508 | peerHtcpParentMiss(p, htcp, psstate); | |
509 | if (psstate->ping.n_recv < psstate->ping.n_replies_expected) | |
510 | return; | |
511 | peerSelectFoo(psstate); | |
512 | } | |
513 | ||
514 | static void | |
515 | peerHtcpParentMiss(peer * p, htcpReplyData * htcp, ps_state * ps) | |
516 | { | |
517 | int rtt; | |
518 | int hops; | |
519 | if (Config.onoff.query_icmp) { | |
520 | if (htcp->cto.rtt > 0) { | |
521 | rtt = (int) htcp->cto.rtt * 1000; | |
522 | hops = (int) htcp->cto.hops * 1000; | |
523 | netdbUpdatePeer(ps->request, p, rtt, hops); | |
524 | if (rtt && (ps->ping.p_rtt == 0 || rtt < ps->ping.p_rtt)) { | |
525 | ps->closest_parent_miss = p->in_addr; | |
526 | ps->ping.p_rtt = rtt; | |
527 | } | |
528 | } | |
529 | } | |
530 | /* if closest-only is set, then don't allow FIRST_PARENT_MISS */ | |
cd196bc8 | 531 | if (p->options.closest_only) |
44e237d0 | 532 | return; |
533 | /* set FIRST_MISS if there is no CLOSEST parent */ | |
534 | if (ps->closest_parent_miss.sin_addr.s_addr != any_addr.s_addr) | |
535 | return; | |
536 | rtt = tvSubMsec(ps->ping.start, current_time) / p->weight; | |
537 | if (ps->ping.w_rtt == 0 || rtt < ps->ping.w_rtt) { | |
538 | ps->first_parent_miss = p->in_addr; | |
539 | ps->ping.w_rtt = rtt; | |
540 | } | |
86aebcda | 541 | } |
542 | #endif | |
543 | ||
544 | static void | |
545 | peerHandlePingReply(peer * p, peer_t type, protocol_t proto, void *ping_data, void *data) | |
546 | { | |
547 | if (proto == PROTO_ICP) | |
548 | peerHandleIcpReply(p, type, ping_data, data); | |
549 | #if USE_HTCP | |
550 | else if (proto == PROTO_HTCP) | |
551 | peerHandleHtcpReply(p, type, ping_data, data); | |
552 | #endif | |
553 | else | |
554 | debug(44, 1) ("peerHandlePingReply: unknown protocol_t %d\n", (int) proto); | |
555 | } |