]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Added initial support for eCAP library (libecap), including required wrappers
authorAlex Rousskov <rousskov@measurement-factory.com>
Thu, 8 May 2008 20:28:58 +0000 (14:28 -0600)
committerAlex Rousskov <rousskov@measurement-factory.com>
Thu, 8 May 2008 20:28:58 +0000 (14:28 -0600)
for libecap::Host classes and a message translator.

TODO: MessageTranslator should probably be renamed to MessageRep for
consistency and brevity reasons. It also lacks most of the code.

src/eCAP/Config.cc [new file with mode: 0644]
src/eCAP/Config.h [new file with mode: 0644]
src/eCAP/Host.cc [new file with mode: 0644]
src/eCAP/Host.h [new file with mode: 0644]
src/eCAP/Makefile.am
src/eCAP/MessageTranslator.cc [new file with mode: 0644]
src/eCAP/MessageTranslator.h [new file with mode: 0644]
src/eCAP/ServiceRep.cc [new file with mode: 0644]
src/eCAP/ServiceRep.h [new file with mode: 0644]
src/eCAP/XactionRep.cc [new file with mode: 0644]
src/eCAP/XactionRep.h [new file with mode: 0644]

diff --git a/src/eCAP/Config.cc b/src/eCAP/Config.cc
new file mode 100644 (file)
index 0000000..4ba2e76
--- /dev/null
@@ -0,0 +1,36 @@
+
+/*
+ * $Id$
+ */
+
+#include "squid.h"
+
+#include <libecap/common/registry.h>
+#include "eCAP/Host.h"
+#include "eCAP/ServiceRep.h"
+#include "eCAP/Config.h"
+
+Ecap::Config Ecap::TheConfig;
+
+Ecap::Config::Config()
+{
+}
+
+Ecap::Config::~Config()
+{
+}
+
+void
+Ecap::Config::finalize() {
+       Adaptation::Config::finalize();
+       static Ecap::Host *TheHost = new Ecap::Host;
+       libecap::RegisterHost(TheHost);
+}
+
+Adaptation::ServicePointer
+Ecap::Config::createService(const Adaptation::ServiceConfig &cfg)
+{
+    Adaptation::ServicePointer s = new Ecap::ServiceRep(cfg);
+    return s.getRaw();
+}
+
diff --git a/src/eCAP/Config.h b/src/eCAP/Config.h
new file mode 100644 (file)
index 0000000..84e7bff
--- /dev/null
@@ -0,0 +1,34 @@
+
+/*
+ * $Id$
+ *
+ */
+
+#ifndef SQUID_ECAP_CONFIG_H
+#define SQUID_ECAP_CONFIG_H
+
+#include "adaptation/Config.h"
+
+namespace Ecap {
+
+class Config: public Adaptation::Config
+{
+
+public:
+    Config();
+    ~Config();
+
+       virtual void finalize();
+
+private:
+    Config(const Config &); // not implemented
+    Config &operator =(const Config &); // not implemented
+
+    virtual Adaptation::ServicePointer createService(const Adaptation::ServiceConfig &cfg);
+};
+
+extern Config TheConfig;
+
+} // namespace Ecap
+
+#endif /* SQUID_ECAP_CONFIG_H */
diff --git a/src/eCAP/Host.cc b/src/eCAP/Host.cc
new file mode 100644 (file)
index 0000000..e070c11
--- /dev/null
@@ -0,0 +1,79 @@
+#include "squid.h"
+#include <libecap/adapter/service.h>
+#include "TextException.h"
+#include "eCAP/ServiceRep.h"
+#include "eCAP/Host.h"
+
+
+std::string
+Ecap::Host::uri() const
+{
+    return "ecap://squid-cache.org/ecap/hosts/squid";
+}
+
+void
+Ecap::Host::describe(std::ostream &os) const
+{
+    os << PACKAGE_NAME << " v" << PACKAGE_VERSION;
+}
+
+void
+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, "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());
+       }
+}
+
+static int
+SquidLogLevel(libecap::LogVerbosity lv)
+{
+       if (lv.critical())
+               return DBG_CRITICAL; // is it a good idea to ignore other flags?
+
+       if (lv.large())
+               return DBG_DATA; // is it a good idea to ignore other flags?
+
+       if (lv.application())
+               return DBG_DATA; // is it a good idea to ignore other flags?
+
+       return 2 + 2*lv.debugging() + 3*lv.operation() + 2*lv.xaction();
+}
+
+std::ostream *
+Ecap::Host::openDebug(libecap::LogVerbosity lv)
+{
+    const int squidLevel = SquidLogLevel(lv);
+    const int squidSection = 93; // XXX: this should be a global constant
+    // XXX: Debug.h should provide this to us
+       if ((Debug::level = squidLevel) <= Debug::Levels[squidSection])
+               return &Debug::getDebugOut();
+       else
+               return NULL;
+}
+
+void
+Ecap::Host::closeDebug(std::ostream *debug)
+{
+       if (debug)
+               Debug::finishDebug();
+}
diff --git a/src/eCAP/Host.h b/src/eCAP/Host.h
new file mode 100644 (file)
index 0000000..a0cf043
--- /dev/null
@@ -0,0 +1,31 @@
+
+/*
+ * $Id$
+ */
+
+#ifndef SQUID_ECAP_HOST_H
+#define SQUID_ECAP_HOST_H
+
+#include <libecap/host/host.h>
+
+namespace Ecap {
+
+// Squid wrapper, providing host application functionality to eCAP services.
+class Host : public libecap::host::Host
+{
+public:
+               // About
+               virtual std::string uri() const; // unique across all vendors
+               virtual void describe(std::ostream &os) const; // free-format info
+
+               // Service management
+               virtual void noteService(const libecap::weak_ptr<libecap::adapter::Service> &s);
+
+               // Logging
+               virtual std::ostream *openDebug(libecap::LogVerbosity lv);
+               virtual void closeDebug(std::ostream *debug);
+};
+
+} // namespace Ecap
+
+#endif /* SQUID_ECAP_HOST_H */
index 9bddacf0a63b03f071f32fe4febe115c59d6f415..f7d2478e47fee4c81ea80a38faee9fed483f77a0 100644 (file)
@@ -9,18 +9,18 @@ AM_CXXFLAGS = @SQUID_CXXFLAGS@
 noinst_LTLIBRARIES = libeCAP.la
 
 libeCAP_la_SOURCES = \
+       Config.h \
+       Config.cc \
+       Host.h \
+       Host.cc \
+       MessageTranslator.h \
+       MessageTranslator.cc \
+       ServiceRep.h \
+       ServiceRep.cc \
+       XactionRep.h \
+       XactionRep.cc \
+       \
        Registry.h
 
 INCLUDES = -I. -I$(top_builddir)/include -I$(top_srcdir)/include \
         -I$(top_srcdir)/src
-
-
-# Sample adapter section.
-
-EXTRA_DIST = \
-       MinimalAdapter.cc
-        
-lib_LTLIBRARIES = MinimalAdapter.la
-MinimalAdapter_la_SOURCES = MinimalAdapter.cc
-MinimalAdapter_la_LDFLAGS = -module -avoid-version
-MinimalAdapter_la_LIBADD = ./libeCAP.la
diff --git a/src/eCAP/MessageTranslator.cc b/src/eCAP/MessageTranslator.cc
new file mode 100644 (file)
index 0000000..f7fabe2
--- /dev/null
@@ -0,0 +1,8 @@
+/*
+ * DEBUG: section XXX
+ */
+
+#include "squid.h"
+#include "adaptation/Message.h"
+#include "eCAP/MessageTranslator.h"
+
diff --git a/src/eCAP/MessageTranslator.h b/src/eCAP/MessageTranslator.h
new file mode 100644 (file)
index 0000000..5abe8d7
--- /dev/null
@@ -0,0 +1,27 @@
+
+/*
+ * $Id$
+ */
+
+#ifndef SQUID__ECAP__MESSAGE_TRANSLATOR_H
+#define SQUID__ECAP__MESSAGE_TRANSLATOR_H
+
+#include "adaptation/forward.h"
+#include <libecap/common/message.h>
+
+namespace Ecap {
+
+// Translates Squid Adaptation::Message into libecap::Message.
+class MessageTranslator: public libecap::Message
+{
+
+public:
+    MessageTranslator(Adaptation::Message &aMessage): theMessage(aMessage) {}
+
+private:
+    Adaptation::Message &theMessage; // the message being translated to libecap
+};
+
+} // namespace Ecap;
+
+#endif /* SQUID__E_CAP__MESSAGE_TRANSLATOR_H */
diff --git a/src/eCAP/ServiceRep.cc b/src/eCAP/ServiceRep.cc
new file mode 100644 (file)
index 0000000..5d1cba5
--- /dev/null
@@ -0,0 +1,76 @@
+#include "squid.h"
+#include <libecap/adapter/service.h>
+#include "TextException.h"
+#include "assert.h"
+#include "eCAP/ServiceRep.h"
+#include "eCAP/XactionRep.h"
+
+Ecap::ServiceRep::ServiceRep(const Adaptation::ServiceConfig &cfg):
+    /*AsyncJob("Ecap::ServiceRep"),*/ Adaptation::Service(cfg)
+{
+}
+
+Ecap::ServiceRep::~ServiceRep()
+{
+}
+
+void Ecap::ServiceRep::noteService(const AdapterService &s) {
+    Must(s != NULL);
+       theService = s;
+       debugs(93,7, "Matched loaded and configured eCAP services: " <<
+               s->uri() << ' ' << cfg().key << "\n");
+}
+
+void Ecap::ServiceRep::invalidate() {
+       theService->retire();
+       theService.reset();
+}
+
+void Ecap::ServiceRep::noteFailure() {
+       assert(false); // XXX: should this be ICAP-specific?
+}
+
+void
+Ecap::ServiceRep::finalize()
+{
+       Adaptation::Service::finalize();
+    if (!theService) {
+               debugs(93,1, "Warning: configured ecap_service was not loaded: " <<
+            cfg().uri);
+       }
+}
+
+bool Ecap::ServiceRep::probed() const
+{
+    return true; // we "probe" the adapter in finalize().
+}
+
+bool Ecap::ServiceRep::up() const
+{
+    return theService != NULL;
+}
+
+bool Ecap::ServiceRep::wantsUrl(const String &urlPath) const
+{
+    Must(up());
+    return theService->wantsUrl(urlPath.buf());
+}
+
+Adaptation::Initiate *
+Ecap::ServiceRep::makeXactLauncher(Adaptation::Initiator *initiator,
+    HttpMsg *virgin, HttpRequest *cause)
+{
+       Must(up());
+       XactionRep *rep = new XactionRep(initiator, virgin, cause, Pointer(this));
+       XactionRep::AdapterXaction x(theService->makeXaction(rep));
+    rep->master(x);
+    return rep;
+}
+
+// returns a temporary string depicting service status, for debugging
+const char *Ecap::ServiceRep::status() const
+{
+    assert(false); // move generic stuff from ICAP to Adaptation
+    // add theService->status()?
+       return NULL;
+}
diff --git a/src/eCAP/ServiceRep.h b/src/eCAP/ServiceRep.h
new file mode 100644 (file)
index 0000000..ae045a1
--- /dev/null
@@ -0,0 +1,53 @@
+
+/*
+ * $Id$
+ */
+
+#ifndef SQUID_ECAP_SERVICE_REP_H
+#define SQUID_ECAP_SERVICE_REP_H
+
+#include "adaptation/Service.h"
+#include "adaptation/forward.h"
+#include <libecap/common/forward.h>
+#include <libecap/common/memory.h>
+
+namespace Ecap {
+
+/* The eCAP service representative maintains information about a single eCAP
+   service that Squid communicates with. One eCAP module may register many 
+   eCAP services. */
+
+class ServiceRep : public Adaptation::Service
+{
+public:
+    ServiceRep(const Adaptation::ServiceConfig &config);
+    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;
+
+    Adaptation::Initiate *makeXactLauncher(Adaptation::Initiator *, HttpMsg *virginHeader, HttpRequest *virginCause);
+
+    // the methods below can only be called on an up() service
+    virtual bool wantsUrl(const String &urlPath) const;
+
+    // called by transactions to report service failure
+    virtual void noteFailure();
+
+       virtual const char *status() const;
+
+private:
+       AdapterService theService; // the actual adaptation service we represent
+};
+
+} // namespace Ecap
+
+#endif /* SQUID_ECAP_SERVICE_REP_H */
diff --git a/src/eCAP/XactionRep.cc b/src/eCAP/XactionRep.cc
new file mode 100644 (file)
index 0000000..46596d0
--- /dev/null
@@ -0,0 +1,164 @@
+#include "squid.h"
+#include <libecap/adapter/xaction.h>
+#include "TextException.h"
+#include "assert.h"
+#include "HttpRequest.h"
+#include "HttpReply.h"
+#include "eCAP/XactionRep.h"
+
+// CBDATA_CLASS_INIT(Ecap::XactionRep);
+// TODO: add CBDATA_NAMESPACED_CLASS_INIT(namespace, classname)
+cbdata_type Ecap::XactionRep::CBDATA_XactionRep = CBDATA_UNKNOWN;
+
+
+Ecap::XactionRep::XactionRep(Adaptation::Initiator *anInitiator,
+    HttpMsg *virginHeader, HttpRequest *virginCause,
+    const Adaptation::ServicePointer &aService):
+    AsyncJob("Ecap::XactionRep"),
+    Adaptation::Initiate("Ecap::XactionRep", anInitiator, aService),
+    theVirgin(virginHeader), theCause(virginCause),
+    theVirginTranslator(theVirgin), theCauseTranslator(theCause),
+    theAnswerTranslator(theAnswer)
+{
+}
+
+Ecap::XactionRep::~XactionRep()
+{
+    assert(!theMaster);
+}
+
+void
+Ecap::XactionRep::master(const AdapterXaction &x)
+{
+    Must(!theMaster);
+    Must(x != NULL);
+    theMaster = x;
+}
+
+void
+Ecap::XactionRep::start()
+{
+    Must(theMaster);
+    theMaster->start();
+}
+
+void
+Ecap::XactionRep::swangSong()
+{
+    terminateMaster();
+    Adaptation::Initiate::swanSong();
+}
+
+void
+Ecap::XactionRep::terminateMaster()
+{
+    if (theMaster) {
+        AdapterXaction x = theMaster;
+        theMaster.reset();
+        x->stop();
+       }
+}
+
+libecap::Message &
+Ecap::XactionRep::virginMessage()
+{
+    return theVirginTranslator;
+}
+
+libecap::Message &
+Ecap::XactionRep::virginCause()
+{
+    return theCauseTranslator;
+}
+
+void 
+Ecap::XactionRep::useVirgin()
+{
+    theMaster.reset();
+    theVirgin.copyTo(theAnswer);
+    sendAnswer(theAnswer.header);
+}
+
+void 
+Ecap::XactionRep::cloneVirgin()
+{
+    theVirgin.copyTo(theAnswer);
+}
+
+void 
+Ecap::XactionRep::makeAdaptedRequest()
+{
+    theAnswer.set(new HttpRequest);
+}
+
+void 
+Ecap::XactionRep::makeAdaptedResponse()
+{
+    theAnswer.set(new HttpReply);
+}
+
+libecap::Message &
+Ecap::XactionRep::adaptedMessage()
+{
+    return theAnswerTranslator;
+}
+
+void 
+Ecap::XactionRep::useAdapted()
+{
+    theMaster.reset();
+    sendAnswer(theAnswer.header);
+}
+
+void 
+Ecap::XactionRep::useNone()
+{
+    theMaster.reset();
+    tellQueryAborted(true); // should eCAP support retries?
+}
+
+void 
+Ecap::XactionRep::noteMoreBodySpaceAvailable(RefCount<BodyPipe> bp)
+{
+    Must(theMaster);
+    theMaster->noteAdaptedSpaceAvailable();
+}
+
+void 
+Ecap::XactionRep::noteBodyConsumerAborted(RefCount<BodyPipe> bp)
+{
+    Must(theMaster);
+    theMaster->noteAdaptedAborted();
+}
+
+void
+Ecap::XactionRep::noteMoreBodyDataAvailable(RefCount<BodyPipe> bp)
+{
+    Must(theMaster);
+    theMaster->noteVirginDataAvailable();
+}
+
+void
+Ecap::XactionRep::noteBodyProductionEnded(RefCount<BodyPipe> bp)
+{
+    Must(theMaster);
+    theMaster->noteVirginDataEnded();
+}
+
+void
+Ecap::XactionRep::noteBodyProducerAborted(RefCount<BodyPipe> bp)
+{
+    Must(theMaster);
+    theMaster->noteVirginAborted();
+}
+
+void
+Ecap::XactionRep::noteInitiatorAborted()
+{
+    mustStop("initiator aborted");
+}
+
+const char *Ecap::XactionRep::status() const
+{
+       return Adaptation::Initiate::status();
+}
diff --git a/src/eCAP/XactionRep.h b/src/eCAP/XactionRep.h
new file mode 100644 (file)
index 0000000..c1b9c0b
--- /dev/null
@@ -0,0 +1,80 @@
+
+/*
+ * $Id$
+ */
+
+#ifndef SQUID_ECAP_XACTION_REP_H
+#define SQUID_ECAP_XACTION_REP_H
+
+#include "BodyPipe.h"
+#include "adaptation/Initiate.h"
+#include "adaptation/Service.h"
+#include "adaptation/Message.h"
+#include "eCAP/MessageTranslator.h"
+#include <libecap/common/forward.h>
+#include <libecap/common/memory.h>
+#include <libecap/host/xaction.h>
+#include <libecap/adapter/xaction.h>
+
+namespace Ecap {
+
+/* The eCAP xaction representative maintains information about a single eCAP
+   xaction that Squid communicates with. One eCAP module may register many 
+   eCAP xactions. */
+class XactionRep : public Adaptation::Initiate, public libecap::host::Xaction,
+    public BodyProducer, public BodyConsumer
+{
+public:
+    XactionRep(Adaptation::Initiator *anInitiator, HttpMsg *virginHeader, HttpRequest *virginCause, const Adaptation::ServicePointer &service);
+    virtual ~XactionRep();
+
+       typedef libecap::shared_ptr<libecap::adapter::Xaction> AdapterXaction;
+       void master(const AdapterXaction &aMaster); // establish a link
+
+    // libecap::host::Xaction API
+    virtual libecap::Message &virginMessage() ; // request or response
+    virtual libecap::Message &virginCause() ; // request for the above response
+    virtual void useVirgin() ;  // final answer: no adaptation
+    virtual void cloneVirgin() ; // adapted message starts as virgin
+    virtual void makeAdaptedRequest() ; // make fresh adapted request
+    virtual void makeAdaptedResponse() ; // make fresh adapted response
+    virtual libecap::Message &adaptedMessage() ; // request or response
+    virtual void useAdapted() ; // final answer: adapted msg is ready
+    virtual void useNone() ; // final answer: no answer
+
+    // BodyProducer API
+    virtual void noteMoreBodySpaceAvailable(RefCount<BodyPipe> bp);
+    virtual void noteBodyConsumerAborted(RefCount<BodyPipe> bp);
+
+    // BodyConsumer API
+    virtual void noteMoreBodyDataAvailable(RefCount<BodyPipe> bp);
+    virtual void noteBodyProductionEnded(RefCount<BodyPipe> bp);
+    virtual void noteBodyProducerAborted(RefCount<BodyPipe> bp);
+
+    //  Initiate API
+    virtual void noteInitiatorAborted();
+
+    // AsyncJob API (via Initiate)
+    virtual void start();
+    virtual void swangSong();
+    virtual const char *status() const;
+
+protected:
+    void terminateMaster();
+
+private:
+       AdapterXaction theMaster; // the actual adaptation xaction we represent
+
+       Adaptation::Message theVirgin;
+       Adaptation::Message theCause;
+       Adaptation::Message theAnswer;
+       MessageTranslator theVirginTranslator;
+       MessageTranslator theCauseTranslator;
+       MessageTranslator theAnswerTranslator;
+
+       CBDATA_CLASS2(XactionRep);
+};
+
+} // namespace Ecap
+
+#endif /* SQUID_ECAP_XACTION_REP_H */