peer_select.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2018 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"
13 #include "base/InstanceId.h"
14 #include "CachePeer.h"
15 #include "carp.h"
16 #include "client_side.h"
17 #include "dns/LookupDetails.h"
18 #include "errorpage.h"
19 #include "event.h"
20 #include "FwdState.h"
21 #include "globals.h"
22 #include "hier_code.h"
23 #include "htcp.h"
24 #include "http/Stream.h"
25 #include "HttpRequest.h"
26 #include "icmp/net_db.h"
27 #include "ICP.h"
28 #include "ip/tools.h"
29 #include "ipcache.h"
30 #include "neighbors.h"
31 #include "peer_sourcehash.h"
32 #include "peer_userhash.h"
33 #include "PeerSelectState.h"
34 #include "SquidConfig.h"
35 #include "SquidTime.h"
36 #include "Store.h"
37 #include "URL.h"
38 
48 class FwdServer
49 {
51 
52 public:
54  _peer(p),
55  code(c),
56  next(nullptr)
57  {}
58 
59  CbcPointer<CachePeer> _peer; /* NULL --> origin server */
62 };
63 
64 static struct {
65  int timeouts;
66 } PeerStats;
67 
68 static const char *DirectStr[] = {
69  "DIRECT_UNKNOWN",
70  "DIRECT_NO",
71  "DIRECT_MAYBE",
72  "DIRECT_YES"
73 };
74 
77 {
78 public:
79  PeerSelectionDumper(const PeerSelector * const aSelector, const CachePeer * const aPeer, const hier_code aCode):
80  selector(aSelector), peer(aPeer), code(aCode) {}
81 
82  const PeerSelector * const selector;
83  const CachePeer * const peer;
84  const hier_code code;
85 };
86 
88 
90 static std::ostream &
91 operator <<(std::ostream &os, const PeerSelectionDumper &fsd)
92 {
93  os << hier_code_str[fsd.code];
94 
95  if (fsd.peer)
96  os << '/' << fsd.peer->host;
97  else if (fsd.selector) // useful for DIRECT and gone PINNED destinations
98  os << '#' << fsd.selector->request->url.host();
99 
100  return os;
101 }
102 
104 {
105  while (servers) {
106  FwdServer *next = servers->next;
107  delete servers;
108  servers = next;
109  }
110 
111  if (entry) {
112  debugs(44, 3, entry->url());
113 
116 
118  }
119 
120  if (acl_checklist) {
121  debugs(44, DBG_IMPORTANT, "BUG: peer selector gone while waiting for a slow ACL");
122  delete acl_checklist;
123  }
124 
126 
127  if (entry) {
129  entry->unlock("peerSelect");
130  entry = NULL;
131  }
132 
133  delete lastError;
134 }
135 
136 static int
137 peerSelectIcpPing(PeerSelector *ps, int direct, StoreEntry * entry)
138 {
139  assert(ps);
140  HttpRequest *request = ps->request;
141 
142  int n;
143  assert(entry);
144  assert(entry->ping_status == PING_NONE);
145  assert(direct != DIRECT_YES);
146  debugs(44, 3, entry->url());
147 
148  if (!request->flags.hierarchical && direct != DIRECT_NO)
149  return 0;
150 
152  if (direct != DIRECT_NO)
153  return 0;
154 
155  n = neighborsCount(ps);
156 
157  debugs(44, 3, "counted " << n << " neighbors");
158 
159  return n;
160 }
161 
162 static void
165  AccessLogEntry::Pointer const &al,
166  StoreEntry * entry)
167 {
168  if (entry)
169  debugs(44, 3, *entry << ' ' << entry->url());
170  else
171  debugs(44, 3, request->method);
172 
173  const auto selector = new PeerSelector(initiator);
174 
175  selector->request = request;
176  HTTPMSGLOCK(selector->request);
177  selector->al = al;
178 
179  selector->entry = entry;
180 
181 #if USE_CACHE_DIGESTS
182 
184 
185 #endif
186 
187  if (selector->entry)
188  selector->entry->lock("peerSelect");
189 
190  selector->selectMore();
191 }
192 
193 void
195 {
196  subscribed = true;
197  peerSelect(this, request, ale, entry);
198  // and wait for noteDestination() and/or noteDestinationsEnd() calls
199 }
200 
201 void
203 {
204  acl_checklist = nullptr;
205  debugs(44, 3, answer);
206  never_direct = answer;
207  switch (answer) {
208  case ACCESS_ALLOWED:
210  direct = DIRECT_NO;
211  debugs(44, 3, "direct = " << DirectStr[direct] << " (never_direct allow)");
212  break;
213  case ACCESS_DENIED: // not relevant.
214  case ACCESS_DUNNO: // not relevant.
215  break;
217  debugs(44, DBG_IMPORTANT, "WARNING: never_direct resulted in " << answer << ". Username ACLs are not reliable here.");
218  break;
219  }
220  selectMore();
221 }
222 
223 void
225 {
226  static_cast<PeerSelector*>(data)->checkNeverDirectDone(answer);
227 }
228 
229 void
231 {
232  acl_checklist = nullptr;
233  debugs(44, 3, answer);
234  always_direct = answer;
235  switch (answer) {
236  case ACCESS_ALLOWED:
238  direct = DIRECT_YES;
239  debugs(44, 3, "direct = " << DirectStr[direct] << " (always_direct allow)");
240  break;
241  case ACCESS_DENIED: // not relevant.
242  case ACCESS_DUNNO: // not relevant.
243  break;
245  debugs(44, DBG_IMPORTANT, "WARNING: always_direct resulted in " << answer << ". Username ACLs are not reliable here.");
246  break;
247  }
248  selectMore();
249 }
250 
251 void
253 {
254  static_cast<PeerSelector*>(data)->checkAlwaysDirectDone(answer);
255 }
256 
259 bool
261 {
262  if (interestedInitiator())
263  return false;
264 
265  debugs(44, 3, "Aborting peer selection: Initiator gone or lost interest.");
266  delete this;
267  return true;
268 }
269 
271 void
273 {
274  if (selectionAborted())
275  return;
276 
277  FwdServer *fs = servers;
278 
279  // Bug 3243: CVE 2009-0801
280  // Bypass of browser same-origin access control in intercepted communication
281  // To resolve this we must use only the original client destination when going DIRECT
282  // on intercepted traffic which failed Host verification
283  const HttpRequest *req = request;
284  const bool isIntercepted = !req->flags.redirected &&
285  (req->flags.intercepted || req->flags.interceptTproxy);
286  const bool useOriginalDst = Config.onoff.client_dst_passthru || !req->flags.hostVerified;
287  const bool choseDirect = fs && fs->code == HIER_DIRECT;
288  if (isIntercepted && useOriginalDst && choseDirect) {
289  // check the client is still around before using any of its details
290  if (req->clientConnectionManager.valid()) {
291  // construct a "result" adding the ORIGINAL_DST to the set instead of DIRECT
294  fs->code = ORIGINAL_DST; // fs->code is DIRECT. This fixes the display.
295  handlePath(p, *fs);
296  }
297 
298  // clear the used fs and continue
299  servers = fs->next;
300  delete fs;
301  resolveSelected();
302  return;
303  }
304 
305  // convert the list of FwdServer destinations into destinations IP addresses
306  if (fs && wantsMoreDestinations()) {
307  // send the next one off for DNS lookup.
308  const char *host = fs->_peer.valid() ? fs->_peer->host : request->url.host();
309  debugs(44, 2, "Find IP destination for: " << url() << "' via " << host);
310  Dns::nbgethostbyname(host, this);
311  return;
312  }
313 
314  // Bug 3605: clear any extra listed FwdServer destinations, when the options exceeds max_foward_tries.
315  // due to the allocation method of fs, we must deallocate each manually.
316  // TODO: use a std::list so we can get the size and abort adding whenever the selection loops reach Config.forward_max_tries
317  if (fs) {
318  assert(fs == servers);
319  while (fs) {
320  servers = fs->next;
321  delete fs;
322  fs = servers;
323  }
324  }
325 
326  // done with DNS lookups. pass back to caller
327 
328  debugs(44, 2, id << " found all " << foundPaths << " destinations for " << url());
329  debugs(44, 2, " always_direct = " << always_direct);
330  debugs(44, 2, " never_direct = " << never_direct);
331  debugs(44, 2, " timedout = " << ping.timedout);
332 
334  request->hier.ping = ping; // final result
335 
336  if (lastError && foundPaths) {
337  // nobody cares about errors if we found destinations despite them
338  debugs(44, 3, "forgetting the last error");
339  delete lastError;
340  lastError = nullptr;
341  }
342 
343  if (const auto initiator = interestedInitiator())
344  initiator->noteDestinationsEnd(lastError);
345  lastError = nullptr; // initiator owns the ErrorState object now
346  delete this;
347 }
348 
349 void
351 {
352  /* ignore lookup delays that occurred after the initiator moved on */
353 
354  if (selectionAborted())
355  return;
356 
357  if (!wantsMoreDestinations())
358  return;
359 
360  request->recordLookup(details);
361 }
362 
363 void
365 {
366  if (selectionAborted())
367  return;
368 
369  if (!wantsMoreDestinations())
370  return;
371 
372  const auto peer = servers->_peer.valid();
373 
374  // for TPROXY spoofing, we must skip unusable addresses
375  if (request->flags.spoofClientIp && !(peer && peer->options.no_tproxy) ) {
376  if (ip.isIPv4() != request->client_addr.isIPv4())
377  return; // cannot spoof the client address on this link
378  }
379 
381  p->remote = ip;
382  p->remote.port(peer ? peer->http_port : request->url.port());
383  handlePath(p, *servers);
384 }
385 
386 void
388 {
389  if (selectionAborted())
390  return;
391 
392  FwdServer *fs = servers;
393  if (!ia) {
394  debugs(44, 3, "Unknown host: " << (fs->_peer.valid() ? fs->_peer->host : request->url.host()));
395  // discard any previous error.
396  delete lastError;
397  lastError = NULL;
398  if (fs->code == HIER_DIRECT) {
400  lastError->dnsError = details.error;
401  }
402  }
403  // else noteIp() calls have already processed all IPs in *ia
404 
405  servers = fs->next;
406  delete fs;
407 
408  // continue resolving selected peers
409  resolveSelected();
410 }
411 
412 int
414 {
415 #if USE_ICMP
416  CachePeer *p;
417  int myrtt;
418  int myhops;
419 
420  if (direct == DIRECT_NO)
421  return 0;
422 
423  /* base lookup on RTT and Hops if ICMP NetDB is enabled. */
424 
425  myrtt = netdbHostRtt(request->url.host());
426  debugs(44, 3, "MY RTT = " << myrtt << " msec");
427  debugs(44, 3, "minimum_direct_rtt = " << Config.minDirectRtt << " msec");
428 
429  if (myrtt && myrtt <= Config.minDirectRtt)
430  return 1;
431 
432  myhops = netdbHostHops(request->url.host());
433 
434  debugs(44, 3, "MY hops = " << myhops);
435  debugs(44, 3, "minimum_direct_hops = " << Config.minDirectHops);
436 
437  if (myhops && myhops <= Config.minDirectHops)
438  return 1;
439 
441 
442  if (p == NULL)
443  return 0;
444 
445  debugs(44, 3, "closest_parent_miss RTT = " << ping.p_rtt << " msec");
446 
447  if (myrtt && myrtt <= ping.p_rtt)
448  return 1;
449 
450 #endif /* USE_ICMP */
451 
452  return 0;
453 }
454 
455 void
457 {
458  if (selectionAborted())
459  return;
460 
461  debugs(44, 3, request->method << ' ' << request->url.host());
462 
464  if (direct == DIRECT_UNKNOWN) {
465  if (always_direct == ACCESS_DUNNO) {
466  debugs(44, 3, "direct = " << DirectStr[direct] << " (always_direct to be checked)");
469  ch->al = al;
470  acl_checklist = ch;
471  acl_checklist->syncAle(request, nullptr);
473  return;
474  } else if (never_direct == ACCESS_DUNNO) {
475  debugs(44, 3, "direct = " << DirectStr[direct] << " (never_direct to be checked)");
478  ch->al = al;
479  acl_checklist = ch;
480  acl_checklist->syncAle(request, nullptr);
482  return;
483  } else if (request->flags.noDirect) {
485  direct = DIRECT_NO;
486  debugs(44, 3, "direct = " << DirectStr[direct] << " (forced non-direct)");
487  } else if (request->flags.loopDetected) {
489  direct = DIRECT_YES;
490  debugs(44, 3, "direct = " << DirectStr[direct] << " (forwarding loop detected)");
491  } else if (checkNetdbDirect()) {
492  direct = DIRECT_YES;
493  debugs(44, 3, "direct = " << DirectStr[direct] << " (checkNetdbDirect)");
494  } else {
496  debugs(44, 3, "direct = " << DirectStr[direct] << " (default)");
497  }
498 
499  debugs(44, 3, "direct = " << DirectStr[direct]);
500  }
501 
502  if (!entry || entry->ping_status == PING_NONE)
503  selectPinned();
504  if (entry == NULL) {
505  (void) 0;
506  } else if (entry->ping_status == PING_NONE) {
508 
510  return;
511  } else if (entry->ping_status == PING_WAITING) {
514  }
515 
516  switch (direct) {
517 
518  case DIRECT_YES:
520  break;
521 
522  case DIRECT_NO:
525  break;
526 
527  default:
528 
531 
535  }
536 
539 
540  break;
541  }
542 
543  // end peer selection; start resolving selected peers
544  resolveSelected();
545 }
546 
547 bool peerAllowedToUse(const CachePeer *, PeerSelector*);
548 
550 void
552 {
553  // TODO: Avoid all repeated calls. Relying on PING_DONE is not enough.
554  if (!request->pinnedConnection())
555  return;
558  const bool usePinned = pear ? peerAllowedToUse(pear, this) : (direct != DIRECT_NO);
559  if (usePinned) {
560  addSelection(pear, PINNED);
561  if (entry)
562  entry->ping_status = PING_DONE; // skip ICP
563  }
564  }
565  // If the pinned connection is prohibited (for this request) or gone, then
566  // the initiator must decide whether it is OK to open a new one instead.
567 }
568 
577 void
579 {
580  CachePeer *p;
583 
584  if (direct == DIRECT_YES) {
586  return;
587  }
588 
589 #if USE_CACHE_DIGESTS
590  if ((p = neighborsDigestSelect(this))) {
591  if (neighborType(p, request->url) == PEER_PARENT)
592  code = CD_PARENT_HIT;
593  else
594  code = CD_SIBLING_HIT;
595  } else
596 #endif
597  if ((p = netdbClosestParent(this))) {
598  code = CLOSEST_PARENT;
599  } else if (peerSelectIcpPing(this, direct, entry)) {
600  debugs(44, 3, "Doing ICP pings");
603  entry,
605  this,
607  &ping.timeout);
608 
609  if (ping.n_sent == 0)
610  debugs(44, DBG_CRITICAL, "WARNING: neighborsUdpPing returned 0");
611  debugs(44, 3, ping.n_replies_expected <<
612  " ICP replies expected, RTT " << ping.timeout <<
613  " msec");
614 
615  if (ping.n_replies_expected > 0) {
617  eventAdd("PeerSelector::HandlePingTimeout",
619  this,
620  0.001 * ping.timeout,
621  0);
622  return;
623  }
624  }
625 
626  if (code != HIER_NONE) {
627  assert(p);
628  addSelection(p, code);
629  }
630 
632 }
633 
635 void
637 {
638  CachePeer *p = NULL;
642 
643  if (checkNetdbDirect()) {
644  code = CLOSEST_DIRECT;
645  addSelection(nullptr, code);
646  return;
647  }
648 
649  if ((p = hit)) {
651  } else {
654  code = CLOSEST_PARENT_MISS;
655  } else if (!first_parent_miss.isAnyAddr()) {
657  code = FIRST_PARENT_MISS;
658  }
659  }
660  if (p && code != HIER_NONE) {
661  addSelection(p, code);
662  }
663 }
664 
666 void
668 {
669  if (direct == DIRECT_NO)
670  return;
671 
672  /* WAIS is not implemented natively */
674  return;
675 
676  addSelection(nullptr, HIER_DIRECT);
677 }
678 
679 void
681 {
682  CachePeer *p;
684  debugs(44, 3, request->method << ' ' << request->url.host());
685 
686  if (direct == DIRECT_YES)
687  return;
688 
689  if ((p = peerSourceHashSelectParent(this))) {
690  code = SOURCEHASH_PARENT;
691 #if USE_AUTH
692  } else if ((p = peerUserHashSelectParent(this))) {
693  code = USERHASH_PARENT;
694 #endif
695  } else if ((p = carpSelectParent(this))) {
696  code = CARP;
697  } else if ((p = getRoundRobinParent(this))) {
698  code = ROUNDROBIN_PARENT;
699  } else if ((p = getWeightedRoundRobinParent(this))) {
700  code = ROUNDROBIN_PARENT;
701  } else if ((p = getFirstUpParent(this))) {
702  code = FIRSTUP_PARENT;
703  } else if ((p = getDefaultParent(this))) {
704  code = DEFAULT_PARENT;
705  }
706 
707  if (code != HIER_NONE) {
708  addSelection(p, code);
709  }
710 }
711 
713 void
715 {
716  CachePeer *p;
717  /* Add all alive parents */
718 
719  for (p = Config.peers; p; p = p->next) {
720  /* XXX: neighbors.c lacks a public interface for enumerating
721  * parents to a request so we have to dig some here..
722  */
723 
724  if (neighborType(p, request->url) != PEER_PARENT)
725  continue;
726 
727  if (!peerHTTPOkay(p, this))
728  continue;
729 
731  }
732 
733  /* XXX: should add dead parents here, but it is currently
734  * not possible to find out which parents are dead or which
735  * simply are not configured to handle the request.
736  */
737  /* Add default parent as a last resort */
738  if ((p = getDefaultParent(this))) {
740  }
741 }
742 
743 void
745 {
746  debugs(44, 3, url());
747 
748  if (entry)
750 
751  if (selectionAborted())
752  return;
753 
754  ++PeerStats.timeouts;
755  ping.timedout = 1;
756  selectMore();
757 }
758 
759 void
761 {
762  static_cast<PeerSelector*>(data)->handlePingTimeout();
763 }
764 
765 void
767 {
768  memset(&PeerStats, '\0', sizeof(PeerStats));
769 }
770 
771 void
773 {
774  int rtt;
775 
776 #if USE_ICMP
777  if (Config.onoff.query_icmp) {
778  if (header->flags & ICP_FLAG_SRC_RTT) {
779  rtt = header->pad & 0xFFFF;
780  int hops = (header->pad >> 16) & 0xFFFF;
781 
782  if (rtt > 0 && rtt < 0xFFFF)
783  netdbUpdatePeer(request->url, p, rtt, hops);
784 
785  if (rtt && (ping.p_rtt == 0 || rtt < ping.p_rtt)) {
787  ping.p_rtt = rtt;
788  }
789  }
790  }
791 #endif /* USE_ICMP */
792 
793  /* if closest-only is set, then don't allow FIRST_PARENT_MISS */
794  if (p->options.closest_only)
795  return;
796 
797  /* set FIRST_MISS if there is no CLOSEST parent */
799  return;
800 
801  rtt = (tvSubMsec(ping.start, current_time) - p->basetime) / p->weight;
802 
803  if (rtt < 1)
804  rtt = 1;
805 
806  if (first_parent_miss.isAnyAddr() || rtt < ping.w_rtt) {
808  ping.w_rtt = rtt;
809  }
810 }
811 
812 void
814 {
815  icp_opcode op = header->getOpCode();
816  debugs(44, 3, icp_opcode_str[op] << ' ' << url());
817 #if USE_CACHE_DIGESTS && 0
818  /* do cd lookup to count false misses */
819 
820  if (p && request)
822  peerDigestLookup(p, this));
823 
824 #endif
825 
826  ++ping.n_recv;
827 
828  if (op == ICP_MISS || op == ICP_DECHO) {
829  if (type == PEER_PARENT)
830  handleIcpParentMiss(p, header);
831  } else if (op == ICP_HIT) {
832  hit = p;
833  hit_type = type;
834  selectMore();
835  return;
836  }
837 
839  return;
840 
841  selectMore();
842 }
843 
844 #if USE_HTCP
845 void
847 {
848  debugs(44, 3, (htcp->hit ? "HIT" : "MISS") << ' ' << url());
849  ++ping.n_recv;
850 
851  if (htcp->hit) {
852  hit = p;
853  hit_type = type;
854  selectMore();
855  return;
856  }
857 
858  if (type == PEER_PARENT)
859  handleHtcpParentMiss(p, htcp);
860 
862  return;
863 
864  selectMore();
865 }
866 
867 void
869 {
870  int rtt;
871 
872 #if USE_ICMP
873  if (Config.onoff.query_icmp) {
874  if (htcp->cto.rtt > 0) {
875  rtt = (int) htcp->cto.rtt * 1000;
876  int hops = (int) htcp->cto.hops * 1000;
877  netdbUpdatePeer(request->url, p, rtt, hops);
878 
879  if (rtt && (ping.p_rtt == 0 || rtt < ping.p_rtt)) {
881  ping.p_rtt = rtt;
882  }
883  }
884  }
885 #endif /* USE_ICMP */
886 
887  /* if closest-only is set, then don't allow FIRST_PARENT_MISS */
888  if (p->options.closest_only)
889  return;
890 
891  /* set FIRST_MISS if there is no CLOSEST parent */
893  return;
894 
895  rtt = (tvSubMsec(ping.start, current_time) - p->basetime) / p->weight;
896 
897  if (rtt < 1)
898  rtt = 1;
899 
900  if (first_parent_miss.isAnyAddr() || rtt < ping.w_rtt) {
902  ping.w_rtt = rtt;
903  }
904 }
905 
906 #endif
907 
908 void
909 PeerSelector::HandlePingReply(CachePeer * p, peer_t type, AnyP::ProtocolType proto, void *pingdata, void *data)
910 {
911  if (proto == AnyP::PROTO_ICP)
912  static_cast<PeerSelector*>(data)->handleIcpReply(p, type, static_cast<icp_common_t*>(pingdata));
913 
914 #if USE_HTCP
915 
916  else if (proto == AnyP::PROTO_HTCP)
917  static_cast<PeerSelector*>(data)->handleHtcpReply(p, type, static_cast<HtcpReplyData*>(pingdata));
918 
919 #endif
920 
921  else
922  debugs(44, DBG_IMPORTANT, "ERROR: ignoring an ICP reply with unknown protocol " << proto);
923 }
924 
925 void
927 {
928  // Find the end of the servers list. Bail on a duplicate destination.
929  auto **serversTail = &servers;
930  while (const auto server = *serversTail) {
931  // There can be at most one PINNED destination.
932  // Non-PINNED destinations are uniquely identified by their CachePeer
933  // (even though a DIRECT destination might match a cache_peer address).
934  const bool duplicate = (server->code == PINNED) ?
935  (code == PINNED) : (server->_peer == peer);
936  if (duplicate) {
937  debugs(44, 3, "skipping " << PeerSelectionDumper(this, peer, code) <<
938  "; have " << PeerSelectionDumper(this, server->_peer.get(), server->code));
939  return;
940  }
941  serversTail = &server->next;
942  }
943 
944  debugs(44, 3, "adding " << PeerSelectionDumper(this, peer, code));
945  *serversTail = new FwdServer(peer, code);
946 }
947 
949  request(nullptr),
950  entry (NULL),
951  always_direct(Config.accessList.AlwaysDirect?ACCESS_DUNNO:ACCESS_DENIED),
952  never_direct(Config.accessList.NeverDirect?ACCESS_DUNNO:ACCESS_DENIED),
953  direct(DIRECT_UNKNOWN),
954  lastError(NULL),
955  servers (NULL),
956  first_parent_miss(),
957  closest_parent_miss(),
958  hit(NULL),
959  hit_type(PEER_NONE),
960  acl_checklist (NULL),
961  initiator_(initiator)
962 {
963  ; // no local defaults.
964 }
965 
966 const SBuf
968 {
969  if (entry)
970  return SBuf(entry->url());
971 
972  if (request)
973  return request->effectiveRequestUri();
974 
975  static const SBuf noUrl("[no URL]");
976  return noUrl;
977 }
978 
982 {
983  const auto initiator = initiator_.valid();
984 
985  if (!initiator) {
986  debugs(44, 3, id << " initiator gone");
987  return nullptr;
988  }
989 
990  if (!initiator->subscribed) {
991  debugs(44, 3, id << " initiator lost interest");
992  return nullptr;
993  }
994 
995  debugs(44, 7, id);
996  return initiator;
997 }
998 
999 bool
1001  const auto maxCount = Config.forward_max_tries;
1002  return maxCount >= 0 && foundPaths <
1003  static_cast<std::make_unsigned<decltype(maxCount)>::type>(maxCount);
1004 }
1005 
1006 void
1008 {
1009  ++foundPaths;
1010 
1011  path->peerType = fs.code;
1012  path->setPeer(fs._peer.get());
1013 
1014  // check for a configured outgoing address for this destination...
1015  getOutgoingAddress(request, path);
1016 
1017  request->hier.ping = ping; // may be updated later
1018 
1019  debugs(44, 2, id << " found " << path << ", destination #" << foundPaths << " for " << url());
1020  debugs(44, 2, " always_direct = " << always_direct);
1021  debugs(44, 2, " never_direct = " << never_direct);
1022  debugs(44, 2, " timedout = " << ping.timedout);
1023 
1024  if (const auto initiator = interestedInitiator())
1025  initiator->noteDestination(path);
1026 }
1027 
1028 InstanceIdDefinitions(PeerSelector, "PeerSelector");
1029 
1031  n_sent(0),
1032  n_recv(0),
1033  n_replies_expected(0),
1034  timeout(0),
1035  timedout(0),
1036  w_rtt(0),
1037  p_rtt(0)
1038 {
1039  start.tv_sec = 0;
1040  start.tv_usec = 0;
1041  stop.tv_sec = 0;
1042  stop.tv_usec = 0;
1043 }
1044 
virtual void noteIps(const Dns::CachedIps *ips, const Dns::LookupDetails &details) override
Definition: peer_select.cc:387
void recordLookup(const Dns::LookupDetails &detail)
Definition: HttpRequest.cc:587
void nonBlockingCheck(ACLCB *callback, void *callback_data)
Definition: Checklist.cc:238
void getOutgoingAddress(HttpRequest *request, Comm::ConnectionPointer conn)
Definition: FwdState.cc:1298
HierarchyLogEntry hier
Definition: HttpRequest.h:145
#define DIRECT_YES
Definition: defines.h:83
bool interceptTproxy
Set for requests handled by a "tproxy" port.
Definition: RequestFlags.h:68
void peerSelectInit(void)
Definition: peer_select.cc:766
CachePeer * getWeightedRoundRobinParent(PeerSelector *ps)
Definition: neighbors.cc:350
HttpRequest * request
ConnStateData * pinnedConnection()
Definition: HttpRequest.cc:654
hier_code code
Definition: peer_select.cc:60
int timeout
Definition: PingData.h:24
size_t foundPaths
number of unique destinations identified so far
#define assert(EX)
Definition: assert.h:17
int n_recv
Definition: PingData.h:22
int timedout
Definition: PingData.h:25
int checkNetdbDirect()
Definition: peer_select.cc:413
bool hierarchical
Definition: RequestFlags.h:34
void checkNeverDirectDone(const allow_t answer)
Definition: peer_select.cc:202
int neighbors_do_private_keys
virtual void noteLookup(const Dns::LookupDetails &details) override
Definition: peer_select.cc:350
ErrorState * lastError
void handleHtcpParentMiss(CachePeer *, HtcpReplyData *)
Definition: peer_select.cc:868
#define MEMPROXY_CLASS(CLASS)
int unlock(const char *context)
Definition: store.cc:460
CachePeer * carpSelectParent(PeerSelector *ps)
Definition: carp.cc:147
CachePeer * netdbClosestParent(PeerSelector *ps)
Definition: net_db.cc:1308
CachePeer * next
Definition: CachePeer.h:154
ping_data ping
bool loopDetected
Definition: RequestFlags.h:36
void resolveSelected()
A single DNS resolution loop iteration: Converts selected FwdServer to IPs.
Definition: peer_select.cc:272
int type
Definition: errorpage.cc:79
Definition: Acl.h:113
Definition: SBuf.h:86
struct SquidConfig::@113 onoff
virtual ~PeerSelector() override
Definition: peer_select.cc:103
HttpRequestMethod method
Definition: HttpRequest.h:102
int prefer_direct
Definition: SquidConfig.h:296
CachePeer * peers
Definition: SquidConfig.h:243
struct _request * request(char *urlin)
Definition: tcp-banger2.c:291
CachePeer * getDefaultParent(PeerSelector *ps)
Definition: neighbors.cc:468
int client_dst_passthru
Definition: SquidConfig.h:338
#define DIRECT_NO
Definition: defines.h:81
ACLChecklist * acl_checklist
FwdServer * servers
a linked list of (unresolved) selected peers
AccessLogEntry::Pointer al
info for the future access.log, and external ACL
Definition: hier_code.h:31
void port(unsigned short p)
Definition: URL.h:74
encapsulates DNS lookup results
Definition: LookupDetails.h:20
void HTTPMSGLOCK(Http::Message *a)
Definition: Message.h:154
int hit
Definition: htcp.h:25
static EVH HandlePingTimeout
static ACLCB CheckNeverDirectDone
int netdbHostRtt(const char *host)
Definition: net_db.cc:1052
Interface for those who need a list of peers to forward a request to.
void checkAlwaysDirectDone(const allow_t answer)
Definition: peer_select.cc:230
#define DBG_CRITICAL
Definition: Debug.h:45
char * p
Definition: membanger.c:43
struct timeval stop
Definition: PingData.h:20
Ip::Address closest_parent_miss
allow_t always_direct
bool hostVerified
Definition: RequestFlags.h:66
int neighborsUdpPing(HttpRequest *request, StoreEntry *entry, IRCB *callback, PeerSelector *ps, int *exprep, int *timeout)
Definition: neighbors.cc:590
struct timeval current_time
Definition: stub_time.cc:15
void handleHtcpReply(CachePeer *, const peer_t, HtcpReplyData *)
Definition: peer_select.cc:846
struct timeval peer_select_start
int timeouts
Definition: peer_select.cc:65
CachePeer * pinnedPeer() const
Definition: client_side.h:196
static struct @89 PeerStats
#define DIRECT_UNKNOWN
Definition: defines.h:80
CachePeer * getRoundRobinParent(PeerSelector *ps)
Definition: neighbors.cc:308
bool isAnyAddr() const
Definition: Address.cc:163
static IRCB HandlePingReply
static const char * DirectStr[]
Definition: peer_select.cc:68
void host(const char *src)
Definition: url.cc:47
int n_replies_expected
Definition: PingData.h:23
void addSelection(CachePeer *, const hier_code)
Definition: peer_select.cc:926
#define DIRECT_MAYBE
Definition: defines.h:82
bool selectionAborted()
Definition: peer_select.cc:260
struct HtcpReplyData::cto_t cto
PeerSelectionInitiator * interestedInitiator()
Definition: peer_select.cc:981
int tvSubMsec(struct timeval, struct timeval)
Definition: stub_time.cc:20
bool IsConnOpen(const Comm::ConnectionPointer &conn)
Definition: Connection.cc:24
ping_status_t ping_status
Definition: Store.h:216
StoreEntry * entry
void const char HLPCB void * data
Definition: stub_helper.cc:16
bool wantsMoreDestinations() const
bool subscribed
whether noteDestination() and noteDestinationsEnd() calls are allowed
CachePeer * getFirstUpParent(PeerSelector *ps)
Definition: neighbors.cc:283
const PeerSelector *const selector
selection parameters
Definition: peer_select.cc:82
void handlePingTimeout()
Definition: peer_select.cc:744
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:124
int minDirectRtt
Definition: SquidConfig.h:256
#define DBG_IMPORTANT
Definition: Debug.h:46
void handlePath(Comm::ConnectionPointer &path, FwdServer &fs)
processes a newly discovered/finalized path
void netdbUpdatePeer(const URL &url, CachePeer *e, int irtt, int ihops)
Definition: net_db.cc:1087
InstanceIdDefinitions(PeerSelector,"PeerSelector")
Ip::Address client_addr
Definition: HttpRequest.h:137
AnyP::UriScheme const & getScheme() const
Definition: URL.h:58
void handleIcpParentMiss(CachePeer *, icp_common_t *)
Definition: peer_select.cc:772
Cbc * valid() const
was set and is valid
Definition: CbcPointer.h:41
int forward_max_tries
Definition: SquidConfig.h:349
const SBuf & effectiveRequestUri() const
RFC 7230 section 5.5 - Effective Request URI.
Definition: HttpRequest.cc:673
Ip::Address in_addr
Definition: CachePeer.h:44
String error
error message for unsuccessful lookups; empty otherwise
Definition: LookupDetails.h:29
CbcPointer< ConnStateData > clientConnectionManager
Definition: HttpRequest.h:218
void nbgethostbyname(const char *name, const CbcPointer< IpReceiver > &receiver)
initiate an (often) asynchronous DNS lookup; the receiver gets the results
Definition: ipcache.cc:607
PeerSelector(PeerSelectionInitiator *)
Definition: peer_select.cc:948
acl_access * NeverDirect
Definition: SquidConfig.h:359
uint16_t flags
Definition: Store.h:206
icp_opcode
Definition: icp_opcode.h:13
CbcPointer< CachePeer > _peer
Definition: peer_select.cc:59
a helper class to report a selected destination (for debugging)
Definition: peer_select.cc:76
const Comm::ConnectionPointer validatePinnedConnection(HttpRequest *request, const CachePeer *peer)
bool isIPv4() const
Definition: Address.cc:151
URL url
the request URI
Definition: HttpRequest.h:103
CachePeer * hit
void selectSomeNeighbor()
Definition: peer_select.cc:578
const char * url() const
Definition: store.cc:1608
unsigned char code
Definition: html_quote.c:20
uint32_t flags
Definition: ICP.h:45
void eventDelete(EVH *func, void *arg)
Definition: event.cc:131
unsigned short port() const
Definition: Address.cc:771
CachePeer * whichPeer(const Ip::Address &from)
Definition: neighbors.cc:95
const CachePeer *const peer
successful selection info
Definition: peer_select.cc:83
CachePeer * peerSourceHashSelectParent(PeerSelector *ps)
void selectSomeNeighborReplies()
Selects a neighbor (parent or sibling) based on ICP/HTCP replies.
Definition: peer_select.cc:636
uint32_t pad
Definition: ICP.h:46
FwdServer(CachePeer *p, hier_code c)
Definition: peer_select.cc:53
Ip::Address local
Definition: Connection.h:135
bool SIGHDLR int STUB void int
Definition: stub_tools.cc:68
struct timeval start
Definition: PingData.h:18
Initiator initiator_
recipient of the destinations we select; use interestedInitiator() to access
void eventAdd(const char *name, EVH *func, void *arg, double when, int weight, bool cbdata)
Definition: event.cc:109
int netdbHostHops(const char *host)
Definition: net_db.cc:1037
RequestFlags flags
Definition: HttpRequest.h:129
virtual void syncAle(HttpRequest *adaptedRequest, const char *logUri) const =0
assigns uninitialized adapted_request and url ALE components
AccessLogEntry::Pointer al
info for the future access.log entry
void setPeer(CachePeer *p)
Definition: Connection.cc:107
Ip::Address remote
Definition: Connection.h:138
CachePeer * peerUserHashSelectParent(PeerSelector *ps)
hier_code
Definition: hier_code.h:12
String dnsError
DNS lookup error message.
Definition: errorpage.h:151
void handleIcpReply(CachePeer *, const peer_t, icp_common_t *header)
Definition: peer_select.cc:813
static char server[MAXLINE]
icp_opcode getOpCode() const
Definition: icp_v2.cc:118
bool intercepted
Definition: RequestFlags.h:64
peer_t neighborType(const CachePeer *p, const URL &url)
Definition: neighbors.cc:114
FwdServer * next
Definition: peer_select.cc:61
void selectAllParents()
Adds alive parents. Used as a last resort for never_direct.
Definition: peer_select.cc:714
#define CBDATA_CLASS_INIT(type)
Definition: cbdata.h:318
int peerHTTPOkay(const CachePeer *p, PeerSelector *ps)
Definition: neighbors.cc:253
static void peerSelect(PeerSelectionInitiator *initiator, HttpRequest *request, AccessLogEntry::Pointer const &al, StoreEntry *entry)
Definition: peer_select.cc:163
void selectSomeParent()
Definition: peer_select.cc:680
int nonhierarchical_direct
Definition: SquidConfig.h:297
struct SquidConfig::@114 accessList
Ip::Address first_parent_miss
CachePeer * neighborsDigestSelect(PeerSelector *ps)
Definition: neighbors.cc:798
lookup_t peerDigestLookup(CachePeer *p, PeerSelector *ps)
Definition: neighbors.cc:754
int weight
Definition: CachePeer.h:126
int w_rtt
Definition: PingData.h:26
peer_t
Definition: enums.h:27
hier_code peerType
Definition: Connection.h:141
ProtocolType
Definition: ProtocolType.h:22
Comm::ConnectionPointer clientConnection
Definition: Server.h:97
struct CachePeer::@31 options
static std::ostream & operator<<(std::ostream &os, const PeerSelectionDumper &fsd)
prints PeerSelectionDumper (for debugging)
Definition: peer_select.cc:91
bool closest_only
Definition: CachePeer.h:91
#define ICP_FLAG_SRC_RTT
Definition: defines.h:73
const hier_code code
selection algorithm
Definition: peer_select.cc:84
const char * hier_code_str[]
void startSelectingDestinations(HttpRequest *request, const AccessLogEntry::Pointer &ale, StoreEntry *entry)
Definition: peer_select.cc:194
PeerSelectionDumper(const PeerSelector *const aSelector, const CachePeer *const aPeer, const hier_code aCode)
Definition: peer_select.cc:79
allow_t never_direct
int n_sent
Definition: PingData.h:21
static ACLCB CheckAlwaysDirectDone
acl_access * AlwaysDirect
Definition: SquidConfig.h:360
int neighborsCount(PeerSelector *ps)
Definition: neighbors.cc:268
void selectMore()
a single selection loop iteration: attempts to add more destinations
Definition: peer_select.cc:456
void peerNoteDigestLookup(HttpRequest *request, CachePeer *p, lookup_t lookup)
Definition: neighbors.cc:863
virtual void noteIp(const Ip::Address &ip) override
Called when/if nbgethostbyname() discovers a new good IP address.
Definition: peer_select.cc:364
int p_rtt
Definition: PingData.h:27
void selectPinned()
Selects a pinned connection if it exists, is valid, and is allowed.
Definition: peer_select.cc:551
bool spoofClientIp
Definition: RequestFlags.h:72
#define EBIT_TEST(flag, bit)
Definition: defines.h:107
int minDirectHops
Definition: SquidConfig.h:255
class SquidConfig Config
Definition: SquidConfig.cc:12
#define NULL
Definition: types.h:166
const SBuf url() const
Definition: peer_select.cc:967
static int peerSelectIcpPing(PeerSelector *ps, int direct, StoreEntry *entry)
Definition: peer_select.cc:137
void selectSomeDirect()
Adds a "direct" entry if the request can be forwarded to the origin server.
Definition: peer_select.cc:667
Cbc * get() const
a temporary valid raw Cbc pointer or NULL
Definition: CbcPointer.h:162
void HTTPMSGUNLOCK(Http::Message *a)
Definition: Message.h:144
char * host
Definition: CachePeer.h:41
int basetime
Definition: CachePeer.h:127
bool peerAllowedToUse(const CachePeer *, PeerSelector *)
Definition: neighbors.cc:137
const char * icp_opcode_str[]

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors