peer_select.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2022 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9/* DEBUG: section 44 Peer Selection Algorithm */
10
11#include "squid.h"
12#include "acl/FilledChecklist.h"
14#include "base/InstanceId.h"
15#include "base/TypeTraits.h"
16#include "CachePeer.h"
17#include "carp.h"
18#include "client_side.h"
19#include "dns/LookupDetails.h"
20#include "errorpage.h"
21#include "event.h"
22#include "FwdState.h"
23#include "globals.h"
24#include "hier_code.h"
25#include "htcp.h"
26#include "http/Stream.h"
27#include "HttpRequest.h"
28#include "icmp/net_db.h"
29#include "ICP.h"
30#include "ip/tools.h"
31#include "ipcache.h"
32#include "neighbors.h"
33#include "peer_sourcehash.h"
34#include "peer_userhash.h"
35#include "PeerSelectState.h"
36#include "SquidConfig.h"
37#include "Store.h"
38#include "time/gadgets.h"
39
50{
52
53public:
55 _peer(p),
56 code(c),
57 next(nullptr)
58 {}
59
60 CbcPointer<CachePeer> _peer; /* NULL --> origin server */
63};
64
65static struct {
68
69static const char *DirectStr[] = {
70 "DIRECT_UNKNOWN",
71 "DIRECT_NO",
72 "DIRECT_MAYBE",
73 "DIRECT_YES"
74};
75
78{
79public:
80 PeerSelectionDumper(const PeerSelector * const aSelector, const CachePeer * const aPeer, const hier_code aCode):
81 selector(aSelector), peer(aPeer), code(aCode) {}
82
83 const PeerSelector * const selector;
84 const CachePeer * const peer;
86};
87
89
91static std::ostream &
92operator <<(std::ostream &os, const PeerSelectionDumper &fsd)
93{
94 os << hier_code_str[fsd.code];
95
96 if (fsd.peer)
97 os << '/' << fsd.peer->host;
98 else if (fsd.selector) // useful for DIRECT and gone PINNED destinations
99 os << '#' << fsd.selector->request->url.host();
100
101 return os;
102}
103
108{
109public:
111 void monitor(PeerSelector *);
112
114 void forget(PeerSelector *);
115
118
119private:
120 static void NoteWaitOver(void *monitor);
121
122 void startWaiting();
123 void abortWaiting();
124 void noteWaitOver();
125
127};
128
132{
133 static const auto Instance = new PeerSelectorPingMonitor();
134 return *Instance;
135}
136
137/* PeerSelectorPingMonitor */
138
140void
142{
143 assert(raw);
144 static_cast<PeerSelectorPingMonitor*>(raw)->noteWaitOver();
145}
146
148void
150{
151 assert(!selectors.empty());
152 const auto interval = tvSubDsec(current_time, selectors.begin()->first);
153 eventAdd("PeerSelectorPingMonitor::NoteWaitOver", &PeerSelectorPingMonitor::NoteWaitOver, this, interval, 0, false);
154}
155
157void
159{
160 // our event may be already in the AsyncCallQueue but that is OK:
161 // such queued calls cannot accumulate, and we ignore any stale ones
163}
164
166void
168{
169 while (!selectors.empty() && current_time >= selectors.begin()->first) {
170 const auto selector = selectors.begin()->second;
171 CallBack(selector->al, [selector,this] {
172 selector->ping.monitorRegistration = npos();
173 AsyncCall::Pointer callback = asyncCall(44, 4, "PeerSelector::HandlePingTimeout",
174 cbdataDialer(PeerSelector::HandlePingTimeout, selector));
175 ScheduleCallHere(callback);
176 });
177 selectors.erase(selectors.begin());
178 }
179
180 if (!selectors.empty()) {
181 // Since abortWaiting() is unreliable, we may have been awakened by a
182 // stale event A after event B has been scheduled. Now we are going to
183 // schedule event C. Prevent event accumulation by deleting B (if any).
184 abortWaiting();
185
186 startWaiting();
187 }
188}
189
190void
192{
193 assert(selector);
194
195 const auto deadline = selector->ping.deadline();
196 const auto position = selectors.emplace(deadline, selector);
197 selector->ping.monitorRegistration = position;
198
199 if (position == selectors.begin()) {
200 if (selectors.size() > 1)
201 abortWaiting(); // remove the previously scheduled earlier event
202 startWaiting();
203 } // else the already scheduled event is still the earliest one
204}
205
206void
208{
209 assert(selector);
210
211 if (selector->ping.monitorRegistration == npos())
212 return; // already forgotten
213
214 const auto wasFirst = selector->ping.monitorRegistration == selectors.begin();
215 selectors.erase(selector->ping.monitorRegistration);
216 selector->ping.monitorRegistration = npos();
217
218 if (wasFirst) {
219 // do not reschedule if there are still elements with the same deadline
220 if (!selectors.empty() && selectors.begin()->first == selector->ping.deadline())
221 return;
222 abortWaiting();
223 if (!selectors.empty())
224 startWaiting();
225 } // else do nothing since the old scheduled event is still the earliest one
226}
227
228/* PeerSelector */
229
231{
232 while (servers) {
233 FwdServer *next = servers->next;
234 delete servers;
235 servers = next;
236 }
237
239
240 if (entry) {
241 debugs(44, 3, entry->url());
243 }
244
245 if (acl_checklist) {
246 debugs(44, DBG_IMPORTANT, "ERROR: Squid BUG: peer selector gone while waiting for a slow ACL");
247 delete acl_checklist;
248 }
249
251
252 if (entry) {
254 entry->unlock("peerSelect");
255 entry = nullptr;
256 }
257
258 delete lastError;
259}
260
261void
263{
264 assert(entry);
266 PingMonitor().monitor(this);
268}
269
270void
272{
273 PingMonitor().forget(this);
274}
275
276static int
278{
279 assert(ps);
281
282 int n;
283 assert(entry);
284 assert(entry->ping_status == PING_NONE);
285 assert(direct != DIRECT_YES);
286 debugs(44, 3, entry->url());
287
288 if (!request->flags.hierarchical && direct != DIRECT_NO)
289 return 0;
290
292 if (direct != DIRECT_NO)
293 return 0;
294
295 n = neighborsCount(ps);
296
297 debugs(44, 3, "counted " << n << " neighbors");
298
299 return n;
300}
301
302static void
305 AccessLogEntry::Pointer const &al,
306 StoreEntry * entry)
307{
308 if (entry)
309 debugs(44, 3, *entry << ' ' << entry->url());
310 else
311 debugs(44, 3, request->method);
312
313 const auto selector = new PeerSelector(initiator);
314
315 selector->request = request;
316 HTTPMSGLOCK(selector->request);
317 selector->al = al;
318
319 selector->entry = entry;
320
321#if USE_CACHE_DIGESTS
322
323 request->hier.peer_select_start = current_time;
324
325#endif
326
327 if (selector->entry)
328 selector->entry->lock("peerSelect");
329
330 selector->selectMore();
331}
332
333void
335{
336 subscribed = true;
337 peerSelect(this, request, ale, entry);
338 // and wait for noteDestination() and/or noteDestinationsEnd() calls
339}
340
341void
343{
344 acl_checklist = nullptr;
345 debugs(44, 3, answer);
346 never_direct = answer;
347 switch (answer) {
348 case ACCESS_ALLOWED:
351 debugs(44, 3, "direct = " << DirectStr[direct] << " (never_direct allow)");
352 break;
353 case ACCESS_DENIED: // not relevant.
354 case ACCESS_DUNNO: // not relevant.
355 break;
357 debugs(44, DBG_IMPORTANT, "WARNING: never_direct resulted in " << answer << ". Username ACLs are not reliable here.");
358 break;
359 }
360 selectMore();
361}
362
363void
365{
366 static_cast<PeerSelector*>(data)->checkNeverDirectDone(answer);
367}
368
369void
371{
372 acl_checklist = nullptr;
373 debugs(44, 3, answer);
374 always_direct = answer;
375 switch (answer) {
376 case ACCESS_ALLOWED:
379 debugs(44, 3, "direct = " << DirectStr[direct] << " (always_direct allow)");
380 break;
381 case ACCESS_DENIED: // not relevant.
382 case ACCESS_DUNNO: // not relevant.
383 break;
385 debugs(44, DBG_IMPORTANT, "WARNING: always_direct resulted in " << answer << ". Username ACLs are not reliable here.");
386 break;
387 }
388 selectMore();
389}
390
391void
393{
394 static_cast<PeerSelector*>(data)->checkAlwaysDirectDone(answer);
395}
396
399bool
401{
403 return false;
404
405 debugs(44, 3, "Aborting peer selection: Initiator gone or lost interest.");
406 delete this;
407 return true;
408}
409
411void
413{
414 if (selectionAborted())
415 return;
416
417 FwdServer *fs = servers;
418
419 // Bug 3243: CVE 2009-0801
420 // Bypass of browser same-origin access control in intercepted communication
421 // To resolve this we must use only the original client destination when going DIRECT
422 // on intercepted traffic which failed Host verification
423 const HttpRequest *req = request;
424 const bool isIntercepted = !req->flags.redirected &&
425 (req->flags.intercepted || req->flags.interceptTproxy);
426 const bool useOriginalDst = Config.onoff.client_dst_passthru || !req->flags.hostVerified;
427 const bool choseDirect = fs && fs->code == HIER_DIRECT;
428 if (isIntercepted && useOriginalDst && choseDirect) {
429 // check the client is still around before using any of its details
430 if (req->clientConnectionManager.valid()) {
431 // construct a "result" adding the ORIGINAL_DST to the set instead of DIRECT
434 fs->code = ORIGINAL_DST; // fs->code is DIRECT. This fixes the display.
435 handlePath(p, *fs);
436 }
437
438 // clear the used fs and continue
439 servers = fs->next;
440 delete fs;
442 return;
443 }
444
445 if (fs && fs->code == PINNED) {
446 // Nil path signals a PINNED destination selection. Our initiator should
447 // borrow and use clientConnectionManager's pinned connection object
448 // (regardless of that connection destination).
449 handlePath(nullptr, *fs);
450 servers = fs->next;
451 delete fs;
453 return;
454 }
455
456 // convert the list of FwdServer destinations into destinations IP addresses
457 if (fs && wantsMoreDestinations()) {
458 // send the next one off for DNS lookup.
459 const char *host = fs->_peer.valid() ? fs->_peer->host : request->url.host();
460 debugs(44, 2, "Find IP destination for: " << url() << "' via " << host);
461 Dns::nbgethostbyname(host, this);
462 return;
463 }
464
465 // Bug 3605: clear any extra listed FwdServer destinations, when the options exceeds max_foward_tries.
466 // due to the allocation method of fs, we must deallocate each manually.
467 // TODO: use a std::list so we can get the size and abort adding whenever the selection loops reach Config.forward_max_tries
468 if (fs) {
469 assert(fs == servers);
470 while (fs) {
471 servers = fs->next;
472 delete fs;
473 fs = servers;
474 }
475 }
476
477 // done with DNS lookups. pass back to caller
478
479 debugs(44, 2, id << " found all " << foundPaths << " destinations for " << url());
480 debugs(44, 2, " always_direct = " << always_direct);
481 debugs(44, 2, " never_direct = " << never_direct);
482 debugs(44, 2, " timedout = " << ping.timedout);
483
485 request->hier.ping = ping; // final result
486
487 if (lastError && foundPaths) {
488 // nobody cares about errors if we found destinations despite them
489 debugs(44, 3, "forgetting the last error");
490 delete lastError;
491 lastError = nullptr;
492 }
493
494 if (const auto initiator = interestedInitiator())
495 initiator->noteDestinationsEnd(lastError);
496 lastError = nullptr; // initiator owns the ErrorState object now
497 delete this;
498}
499
500void
502{
503 /* ignore lookup delays that occurred after the initiator moved on */
504
505 if (selectionAborted())
506 return;
507
509 return;
510
511 request->recordLookup(details);
512}
513
514void
516{
517 if (selectionAborted())
518 return;
519
521 return;
522
523 const auto peer = servers->_peer.valid();
524
525 // for TPROXY spoofing, we must skip unusable addresses
526 if (request->flags.spoofClientIp && !(peer && peer->options.no_tproxy) ) {
527 if (ip.isIPv4() != request->client_addr.isIPv4())
528 return; // cannot spoof the client address on this link
529 }
530
532 p->remote = ip;
533 p->remote.port(peer ? peer->http_port : request->url.port());
534 handlePath(p, *servers);
535}
536
537void
539{
540 if (selectionAborted())
541 return;
542
543 FwdServer *fs = servers;
544 if (!ia) {
545 debugs(44, 3, "Unknown host: " << (fs->_peer.valid() ? fs->_peer->host : request->url.host()));
546 // discard any previous error.
547 delete lastError;
548 lastError = nullptr;
549 if (fs->code == HIER_DIRECT) {
551 lastError->dnsError = details.error;
552 }
553 }
554 // else noteIp() calls have already processed all IPs in *ia
555
556 servers = fs->next;
557 delete fs;
558
559 // continue resolving selected peers
561}
562
563int
565{
566#if USE_ICMP
567 CachePeer *p;
568 int myrtt;
569 int myhops;
570
571 if (direct == DIRECT_NO)
572 return 0;
573
574 /* base lookup on RTT and Hops if ICMP NetDB is enabled. */
575
576 myrtt = netdbHostRtt(request->url.host());
577 debugs(44, 3, "MY RTT = " << myrtt << " msec");
578 debugs(44, 3, "minimum_direct_rtt = " << Config.minDirectRtt << " msec");
579
580 if (myrtt && myrtt <= Config.minDirectRtt)
581 return 1;
582
583 myhops = netdbHostHops(request->url.host());
584
585 debugs(44, 3, "MY hops = " << myhops);
586 debugs(44, 3, "minimum_direct_hops = " << Config.minDirectHops);
587
588 if (myhops && myhops <= Config.minDirectHops)
589 return 1;
590
592
593 if (p == nullptr)
594 return 0;
595
596 debugs(44, 3, "closest_parent_miss RTT = " << ping.p_rtt << " msec");
597
598 if (myrtt && myrtt <= ping.p_rtt)
599 return 1;
600
601#endif /* USE_ICMP */
602
603 return 0;
604}
605
606void
608{
609 if (selectionAborted())
610 return;
611
612 debugs(44, 3, request->method << ' ' << request->url.host());
613
615 if (direct == DIRECT_UNKNOWN) {
617 debugs(44, 3, "direct = " << DirectStr[direct] << " (always_direct to be checked)");
620 ch->al = al;
621 acl_checklist = ch;
622 acl_checklist->syncAle(request, nullptr);
624 return;
625 } else if (never_direct == ACCESS_DUNNO) {
626 debugs(44, 3, "direct = " << DirectStr[direct] << " (never_direct to be checked)");
629 ch->al = al;
630 acl_checklist = ch;
631 acl_checklist->syncAle(request, nullptr);
633 return;
634 } else if (request->flags.noDirect) {
637 debugs(44, 3, "direct = " << DirectStr[direct] << " (forced non-direct)");
638 } else if (request->flags.loopDetected) {
641 debugs(44, 3, "direct = " << DirectStr[direct] << " (forwarding loop detected)");
642 } else if (checkNetdbDirect()) {
644 debugs(44, 3, "direct = " << DirectStr[direct] << " (checkNetdbDirect)");
645 } else {
647 debugs(44, 3, "direct = " << DirectStr[direct] << " (default)");
648 }
649
650 debugs(44, 3, "direct = " << DirectStr[direct]);
651 }
652
653 if (!entry || entry->ping_status == PING_NONE)
654 selectPinned();
655 if (entry == nullptr) {
656 (void) 0;
657 } else if (entry->ping_status == PING_NONE) {
659
661 return;
662 } else if (entry->ping_status == PING_WAITING) {
666 }
667
668 switch (direct) {
669
670 case DIRECT_YES:
672 break;
673
674 case DIRECT_NO:
677 break;
678
679 default:
680
683
687 }
688
691
692 break;
693 }
694
695 // end peer selection; start resolving selected peers
697}
698
700
702void
704{
705 // TODO: Avoid all repeated calls. Relying on PING_DONE is not enough.
707 return;
708
709 const auto peer = request->pinnedConnection()->pinnedPeer();
710 const auto usePinned = peer ? peerAllowedToUse(peer, this) : (direct != DIRECT_NO);
711 // If the pinned connection is prohibited (for this request) then
712 // the initiator must decide whether it is OK to open a new one instead.
714
715 addSelection(peer, PINNED);
716 if (entry)
717 entry->ping_status = PING_DONE; // skip ICP
718}
719
728void
730{
731 CachePeer *p;
734
735 if (direct == DIRECT_YES) {
737 return;
738 }
739
740#if USE_CACHE_DIGESTS
741 if ((p = neighborsDigestSelect(this))) {
744 else
746 } else
747#endif
748 if ((p = netdbClosestParent(this))) {
750 } else if (peerSelectIcpPing(this, direct, entry)) {
751 debugs(44, 3, "Doing ICP pings");
754 entry,
756 this,
758 &ping.timeout);
759 // TODO: Refactor neighborsUdpPing() to guarantee positive timeouts.
760 if (ping.timeout < 0)
761 ping.timeout = 0;
762
763 if (ping.n_sent == 0)
764 debugs(44, DBG_CRITICAL, "WARNING: neighborsUdpPing returned 0");
766 " ICP replies expected, RTT " << ping.timeout <<
767 " msec");
768
769 if (ping.n_replies_expected > 0) {
771 return;
772 }
773 }
774
775 if (code != HIER_NONE) {
776 assert(p);
777 addSelection(p, code);
778 }
779
781}
782
784void
786{
787 CachePeer *p = nullptr;
791
792 if (checkNetdbDirect()) {
794 addSelection(nullptr, code);
795 return;
796 }
797
798 if ((p = hit)) {
800 } else {
804 } else if (!first_parent_miss.isAnyAddr()) {
807 }
808 }
809 if (p && code != HIER_NONE) {
810 addSelection(p, code);
811 }
812}
813
815void
817{
818 if (direct == DIRECT_NO)
819 return;
820
821 /* WAIS is not implemented natively */
823 return;
824
825 addSelection(nullptr, HIER_DIRECT);
826}
827
828void
830{
831 CachePeer *p;
833 debugs(44, 3, request->method << ' ' << request->url.host());
834
835 if (direct == DIRECT_YES)
836 return;
837
838 if ((p = peerSourceHashSelectParent(this))) {
840#if USE_AUTH
841 } else if ((p = peerUserHashSelectParent(this))) {
843#endif
844 } else if ((p = carpSelectParent(this))) {
845 code = CARP;
846 } else if ((p = getRoundRobinParent(this))) {
848 } else if ((p = getWeightedRoundRobinParent(this))) {
850 } else if ((p = getFirstUpParent(this))) {
852 } else if ((p = getDefaultParent(this))) {
854 }
855
856 if (code != HIER_NONE) {
857 addSelection(p, code);
858 }
859}
860
862void
864{
865 CachePeer *p;
866 /* Add all alive parents */
867
868 for (p = Config.peers; p; p = p->next) {
869 /* XXX: neighbors.c lacks a public interface for enumerating
870 * parents to a request so we have to dig some here..
871 */
872
874 continue;
875
876 if (!peerHTTPOkay(p, this))
877 continue;
878
880 }
881
882 /* XXX: should add dead parents here, but it is currently
883 * not possible to find out which parents are dead or which
884 * simply are not configured to handle the request.
885 */
886 /* Add default parent as a last resort */
887 if ((p = getDefaultParent(this))) {
889 }
890}
891
892void
894{
895 debugs(44, 3, url());
896
897 // do nothing if ping reply came while handlePingTimeout() was queued
899 return;
900
902
903 if (selectionAborted())
904 return;
905
906 ++PeerStats.timeouts;
907 ping.timedout = 1;
908 selectMore();
909}
910
911void
913{
914 selector->handlePingTimeout();
915}
916
917void
919{
920 memset(&PeerStats, '\0', sizeof(PeerStats));
921}
922
923void
925{
926 int rtt;
927
928#if USE_ICMP
929 if (Config.onoff.query_icmp) {
930 if (header->flags & ICP_FLAG_SRC_RTT) {
931 rtt = header->pad & 0xFFFF;
932 int hops = (header->pad >> 16) & 0xFFFF;
933
934 if (rtt > 0 && rtt < 0xFFFF)
935 netdbUpdatePeer(request->url, p, rtt, hops);
936
937 if (rtt && (ping.p_rtt == 0 || rtt < ping.p_rtt)) {
939 ping.p_rtt = rtt;
940 }
941 }
942 }
943#else
944 (void)header;
945#endif /* USE_ICMP */
946
947 /* if closest-only is set, then don't allow FIRST_PARENT_MISS */
948 if (p->options.closest_only)
949 return;
950
951 /* set FIRST_MISS if there is no CLOSEST parent */
953 return;
954
955 rtt = (tvSubMsec(ping.start, current_time) - p->basetime) / p->weight;
956
957 if (rtt < 1)
958 rtt = 1;
959
960 if (first_parent_miss.isAnyAddr() || rtt < ping.w_rtt) {
962 ping.w_rtt = rtt;
963 }
964}
965
966void
968{
969 icp_opcode op = header->getOpCode();
970 debugs(44, 3, icp_opcode_str[op] << ' ' << url());
971#if USE_CACHE_DIGESTS && 0
972 /* do cd lookup to count false misses */
973
974 if (p && request)
976 peerDigestLookup(p, this));
977
978#endif
979
980 ++ping.n_recv;
981
982 if (op == ICP_MISS || op == ICP_DECHO) {
983 if (type == PEER_PARENT)
984 handleIcpParentMiss(p, header);
985 } else if (op == ICP_HIT) {
986 hit = p;
987 hit_type = type;
988 selectMore();
989 return;
990 }
991
993 return;
994
995 selectMore();
996}
997
998#if USE_HTCP
999void
1001{
1002 debugs(44, 3, (htcp->hit ? "HIT" : "MISS") << ' ' << url());
1003 ++ping.n_recv;
1004
1005 if (htcp->hit) {
1006 hit = p;
1007 hit_type = type;
1008 selectMore();
1009 return;
1010 }
1011
1012 if (type == PEER_PARENT)
1013 handleHtcpParentMiss(p, htcp);
1014
1016 return;
1017
1018 selectMore();
1019}
1020
1021void
1023{
1024 int rtt;
1025
1026#if USE_ICMP
1027 if (Config.onoff.query_icmp) {
1028 if (htcp->cto.rtt > 0) {
1029 rtt = (int) htcp->cto.rtt * 1000;
1030 int hops = (int) htcp->cto.hops * 1000;
1031 netdbUpdatePeer(request->url, p, rtt, hops);
1032
1033 if (rtt && (ping.p_rtt == 0 || rtt < ping.p_rtt)) {
1035 ping.p_rtt = rtt;
1036 }
1037 }
1038 }
1039#else
1040 (void)htcp;
1041#endif /* USE_ICMP */
1042
1043 /* if closest-only is set, then don't allow FIRST_PARENT_MISS */
1044 if (p->options.closest_only)
1045 return;
1046
1047 /* set FIRST_MISS if there is no CLOSEST parent */
1049 return;
1050
1051 rtt = (tvSubMsec(ping.start, current_time) - p->basetime) / p->weight;
1052
1053 if (rtt < 1)
1054 rtt = 1;
1055
1056 if (first_parent_miss.isAnyAddr() || rtt < ping.w_rtt) {
1058 ping.w_rtt = rtt;
1059 }
1060}
1061
1062#endif
1063
1064void
1065PeerSelector::HandlePingReply(CachePeer * p, peer_t type, AnyP::ProtocolType proto, void *pingdata, void *data)
1066{
1067 if (proto == AnyP::PROTO_ICP)
1068 static_cast<PeerSelector*>(data)->handleIcpReply(p, type, static_cast<icp_common_t*>(pingdata));
1069
1070#if USE_HTCP
1071
1072 else if (proto == AnyP::PROTO_HTCP)
1073 static_cast<PeerSelector*>(data)->handleHtcpReply(p, type, static_cast<HtcpReplyData*>(pingdata));
1074
1075#endif
1076
1077 else
1078 debugs(44, DBG_IMPORTANT, "ERROR: ignoring an ICP reply with unknown protocol " << proto);
1079}
1080
1081void
1083{
1084 // Find the end of the servers list. Bail on a duplicate destination.
1085 auto **serversTail = &servers;
1086 while (const auto server = *serversTail) {
1087 // There can be at most one PINNED destination.
1088 // Non-PINNED destinations are uniquely identified by their CachePeer
1089 // (even though a DIRECT destination might match a cache_peer address).
1090 // TODO: We may still add duplicates because the same peer could have
1091 // been removed from `servers` already (and given to the requestor).
1092 const bool duplicate = (server->code == PINNED) ?
1093 (code == PINNED) : (server->_peer == peer);
1094 if (duplicate) {
1095 debugs(44, 3, "skipping " << PeerSelectionDumper(this, peer, code) <<
1096 "; have " << PeerSelectionDumper(this, server->_peer.get(), server->code));
1097 return;
1098 }
1099 serversTail = &server->next;
1100 }
1101
1102 debugs(44, 3, "adding " << PeerSelectionDumper(this, peer, code));
1103 *serversTail = new FwdServer(peer, code);
1104}
1105
1107 request(nullptr),
1108 entry (nullptr),
1109 always_direct(Config.accessList.AlwaysDirect?ACCESS_DUNNO:ACCESS_DENIED),
1110 never_direct(Config.accessList.NeverDirect?ACCESS_DUNNO:ACCESS_DENIED),
1111 direct(DIRECT_UNKNOWN),
1112 lastError(nullptr),
1113 servers (nullptr),
1114 first_parent_miss(),
1115 closest_parent_miss(),
1116 hit(nullptr),
1117 hit_type(PEER_NONE),
1118 acl_checklist (nullptr),
1119 initiator_(initiator)
1120{
1121 ; // no local defaults.
1122}
1123
1124const SBuf
1126{
1127 if (entry)
1128 return SBuf(entry->url());
1129
1130 if (request)
1131 return request->effectiveRequestUri();
1132
1133 static const SBuf noUrl("[no URL]");
1134 return noUrl;
1135}
1136
1140{
1141 const auto initiator = initiator_.valid();
1142
1143 if (!initiator) {
1144 debugs(44, 3, id << " initiator gone");
1145 return nullptr;
1146 }
1147
1148 if (!initiator->subscribed) {
1149 debugs(44, 3, id << " initiator lost interest");
1150 return nullptr;
1151 }
1152
1153 debugs(44, 7, id);
1154 return initiator;
1155}
1156
1157bool
1159 const auto maxCount = Config.forward_max_tries;
1160 return maxCount >= 0 && foundPaths < static_cast<size_t>(maxCount);
1161}
1162
1163void
1165{
1166 ++foundPaths;
1167
1168 if (path) {
1169 path->peerType = fs.code;
1170 path->setPeer(fs._peer.get());
1171
1172 // check for a configured outgoing address for this destination...
1174 debugs(44, 2, id << " found " << path << ", destination #" << foundPaths << " for " << url());
1175 } else
1176 debugs(44, 2, id << " found pinned, destination #" << foundPaths << " for " << url());
1177
1178 request->hier.ping = ping; // may be updated later
1179
1180 debugs(44, 2, " always_direct = " << always_direct);
1181 debugs(44, 2, " never_direct = " << never_direct);
1182 debugs(44, 2, " timedout = " << ping.timedout);
1183
1184 if (const auto initiator = interestedInitiator())
1185 initiator->noteDestination(path);
1186}
1187
1189
1191 n_sent(0),
1192 n_recv(0),
1193 n_replies_expected(0),
1194 timeout(0),
1195 timedout(0),
1196 w_rtt(0),
1197 p_rtt(0),
1198 monitorRegistration(PingMonitor().npos())
1199{
1200 start.tv_sec = 0;
1201 start.tv_usec = 0;
1202 stop.tv_sec = 0;
1203 stop.tv_usec = 0;
1204}
1205
1206timeval
1208{
1209 timeval timeInterval;
1210 timeInterval.tv_sec = timeout / 1000;
1211 timeInterval.tv_usec = (timeout % 1000) * 1000;
1212
1213 timeval result;
1214 tvAdd(result, start, timeInterval);
1215 return result;
1216}
1217
static CodeContext::Pointer & Instance()
guarantees the forever existence of the pointer, starting from the first use
Definition: CodeContext.cc:26
void CallBack(const CodeContext::Pointer &callbackContext, Fun &&callback)
Definition: CodeContext.h:112
void getOutgoingAddress(HttpRequest *request, const Comm::ConnectionPointer &conn)
Definition: FwdState.cc:1519
@ duplicate
Definition: GnuRegex.c:293
WaitingPeerSelectors::iterator WaitingPeerSelectorPosition
Definition: PingData.h:22
std::multimap< timeval, PeerSelector *, std::less< timeval >, PoolingAllocator< WaitingPeerSelector > > WaitingPeerSelectors
waiting PeerSelector objects, ordered by their absolute deadlines
Definition: PingData.h:21
class SquidConfig Config
Definition: SquidConfig.cc:12
#define assert(EX)
Definition: assert.h:19
static char server[MAXLINE]
CachePeer * carpSelectParent(PeerSelector *ps)
Definition: carp.cc:147
#define CBDATA_CLASS_INIT(type)
Definition: cbdata.h:318
virtual void syncAle(HttpRequest *adaptedRequest, const char *logUri) const =0
assigns uninitialized adapted_request and url ALE components
void nonBlockingCheck(ACLCB *callback, void *callback_data)
Definition: Checklist.cc:237
AccessLogEntry::Pointer al
info for the future access.log, and external ACL
AnyP::UriScheme const & getScheme() const
Definition: Uri.h:67
void port(unsigned short p)
Definition: Uri.h:94
void host(const char *src)
Definition: Uri.cc:99
bool closest_only
Definition: CachePeer.h:90
int weight
Definition: CachePeer.h:125
struct CachePeer::@33 options
int basetime
Definition: CachePeer.h:126
char * host
Definition: CachePeer.h:40
CachePeer * next
Definition: CachePeer.h:153
Ip::Address in_addr
Definition: CachePeer.h:43
Cbc * valid() const
was set and is valid
Definition: CbcPointer.h:41
Cbc * get() const
a temporary valid raw Cbc pointer or NULL
Definition: CbcPointer.h:162
hier_code peerType
Definition: Connection.h:152
Ip::Address remote
Definition: Connection.h:149
Ip::Address local
Definition: Connection.h:146
void setPeer(CachePeer *p)
Definition: Connection.cc:133
struct ConnStateData::@42 pinning
CachePeer * pinnedPeer() const
Definition: client_side.h:204
bool peerAccessDenied
cache_peer_access denied pinned connection reuse
Definition: client_side.h:151
encapsulates DNS lookup results
Definition: LookupDetails.h:21
String error
error message for unsuccessful lookups; empty otherwise
Definition: LookupDetails.h:29
String dnsError
DNS lookup error message.
Definition: errorpage.h:179
FwdServer * next
Definition: peer_select.cc:62
CbcPointer< CachePeer > _peer
Definition: peer_select.cc:60
FwdServer(CachePeer *p, hier_code c)
Definition: peer_select.cc:54
hier_code code
Definition: peer_select.cc:61
MEMPROXY_CLASS(FwdServer)
struct HtcpReplyData::cto_t cto
int hit
Definition: htcp.h:29
void recordLookup(const Dns::LookupDetails &detail)
Definition: HttpRequest.cc:583
CbcPointer< ConnStateData > clientConnectionManager
Definition: HttpRequest.h:232
HttpRequestMethod method
Definition: HttpRequest.h:114
HierarchyLogEntry hier
Definition: HttpRequest.h:157
RequestFlags flags
Definition: HttpRequest.h:141
ConnStateData * pinnedConnection()
Definition: HttpRequest.cc:728
AnyP::Uri url
the request URI
Definition: HttpRequest.h:115
Ip::Address client_addr
Definition: HttpRequest.h:149
const SBuf & effectiveRequestUri() const
RFC 7230 section 5.5 - Effective Request URI.
Definition: HttpRequest.cc:747
bool isIPv4() const
Definition: Address.cc:158
bool isAnyAddr() const
Definition: Address.cc:170
unsigned short port() const
Definition: Address.cc:778
a helper class to report a selected destination (for debugging)
Definition: peer_select.cc:78
PeerSelectionDumper(const PeerSelector *const aSelector, const CachePeer *const aPeer, const hier_code aCode)
Definition: peer_select.cc:80
const CachePeer *const peer
successful selection info
Definition: peer_select.cc:84
const PeerSelector *const selector
selection parameters
Definition: peer_select.cc:83
const hier_code code
selection algorithm
Definition: peer_select.cc:85
Interface for those who need a list of peers to forward a request to.
bool subscribed
whether noteDestination() and noteDestinationsEnd() calls are allowed
void startSelectingDestinations(HttpRequest *request, const AccessLogEntry::Pointer &ale, StoreEntry *entry)
Definition: peer_select.cc:334
void monitor(PeerSelector *)
registers the given selector to be notified about the IPC ping timeout
Definition: peer_select.cc:191
static void NoteWaitOver(void *monitor)
PeerSelectorPingMonitor::noteWaitOver() wrapper.
Definition: peer_select.cc:141
void abortWaiting()
undoes an earlier startWaiting() call
Definition: peer_select.cc:158
WaitingPeerSelectorPosition npos()
Definition: peer_select.cc:117
void startWaiting()
schedules a single event to represent all waiting selectors
Definition: peer_select.cc:149
void forget(PeerSelector *)
removes a PeerSelector from the waiting list
Definition: peer_select.cc:207
void noteWaitOver()
calls back all ready PeerSelectors and continues to wait for others
Definition: peer_select.cc:167
WaitingPeerSelectors selectors
Definition: peer_select.cc:126
Ip::Address closest_parent_miss
bool selectionAborted()
Definition: peer_select.cc:400
void selectAllParents()
Adds alive parents. Used as a last resort for never_direct.
Definition: peer_select.cc:863
PeerSelectionInitiator * interestedInitiator()
void handlePingTimeout()
Definition: peer_select.cc:893
FwdServer * servers
a linked list of (unresolved) selected peers
HttpRequest * request
Initiator initiator_
recipient of the destinations we select; use interestedInitiator() to access
ErrorState * lastError
static void HandlePingTimeout(PeerSelector *)
called when the given selector should stop expecting ICP ping responses
Definition: peer_select.cc:912
virtual void noteIps(const Dns::CachedIps *ips, const Dns::LookupDetails &details) override
Definition: peer_select.cc:538
Acl::Answer always_direct
void selectMore()
a single selection loop iteration: attempts to add more destinations
Definition: peer_select.cc:607
void startPingWaiting()
switches into the PING_WAITING state (and associated timeout monitoring)
Definition: peer_select.cc:262
void handleIcpParentMiss(CachePeer *, icp_common_t *)
Definition: peer_select.cc:924
void cancelPingTimeoutMonitoring()
terminates ICP ping timeout monitoring
Definition: peer_select.cc:271
int checkNetdbDirect()
Definition: peer_select.cc:564
Ip::Address first_parent_miss
void handlePath(const Comm::ConnectionPointer &path, FwdServer &fs)
processes a newly discovered/finalized path
const SBuf url() const
AccessLogEntry::Pointer al
info for the future access.log entry
bool wantsMoreDestinations() const
void checkNeverDirectDone(const Acl::Answer answer)
Definition: peer_select.cc:342
void checkAlwaysDirectDone(const Acl::Answer answer)
Definition: peer_select.cc:370
void handleHtcpReply(CachePeer *, const peer_t, HtcpReplyData *)
ping_data ping
void handleIcpReply(CachePeer *, const peer_t, icp_common_t *header)
Definition: peer_select.cc:967
static ACLCB CheckNeverDirectDone
void addSelection(CachePeer *, const hier_code)
static ACLCB CheckAlwaysDirectDone
virtual void noteLookup(const Dns::LookupDetails &details) override
Definition: peer_select.cc:501
void selectSomeDirect()
Adds a "direct" entry if the request can be forwarded to the origin server.
Definition: peer_select.cc:816
StoreEntry * entry
virtual void noteIp(const Ip::Address &ip) override
Called when/if nbgethostbyname() discovers a new good IP address.
Definition: peer_select.cc:515
Acl::Answer never_direct
PeerSelector(PeerSelectionInitiator *)
void resolveSelected()
A single DNS resolution loop iteration: Converts selected FwdServer to IPs.
Definition: peer_select.cc:412
void selectSomeNeighbor()
Definition: peer_select.cc:729
void selectSomeParent()
Definition: peer_select.cc:829
CachePeer * hit
void selectPinned()
Selects a pinned connection if it exists, is valid, and is allowed.
Definition: peer_select.cc:703
virtual ~PeerSelector() override
Definition: peer_select.cc:230
void selectSomeNeighborReplies()
Selects a neighbor (parent or sibling) based on ICP/HTCP replies.
Definition: peer_select.cc:785
size_t foundPaths
number of unique destinations identified so far
void handleHtcpParentMiss(CachePeer *, HtcpReplyData *)
static IRCB HandlePingReply
ACLChecklist * acl_checklist
bool interceptTproxy
Set for requests handled by a "tproxy" port.
Definition: RequestFlags.h:66
bool hostVerified
Definition: RequestFlags.h:64
bool intercepted
Definition: RequestFlags.h:62
bool loopDetected
Definition: RequestFlags.h:36
bool spoofClientIp
Definition: RequestFlags.h:70
bool hierarchical
Definition: RequestFlags.h:34
Definition: SBuf.h:94
Comm::ConnectionPointer clientConnection
Definition: Server.h:98
int nonhierarchical_direct
Definition: SquidConfig.h:297
struct SquidConfig::@111 onoff
int client_dst_passthru
Definition: SquidConfig.h:336
int forward_max_tries
Definition: SquidConfig.h:349
struct SquidConfig::@112 accessList
int minDirectRtt
Definition: SquidConfig.h:258
int prefer_direct
Definition: SquidConfig.h:296
CachePeer * peers
Definition: SquidConfig.h:245
int minDirectHops
Definition: SquidConfig.h:257
acl_access * NeverDirect
Definition: SquidConfig.h:361
acl_access * AlwaysDirect
Definition: SquidConfig.h:362
uint16_t flags
Definition: Store.h:232
int unlock(const char *context)
Definition: store.cc:442
const char * url() const
Definition: store.cc:1533
ping_status_t ping_status
Definition: Store.h:242
uint32_t flags
Definition: ICP.h:45
icp_opcode getOpCode() const
Definition: icp_v2.cc:128
uint32_t pad
Definition: ICP.h:46
int timedout
Definition: PingData.h:42
struct timeval start
Definition: PingData.h:35
int p_rtt
Definition: PingData.h:44
int n_recv
Definition: PingData.h:39
int timeout
Definition: PingData.h:41
WaitingPeerSelectorPosition monitorRegistration
maintained by PeerSelectorPingMonitor
Definition: PingData.h:49
struct timeval stop
Definition: PingData.h:37
timeval deadline() const
int n_replies_expected
Definition: PingData.h:40
int w_rtt
Definition: PingData.h:43
int n_sent
Definition: PingData.h:38
#define DBG_IMPORTANT
Definition: Stream.h:41
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:196
#define DBG_CRITICAL
Definition: Stream.h:40
#define DIRECT_NO
Definition: defines.h:49
#define DIRECT_MAYBE
Definition: defines.h:50
#define ICP_FLAG_SRC_RTT
Definition: defines.h:41
#define DIRECT_UNKNOWN
Definition: defines.h:48
#define EBIT_TEST(flag, bit)
Definition: defines.h:69
#define DIRECT_YES
Definition: defines.h:51
@ PING_WAITING
Sent ICP queries to peers and still awaiting responses.
Definition: enums.h:43
@ PING_NONE
Has not considered whether to send ICP queries to peers yet.
Definition: enums.h:41
@ PING_DONE
Definition: enums.h:46
peer_t
Definition: enums.h:27
@ PEER_PARENT
Definition: enums.h:30
@ PEER_NONE
Definition: enums.h:28
@ KEY_PRIVATE
Definition: enums.h:102
@ ERR_DNS_FAIL
Definition: forward.h:35
int type
Definition: errorpage.cc:152
void eventDelete(EVH *func, void *arg)
Definition: event.cc:127
void eventAdd(const char *name, EVH *func, void *arg, double when, int weight, bool cbdata)
Definition: event.cc:107
int neighbors_do_private_keys
@ ACCESS_AUTH_REQUIRED
Definition: Acl.h:114
@ ACCESS_DENIED
Definition: Acl.h:109
@ ACCESS_ALLOWED
Definition: Acl.h:110
@ ACCESS_DUNNO
Definition: Acl.h:111
icp_opcode
Definition: icp_opcode.h:13
@ ICP_DECHO
Definition: icp_opcode.h:26
@ ICP_MISS
Definition: icp_opcode.h:18
@ ICP_HIT
Definition: icp_opcode.h:17
const char * hier_code_str[]
hier_code
Definition: hier_code.h:12
@ CARP
Definition: hier_code.h:31
@ SOURCEHASH_PARENT
Definition: hier_code.h:34
@ CD_SIBLING_HIT
Definition: hier_code.h:29
@ CD_PARENT_HIT
Definition: hier_code.h:28
@ HIER_NONE
Definition: hier_code.h:13
@ PARENT_HIT
Definition: hier_code.h:16
@ CLOSEST_PARENT
Definition: hier_code.h:22
@ SIBLING_HIT
Definition: hier_code.h:15
@ DEFAULT_PARENT
Definition: hier_code.h:17
@ CLOSEST_DIRECT
Definition: hier_code.h:23
@ USERHASH_PARENT
Definition: hier_code.h:33
@ PINNED
Definition: hier_code.h:35
@ FIRST_PARENT_MISS
Definition: hier_code.h:20
@ ROUNDROBIN_PARENT
Definition: hier_code.h:26
@ FIRSTUP_PARENT
Definition: hier_code.h:19
@ CLOSEST_PARENT_MISS
Definition: hier_code.h:21
@ ANY_OLD_PARENT
Definition: hier_code.h:32
@ ORIGINAL_DST
Definition: hier_code.h:36
@ HIER_DIRECT
Definition: hier_code.h:14
unsigned char code
Definition: html_quote.c:20
void HTTPMSGUNLOCK(M *&a)
Definition: Message.h:149
void HTTPMSGLOCK(Http::Message *a)
Definition: Message.h:160
const char * icp_opcode_str[]
ProtocolType
Definition: ProtocolType.h:23
@ PROTO_HTCP
Definition: ProtocolType.h:34
@ PROTO_ICP
Definition: ProtocolType.h:32
@ PROTO_WAIS
Definition: ProtocolType.h:30
void nbgethostbyname(const char *name, const CbcPointer< IpReceiver > &receiver)
initiate an (often) asynchronous DNS lookup; the receiver gets the results
Definition: ipcache.cc:606
@ scServiceUnavailable
Definition: StatusCode.h:74
code related to Squid Instance and PID file management
Definition: Instance.h:17
SSL Connection
Definition: Session.h:45
void peerNoteDigestLookup(HttpRequest *request, CachePeer *p, lookup_t lookup)
Definition: neighbors.cc:872
CachePeer * getFirstUpParent(PeerSelector *ps)
Definition: neighbors.cc:288
CachePeer * whichPeer(const Ip::Address &from)
Definition: neighbors.cc:96
int neighborsCount(PeerSelector *ps)
Definition: neighbors.cc:273
int peerHTTPOkay(const CachePeer *p, PeerSelector *ps)
Definition: neighbors.cc:258
CachePeer * getDefaultParent(PeerSelector *ps)
Definition: neighbors.cc:474
CachePeer * getRoundRobinParent(PeerSelector *ps)
Definition: neighbors.cc:313
peer_t neighborType(const CachePeer *p, const AnyP::Uri &url)
Definition: neighbors.cc:115
int neighborsUdpPing(HttpRequest *request, StoreEntry *entry, IRCB *callback, PeerSelector *ps, int *exprep, int *timeout)
Definition: neighbors.cc:595
CachePeer * neighborsDigestSelect(PeerSelector *ps)
Definition: neighbors.cc:805
lookup_t peerDigestLookup(CachePeer *p, PeerSelector *ps)
Definition: neighbors.cc:759
CachePeer * getWeightedRoundRobinParent(PeerSelector *ps)
Definition: neighbors.cc:355
int netdbHostHops(const char *host)
Definition: net_db.cc:1007
int netdbHostRtt(const char *host)
Definition: net_db.cc:1023
void netdbUpdatePeer(const AnyP::Uri &url, CachePeer *e, int irtt, int ihops)
Definition: net_db.cc:1065
CachePeer * netdbClosestParent(PeerSelector *ps)
Definition: net_db.cc:1300
int timeouts
Definition: peer_select.cc:66
InstanceIdDefinitions(PeerSelector, "PeerSelector")
static int peerSelectIcpPing(PeerSelector *ps, int direct, StoreEntry *entry)
Definition: peer_select.cc:277
void peerSelectInit(void)
Definition: peer_select.cc:918
static struct @87 PeerStats
bool peerAllowedToUse(const CachePeer *, PeerSelector *)
Definition: neighbors.cc:138
static const char * DirectStr[]
Definition: peer_select.cc:69
static void peerSelect(PeerSelectionInitiator *initiator, HttpRequest *request, AccessLogEntry::Pointer const &al, StoreEntry *entry)
Definition: peer_select.cc:303
static std::ostream & operator<<(std::ostream &os, const PeerSelectionDumper &fsd)
prints PeerSelectionDumper (for debugging)
Definition: peer_select.cc:92
static PeerSelectorPingMonitor & PingMonitor()
monitors all PeerSelector ICP ping timeouts
Definition: peer_select.cc:131
CachePeer * peerSourceHashSelectParent(PeerSelector *ps)
CachePeer * peerUserHashSelectParent(PeerSelector *ps)
char method[16]
Definition: tcp-banger2.c:115
int unsigned int
Definition: stub_fd.cc:19
time_t struct timeval struct timeval struct timeval struct timeval const struct timeval const &STUB void tvAdd(struct timeval &, struct timeval const &, struct timeval const &) STUB void tvAssignAdd(struct timeval &
struct _request * request(char *urlin)
Definition: tcp-banger2.c:291
double tvSubDsec(struct timeval t1, struct timeval t2)
Definition: gadgets.cc:44
struct timeval current_time
the current UNIX time in timeval {seconds, microseconds} format
Definition: gadgets.cc:17
int tvSubMsec(struct timeval t1, struct timeval t2)
Definition: gadgets.cc:51

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors