void
Adaptation::Config::freeService()
{
+ FreeAccess();
+ FreeServiceGroups();
+
+ DetachServices();
+
while (!serviceConfigs.empty()) {
delete serviceConfigs.back();
serviceConfigs.pop_back();
// with global arrays shared by those individual configs
Adaptation::Config::~Config()
{
- FreeAccess();
- FreeServiceGroups();
-
- // invalidate each service so that it can be deleted when refcount=0
- while (!AllServices().empty()) {
- AllServices().back()->invalidate();
- AllServices().pop_back();
- }
-
freeService();
}
}
return NULL;
}
+
+void Adaptation::DetachServices()
+{
+ while (!AllServices().empty())
+ AllServices().pop_back()->detach();
+}
Service(const ServiceConfig &aConfig);
virtual ~Service();
- // call when the service is no longer needed or valid
- virtual void invalidate() = 0;
-
virtual bool probed() const = 0; // see comments above
virtual bool broken() const;
virtual bool up() const = 0; // see comments above
virtual void finalize(); // called after creation
+ /// called when removed from the config; the service will be
+ /// auto-destroyed when the last refcounting user leaves
+ virtual void detach() = 0;
+ /// whether detached() was called
+ virtual bool detached() const = 0;
+
protected:
ServiceConfig &writeableCfg() { return theConfig; }
extern Services &AllServices();
extern ServicePointer FindService(const Service::Id &key);
+/// detach all adaptation services from current configuration
+extern void DetachServices();
+
} // namespace Adaptation
#endif /* SQUID_ADAPTATION__SERVICE_H */
*/
#include "squid.h"
-#include <libecap/common/registry.h>
#include "adaptation/ecap/Host.h"
#include "adaptation/ecap/ServiceRep.h"
#include "adaptation/ecap/Config.h"
Adaptation::Ecap::Config::finalize()
{
Adaptation::Config::finalize();
- libecap::shared_ptr<Adaptation::Ecap::Host> host(new Adaptation::Ecap::Host);
- libecap::RegisterHost(host);
+ Host::Register();
+ CheckUnusedAdapterServices(AllServices());
}
Adaptation::ServicePointer
#include "squid.h"
#include <libecap/adapter/service.h>
#include <libecap/common/names.h>
+#include <libecap/common/registry.h>
#include "TextException.h"
#include "adaptation/ecap/ServiceRep.h"
#include "adaptation/ecap/Host.h"
const libecap::Name Adaptation::Ecap::protocolHtcp("Htcp", libecap::Name::NextId());
#endif
+/// the host application (i.e., Squid) wrapper registered with libecap
+static libecap::shared_ptr<Adaptation::Ecap::Host> TheHost;
+
Adaptation::Ecap::Host::Host()
{
// assign our host-specific IDs to well-known names
+ // this code can run only once
+
libecap::headerReferer.assignHostId(HDR_REFERER);
libecap::protocolHttp.assignHostId(PROTO_HTTP);
void
Adaptation::Ecap::Host::noteService(const libecap::weak_ptr<libecap::adapter::Service> &weak)
{
- // Many ecap_service lines may use the same service URI. Find each
- // matching service rep, make sure it is an eCAP rep,
- // and update it with the actual eCAP service.
- int found = 0;
-
- libecap::shared_ptr<libecap::adapter::Service> shared(weak);
- typedef Adaptation::Services::iterator SI;
- for (SI i = Adaptation::AllServices().begin(); i != Adaptation::AllServices().end(); ++i) {
- if ((*i)->cfg().uri == shared->uri().c_str()) {
- ServiceRep *rep = dynamic_cast<ServiceRep*>(i->getRaw());
- Must(rep);
- rep->noteService(shared);
- ++found;
- }
- }
-
- debugs(93,5, HERE << "Found " << found << " ecap_service configs for " <<
- shared->uri());
- if (!found) {
- debugs(93,1, "Warning: ignoring loaded eCAP module service without " <<
- "a matching ecap_service configuration: " << shared->uri());
- }
+ Must(!weak.expired());
+ RegisterAdapterService(weak.lock());
}
static int
if (debug)
Debug::finishDebug();
}
+
+void
+Adaptation::Ecap::Host::Register()
+{
+ if (!TheHost) {
+ TheHost.reset(new Adaptation::Ecap::Host);
+ libecap::RegisterHost(TheHost);
+ }
+}
class Host : public libecap::host::Host
{
public:
- Host();
-
// About
virtual std::string uri() const; // unique across all vendors
virtual void describe(std::ostream &os) const; // free-format info
// Logging
virtual std::ostream *openDebug(libecap::LogVerbosity lv);
virtual void closeDebug(std::ostream *debug);
+
+ static void Register(); ///< register adaptation host
+
+private:
+ Host();
+ Host (const Host&); ///< not implemented
+ Host& operator= (const Host&); ///< not implemented
};
extern const libecap::Name protocolInternal;
* DEBUG: section 93 eCAP Interface
*/
#include "squid.h"
+#include <list>
#include <libecap/adapter/service.h>
#include "TextException.h"
#include "adaptation/ecap/ServiceRep.h"
#include "adaptation/ecap/XactionRep.h"
+// configured eCAP service wrappers
+static std::list<Adaptation::Ecap::ServiceRep::AdapterService> TheServices;
+
Adaptation::Ecap::ServiceRep::ServiceRep(const Adaptation::ServiceConfig &cfg):
- /*AsyncJob("Adaptation::Ecap::ServiceRep"),*/ Adaptation::Service(cfg)
+ /*AsyncJob("Adaptation::Ecap::ServiceRep"),*/ Adaptation::Service(cfg),
+ isDetached(false)
{
}
{
}
-void Adaptation::Ecap::ServiceRep::noteService(const AdapterService &s)
-{
- Must(s != NULL);
- theService = s;
- debugs(93,7, HERE << "matched loaded and configured eCAP services: " <<
- s->uri() << ' ' << cfg().key << "\n");
-}
-
-void Adaptation::Ecap::ServiceRep::invalidate()
-{
- theService->retire();
- theService.reset();
-}
-
void Adaptation::Ecap::ServiceRep::noteFailure()
{
assert(false); // XXX: should this be ICAP-specific?
Adaptation::Ecap::ServiceRep::finalize()
{
Adaptation::Service::finalize();
+ theService = FindAdapterService(cfg().uri);
if (theService) {
debugs(93,3, HERE << "starting eCAP service: " << theService->uri());
theService->start();
// returns a temporary string depicting service status, for debugging
const char *Adaptation::Ecap::ServiceRep::status() const
{
- assert(false); // move generic stuff from ICAP to Adaptation
- // add theService->status()?
- return NULL;
+ // TODO: move generic stuff from eCAP and ICAP to Adaptation
+ static MemBuf buf;
+
+ buf.reset();
+ buf.append("[", 1);
+
+ if (up())
+ buf.append("up", 2);
+ else
+ buf.append("down", 4);
+
+ if (detached())
+ buf.append(",detached", 9);
+
+ buf.append("]", 1);
+ buf.terminate();
+
+ return buf.content();
+}
+
+void Adaptation::Ecap::ServiceRep::detach()
+{
+ isDetached = true;
+}
+
+bool Adaptation::Ecap::ServiceRep::detached() const
+{
+ return isDetached;
+}
+
+Adaptation::Ecap::ServiceRep::AdapterService
+Adaptation::Ecap::FindAdapterService(const String& serviceUri)
+{
+ typedef std::list<ServiceRep::AdapterService>::const_iterator ASCI;
+ for (ASCI s = TheServices.begin(); s != TheServices.end(); ++s) {
+ Must(*s);
+ if (serviceUri == (*s)->uri().c_str())
+ return *s;
+ }
+ return ServiceRep::AdapterService();
+}
+
+void
+Adaptation::Ecap::RegisterAdapterService(const Adaptation::Ecap::ServiceRep::AdapterService& adapterService)
+{
+ typedef std::list<ServiceRep::AdapterService>::iterator ASI;
+ for (ASI s = TheServices.begin(); s != TheServices.end(); ++s) {
+ Must(*s);
+ if (adapterService->uri() == (*s)->uri()) {
+ *s = adapterService;
+ debugs(93, 3, "updated eCAP module service: " <<
+ adapterService->uri());
+ return;
+ }
+ }
+ TheServices.push_back(adapterService);
+ debugs(93, 3, "registered eCAP module service: " << adapterService->uri());
+}
+
+void
+Adaptation::Ecap::UnregisterAdapterService(const String& serviceUri)
+{
+ typedef std::list<ServiceRep::AdapterService>::iterator ASI;
+ for (ASI s = TheServices.begin(); s != TheServices.end(); ++s) {
+ if (serviceUri == (*s)->uri().c_str()) {
+ TheServices.erase(s);
+ debugs(93, 3, "unregistered eCAP module service: " << serviceUri);
+ return;
+ }
+ }
+ debugs(93, 3, "failed to unregister eCAP module service: " << serviceUri);
+}
+
+void
+Adaptation::Ecap::CheckUnusedAdapterServices(const Adaptation::Services& cfgs)
+{
+ typedef std::list<ServiceRep::AdapterService>::const_iterator ASCI;
+ for (ASCI loaded = TheServices.begin(); loaded != TheServices.end();
+ ++loaded) {
+ bool found = false;
+ for (Services::const_iterator cfged = cfgs.begin();
+ cfged != cfgs.end() && !found; ++cfged) {
+ found = (*cfged)->cfg().uri == (*loaded)->uri().c_str();
+ }
+ if (!found)
+ debugs(93, 1, "Warning: loaded eCAP service has no matching " <<
+ "ecap_service config option: " << (*loaded)->uri());
+ }
}
virtual ~ServiceRep();
typedef libecap::shared_ptr<libecap::adapter::Service> AdapterService;
- void noteService(const AdapterService &s);
virtual void finalize();
- // call when the service is no longer needed or valid
- virtual void invalidate();
-
virtual bool probed() const;
virtual bool up() const;
virtual const char *status() const;
+ virtual void detach();
+ virtual bool detached() const;
+
private:
AdapterService theService; // the actual adaptation service we represent
+ bool isDetached;
};
+/// register loaded eCAP module service
+extern void RegisterAdapterService(const ServiceRep::AdapterService& adapterService);
+/// unregister loaded eCAP module service by service uri
+extern void UnregisterAdapterService(const String& serviceUri);
+
+/// returns loaded eCAP module service by service uri
+extern ServiceRep::AdapterService FindAdapterService(const String& serviceUri);
+
+/// check for loaded eCAP services without matching ecap_service in squid.conf
+extern void CheckUnusedAdapterServices(const Services& services);
} // namespace Ecap
} // namespace Adaptation
Adaptation::ServicePointer
Adaptation::Icap::Config::createService(const Adaptation::ServiceConfig &cfg)
{
- Adaptation::Icap::ServiceRep::Pointer s = new Adaptation::Icap::ServiceRep(cfg);
- s->setSelf(s);
- return s.getRaw();
+ return new Adaptation::Icap::ServiceRep(cfg);
}
time_t Adaptation::Icap::Config::connect_timeout(bool bypassable) const
AsyncJob("Adaptation::Icap::ServiceRep"), Adaptation::Service(svcCfg),
theOptions(NULL), theOptionsFetcher(0), theLastUpdate(0),
theSessionFailures(0), isSuspended(0), notifying(false),
- updateScheduled(false), self(NULL),
- wasAnnouncedUp(true) // do not announce an "up" service at startup
+ updateScheduled(false),
+ wasAnnouncedUp(true), // do not announce an "up" service at startup
+ isDetached(false)
{}
Adaptation::Icap::ServiceRep::~ServiceRep()
{
Must(!theOptionsFetcher);
- changeOptions(0);
-}
-
-void
-Adaptation::Icap::ServiceRep::setSelf(Pointer &aSelf)
-{
- assert(!self && aSelf != NULL);
- self = aSelf;
+ delete theOptions;
}
void
Adaptation::Icap::ServiceRep::finalize()
{
Adaptation::Service::finalize();
- assert(self != NULL);
// use /etc/services or default port if needed
const bool have_port = cfg().port >= 0;
}
}
-void Adaptation::Icap::ServiceRep::invalidate()
-{
- assert(self != NULL);
- Pointer savedSelf = self; // to prevent destruction when we nullify self
- self = NULL;
-
- announceStatusChange("invalidated by reconfigure", false);
-
- savedSelf = NULL; // may destroy us and, hence, invalidate cbdata(this)
- // TODO: it would be nice to invalidate cbdata(this) when not destroyed
-}
-
void Adaptation::Icap::ServiceRep::noteFailure()
{
++theSessionFailures;
bool Adaptation::Icap::ServiceRep::up() const
{
- return self != NULL && !isSuspended && hasOptions();
+ return !isSuspended && hasOptions();
}
bool Adaptation::Icap::ServiceRep::wantsUrl(const String &urlPath) const
void Adaptation::Icap::ServiceRep::noteTimeToUpdate()
{
- if (self != NULL)
+ if (!detached())
updateScheduled = false;
- if (!self || theOptionsFetcher) {
+ if (detached() || theOptionsFetcher) {
debugs(93,5, HERE << "ignores options update " << status());
return;
}
debugs(93,5, HERE << "Adaptation::Icap::Service is asked to call " << *cb <<
" when ready " << status());
- Must(self != NULL);
Must(!broken()); // we do not wait for a broken service
Client i;
- i.service = self; // TODO: is this really needed?
+ i.service = Pointer(this); // TODO: is this really needed?
i.callback = cb;
theClients.push_back(i);
bool Adaptation::Icap::ServiceRep::needNewOptions() const
{
- return self != NULL && !up();
+ return !detached() && !up();
}
void Adaptation::Icap::ServiceRep::changeOptions(Adaptation::Icap::Options *newOptions)
buf.append("up", 2);
else {
buf.append("down", 4);
- if (!self)
- buf.append(",gone", 5);
if (isSuspended)
buf.append(",susp", 5);
buf.append(",stale", 6);
}
+ if (detached())
+ buf.append(",detached", 9);
+
if (theOptionsFetcher)
buf.append(",fetch", 6);
return buf.content();
}
+
+void Adaptation::Icap::ServiceRep::detach()
+{
+ debugs(93,3, HERE << "detaching ICAP service: " << cfg().uri <<
+ ' ' << status());
+ isDetached = true;
+}
+
+bool Adaptation::Icap::ServiceRep::detached() const
+{
+ return isDetached;
+}
ServiceRep(const Adaptation::ServiceConfig &config);
virtual ~ServiceRep();
- void setSelf(Pointer &aSelf); // needs self pointer for OptXact
virtual void finalize();
- void invalidate(); // call when the service is no longer needed or valid
-
- bool probed() const; // see comments above
- bool up() const; // see comments above
+ virtual bool probed() const; // see comments above
+ virtual bool up() const; // see comments above
virtual Adaptation::Initiate *makeXactLauncher(Adaptation::Initiator *, HttpMsg *virginHeader, HttpRequest *virginCause);
//AsyncJob virtual methods
virtual bool doneAll() const { return Adaptation::Initiator::doneAll() && false;}
+ virtual void detach();
+ virtual bool detached() const;
+
public: // treat these as private, they are for callbacks only
void noteTimeToUpdate();
void noteTimeToNotify();
const char *status() const;
- Pointer self;
mutable bool wasAnnouncedUp; // prevent sequential same-state announcements
+ bool isDetached;
CBDATA_CLASS2(ServiceRep);
};
parseEtcHosts();
errorInitialize(); /* reload error pages */
accessLogInit();
+
+#if USE_LOADABLE_MODULES
+ LoadableModulesConfigure(Config.loadable_module_names);
+#endif
+
+#if USE_ADAPTATION
+ bool enableAdaptation = false;
+#if ICAP_CLIENT
+ Adaptation::Icap::TheConfig.finalize();
+ enableAdaptation = Adaptation::Icap::TheConfig.onoff || enableAdaptation;
+#endif
+#if USE_ECAP
+ Adaptation::Ecap::TheConfig.finalize(); // must be after we load modules
+ enableAdaptation = Adaptation::Ecap::TheConfig.onoff || enableAdaptation;
+#endif
+ Adaptation::Config::Finalize(enableAdaptation);
+#endif
+
#if ICAP_CLIENT
icapLogOpen();
#endif