ServiceRep.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2017 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 eCAP Interface */
10 
11 #include "squid.h"
12 #include "adaptation/ecap/Config.h"
13 #include "adaptation/ecap/Host.h"
16 #include "AsyncEngine.h"
17 #include "base/TextException.h"
18 #include "Debug.h"
19 #include "EventLoop.h"
20 
21 #include <libecap/adapter/service.h>
22 #include <libecap/common/options.h>
23 #include <libecap/common/name.h>
24 #include <libecap/common/named_values.h>
25 #include <limits>
26 #include <map>
27 
29 typedef std::map<std::string, Adaptation::Ecap::ServiceRep::AdapterService> AdapterServices;
31 static AdapterServices TheServices;
33 static AdapterServices AsyncServices;
34 
35 namespace Adaptation
36 {
37 namespace Ecap
38 {
39 
42 {
43 public:
45  typedef libecap::Name Name;
46  typedef libecap::Area Area;
47 
48  ConfigRep(const Master &aMaster);
49 
50  // libecap::Options API
51  virtual const libecap::Area option(const libecap::Name &name) const;
52  virtual void visitEachOption(libecap::NamedValueVisitor &visitor) const;
53 
54  const Master &master;
55 };
56 
58 class Engine: public AsyncEngine
59 {
60 public:
61  /* AsyncEngine API */
62  virtual int checkEvents(int timeout);
63 
64 private:
65  void kickAsyncServices(timeval &timeout);
66 };
67 
68 } // namespace Ecap
69 } // namespace Adaptation
70 
71 Adaptation::Ecap::ConfigRep::ConfigRep(const Master &aMaster): master(aMaster)
72 {
73 }
74 
75 const libecap::Area
76 Adaptation::Ecap::ConfigRep::option(const libecap::Name &name) const
77 {
78  // we may supply the params we know about, but only when names have host ID
79  if (name == metaBypassable)
80  return Area(master.bypass ? "1" : "0", 1);
81 
82  // TODO: We could build a by-name index, but is it worth it? Good adapters
83  // should use visitEachOption() instead, to check for name typos/errors.
84  typedef Master::Extensions::const_iterator MECI;
85  for (MECI i = master.extensions.begin(); i != master.extensions.end(); ++i) {
86  if (name == i->first)
87  return Area(i->second.data(), i->second.size());
88  }
89 
90  return Area();
91 }
92 
93 void
94 Adaptation::Ecap::ConfigRep::visitEachOption(libecap::NamedValueVisitor &visitor) const
95 {
96  // we may supply the params we know about too, but only if we set host ID
97  visitor.visit(metaBypassable, Area(master.bypass ? "1" : "0", 1));
98 
99  // visit adapter-specific options (i.e., those not recognized by Squid)
100  typedef Master::Extensions::const_iterator MECI;
101  for (MECI i = master.extensions.begin(); i != master.extensions.end(); ++i)
102  visitor.visit(Name(i->first), Area::FromTempString(i->second));
103 }
104 
105 /* Adaptation::Ecap::Engine */
106 
107 int
109 {
110  // Start with the default I/O loop timeout, convert from milliseconds.
111  static const struct timeval maxTimeout = {
112  EVENT_LOOP_TIMEOUT/1000, // seconds
113  (EVENT_LOOP_TIMEOUT % 1000)*1000
114  }; // microseconds
115  struct timeval timeout = maxTimeout;
116 
117  kickAsyncServices(timeout);
118  if (timeout.tv_sec == maxTimeout.tv_sec && timeout.tv_usec == maxTimeout.tv_usec)
119  return EVENT_IDLE;
120 
121  debugs(93, 7, "timeout: " << timeout.tv_sec << "s+" << timeout.tv_usec << "us");
122 
123  // convert back to milliseconds, avoiding int overflows
124  if (timeout.tv_sec >= std::numeric_limits<int>::max()/1000 - 1000)
126  else
127  return timeout.tv_sec*1000 + timeout.tv_usec/1000;
128 }
129 
131 void
133 {
134  if (AsyncServices.empty())
135  return;
136 
137  debugs(93, 3, "async services: " << AsyncServices.size());
138 
139  // Activate waiting async transactions, if any.
140  typedef AdapterServices::iterator ASI;
141  for (ASI s = AsyncServices.begin(); s != AsyncServices.end(); ++s) {
142  assert(s->second);
143  s->second->resume(); // may call Ecap::Xaction::resume()
144  }
145 
146  // Give services a chance to decrease the default timeout.
147  for (ASI s = AsyncServices.begin(); s != AsyncServices.end(); ++s) {
148  s->second->suspend(timeout);
149  }
150 }
151 
152 /* Adaptation::Ecap::ServiceRep */
153 
155 /*AsyncJob("Adaptation::Ecap::ServiceRep"),*/ Adaptation::Service(cfg),
156  isDetached(false)
157 {
158 }
159 
161 {
162 }
163 
165 {
166  assert(false); // XXX: should this be ICAP-specific?
167 }
168 
169 void
171 {
173  if (!cfg().connectionEncryption.configured())
174  writeableCfg().connectionEncryption.defaultTo(true);
175  theService = FindAdapterService(cfg().uri);
176  if (theService) {
177  try {
178  tryConfigureAndStart();
179  Must(up());
180  } catch (const std::exception &e) { // standardized exceptions
181  if (!handleFinalizeFailure(e.what()))
182  throw; // rethrow for upper layers to handle
183  } catch (...) { // all other exceptions
184  if (!handleFinalizeFailure("unrecognized exception"))
185  throw; // rethrow for upper layers to handle
186  }
187  return; // success or handled exception
188  } else {
189  debugs(93,DBG_IMPORTANT, "WARNING: configured ecap_service was not loaded: " << cfg().uri);
190  }
191 }
192 
194 void
196 {
197  debugs(93,2, HERE << "configuring eCAP service: " << theService->uri());
198  const ConfigRep cfgRep(dynamic_cast<const ServiceConfig&>(cfg()));
199  theService->configure(cfgRep);
200 
201  debugs(93,DBG_IMPORTANT, "Starting eCAP service: " << theService->uri());
202  theService->start();
203 
204  if (theService->makesAsyncXactions()) {
205  AsyncServices[theService->uri()] = theService;
206  debugs(93, 5, "asyncs: " << AsyncServices.size());
207  }
208 }
209 
212 bool
214 {
215  const bool salvage = cfg().bypass;
216  const int level = salvage ? DBG_IMPORTANT :DBG_CRITICAL;
217  const char *kind = salvage ? "optional" : "essential";
218  debugs(93, level, "ERROR: failed to start " << kind << " eCAP service: " <<
219  cfg().uri << ":\n" << error);
220 
221  if (!salvage)
222  return false; // we cannot handle the problem; the caller may escalate
223 
224  // make up() false, preventing new adaptation requests and enabling bypass
225  theService.reset();
226  debugs(93, level, "WARNING: " << kind << " eCAP service is " <<
227  "down after initialization failure: " << cfg().uri);
228 
229  return true; // tell the caller to ignore the problem because we handled it
230 }
231 
233 {
234  return true; // we "probe" the adapter in finalize().
235 }
236 
238 {
239  return bool(theService);
240 }
241 
243 {
244  Must(up());
245  SBuf nonConstUrlPath = urlPath;
246  // c_str() reallocates and terminates for libecap API
247  return theService->wantsUrl(nonConstUrlPath.c_str());
248 }
249 
253 {
254  Must(up());
255 
256  // register now because (a) we need EventLoop::Running and (b) we do not
257  // want to add more main loop overheads unless an async service is used.
258  static AsyncEngine *TheEngine = NULL;
259  if (AsyncServices.size() && !TheEngine && EventLoop::Running) {
260  TheEngine = new Engine;
262  debugs(93, 3, "asyncs: " << AsyncServices.size() << ' ' << TheEngine);
263  }
264 
265  XactionRep *rep = new XactionRep(virgin, cause, alp, Pointer(this));
266  XactionRep::AdapterXaction x(theService->makeXaction(rep));
267  rep->master(x);
268  return rep;
269 }
270 
271 // returns a temporary string depicting service status, for debugging
273 {
274  // TODO: move generic stuff from eCAP and ICAP to Adaptation
275  static MemBuf buf;
276 
277  buf.reset();
278  buf.append("[", 1);
279 
280  if (up())
281  buf.append("up", 2);
282  else
283  buf.append("down", 4);
284 
285  if (detached())
286  buf.append(",detached", 9);
287 
288  buf.append("]", 1);
289  buf.terminate();
290 
291  return buf.content();
292 }
293 
295 {
296  isDetached = true;
297 }
298 
300 {
301  return isDetached;
302 }
303 
306 {
307  AdapterServices::const_iterator pos = TheServices.find(serviceUri.termedBuf());
308  if (pos != TheServices.end()) {
309  Must(pos->second);
310  return pos->second;
311  }
313 }
314 
315 void
317 {
318  TheServices[adapterService->uri()] = adapterService; // may update old one
319  debugs(93, 3, "stored eCAP module service: " << adapterService->uri());
320  // We do not update AsyncServices here in case they are not configured.
321 }
322 
323 void
325 {
326  if (TheServices.erase(serviceUri.termedBuf())) {
327  debugs(93, 3, "unregistered eCAP module service: " << serviceUri);
328  AsyncServices.erase(serviceUri.termedBuf()); // no-op for non-async
329  return;
330  }
331  debugs(93, 3, "failed to unregister eCAP module service: " << serviceUri);
332 }
333 
334 void
336 {
337  typedef AdapterServices::const_iterator ASCI;
338  for (ASCI loaded = TheServices.begin(); loaded != TheServices.end();
339  ++loaded) {
340  bool found = false;
341  for (Services::const_iterator cfged = cfgs.begin();
342  cfged != cfgs.end() && !found; ++cfged) {
343  found = (*cfged)->cfg().uri == loaded->second->uri().c_str();
344  }
345  if (!found)
346  debugs(93, DBG_IMPORTANT, "Warning: loaded eCAP service has no matching " <<
347  "ecap_service config option: " << loaded->second->uri());
348  }
349 }
350 
std::vector< Adaptation::ServicePointer > Services
Definition: Service.h:70
const Master & master
the configuration being wrapped
Definition: ServiceRep.cc:54
#define assert(EX)
Definition: assert.h:17
virtual const char * status() const
Definition: ServiceRep.cc:272
ServiceRep::AdapterService FindAdapterService(const String &serviceUri)
returns loaded eCAP module service by service uri
Definition: ServiceRep.cc:305
virtual void append(const char *c, int sz)
Definition: MemBuf.cc:225
const libecap::Name metaBypassable
an ecap_service parameter
Definition: SBuf.h:87
void master(const AdapterXaction &aMaster)
Definition: XactionRep.cc:73
virtual bool probed() const
Definition: ServiceRep.cc:232
void error(char *format,...)
int i
Definition: membanger.c:49
void UnregisterAdapterService(const String &serviceUri)
unregister loaded eCAP module service by service uri
Definition: ServiceRep.cc:324
static AdapterServices AsyncServices
configured services producing async transactions
Definition: ServiceRep.cc:33
#define DBG_CRITICAL
Definition: Debug.h:44
void CheckUnusedAdapterServices(const Services &services)
check for loaded eCAP services without matching ecap_service in squid.conf
Definition: ServiceRep.cc:335
std::map< std::string, Adaptation::Ecap::ServiceRep::AdapterService > AdapterServices
libecap::adapter::services indexed by their URI
Definition: ServiceRep.cc:29
A const & max(A const &lhs, A const &rhs)
void tryConfigureAndStart()
attempts to configure and start eCAP service; the caller handles exceptions
Definition: ServiceRep.cc:195
virtual const libecap::Area option(const libecap::Name &name) const
Definition: ServiceRep.cc:76
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:123
#define DBG_IMPORTANT
Definition: Debug.h:45
#define EVENT_LOOP_TIMEOUT
Definition: EventLoop.h:14
virtual bool up() const
Definition: ServiceRep.cc:237
void reset()
Definition: MemBuf.cc:141
char const * termedBuf() const
Definition: SquidString.h:90
eCAP service configuration
Definition: Config.h:25
common parts of HttpRequest and HttpReply
Definition: Message.h:24
virtual void visitEachOption(libecap::NamedValueVisitor &visitor) const
Definition: ServiceRep.cc:94
const char * c_str()
Definition: SBuf.cc:546
char * content()
start of the added data
Definition: MemBuf.h:41
void const char * buf
Definition: stub_helper.cc:16
ServiceRep(const ServiceConfigPointer &aConfig)
Definition: ServiceRep.cc:154
std::ostream & HERE(std::ostream &s)
Definition: Debug.h:147
libecap::shared_ptr< libecap::adapter::Service > AdapterService
Definition: ServiceRep.h:34
#define Must(cond)
Definition: TextException.h:89
virtual void finalize()
Definition: Service.cc:26
virtual int checkEvents(int timeout)
Definition: ServiceRep.cc:108
void kickAsyncServices(timeval &timeout)
resumes async transactions (if any) and returns true if they set a timeout
Definition: ServiceRep.cc:132
static EventLoop * Running
Definition: EventLoop.h:72
std::map< OptionName, const Option *, OptionNameCmp > Options
name:option map
Definition: Options.h:159
Definition: MemBuf.h:23
libecap::shared_ptr< libecap::adapter::Xaction > AdapterXaction
Definition: XactionRep.h:41
bool handleFinalizeFailure(const char *error)
Definition: ServiceRep.cc:213
virtual Adaptation::Initiate * makeXactLauncher(Http::Message *virginHeader, HttpRequest *virginCause, AccessLogEntry::Pointer &alp)
Definition: ServiceRep.cc:251
Adaptation::Ecap::ServiceConfig Master
Definition: ServiceRep.cc:44
virtual bool detached() const
whether detached() was called
Definition: ServiceRep.cc:299
void registerEngine(AsyncEngine *engine)
Definition: EventLoop.cc:70
virtual bool wantsUrl(const SBuf &urlPath) const
Definition: ServiceRep.cc:242
static AdapterServices TheServices
all loaded services
Definition: ServiceRep.cc:31
ConfigRep(const Master &aMaster)
Definition: ServiceRep.cc:71
void RegisterAdapterService(const ServiceRep::AdapterService &adapterService)
register loaded eCAP module service
Definition: ServiceRep.cc:316
#define NULL
Definition: types.h:166
manages async eCAP transactions
Definition: ServiceRep.cc:58
#define false
Definition: GnuRegex.c:233
wraps Adaptation::Ecap::ServiceConfig to allow eCAP visitors
Definition: ServiceRep.cc:41
void terminate()
Definition: MemBuf.cc:259

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors