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 eCAP Interface */
10
11#include "squid.h"
16#include "AsyncEngine.h"
17#include "base/TextException.h"
18#include "debug/Stream.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
29typedef std::map<std::string, Adaptation::Ecap::ServiceRep::AdapterService> AdapterServices;
34
35namespace Adaptation
36{
37namespace Ecap
38{
39
42{
43public:
45 typedef libecap::Name Name;
46 typedef libecap::Area Area;
47
48 ConfigRep(const Master &aMaster);
49
50 // libecap::Options API
51 const libecap::Area option(const libecap::Name &name) const override;
52 void visitEachOption(libecap::NamedValueVisitor &visitor) const override;
53
54 const Master &master;
55};
56
58class Engine: public AsyncEngine
59{
60public:
61 /* AsyncEngine API */
62 int checkEvents(int timeout) override;
63
64private:
65 void kickAsyncServices(timeval &timeout);
66};
67
68} // namespace Ecap
69} // namespace Adaptation
70
71Adaptation::Ecap::ConfigRep::ConfigRep(const Master &aMaster): master(aMaster)
72{
73}
74
75const libecap::Area
76Adaptation::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
93void
94Adaptation::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
107int
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
131void
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
169void
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
194void
196{
197 debugs(93,2, "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
212bool
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 = nullptr;
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
315void
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
323void
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
334void
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
#define EVENT_LOOP_TIMEOUT
Definition: EventLoop.h:16
#define Must(condition)
Definition: TextException.h:75
void error(char *format,...)
#define assert(EX)
Definition: assert.h:17
wraps Adaptation::Ecap::ServiceConfig to allow eCAP visitors
Definition: ServiceRep.cc:42
void visitEachOption(libecap::NamedValueVisitor &visitor) const override
Definition: ServiceRep.cc:94
const Master & master
the configuration being wrapped
Definition: ServiceRep.cc:54
ConfigRep(const Master &aMaster)
Definition: ServiceRep.cc:71
Adaptation::Ecap::ServiceConfig Master
Definition: ServiceRep.cc:44
const libecap::Area option(const libecap::Name &name) const override
Definition: ServiceRep.cc:76
manages async eCAP transactions
Definition: ServiceRep.cc:59
void kickAsyncServices(timeval &timeout)
resumes async transactions (if any) and returns true if they set a timeout
Definition: ServiceRep.cc:132
int checkEvents(int timeout) override
Definition: ServiceRep.cc:108
eCAP service configuration
Definition: Config.h:26
ServiceRep(const ServiceConfigPointer &aConfig)
Definition: ServiceRep.cc:154
bool probed() const override
Definition: ServiceRep.cc:232
void tryConfigureAndStart()
attempts to configure and start eCAP service; the caller handles exceptions
Definition: ServiceRep.cc:195
bool wantsUrl(const SBuf &urlPath) const override
Definition: ServiceRep.cc:242
Adaptation::Initiate * makeXactLauncher(Http::Message *virginHeader, HttpRequest *virginCause, AccessLogEntry::Pointer &alp) override
Definition: ServiceRep.cc:251
bool handleFinalizeFailure(const char *error)
Definition: ServiceRep.cc:213
bool up() const override
Definition: ServiceRep.cc:237
virtual const char * status() const
Definition: ServiceRep.cc:272
void noteFailure() override
Definition: ServiceRep.cc:164
bool detached() const override
whether detached() was called
Definition: ServiceRep.cc:299
libecap::shared_ptr< libecap::adapter::Service > AdapterService
Definition: ServiceRep.h:34
void master(const AdapterXaction &aMaster)
Definition: XactionRep.cc:72
libecap::shared_ptr< libecap::adapter::Xaction > AdapterXaction
Definition: XactionRep.h:41
virtual void finalize()
Definition: Service.cc:26
static EventLoop * Running
Definition: EventLoop.h:73
void registerEngine(AsyncEngine *engine)
Definition: EventLoop.cc:70
common parts of HttpRequest and HttpReply
Definition: Message.h:26
Definition: MemBuf.h:24
void append(const char *c, int sz) override
Definition: MemBuf.cc:209
char * content()
start of the added data
Definition: MemBuf.h:41
void reset()
Definition: MemBuf.cc:129
void terminate()
Definition: MemBuf.cc:241
Definition: SBuf.h:94
const char * c_str()
Definition: SBuf.cc:516
char const * termedBuf() const
Definition: SquidString.h:92
A const & max(A const &lhs, A const &rhs)
#define DBG_IMPORTANT
Definition: Stream.h:38
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:194
#define DBG_CRITICAL
Definition: Stream.h:37
static AdapterServices TheServices
all loaded services
Definition: ServiceRep.cc:31
std::map< std::string, Adaptation::Ecap::ServiceRep::AdapterService > AdapterServices
libecap::adapter::services indexed by their URI
Definition: ServiceRep.cc:29
static AdapterServices AsyncServices
configured services producing async transactions
Definition: ServiceRep.cc:33
std::vector< const Option * > Options
Definition: Options.h:214
void RegisterAdapterService(const ServiceRep::AdapterService &adapterService)
register loaded eCAP module service
Definition: ServiceRep.cc:316
const libecap::Name metaBypassable
an ecap_service parameter
void CheckUnusedAdapterServices(const Services &services)
check for loaded eCAP services without matching ecap_service in squid.conf
Definition: ServiceRep.cc:335
ServiceRep::AdapterService FindAdapterService(const String &serviceUri)
returns loaded eCAP module service by service uri
Definition: ServiceRep.cc:305
void UnregisterAdapterService(const String &serviceUri)
unregister loaded eCAP module service by service uri
Definition: ServiceRep.cc:324
std::vector< Adaptation::ServicePointer > Services
Definition: Service.h:70

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors