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

 

Introduction

Documentation

Support

Miscellaneous