]>
Commit | Line | Data |
---|---|---|
b510f3a1 AJ |
1 | /* |
2 | * DEBUG: section 93 eCAP Interface | |
3 | */ | |
f7f3304a | 4 | #include "squid-old.h" |
76fc7e57 | 5 | #include <list> |
fdc96a39 | 6 | #include <libecap/adapter/service.h> |
22fff3bf | 7 | #include <libecap/common/options.h> |
e1e90d26 AR |
8 | #include <libecap/common/name.h> |
9 | #include <libecap/common/named_values.h> | |
10 | #include "adaptation/ecap/Config.h" | |
22fff3bf | 11 | #include "adaptation/ecap/Host.h" |
1f3c65fc AR |
12 | #include "adaptation/ecap/ServiceRep.h" |
13 | #include "adaptation/ecap/XactionRep.h" | |
3d93a84d | 14 | #include "base/TextException.h" |
fdc96a39 | 15 | |
76fc7e57 AJ |
16 | // configured eCAP service wrappers |
17 | static std::list<Adaptation::Ecap::ServiceRep::AdapterService> TheServices; | |
18 | ||
22fff3bf AR |
19 | namespace Adaptation |
20 | { | |
21 | namespace Ecap | |
22 | { | |
23 | ||
e1e90d26 | 24 | /// wraps Adaptation::Ecap::ServiceConfig to allow eCAP visitors |
22fff3bf | 25 | class ConfigRep: public libecap::Options |
e1e90d26 AR |
26 | { |
27 | public: | |
28 | typedef Adaptation::Ecap::ServiceConfig Master; | |
29 | typedef libecap::Name Name; | |
30 | typedef libecap::Area Area; | |
31 | ||
22fff3bf | 32 | ConfigRep(const Master &aMaster); |
e1e90d26 | 33 | |
22fff3bf AR |
34 | // libecap::Options API |
35 | virtual const libecap::Area option(const libecap::Name &name) const; | |
36 | virtual void visitEachOption(libecap::NamedValueVisitor &visitor) const; | |
e1e90d26 AR |
37 | |
38 | const Master &master; ///< the configuration being wrapped | |
39 | }; | |
40 | ||
22fff3bf AR |
41 | } // namespace Ecap |
42 | } // namespace Adaptation | |
43 | ||
44 | ||
45 | Adaptation::Ecap::ConfigRep::ConfigRep(const Master &aMaster): master(aMaster) | |
46 | { | |
47 | } | |
48 | ||
49 | const libecap::Area | |
50 | Adaptation::Ecap::ConfigRep::option(const libecap::Name &name) const | |
51 | { | |
52 | // we may supply the params we know about, but only when names have host ID | |
53 | if (name == metaBypassable) | |
54 | return Area(master.bypass ? "1" : "0", 1); | |
55 | ||
56 | // TODO: We could build a by-name index, but is it worth it? Good adapters | |
57 | // should use visitEachOption() instead, to check for name typos/errors. | |
58 | typedef Master::Extensions::const_iterator MECI; | |
59 | for (MECI i = master.extensions.begin(); i != master.extensions.end(); ++i) { | |
60 | if (name == i->first) | |
61 | return Area(i->second.data(), i->second.size()); | |
62 | } | |
63 | ||
64 | return Area(); | |
65 | } | |
66 | ||
e1e90d26 | 67 | void |
22fff3bf | 68 | Adaptation::Ecap::ConfigRep::visitEachOption(libecap::NamedValueVisitor &visitor) const |
e1e90d26 AR |
69 | { |
70 | // we may supply the params we know about too, but only if we set host ID | |
22fff3bf | 71 | visitor.visit(metaBypassable, Area(master.bypass ? "1" : "0", 1)); |
e1e90d26 AR |
72 | |
73 | // visit adapter-specific options (i.e., those not recognized by Squid) | |
74 | typedef Master::Extensions::const_iterator MECI; | |
75 | for (MECI i = master.extensions.begin(); i != master.extensions.end(); ++i) | |
76 | visitor.visit(Name(i->first), Area::FromTempString(i->second)); | |
77 | } | |
78 | ||
79 | ||
80 | ||
6666da11 | 81 | Adaptation::Ecap::ServiceRep::ServiceRep(const ServiceConfigPointer &cfg): |
76fc7e57 AJ |
82 | /*AsyncJob("Adaptation::Ecap::ServiceRep"),*/ Adaptation::Service(cfg), |
83 | isDetached(false) | |
fdc96a39 AR |
84 | { |
85 | } | |
86 | ||
574b508c | 87 | Adaptation::Ecap::ServiceRep::~ServiceRep() |
fdc96a39 AR |
88 | { |
89 | } | |
90 | ||
574b508c | 91 | void Adaptation::Ecap::ServiceRep::noteFailure() |
26ac0430 AJ |
92 | { |
93 | assert(false); // XXX: should this be ICAP-specific? | |
fdc96a39 AR |
94 | } |
95 | ||
96 | void | |
574b508c | 97 | Adaptation::Ecap::ServiceRep::finalize() |
fdc96a39 | 98 | { |
26ac0430 | 99 | Adaptation::Service::finalize(); |
76fc7e57 | 100 | theService = FindAdapterService(cfg().uri); |
e1d1bd27 | 101 | if (theService) { |
45d2da8b AR |
102 | try { |
103 | tryConfigureAndStart(); | |
104 | Must(up()); | |
aa420fc9 | 105 | } catch (const std::exception &e) { // standardized exceptions |
45d2da8b AR |
106 | if (!handleFinalizeFailure(e.what())) |
107 | throw; // rethrow for upper layers to handle | |
aa420fc9 | 108 | } catch (...) { // all other exceptions |
45d2da8b AR |
109 | if (!handleFinalizeFailure("unrecognized exception")) |
110 | throw; // rethrow for upper layers to handle | |
111 | } | |
112 | return; // success or handled exception | |
e1d1bd27 | 113 | } else { |
1159e19b | 114 | debugs(93,DBG_IMPORTANT, "WARNING: configured ecap_service was not loaded: " << cfg().uri); |
26ac0430 | 115 | } |
fdc96a39 AR |
116 | } |
117 | ||
45d2da8b AR |
118 | /// attempts to configure and start eCAP service; the caller handles exceptions |
119 | void | |
120 | Adaptation::Ecap::ServiceRep::tryConfigureAndStart() | |
121 | { | |
122 | debugs(93,2, HERE << "configuring eCAP service: " << theService->uri()); | |
123 | const ConfigRep cfgRep(dynamic_cast<const ServiceConfig&>(cfg())); | |
124 | theService->configure(cfgRep); | |
125 | ||
126 | debugs(93,DBG_IMPORTANT, "Starting eCAP service: " << theService->uri()); | |
127 | theService->start(); | |
128 | } | |
129 | ||
130 | /// handles failures while configuring or starting an eCAP service; | |
131 | /// returns false if the error must be propagated to higher levels | |
132 | bool | |
133 | Adaptation::Ecap::ServiceRep::handleFinalizeFailure(const char *error) | |
134 | { | |
135 | const bool salvage = cfg().bypass; | |
aa420fc9 | 136 | const int level = salvage ? DBG_IMPORTANT :DBG_CRITICAL; |
45d2da8b AR |
137 | const char *kind = salvage ? "optional" : "essential"; |
138 | debugs(93, level, "ERROR: failed to start " << kind << " eCAP service: " << | |
139 | cfg().uri << ":\n" << error); | |
140 | ||
141 | if (!salvage) | |
142 | return false; // we cannot handle the problem; the caller may escalate | |
143 | ||
144 | // make up() false, preventing new adaptation requests and enabling bypass | |
145 | theService.reset(); | |
146 | debugs(93, level, "WARNING: " << kind << " eCAP service is " << | |
147 | "down after initialization failure: " << cfg().uri); | |
148 | ||
aa420fc9 | 149 | return true; // tell the caller to ignore the problem because we handled it |
45d2da8b AR |
150 | } |
151 | ||
574b508c | 152 | bool Adaptation::Ecap::ServiceRep::probed() const |
fdc96a39 AR |
153 | { |
154 | return true; // we "probe" the adapter in finalize(). | |
155 | } | |
156 | ||
574b508c | 157 | bool Adaptation::Ecap::ServiceRep::up() const |
fdc96a39 AR |
158 | { |
159 | return theService != NULL; | |
160 | } | |
161 | ||
574b508c | 162 | bool Adaptation::Ecap::ServiceRep::wantsUrl(const String &urlPath) const |
fdc96a39 AR |
163 | { |
164 | Must(up()); | |
c1945e7d | 165 | return theService->wantsUrl(urlPath.termedBuf()); |
fdc96a39 AR |
166 | } |
167 | ||
168 | Adaptation::Initiate * | |
4299f876 | 169 | Adaptation::Ecap::ServiceRep::makeXactLauncher(HttpMsg *virgin, |
4cb2536f | 170 | HttpRequest *cause) |
fdc96a39 | 171 | { |
26ac0430 | 172 | Must(up()); |
4299f876 | 173 | XactionRep *rep = new XactionRep(virgin, cause, Pointer(this)); |
26ac0430 | 174 | XactionRep::AdapterXaction x(theService->makeXaction(rep)); |
fdc96a39 AR |
175 | rep->master(x); |
176 | return rep; | |
177 | } | |
178 | ||
179 | // returns a temporary string depicting service status, for debugging | |
574b508c | 180 | const char *Adaptation::Ecap::ServiceRep::status() const |
fdc96a39 | 181 | { |
76fc7e57 AJ |
182 | // TODO: move generic stuff from eCAP and ICAP to Adaptation |
183 | static MemBuf buf; | |
184 | ||
185 | buf.reset(); | |
186 | buf.append("[", 1); | |
187 | ||
188 | if (up()) | |
189 | buf.append("up", 2); | |
190 | else | |
191 | buf.append("down", 4); | |
192 | ||
193 | if (detached()) | |
194 | buf.append(",detached", 9); | |
195 | ||
196 | buf.append("]", 1); | |
197 | buf.terminate(); | |
198 | ||
199 | return buf.content(); | |
200 | } | |
201 | ||
202 | void Adaptation::Ecap::ServiceRep::detach() | |
203 | { | |
204 | isDetached = true; | |
205 | } | |
d090e020 | 206 | |
76fc7e57 AJ |
207 | bool Adaptation::Ecap::ServiceRep::detached() const |
208 | { | |
209 | return isDetached; | |
210 | } | |
211 | ||
212 | Adaptation::Ecap::ServiceRep::AdapterService | |
213 | Adaptation::Ecap::FindAdapterService(const String& serviceUri) | |
214 | { | |
215 | typedef std::list<ServiceRep::AdapterService>::const_iterator ASCI; | |
216 | for (ASCI s = TheServices.begin(); s != TheServices.end(); ++s) { | |
217 | Must(*s); | |
218 | if (serviceUri == (*s)->uri().c_str()) | |
219 | return *s; | |
220 | } | |
221 | return ServiceRep::AdapterService(); | |
222 | } | |
223 | ||
224 | void | |
225 | Adaptation::Ecap::RegisterAdapterService(const Adaptation::Ecap::ServiceRep::AdapterService& adapterService) | |
226 | { | |
227 | typedef std::list<ServiceRep::AdapterService>::iterator ASI; | |
228 | for (ASI s = TheServices.begin(); s != TheServices.end(); ++s) { | |
229 | Must(*s); | |
230 | if (adapterService->uri() == (*s)->uri()) { | |
231 | *s = adapterService; | |
232 | debugs(93, 3, "updated eCAP module service: " << | |
d090e020 | 233 | adapterService->uri()); |
76fc7e57 AJ |
234 | return; |
235 | } | |
236 | } | |
237 | TheServices.push_back(adapterService); | |
238 | debugs(93, 3, "registered eCAP module service: " << adapterService->uri()); | |
239 | } | |
240 | ||
241 | void | |
242 | Adaptation::Ecap::UnregisterAdapterService(const String& serviceUri) | |
243 | { | |
244 | typedef std::list<ServiceRep::AdapterService>::iterator ASI; | |
245 | for (ASI s = TheServices.begin(); s != TheServices.end(); ++s) { | |
246 | if (serviceUri == (*s)->uri().c_str()) { | |
247 | TheServices.erase(s); | |
248 | debugs(93, 3, "unregistered eCAP module service: " << serviceUri); | |
249 | return; | |
250 | } | |
251 | } | |
252 | debugs(93, 3, "failed to unregister eCAP module service: " << serviceUri); | |
253 | } | |
254 | ||
255 | void | |
256 | Adaptation::Ecap::CheckUnusedAdapterServices(const Adaptation::Services& cfgs) | |
257 | { | |
258 | typedef std::list<ServiceRep::AdapterService>::const_iterator ASCI; | |
259 | for (ASCI loaded = TheServices.begin(); loaded != TheServices.end(); | |
d090e020 | 260 | ++loaded) { |
76fc7e57 AJ |
261 | bool found = false; |
262 | for (Services::const_iterator cfged = cfgs.begin(); | |
d090e020 | 263 | cfged != cfgs.end() && !found; ++cfged) { |
76fc7e57 AJ |
264 | found = (*cfged)->cfg().uri == (*loaded)->uri().c_str(); |
265 | } | |
266 | if (!found) | |
267 | debugs(93, 1, "Warning: loaded eCAP service has no matching " << | |
d090e020 | 268 | "ecap_service config option: " << (*loaded)->uri()); |
76fc7e57 | 269 | } |
fdc96a39 | 270 | } |