ServiceRep.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2023 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 93 ICAP (RFC 3507) Client */
10 
11 #include "squid.h"
12 #include "adaptation/Answer.h"
13 #include "adaptation/icap/Config.h"
18 #include "base/TextException.h"
19 #include "comm/Connection.h"
20 #include "ConfigParser.h"
21 #include "debug/Stream.h"
22 #include "fde.h"
23 #include "globals.h"
24 #include "HttpReply.h"
25 #include "ip/tools.h"
26 #include "SquidConfig.h"
27 
28 #define DEFAULT_ICAP_PORT 1344
29 #define DEFAULT_ICAPS_PORT 11344
30 
32 
34  AsyncJob("Adaptation::Icap::ServiceRep"), Adaptation::Service(svcCfg),
35  tlsContext(writeableCfg().secure, sslContext),
36  theOptions(nullptr), theOptionsFetcher(nullptr), theLastUpdate(0),
37  theBusyConns(0),
38  theAllWaiters(0),
39  connOverloadReported(false),
40  theIdleConns(nullptr),
41  isSuspended(nullptr), notifying(false),
42  updateScheduled(false),
43  wasAnnouncedUp(true), // do not announce an "up" service at startup
44  isDetached(false)
45 {
47  theIdleConns = new IdleConnList("ICAP Service", nullptr);
48 }
49 
51 {
53  delete theIdleConns;
54  Must(!theOptionsFetcher);
55  delete theOptions;
56  });
57 }
58 
59 void
61 {
63 
64  // use /etc/services or default port if needed
65  const bool have_port = cfg().port >= 0;
66  if (!have_port) {
67  struct servent *serv;
68  if (cfg().protocol.caseCmp("icaps") == 0)
69  serv = getservbyname("icaps", "tcp");
70  else
71  serv = getservbyname("icap", "tcp");
72 
73  if (serv) {
74  writeableCfg().port = htons(serv->s_port);
75  } else {
76  writeableCfg().port = cfg().protocol.caseCmp("icaps") == 0 ? DEFAULT_ICAPS_PORT : DEFAULT_ICAP_PORT;
77  }
78  }
79 
80  if (cfg().protocol.caseCmp("icaps") == 0)
81  writeableCfg().secure.encryptTransport = true;
82 
83  if (cfg().secure.encryptTransport) {
84  debugs(3, 2, "initializing service " << cfg().resource << " SSL context");
85  sslContext = writeableCfg().secure.createClientContext(true);
86  }
87 
88  if (!cfg().connectionEncryption.configured())
89  writeableCfg().connectionEncryption.defaultTo(cfg().secure.encryptTransport);
90 
91  theSessionFailures.configure(TheConfig.oldest_service_failure > 0 ?
93 }
94 
96 {
97  const int failures = theSessionFailures.count(1);
98  debugs(93,4, " failure " << failures << " out of " <<
99  TheConfig.service_failure_limit << " allowed in " <<
100  TheConfig.oldest_service_failure << "sec " << status());
101 
102  if (isSuspended)
103  return;
104 
105  if (TheConfig.service_failure_limit >= 0 &&
106  failures > TheConfig.service_failure_limit)
107  suspend("too many failures");
108 
109  // TODO: Should bypass setting affect how much Squid tries to talk to
110  // the ICAP service that is currently unusable and is likely to remain
111  // so for some time? The current code says "no". Perhaps the answer
112  // should be configurable.
113 }
114 
115 // TODO: getIdleConnection() and putConnection()/noteConnectionFailed() manage a
116 // "used connection slot" resource. Automate that resource tracking (RAII/etc.).
119 {
120  Comm::ConnectionPointer connection;
121 
122  /* 2011-06-17: rousskov:
123  * There are two things that happen at the same time in pop(). Both are important.
124  * 1) Ensure that we can use a pconn for this transaction.
125  * 2) Ensure that the number of idle pconns does not grow without bounds.
126  *
127  * Both happen in the beginning of the transaction. Both are dictated by real-world problems.
128  * retriable means you can repeat the request if you suspect the first try failed due to a pconn race.
129  * HTTP and ICAP rules prohibit the use of pconns for non-retriable requests.
130  *
131  * If there are zero idle connections, (2) is irrelevant. (2) is only relevant when there are many
132  * idle connections and we should not open more connections without closing some idle ones,
133  * or instead of just opening a new connection and leaving idle connections as is.
134  * In other words, (2) tells us to close one FD for each new one we open due to retriable.
135  */
136  if (retriableXact)
137  connection = theIdleConns->pop();
138  else
139  theIdleConns->closeN(1);
140 
141  ++theBusyConns;
142  debugs(93,3, "got connection: " << connection);
143  return connection;
144 }
145 
146 // pools connection if it is reusable or closes it
147 void Adaptation::Icap::ServiceRep::putConnection(const Comm::ConnectionPointer &conn, bool isReusable, bool sendReset, const char *comment)
148 {
149  Must(Comm::IsConnOpen(conn));
150  // do not pool an idle connection if we owe connections
151  if (isReusable && excessConnections() == 0) {
152  debugs(93, 3, "pushing pconn" << comment);
153  theIdleConns->push(conn);
154  } else {
155  debugs(93, 3, (sendReset ? "RST" : "FIN") << "-closing " <<
156  comment);
157  // comm_close called from Connection::close will clear timeout
158  // TODO: add "bool sendReset = false" to Connection::close()?
159  if (sendReset)
160  comm_reset_close(conn);
161  else
162  conn->close();
163  }
164 
165  Must(theBusyConns > 0);
166  --theBusyConns;
167  // a connection slot released. Check if there are waiters....
168  busyCheckpoint();
169 }
170 
171 // a wrapper to avoid exposing theIdleConns
173 {
174  Must(Comm::IsConnOpen(conn));
175  fd_table[conn->fd].noteUse(); // pconn re-use, albeit not via PconnPool API
176 }
177 
179 {
180  debugs(93, 3, "Connection failed: " << comment);
181  --theBusyConns;
182 }
183 
185 {
186  if (cfg().maxConn >= 0)
187  theMaxConnections = cfg().maxConn;
188  else if (theOptions && theOptions->max_connections >= 0)
189  theMaxConnections = theOptions->max_connections;
190  else {
191  theMaxConnections = -1;
192  return;
193  }
194 
195  if (::Config.workers > 1 )
196  theMaxConnections /= ::Config.workers;
197 }
198 
200 {
201  if (theMaxConnections < 0)
202  return -1;
203 
204  // we are available if we can open or reuse connections
205  // in other words, if we will not create debt
206  int available = max(0, theMaxConnections - theBusyConns);
207 
208  if (!available && !connOverloadReported) {
209  debugs(93, DBG_IMPORTANT, "WARNING: ICAP Max-Connections limit " <<
210  "exceeded for service " << cfg().uri << ". Open connections now: " <<
211  theBusyConns + theIdleConns->count() << ", including " <<
212  theIdleConns->count() << " idle persistent connections.");
213  connOverloadReported = true;
214  }
215 
216  if (cfg().onOverload == srvForce)
217  return -1;
218 
219  return available;
220 }
221 
222 // The number of connections which excess the Max-Connections limit
224 {
225  if (theMaxConnections < 0)
226  return 0;
227 
228  // Waiters affect the number of needed connections but a needed
229  // connection may still be excessive from Max-Connections p.o.v.
230  // so we should not account for waiting transaction needs here.
231  const int debt = theBusyConns + theIdleConns->count() - theMaxConnections;
232  if (debt > 0)
233  return debt;
234  else
235  return 0;
236 }
237 
239 {
240  --theAllWaiters;
241 
242  // in case the notified transaction did not take the connection slot
243  busyCheckpoint();
244 }
245 
246 // called when a connection slot may become available
248 {
249  if (theNotificationWaiters.empty()) // nobody is waiting for a slot
250  return;
251 
252  int freed = 0;
253  int available = availableConnections();
254 
255  if (available < 0) {
256  // It is possible to have waiters when no limit on connections exist in
257  // case of reconfigure or because new Options received.
258  // In this case, notify all waiting transactions.
259  freed = theNotificationWaiters.size();
260  } else {
261  // avoid notifying more waiters than there will be available slots
262  const int notifiedWaiters = theAllWaiters - theNotificationWaiters.size();
263  freed = available - notifiedWaiters;
264  }
265 
266  debugs(93,7, "Available connections: " << available <<
267  " freed slots: " << freed <<
268  " waiting in queue: " << theNotificationWaiters.size());
269 
270  while (freed > 0 && !theNotificationWaiters.empty()) {
271  Client i = theNotificationWaiters.front();
272  theNotificationWaiters.pop_front();
274  i.callback = nullptr;
275  --freed;
276  }
277 }
278 
280 {
281  if (isSuspended) {
282  debugs(93,4, "keeping suspended, also for " << reason);
283  } else {
284  isSuspended = reason;
285  debugs(93, DBG_IMPORTANT, "suspending ICAP service for " << reason);
287  announceStatusChange("suspended", true);
288  }
289 }
290 
292 {
293  return theLastUpdate != 0;
294 }
295 
297 {
298  return theOptions && theOptions->valid() && theOptions->fresh();
299 }
300 
302 {
303  return !isSuspended && hasOptions();
304 }
305 
307 {
308  Must(up());
309  int available = availableConnections();
310  if (available < 0)
311  return true;
312  else
313  return (available - theAllWaiters > 0);
314 }
315 
317 {
318  Must(up());
319 
320  int available = availableConnections();
321  return (available != 0); // it is -1 (no limit) or has available slots
322 }
323 
325 {
326  Must(hasOptions());
327  return theOptions->transferKind(urlPath) != Adaptation::Icap::Options::xferIgnore;
328 }
329 
330 bool Adaptation::Icap::ServiceRep::wantsPreview(const SBuf &urlPath, size_t &wantedSize) const
331 {
332  Must(hasOptions());
333 
334  if (theOptions->preview < 0)
335  return false;
336 
337  if (theOptions->transferKind(urlPath) != Adaptation::Icap::Options::xferPreview)
338  return false;
339 
340  wantedSize = theOptions->preview;
341 
342  return true;
343 }
344 
346 {
347  Must(hasOptions());
348  return true; // in the future, we may have ACLs to prevent 204s
349 }
350 
352 {
353  Must(hasOptions());
354  if (theOptions->allow206)
355  return true; // in the future, we may have ACLs to prevent 206s
356  return false;
357 }
358 
359 static
361 {
362  Adaptation::Icap::ServiceRep *service = static_cast<Adaptation::Icap::ServiceRep*>(data);
363  Must(service);
364  service->noteTimeToUpdate();
365 }
366 
368 {
369  if (!detached())
370  updateScheduled = false;
371 
372  if (detached() || theOptionsFetcher.set()) {
373  debugs(93,5, "ignores options update " << status());
374  return;
375  }
376 
377  debugs(93,5, "performs a regular options update " << status());
378  startGettingOptions();
379 }
380 
382 {
383  Must(!notifying);
384  notifying = true;
385  debugs(93,7, "notifies " << theClients.size() << " clients " <<
386  status());
387 
388  // note: we must notify even if we are invalidated
389 
390  Pointer us = nullptr;
391 
392  while (!theClients.empty()) {
393  Client i = theClients.back();
394  theClients.pop_back();
396  i.callback = nullptr;
397  }
398 
399  notifying = false;
400 }
401 
403 {
404  debugs(93,8, "ICAPServiceRep::callWhenAvailable");
405  Must(cb!=nullptr);
406  Must(up());
407  Must(!theIdleConns->count()); // or we should not be waiting
408 
409  Client i;
410  i.service = Pointer(this);
411  i.callback = cb;
412  if (priority)
413  theNotificationWaiters.push_front(i);
414  else
415  theNotificationWaiters.push_back(i);
416 
417  busyCheckpoint();
418 }
419 
421 {
422  Must(cb!=nullptr);
423 
424  debugs(93,5, "Adaptation::Icap::Service is asked to call " << *cb <<
425  " when ready " << status());
426 
427  Must(!broken()); // we do not wait for a broken service
428 
429  Client i;
430  i.service = Pointer(this); // TODO: is this really needed?
431  i.callback = cb;
432  theClients.push_back(i);
433 
434  if (theOptionsFetcher.set() || notifying)
435  return; // do nothing, we will be picked up in noteTimeToNotify()
436 
437  if (needNewOptions())
438  startGettingOptions();
439  else
440  scheduleNotification();
441 }
442 
444 {
445  debugs(93,7, "will notify " << theClients.size() << " clients");
446  CallJobHere(93, 5, this, Adaptation::Icap::ServiceRep, noteTimeToNotify);
447 }
448 
450 {
451  return !detached() && !up();
452 }
453 
455 {
456  debugs(93,8, "changes options from " << theOptions << " to " <<
457  newOptions << ' ' << status());
458 
459  delete theOptions;
460  theOptions = newOptions;
461  theSessionFailures.clear();
462  isSuspended = nullptr;
463  theLastUpdate = squid_curtime;
464 
465  checkOptions();
466  announceStatusChange("down after an options fetch failure", true);
467 }
468 
470 {
471  if (theOptions == nullptr)
472  return;
473 
474  if (!theOptions->valid()) {
475  debugs(93, DBG_IMPORTANT, "WARNING: Squid got an invalid ICAP OPTIONS response " <<
476  "from service " << cfg().uri << "; error: " << theOptions->error);
477  return;
478  }
479 
480  /*
481  * Issue a warning if the ICAP server returned methods in the
482  * options response that don't match the method from squid.conf.
483  */
484 
485  if (!theOptions->methods.empty()) {
486  bool method_found = false;
487  String method_list;
488  std::vector <ICAP::Method>::iterator iter = theOptions->methods.begin();
489 
490  while (iter != theOptions->methods.end()) {
491 
492  if (*iter == cfg().method) {
493  method_found = true;
494  break;
495  }
496 
497  method_list.append(ICAP::methodStr(*iter));
498  method_list.append(" ", 1);
499  ++iter;
500  }
501 
502  if (!method_found) {
503  debugs(93, DBG_IMPORTANT, "WARNING: Squid is configured to use ICAP method " <<
504  cfg().methodStr() <<
505  " for service " << cfg().uri <<
506  " but OPTIONS response declares the methods are " << method_list);
507  }
508  }
509 
510  /*
511  * Check the ICAP server's date header for clock skew
512  */
513  const int skew = (int)(theOptions->timestamp() - squid_curtime);
514  if (abs(skew) > theOptions->ttl()) {
515  // TODO: If skew is negative, the option will be considered down
516  // because of stale options. We should probably change this.
517  debugs(93, DBG_IMPORTANT, "ICAP service's clock is skewed by " << skew <<
518  " seconds: " << cfg().uri);
519  }
520 }
521 
522 void Adaptation::Icap::ServiceRep::announceStatusChange(const char *downPhrase, bool important) const
523 {
524  if (wasAnnouncedUp == up()) // no significant changes to announce
525  return;
526 
527  const char *what = cfg().bypass ? "optional" : "essential";
528  const char *state = wasAnnouncedUp ? downPhrase : "up";
529  const int level = important ? 1 :2;
530  debugs(93,level, what << " ICAP service is " << state << ": " <<
531  cfg().uri << ' ' << status());
532 
533  wasAnnouncedUp = !wasAnnouncedUp;
534 }
535 
536 // we are receiving ICAP OPTIONS response headers here or NULL on failures
538 {
539  Must(initiated(theOptionsFetcher));
540  clearAdaptation(theOptionsFetcher);
541 
542  if (answer.kind == Answer::akError) {
543  debugs(93,3, "failed to fetch options " << status());
544  handleNewOptions(nullptr);
545  return;
546  }
547 
548  Must(answer.kind == Answer::akForward); // no akBlock for OPTIONS requests
549  const Http::Message *msg = answer.message.getRaw();
550  Must(msg);
551 
552  debugs(93,5, "is interpreting new options " << status());
553 
554  Adaptation::Icap::Options *newOptions = nullptr;
555  if (const HttpReply *r = dynamic_cast<const HttpReply*>(msg)) {
556  newOptions = new Adaptation::Icap::Options;
557  newOptions->configure(r);
558  } else {
559  debugs(93, DBG_IMPORTANT, "ICAP service got wrong options message " << status());
560  }
561 
562  handleNewOptions(newOptions);
563 }
564 
565 // we (a) must keep trying to get OPTIONS and (b) are RefCounted so we
566 // must keep our job alive (XXX: until nobody needs us)
567 void Adaptation::Icap::ServiceRep::callException(const std::exception &e)
568 {
569  clearAdaptation(theOptionsFetcher);
570  debugs(93,2, "ICAP probably failed to fetch options (" << e.what() <<
571  ")" << status());
572  handleNewOptions(nullptr);
573 }
574 
576 {
577  // new options may be NULL
578  changeOptions(newOptions);
579 
580  debugs(93,3, "got new options and is now " << status());
581 
582  scheduleUpdate(optionsFetchTime());
583 
584  // XXX: this whole feature bases on the false assumption a service only has one IP
585  setMaxConnections();
586  const int excess = excessConnections();
587  // if we owe connections and have idle pconns, close the latter
588  if (excess && theIdleConns->count() > 0) {
589  const int n = min(excess, theIdleConns->count());
590  debugs(93,5, "closing " << n << " pconns to relief debt");
591  theIdleConns->closeN(n);
592  }
593 
594  scheduleNotification();
595 }
596 
598 {
599  Must(!theOptionsFetcher);
600  debugs(93,6, "will get new options " << status());
601 
602  // XXX: "this" here is "self"; works until refcounting API changes
603  theOptionsFetcher = initiateAdaptation(
605  // TODO: timeout in case Adaptation::Icap::OptXact never calls us back?
606  // Such a timeout should probably be a generic AsyncStart feature.
607 }
608 
610 {
611  if (updateScheduled) {
612  debugs(93,7, "reschedules update");
613  // XXX: check whether the event is there because AR saw
614  // an unreproducible eventDelete assertion on 2007/06/18
617  else
618  debugs(93, DBG_IMPORTANT, "ERROR: Squid BUG: ICAP service lost an update event.");
619  updateScheduled = false;
620  }
621 
622  debugs(93,7, "raw OPTIONS fetch at " << when << " or in " <<
623  (when - squid_curtime) << " sec");
624  debugs(93,9, "last fetched at " << theLastUpdate << " or " <<
625  (squid_curtime - theLastUpdate) << " sec ago");
626 
627  /* adjust update time to prevent too-frequent updates */
628 
629  if (when < squid_curtime)
630  when = squid_curtime;
631 
632  // XXX: move hard-coded constants from here to Adaptation::Icap::TheConfig
633  const int minUpdateGap = 30; // seconds
634  if (when < theLastUpdate + minUpdateGap)
635  when = theLastUpdate + minUpdateGap;
636 
637  const int delay = when - squid_curtime;
638  debugs(93,5, "will fetch OPTIONS in " << delay << " sec");
639 
640  eventAdd("Adaptation::Icap::ServiceRep::noteTimeToUpdate",
641  &ServiceRep_noteTimeToUpdate, this, delay, 0, true);
642  updateScheduled = true;
643 }
644 
645 // returns absolute time when OPTIONS should be fetched
646 time_t
648 {
649  if (theOptions && theOptions->valid()) {
650  const time_t expire = theOptions->expire();
651  debugs(93,7, "options expire on " << expire << " >= " << squid_curtime);
652 
653  // conservative estimate of how long the OPTIONS transaction will take
654  // XXX: move hard-coded constants from here to Adaptation::Icap::TheConfig
655  const int expectedWait = 20; // seconds
656 
657  // Unknown or invalid (too small) expiration times should not happen.
658  // Adaptation::Icap::Options should use the default TTL, and ICAP servers should not
659  // send invalid TTLs, but bugs and attacks happen.
660  if (expire < expectedWait)
661  return squid_curtime;
662  else
663  return expire - expectedWait; // before the current options expire
664  }
665 
666  // use revival delay as "expiration" time for a service w/o valid options
668 }
669 
673 {
674  return new Adaptation::Icap::ModXactLauncher(virgin, cause, alp, this);
675 }
676 
677 // returns a temporary string depicting service status, for debugging
679 {
680  static MemBuf buf;
681 
682  buf.reset();
683  buf.append("[", 1);
684 
685  if (up())
686  buf.append("up", 2);
687  else {
688  buf.append("down", 4);
689  if (isSuspended)
690  buf.append(",susp", 5);
691 
692  if (!theOptions)
693  buf.append(",!opt", 5);
694  else if (!theOptions->valid())
695  buf.append(",!valid", 7);
696  else if (!theOptions->fresh())
697  buf.append(",stale", 6);
698  }
699 
700  if (detached())
701  buf.append(",detached", 9);
702 
703  if (theOptionsFetcher.set())
704  buf.append(",fetch", 6);
705 
706  if (notifying)
707  buf.append(",notif", 6);
708 
709  if (const int failures = theSessionFailures.remembered())
710  buf.appendf(",fail%d", failures);
711 
712  buf.append("]", 1);
713  buf.terminate();
714 
715  return buf.content();
716 }
717 
719 {
720  debugs(93,3, "detaching ICAP service: " << cfg().uri <<
721  ' ' << status());
722  isDetached = true;
723 }
724 
726 {
727  return isDetached;
728 }
729 
732  Parent(xact, aHandler)
733 {
734  theService = &xact->service();
735  theService->noteNewWaiter();
736 }
737 
739 {
740  theService = aConnWaiter.theService;
741  theService->noteNewWaiter();
742 }
743 
745 {
746  theService->noteGoneWaiter();
747 }
748 
int eventFind(EVH *func, void *arg)
Definition: event.cc:145
void terminate()
Definition: MemBuf.cc:241
void appendf(const char *fmt,...) PRINTF_FORMAT_ARG2
Append operation with printf-style arguments.
Definition: Packable.h:61
common parts of HttpRequest and HttpReply
Definition: Message.h:25
Config TheConfig
Definition: Config.cc:19
std::vector< const Option * > Options
Definition: Options.h:217
void eventDelete(EVH *func, void *arg)
Definition: event.cc:127
virtual void finalize()
Definition: Service.cc:26
const char * status() const override
internal cleanup; do not call directly
Definition: ServiceRep.cc:678
void suspend(const char *reason)
Definition: ServiceRep.cc:279
#define ScheduleCallHere(call)
Definition: AsyncCall.h:166
void callException(const std::exception &e) override
called when the job throws during an async call
Definition: ServiceRep.cc:567
CBDATA_NAMESPACED_CLASS_INIT(Adaptation::Icap, ServiceRep)
Definition: SBuf.h:93
void callWhenAvailable(AsyncCall::Pointer &cb, bool priority=false)
Definition: ServiceRep.cc:402
time_t oldest_service_failure
Definition: Config.h:55
ServiceRep & service()
Definition: Xaction.cc:110
ServiceRep(const ServiceConfigPointer &aConfig)
Definition: ServiceRep.cc:33
const A & max(A const &lhs, A const &rhs)
C * getRaw() const
Definition: RefCount.h:89
bool IsConnOpen(const Comm::ConnectionPointer &conn)
Definition: Connection.cc:27
int service_failure_limit
Definition: Config.h:54
#define DEFAULT_ICAP_PORT
Definition: ServiceRep.cc:28
@ akForward
forward the supplied adapted HTTP message
Definition: Answer.h:29
static void ServiceRep_noteTimeToUpdate(void *data)
Definition: ServiceRep.cc:360
void noteConnectionFailed(const char *comment)
Definition: ServiceRep.cc:178
ServiceRep::Pointer theService
Definition: ServiceRep.h:201
void configure(const HttpReply *reply)
Definition: Options.cc:84
bool availableForOld() const
a transaction notified about connection slot availability may start communicating with the service
Definition: ServiceRep.cc:316
Initiate * makeXactLauncher(Http::Message *virginHeader, HttpRequest *virginCause, AccessLogEntry::Pointer &alp) override
Definition: ServiceRep.cc:671
int service_revival_delay
Definition: Config.h:56
void append(const char *c, int sz) override
Definition: MemBuf.cc:209
Comm::ConnectionPointer getIdleConnection(bool isRetriable)
Definition: ServiceRep.cc:118
ConnWaiterDialer(const CbcPointer< Adaptation::Icap::ModXact > &xact, Adaptation::Icap::ConnWaiterDialer::Parent::Method aHandler)
Definition: ServiceRep.cc:730
void append(char const *buf, int len)
Definition: String.cc:130
void scheduleUpdate(time_t when)
Definition: ServiceRep.cc:609
Definition: MemBuf.h:23
void putConnection(const Comm::ConnectionPointer &conn, bool isReusable, bool sendReset, const char *comment)
Definition: ServiceRep.cc:147
Kind kind
the type of the answer
Definition: Answer.h:47
void noteConnectionUse(const Comm::ConnectionPointer &conn)
Definition: ServiceRep.cc:172
#define CallJobHere(debugSection, debugLevel, job, Class, method)
Definition: AsyncJobCalls.h:59
void comm_reset_close(const Comm::ConnectionPointer &conn)
Definition: comm.cc:797
void callWhenReady(AsyncCall::Pointer &cb)
Definition: ServiceRep.cc:420
bool wantsUrl(const SBuf &urlPath) const override
Definition: ServiceRep.cc:324
void noteGoneWaiter()
An xaction is not waiting any more for service to be available.
Definition: ServiceRep.cc:238
void finalize() override
Definition: ServiceRep.cc:60
const char * methodStr(Method)
Definition: Elements.cc:15
@ srvForce
Definition: Elements.h:19
time_t squid_curtime
Definition: stub_libtime.cc:20
time_t optionsFetchTime() const
Definition: ServiceRep.cc:647
#define DEFAULT_ICAPS_PORT
Definition: ServiceRep.cc:29
void(ModXact ::* Method)()
Definition: AsyncJobCalls.h:94
summarizes adaptation service answer for the noteAdaptationAnswer() API
Definition: Answer.h:24
bool wantsPreview(const SBuf &urlPath, size_t &wantedSize) const
Definition: ServiceRep.cc:330
#define fd_table
Definition: fde.h:189
IdleConnList * theIdleConns
idle persistent connection pool
Definition: ServiceRep.h:145
Http::MessagePointer message
HTTP request or response to forward.
Definition: Answer.h:44
@ akError
no adapted message will come; see bypassable
Definition: Answer.h:31
char * content()
start of the added data
Definition: MemBuf.h:41
bool probed() const override
Definition: ServiceRep.cc:291
#define Must(condition)
Definition: TextException.h:75
#define DBG_IMPORTANT
Definition: Stream.h:38
void reset()
Definition: MemBuf.cc:129
void changeOptions(Options *newOptions)
Definition: ServiceRep.cc:454
bool up() const override
Definition: ServiceRep.cc:301
bool availableForNew() const
a new transaction may start communicating with the service
Definition: ServiceRep.cc:306
#define SWALLOW_EXCEPTIONS(code)
Definition: TextException.h:79
bool detached() const override
whether detached() was called
Definition: ServiceRep.cc:725
void setMaxConnections()
Set the maximum allowed connections for the service.
Definition: ServiceRep.cc:184
void noteAdaptationAnswer(const Answer &answer) override
Definition: ServiceRep.cc:537
void noteFailure() override
Definition: ServiceRep.cc:95
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:192
const A & min(A const &lhs, A const &rhs)
int excessConnections() const
The number of connections which excess the Max-Connections limit.
Definition: ServiceRep.cc:223
void handleNewOptions(Options *newOptions)
Definition: ServiceRep.cc:575
void eventAdd(const char *name, EVH *func, void *arg, double when, int weight, bool cbdata)
Definition: event.cc:107
void announceStatusChange(const char *downPhrase, bool important) const
Definition: ServiceRep.cc:522
int unsigned int
Definition: stub_fd.cc:19

 

Introduction

Documentation

Support

Miscellaneous