The attached patch implements aggregation of SNMP responses, similar to how we aggregate some cache manager stats. The code contains changes that allow us to share some of the classes between Cache Manager and SNMP code: * implement the following base classes under the ipc directory/module: - Ipc::Forwarder (ipc/Forwarder{.cc,.h} files) - Ipc::Inquirer (ipc/Inquirer{.cc,.h} files) - Ipc::Request (ipc/Request{.cc,.h} files) - Ipc::Response (ipc/Response{.cc,.h} files) * fix the Mgr::Forwarder, Mgr::Inquirer, Mgr::Request and Mgr::Response classes to be implemented as kid classes of the equivalent Icp::* classes. Also implements for the SNMP the same mechanism used for cache manager: The SNMP requests forwarder to coordinator which collects the statistics from kids and aggregate them. === modified file 'configure.ac' --- configure.ac 2011-01-12 12:54:10 +0000 +++ configure.ac 2011-01-28 16:19:29 +0000 @@ -976,41 +976,41 @@ AC_MSG_NOTICE([Web Cache Coordination V2 Protocol enabled: $enable_wccpv2]) AC_ARG_ENABLE(kill-parent-hack, AS_HELP_STRING([--enable-kill-parent-hack],[Kill parent on shutdown]), [ SQUID_YESNO([$enableval], [unrecognized argument to --enable-kill-parent-hack: $enableval]) ]) SQUID_DEFINE_BOOL(KILL_PARENT_OPT,${enable_kill_parent_hack:=no}, [A dangerous feature which causes Squid to kill its parent process (presumably the RunCache script) upon receipt of SIGTERM or SIGINT. Deprecated, Use with caution.]) AC_MSG_NOTICE([Kill parent on shutdown hack enabled: $enable_kill_parent_hack]) AC_ARG_ENABLE(snmp, AS_HELP_STRING([--disable-snmp],[Disable SNMP monitoring support]), [ SQUID_YESNO([$enableval], [unrecognized argument to --disable-snmp: $enableval]) ]) SQUID_DEFINE_BOOL(SQUID_SNMP,${enable_snmp:=yes}, [Define to enable SNMP monitoring of Squid]) -AM_CONDITIONAL(USE_SNMP, [test "x$enable_snmp" = "xyes"]) +AM_CONDITIONAL(ENABLE_SNMP, [test "x$enable_snmp" = "xyes"]) if test "x$enable_snmp" = "xyes"; then SNMPLIB='../snmplib/libsnmp.a' makesnmplib=snmplib fi AC_MSG_NOTICE([SNMP support enabled: $enable_snmp]) AC_SUBST(SNMPLIB) AC_SUBST(makesnmplib) AC_ARG_ENABLE(cachemgr-hostname, AS_HELP_STRING([--enable-cachemgr-hostname=hostname], [Make cachemgr.cgi default to this host. If unspecified, uses the name of the build-host]), [ case $enableval in yes) AC_DEFINE(CACHEMGR_HOSTNAME,[getfullhostname()], [If you are upset that the cachemgr.cgi form comes up with the hostname field blank, then define this to getfullhostname()]) AC_MSG_NOTICE([Cachemgr default hostname == host where cachemgr runs]) ;; no) : # Nothing to do.. @@ -3353,40 +3353,41 @@ scripts/Makefile \ src/Makefile \ src/base/Makefile \ src/acl/Makefile \ src/fs/Makefile \ src/repl/Makefile \ src/auth/Makefile \ src/adaptation/Makefile \ src/adaptation/icap/Makefile \ src/adaptation/ecap/Makefile \ src/comm/Makefile \ src/esi/Makefile \ src/eui/Makefile \ src/icmp/Makefile \ src/ident/Makefile \ src/ip/Makefile \ src/log/Makefile \ src/ipc/Makefile \ src/ssl/Makefile \ src/mgr/Makefile \ + src/snmpx/Makefile \ contrib/Makefile \ snmplib/Makefile \ icons/Makefile \ errors/Makefile \ test-suite/Makefile \ doc/Makefile \ doc/manuals/Makefile \ helpers/Makefile \ helpers/basic_auth/Makefile \ helpers/basic_auth/DB/Makefile \ helpers/basic_auth/fake/Makefile \ helpers/basic_auth/getpwnam/Makefile \ helpers/basic_auth/LDAP/Makefile \ helpers/basic_auth/MSNT/Makefile \ helpers/basic_auth/MSNT-multi-domain/Makefile \ helpers/basic_auth/NCSA/Makefile \ helpers/basic_auth/NIS/Makefile \ helpers/basic_auth/PAM/Makefile \ helpers/basic_auth/POP3/Makefile \ helpers/basic_auth/RADIUS/Makefile \ === modified file 'include/Range.h' --- include/Range.h 2010-11-21 04:40:05 +0000 +++ include/Range.h 2011-01-17 15:10:36 +0000 @@ -35,52 +35,52 @@ #if HAVE_IOSFWD #include #endif #if HAVE_OSTREAM #include #endif /* represents [start, end) */ template class Range { public: Range (); Range (C start_, C end_); C start; C end; Range intersection (Range const &) const; - C size() const; + size_t size() const; }; template std::ostream& operator << (std::ostream &os, Range const &aRange) { os << "[" << aRange.start << "," << aRange.end << ")"; return os; } template Range::Range () : start(), end() {} template Range::Range (C start_, C end_) : start(start_), end(end_) {} template Range Range::intersection (Range const &rhs) const { Range result (max(start, rhs.start), min(end, rhs.end)); return result; } template -C +size_t Range::size() const { return end > start ? end - start : 0; } #endif /* SQUID_RANGE_H */ === modified file 'src/Makefile.am' --- src/Makefile.am 2011-01-10 09:43:43 +0000 +++ src/Makefile.am 2011-01-28 17:16:40 +0000 @@ -8,65 +8,71 @@ AUTOMAKE_OPTIONS = subdir-objects if USE_DNSSERVER DNSSOURCE = dns.cc DNSSERVER = dnsserver else DNSSOURCE = dns_internal.cc DNSSERVER = endif DNSSOURCE += \ DnsLookupDetails.h \ DnsLookupDetails.cc SBUF_SOURCE= \ base/InstanceId.h \ MemBlob.h \ MemBlob.cc SNMP_ALL_SOURCE = \ + snmp_core.h \ snmp_core.cc \ snmp_agent.cc -if USE_SNMP +if ENABLE_SNMP SNMP_SOURCE = $(SNMP_ALL_SOURCE) else SNMP_SOURCE = endif LOADABLE_MODULES_SOURCES = \ LoadableModule.h \ LoadableModule.cc \ LoadableModules.h \ LoadableModules.cc SUBDIRS = base comm eui acl fs repl auth ip icmp ident log ipc mgr if ENABLE_SSL SUBDIRS += ssl SSL_LIBS = \ ssl/libsslutil.la \ ssl/libsslsquid.la else SSL_LOCAL_LIBS = endif +if ENABLE_SNMP +SUBDIRS += snmpx +SNMPX_LIBS = snmpx/libsnmpx.la +endif + if USE_ADAPTATION SUBDIRS += adaptation endif if USE_ESI SUBDIRS += esi ESI_LOCAL_LIBS = \ esi/libesi.la \ $(top_builddir)/lib/libTrie/src/libTrie.a ESI_LIBS = $(ESI_LOCAL_LIBS) \ $(XMLLIB) \ $(EXPATLIB) else ESI_LIBS = endif DELAY_POOL_ALL_SOURCE = \ CommonPool.h \ CompositePoolNode.h \ delay_pools.cc \ @@ -530,40 +536,41 @@ CLEANFILES += $(BUILT_SOURCES) nodist_squid_SOURCES = \ $(DISKIO_GEN_SOURCE) \ $(BUILT_SOURCES) squid_LDADD = \ $(COMMON_LIBS) \ comm/libcomm.la \ eui/libeui.la \ icmp/libicmp.la icmp/libicmp-core.la \ log/liblog.la \ $(XTRA_OBJS) \ $(DISK_LINKOBJS) \ $(REPL_OBJS) \ $(DISK_LIBS) \ $(DISK_OS_LIBS) \ $(CRYPTLIB) \ $(REGEXLIB) \ $(SNMPLIB) \ + $(SNMPX_LIBS) \ ${ADAPTATION_LIBS} \ $(ESI_LIBS) \ $(SSL_LIBS) \ $(top_builddir)/lib/libmisccontainers.la \ $(top_builddir)/lib/libmiscencoding.la \ $(top_builddir)/lib/libmiscutil.la \ $(SSLLIB) \ $(EPOLL_LIBS) \ $(MINGW_LIBS) \ $(KRB5LIBS) \ $(COMPAT_LIB) \ $(XTRA_LIBS) squid_DEPENDENCIES = \ $(DISK_LIBS) \ $(DISK_LINKOBJS) \ $(REPL_OBJS) \ $(SNMPLIB) \ ${ADAPTATION_LIBS} \ $(ESI_LOCAL_LIBS) \ $(SSL_LIBS) \ === modified file 'src/client_side.cc' --- src/client_side.cc 2011-01-10 09:43:43 +0000 +++ src/client_side.cc 2011-01-19 16:45:40 +0000 @@ -1043,41 +1043,41 @@ /** * extracts a "range" from *buf and appends them to mb, updating * all offsets and such. */ void ClientSocketContext::packRange(StoreIOBuffer const &source, MemBuf * mb) { HttpHdrRangeIter * i = &http->range_iter; Range available (source.range()); char const *buf = source.data; while (i->currentSpec() && available.size()) { const size_t copy_sz = lengthToSend(available); if (copy_sz) { /* * intersection of "have" and "need" ranges must not be empty */ assert(http->out.offset < i->currentSpec()->offset + i->currentSpec()->length); - assert(http->out.offset + available.size() > i->currentSpec()->offset); + assert(http->out.offset + available.size() > (uint64_t)i->currentSpec()->offset); /* * put boundary and headers at the beginning of a range in a * multi-range */ if (http->multipartRangeRequest() && i->debt() == i->currentSpec()->length) { assert(http->memObject()); clientPackRangeHdr( http->memObject()->getReply(), /* original reply */ i->currentSpec(), /* current range */ i->boundary, /* boundary, the same for all */ mb); } /* * append content */ debugs(33, 3, "clientPackRange: appending " << copy_sz << " bytes"); @@ -1101,41 +1101,41 @@ if (!canPackMoreRanges()) { debugs(33, 3, "clientPackRange: Returning because !canPackMoreRanges."); if (i->debt() == 0) /* put terminating boundary for multiparts */ clientPackTermBound(i->boundary, mb); return; } int64_t nextOffset = getNextRangeOffset(); assert (nextOffset >= http->out.offset); int64_t skip = nextOffset - http->out.offset; /* adjust for not to be transmitted bytes */ http->out.offset = nextOffset; - if (available.size() <= skip) + if (available.size() <= (uint64_t)skip) return; available.start += skip; buf += skip; if (copy_sz == 0) return; } } /** returns expected content length for multi-range replies * note: assumes that httpHdrRangeCanonize has already been called * warning: assumes that HTTP headers for individual ranges at the * time of the actuall assembly will be exactly the same as * the headers when clientMRangeCLen() is called */ int ClientHttpRequest::mRangeCLen() { int64_t clen = 0; === modified file 'src/ipc/Coordinator.cc' --- src/ipc/Coordinator.cc 2010-10-29 00:12:28 +0000 +++ src/ipc/Coordinator.cc 2011-01-28 16:26:27 +0000 @@ -1,40 +1,42 @@ /* * $Id$ * * DEBUG: section 54 Interprocess Communication * */ #include "config.h" #include "base/TextException.h" #include "CacheManager.h" #include "comm.h" #include "ipc/Coordinator.h" -#include "ipc/FdNotes.h" #include "ipc/SharedListen.h" #include "mgr/Inquirer.h" #include "mgr/Request.h" #include "mgr/Response.h" -#include "mgr/StoreToCommWriter.h" - +#if SQUID_SNMP +#include "snmpx/Inquirer.h" +#include "snmpx/Request.h" +#include "snmpx/Response.h" +#endif CBDATA_NAMESPACED_CLASS_INIT(Ipc, Coordinator); Ipc::Coordinator* Ipc::Coordinator::TheInstance = NULL; Ipc::Coordinator::Coordinator(): Port(coordinatorAddr) { } void Ipc::Coordinator::start() { Port::start(); } Ipc::StrandCoord* Ipc::Coordinator::findStrand(int kidId) { typedef StrandCoords::iterator SI; for (SI iter = strands_.begin(); iter != strands_.end(); ++iter) { if (iter->kidId == kidId) @@ -57,40 +59,52 @@ case mtRegistration: debugs(54, 6, HERE << "Registration request"); handleRegistrationRequest(StrandCoord(message)); break; case mtSharedListenRequest: debugs(54, 6, HERE << "Shared listen request"); handleSharedListenRequest(SharedListenRequest(message)); break; case mtCacheMgrRequest: debugs(54, 6, HERE << "Cache manager request"); handleCacheMgrRequest(Mgr::Request(message)); break; case mtCacheMgrResponse: debugs(54, 6, HERE << "Cache manager response"); handleCacheMgrResponse(Mgr::Response(message)); break; +#if SQUID_SNMP + case mtSnmpRequest: + debugs(54, 6, HERE << "SNMP request"); + handleSnmpRequest(Snmp::Request(message)); + break; + + case mtSnmpResponse: + debugs(54, 6, HERE << "SNMP response"); + handleSnmpResponse(Snmp::Response(message)); + break; +#endif + default: debugs(54, 1, HERE << "Unhandled message type: " << message.type()); break; } } void Ipc::Coordinator::handleRegistrationRequest(const StrandCoord& strand) { registerStrand(strand); // send back an acknowledgement; TODO: remove as not needed? TypedMsgHdr message; strand.pack(message); SendMessage(MakeAddr(strandAddrPfx, strand.kidId), message); } void Ipc::Coordinator::handleSharedListenRequest(const SharedListenRequest& request) { debugs(54, 4, HERE << "kid" << request.requestorId << @@ -106,50 +120,71 @@ SharedListenResponse response(sock, errNo, request.mapId); TypedMsgHdr message; response.pack(message); SendMessage(MakeAddr(strandAddrPfx, request.requestorId), message); } void Ipc::Coordinator::handleCacheMgrRequest(const Mgr::Request& request) { debugs(54, 4, HERE); // Let the strand know that we are now responsible for handling the request Mgr::Response response(request.requestId); TypedMsgHdr message; response.pack(message); SendMessage(MakeAddr(strandAddrPfx, request.requestorId), message); Mgr::Action::Pointer action = CacheManager::GetInstance()->createRequestedAction(request.params); - AsyncJob::Start(new Mgr::Inquirer(action, - Mgr::ImportHttpFdIntoComm(request.fd), request, strands_)); + AsyncJob::Start(new Mgr::Inquirer(action, request, strands_)); } void Ipc::Coordinator::handleCacheMgrResponse(const Mgr::Response& response) { Mgr::Inquirer::HandleRemoteAck(response); } +#if SQUID_SNMP +void +Ipc::Coordinator::handleSnmpRequest(const Snmp::Request& request) +{ + debugs(54, 4, HERE); + + Snmp::Response response(request.requestId); + TypedMsgHdr message; + response.pack(message); + SendMessage(MakeAddr(strandAddrPfx, request.requestorId), message); + + AsyncJob::Start(new Snmp::Inquirer(request, strands_)); +} + +void +Ipc::Coordinator::handleSnmpResponse(const Snmp::Response& response) +{ + debugs(54, 4, HERE); + Snmp::Inquirer::HandleRemoteAck(response); +} +#endif + int Ipc::Coordinator::openListenSocket(const SharedListenRequest& request, int &errNo) { const OpenListenerParams &p = request.params; debugs(54, 6, HERE << "opening listen FD at " << p.addr << " for kid" << request.requestorId); Ip::Address addr = p.addr; // comm_open_listener may modify it enter_suid(); const int sock = comm_open_listener(p.sock_type, p.proto, addr, p.flags, FdNote(p.fdNote)); errNo = (sock >= 0) ? 0 : errno; leave_suid(); // cache positive results if (sock >= 0) listeners[request.params] = sock; === modified file 'src/ipc/Coordinator.h' --- src/ipc/Coordinator.h 2010-10-28 18:52:59 +0000 +++ src/ipc/Coordinator.h 2011-01-28 16:25:41 +0000 @@ -1,69 +1,74 @@ /* * $Id$ * * DEBUG: section 54 Interprocess Communication * */ #ifndef SQUID_IPC_COORDINATOR_H #define SQUID_IPC_COORDINATOR_H #include "Array.h" #include "ipc/Messages.h" #include "ipc/Port.h" #include "ipc/SharedListen.h" #include "ipc/StrandCoords.h" #include "mgr/forward.h" - +#if SQUID_SNMP +#include "snmpx/forward.h" +#endif #include namespace Ipc { /// Coordinates shared activities of Strands (Squid processes or threads) class Coordinator: public Port { public: static Coordinator* Instance(); public: Coordinator(); void broadcastSignal(int sig) const; ///< send sig to registered strands const StrandCoords &strands() const; ///< currently registered strands protected: virtual void start(); // Port (AsyncJob) API virtual void receive(const TypedMsgHdr& message); // Port API StrandCoord* findStrand(int kidId); ///< registered strand or NULL void registerStrand(const StrandCoord &); ///< adds or updates existing void handleRegistrationRequest(const StrandCoord &); ///< register,ACK /// returns cached socket or calls openListenSocket() void handleSharedListenRequest(const SharedListenRequest& request); void handleCacheMgrRequest(const Mgr::Request& request); void handleCacheMgrResponse(const Mgr::Response& response); - +#if SQUID_SNMP + void handleSnmpRequest(const Snmp::Request& request); + void handleSnmpResponse(const Snmp::Response& response); +#endif /// calls comm_open_listener() int openListenSocket(const SharedListenRequest& request, int &errNo); private: StrandCoords strands_; ///< registered processes and threads typedef std::map Listeners; ///< params:fd map Listeners listeners; ///< cached comm_open_listener() results static Coordinator* TheInstance; ///< the only class instance in existence private: Coordinator(const Coordinator&); // not implemented Coordinator& operator =(const Coordinator&); // not implemented CBDATA_CLASS2(Coordinator); }; } // namespace Ipc === modified file 'src/ipc/FdNotes.cc' --- src/ipc/FdNotes.cc 2010-06-14 21:22:01 +0000 +++ src/ipc/FdNotes.cc 2011-01-28 16:29:27 +0000 @@ -1,31 +1,33 @@ /* * $Id$ * * DEBUG: section 54 Interprocess Communication * */ #include "config.h" #include "Debug.h" #include "ipc/FdNotes.h" const char * Ipc::FdNote(int fdNoteId) { static const char *FdNotes[Ipc::fdnEnd] = { "None", // fdnNone "HTTP Socket", // fdnHttpSocket "HTTPS Socket", // fdnHttpsSocket +#if SQUID_SNMP "Incoming SNMP Socket", // fdnInSnmpSocket "Outgoing SNMP Socket", // fdnOutSnmpSocket +#endif "Incoming ICP Socket", // fdnInIcpSocket "Incoming HTCP Socket" // fdnInHtcpSocket }; if (fdnNone < fdNoteId && fdNoteId < fdnEnd) return FdNotes[fdNoteId]; debugs(54, 1, HERE << "salvaged bug: wrong fd_note ID: " << fdNoteId); return FdNotes[fdnNone]; } === modified file 'src/ipc/FdNotes.h' --- src/ipc/FdNotes.h 2010-07-06 18:58:38 +0000 +++ src/ipc/FdNotes.h 2011-01-28 16:29:10 +0000 @@ -1,27 +1,29 @@ /* * $Id$ * * DEBUG: section 54 Interprocess Communication * */ #ifndef SQUID_IPC_FD_NOTES_H #define SQUID_IPC_FD_NOTES_H namespace Ipc { /// We cannot send char* FD notes to other processes. Pass int IDs and convert. /// fd_note() label ID typedef enum { fdnNone, fdnHttpSocket, fdnHttpsSocket, +#if SQUID_SNMP fdnInSnmpSocket, fdnOutSnmpSocket, +#endif fdnInIcpSocket, fdnInHtcpSocket, fdnEnd } FdNoteId; extern const char *FdNote(int fdNodeId); ///< converts FdNoteId into a string } // namespace Ipc; #endif /* SQUID_IPC_FD_NOTES_H */ === renamed file 'src/mgr/Forwarder.cc' => 'src/ipc/Forwarder.cc' --- src/mgr/Forwarder.cc 2010-11-26 00:13:51 +0000 +++ src/ipc/Forwarder.cc 2011-01-27 11:16:41 +0000 @@ -1,240 +1,177 @@ /* * $Id$ * - * DEBUG: section 16 Cache Manager API + * DEBUG: section 54 Interprocess Communication * */ #include "config.h" #include "base/AsyncJobCalls.h" #include "base/TextException.h" -#include "CommCalls.h" -#include "errorpage.h" -#include "HttpReply.h" -#include "HttpRequest.h" +#include "ipc/Forwarder.h" #include "ipc/Port.h" -#include "mgr/Forwarder.h" -#include "mgr/Request.h" -#include "SquidTime.h" -#include "Store.h" +#include "ipc/TypedMsgHdr.h" -CBDATA_NAMESPACED_CLASS_INIT(Mgr, Forwarder); +CBDATA_NAMESPACED_CLASS_INIT(Ipc, Forwarder); -Mgr::Forwarder::RequestsMap Mgr::Forwarder::TheRequestsMap; -unsigned int Mgr::Forwarder::LastRequestId = 0; +Ipc::Forwarder::RequestsMap Ipc::Forwarder::TheRequestsMap; +unsigned int Ipc::Forwarder::LastRequestId = 0; -Mgr::Forwarder::Forwarder(int aFd, const ActionParams &aParams, - HttpRequest* aRequest, StoreEntry* anEntry): - AsyncJob("Mgr::Forwarder"), - params(aParams), - request(aRequest), entry(anEntry), fd(aFd), requestId(0), closer(NULL) +Ipc::Forwarder::Forwarder(Request::Pointer aRequest, double aTimeout): + AsyncJob("Ipc::Forwarder"), + request(aRequest), timeout(aTimeout) { - debugs(16, 5, HERE << "FD " << aFd); - Must(fd >= 0); - Must(request != NULL); - Must(entry != NULL); - - HTTPMSGLOCK(request); - entry->lock(); - EBIT_SET(entry->flags, ENTRY_FWD_HDR_WAIT); - - closer = asyncCall(16, 5, "Mgr::Forwarder::noteCommClosed", - CommCbMemFunT(this, &Forwarder::noteCommClosed)); - comm_add_close_handler(fd, closer); + debugs(54, 5, HERE); } -Mgr::Forwarder::~Forwarder() +Ipc::Forwarder::~Forwarder() { - debugs(16, 5, HERE); - Must(request != NULL); - Must(entry != NULL); - Must(requestId == 0); - - HTTPMSGUNLOCK(request); - entry->unregisterAbort(); - entry->unlock(); - close(); + debugs(54, 5, HERE); + Must(request->requestId == 0); + cleanup(); } -/// closes our copy of the client HTTP connection socket +/// perform cleanup actions void -Mgr::Forwarder::close() +Ipc::Forwarder::cleanup() { - if (fd >= 0) { - if (closer != NULL) { - comm_remove_close_handler(fd, closer); - closer = NULL; - } - comm_close(fd); - fd = -1; - } } void -Mgr::Forwarder::start() +Ipc::Forwarder::start() { - debugs(16, 3, HERE); - entry->registerAbort(&Forwarder::Abort, this); + debugs(54, 3, HERE); - typedef NullaryMemFunT Dialer; - AsyncCall::Pointer callback = JobCallback(16, 5, Dialer, this, - Forwarder::handleRemoteAck); - if (++LastRequestId == 0) // don't use zero value as requestId + typedef NullaryMemFunT Dialer; + AsyncCall::Pointer callback = JobCallback(54, 5, Dialer, this, Forwarder::handleRemoteAck); + if (++LastRequestId == 0) // don't use zero value as request->requestId ++LastRequestId; - requestId = LastRequestId; - TheRequestsMap[requestId] = callback; - Request mgrRequest(KidIdentifier, requestId, fd, params); - Ipc::TypedMsgHdr message; + request->requestId = LastRequestId; + TheRequestsMap[request->requestId] = callback; + TypedMsgHdr message; try { - mgrRequest.pack(message); + request->pack(message); } catch (...) { // assume the pack() call failed because the message did not fit // TODO: add a more specific exception? - debugs(16, DBG_CRITICAL, "ERROR: uri " << entry->url() << " exceeds buffer size"); - quitOnError("long URI", errorCon(ERR_INVALID_URL, HTTP_REQUEST_URI_TOO_LARGE, request)); + handleError(); } - Ipc::SendMessage(Ipc::coordinatorAddr, message); - const double timeout = 10; // in seconds - eventAdd("Mgr::Forwarder::requestTimedOut", &Forwarder::RequestTimedOut, + SendMessage(coordinatorAddr, message); + eventAdd("Ipc::Forwarder::requestTimedOut", &Forwarder::RequestTimedOut, this, timeout, 0, false); } void -Mgr::Forwarder::swanSong() +Ipc::Forwarder::swanSong() { - debugs(16, 5, HERE); + debugs(54, 5, HERE); removeTimeoutEvent(); - if (requestId > 0) { - DequeueRequest(requestId); - requestId = 0; + if (request->requestId > 0) { + DequeueRequest(request->requestId); + request->requestId = 0; } - close(); + cleanup(); } bool -Mgr::Forwarder::doneAll() const +Ipc::Forwarder::doneAll() const { - debugs(16, 5, HERE); - return requestId == 0; -} - -/// called when the client socket gets closed by some external force -void -Mgr::Forwarder::noteCommClosed(const CommCloseCbParams &io) -{ - debugs(16, 5, HERE); - Must(fd == io.fd); - fd = -1; - mustStop("commClosed"); + debugs(54, 5, HERE); + return request->requestId == 0; } /// called when Coordinator starts processing the request void -Mgr::Forwarder::handleRemoteAck() +Ipc::Forwarder::handleRemoteAck() { - debugs(16, 3, HERE); - Must(entry != NULL); - - requestId = 0; - EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT); - entry->complete(); + debugs(54, 3, HERE); + request->requestId = 0; } -/// Mgr::Forwarder::requestTimedOut wrapper +/// Ipc::Forwarder::requestTimedOut wrapper void -Mgr::Forwarder::RequestTimedOut(void* param) +Ipc::Forwarder::RequestTimedOut(void* param) { - debugs(16, 3, HERE); + debugs(54, 3, HERE); Must(param != NULL); - Forwarder* mgrFwdr = static_cast(param); + Forwarder* fwdr = static_cast(param); // use async call to enable job call protection that time events lack - CallJobHere(16, 5, mgrFwdr, Mgr::Forwarder, requestTimedOut); + CallJobHere(54, 5, fwdr, Forwarder, requestTimedOut); } /// called when Coordinator fails to start processing the request [in time] void -Mgr::Forwarder::requestTimedOut() +Ipc::Forwarder::requestTimedOut() { - debugs(16, 3, HERE); - quitOnError("timeout", errorCon(ERR_LIFETIME_EXP, HTTP_REQUEST_TIMEOUT, request)); + debugs(54, 3, HERE); + handleTimeout(); } -/// terminate with an error void -Mgr::Forwarder::quitOnError(const char *reason, ErrorState *error) +Ipc::Forwarder::handleError() { - debugs(16, 3, HERE); - Must(reason != NULL); - Must(error != NULL); - Must(entry != NULL); - Must(request != NULL); + mustStop("error"); +} - EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT); - entry->buffer(); - entry->replaceHttpReply(error->BuildHttpReply()); - entry->expires = squid_curtime; - errorStateFree(error); - entry->flush(); - entry->complete(); +void +Ipc::Forwarder::handleTimeout() +{ + mustStop("timeout"); +} - mustStop(reason); +/// terminate with an error +void +Ipc::Forwarder::handleException(const std::exception& e) +{ + debugs(54, 3, HERE << e.what()); + mustStop("exception"); } void -Mgr::Forwarder::callException(const std::exception& e) +Ipc::Forwarder::callException(const std::exception& e) { try { - if (entry != NULL && request != NULL && fd >= 0) - quitOnError("exception", errorCon(ERR_INVALID_RESP, HTTP_INTERNAL_SERVER_ERROR, request)); + handleException(e); } catch (const std::exception& ex) { - debugs(16, DBG_CRITICAL, HERE << ex.what()); + debugs(54, DBG_CRITICAL, HERE << ex.what()); } AsyncJob::callException(e); } /// returns and forgets the right Forwarder callback for the request AsyncCall::Pointer -Mgr::Forwarder::DequeueRequest(unsigned int requestId) +Ipc::Forwarder::DequeueRequest(unsigned int requestId) { - debugs(16, 3, HERE); + debugs(54, 3, HERE); Must(requestId != 0); AsyncCall::Pointer call; RequestsMap::iterator request = TheRequestsMap.find(requestId); if (request != TheRequestsMap.end()) { call = request->second; Must(call != NULL); TheRequestsMap.erase(request); } return call; } /// called when we are no longer waiting for Coordinator to respond void -Mgr::Forwarder::removeTimeoutEvent() +Ipc::Forwarder::removeTimeoutEvent() { if (eventFind(&Forwarder::RequestTimedOut, this)) eventDelete(&Forwarder::RequestTimedOut, this); } void -Mgr::Forwarder::HandleRemoteAck(unsigned int requestId) +Ipc::Forwarder::HandleRemoteAck(unsigned int requestId) { - debugs(16, 3, HERE); + debugs(54, 3, HERE); Must(requestId != 0); AsyncCall::Pointer call = DequeueRequest(requestId); if (call != NULL) ScheduleCallHere(call); } - -/// called when something goes wrong with the Store entry -void -Mgr::Forwarder::Abort(void* param) -{ - Forwarder* mgrFwdr = static_cast(param); - if (mgrFwdr->fd >= 0) - comm_close(mgrFwdr->fd); -} === renamed file 'src/mgr/Forwarder.h' => 'src/ipc/Forwarder.h' --- src/mgr/Forwarder.h 2010-10-29 00:12:28 +0000 +++ src/ipc/Forwarder.h 2011-01-17 15:10:36 +0000 @@ -1,77 +1,68 @@ /* * $Id$ * - * DEBUG: section 16 Cache Manager API + * DEBUG: section 54 Interprocess Communication * */ -#ifndef SQUID_MGR_FORWARDER_H -#define SQUID_MGR_FORWARDER_H +#ifndef SQUID_IPC_FORWARDER_H +#define SQUID_IPC_FORWARDER_H #include "base/AsyncJob.h" -#include "mgr/ActionParams.h" +#include "ipc/Request.h" #include -class CommCloseCbParams; -class HttpRequest; -class StoreEntry; -class ErrorState; - -namespace Mgr +namespace Ipc { -/** Forwards a single client cache manager request to Coordinator. - * Waits for an ACK from Coordinator while holding the Store entry. - * Fills the store entry with an error response if forwarding fails. +/** Forwards a worker request to coordinator. + * Waits for an ACK from Coordinator + * Send the data unit with an error response if forwarding fails. */ class Forwarder: public AsyncJob { public: - Forwarder(int aFd, const ActionParams &aParams, HttpRequest* aRequest, - StoreEntry* anEntry); + Forwarder(Request::Pointer aRequest, double aTimeout); virtual ~Forwarder(); /// finds and calls the right Forwarder upon Coordinator's response static void HandleRemoteAck(unsigned int requestId); /* has-to-be-public AsyncJob API */ virtual void callException(const std::exception& e); protected: /* AsyncJob API */ virtual void start(); virtual void swanSong(); virtual bool doneAll() const; + virtual void cleanup(); ///< perform cleanup actions + virtual void handleError(); + virtual void handleTimeout(); + virtual void handleException(const std::exception& e); + virtual void handleRemoteAck(); + private: - void handleRemoteAck(); static void RequestTimedOut(void* param); void requestTimedOut(); - void quitOnError(const char *reason, ErrorState *error); - void noteCommClosed(const CommCloseCbParams& params); void removeTimeoutEvent(); static AsyncCall::Pointer DequeueRequest(unsigned int requestId); - static void Abort(void* param); - void close(); -private: - ActionParams params; ///< action parameters to pass to the other side - HttpRequest* request; ///< HTTP client request for detailing errors - StoreEntry* entry; ///< Store entry expecting the response - int fd; ///< HTTP client connection descriptor - unsigned int requestId; ///< request id - AsyncCall::Pointer closer; ///< comm_close handler for the HTTP connection +protected: + Request::Pointer request; + const double timeout; ///< response wait timeout in seconds - /// maps requestId to Forwarder::handleRemoteAck callback + /// maps request->id to Forwarder::handleRemoteAck callback typedef std::map RequestsMap; static RequestsMap TheRequestsMap; ///< pending Coordinator requests static unsigned int LastRequestId; ///< last requestId used CBDATA_CLASS2(Forwarder); }; -} // namespace Mgr +} // namespace Ipc -#endif /* SQUID_MGR_FORWARDER_H */ +#endif /* SQUID_IPC_FORWARDER_H */ === renamed file 'src/mgr/Inquirer.cc' => 'src/ipc/Inquirer.cc' --- src/mgr/Inquirer.cc 2010-11-27 01:46:22 +0000 +++ src/ipc/Inquirer.cc 2011-01-27 11:17:17 +0000 @@ -1,253 +1,206 @@ /* * $Id$ * - * DEBUG: section 16 Cache Manager API + * DEBUG: section 54 Interprocess Communication * */ #include "config.h" #include "base/TextException.h" #include "comm/Write.h" -#include "CommCalls.h" -#include "HttpReply.h" -#include "ipc/Coordinator.h" -#include "mgr/ActionWriter.h" -#include "mgr/Command.h" -#include "mgr/Inquirer.h" -#include "mgr/Request.h" -#include "mgr/Response.h" -#include "SquidTime.h" -#include +#include "ipc/Inquirer.h" +#include "ipc/Port.h" +#include "ipc/TypedMsgHdr.h" +#include "MemBuf.h" #include -CBDATA_NAMESPACED_CLASS_INIT(Mgr, Inquirer); +CBDATA_NAMESPACED_CLASS_INIT(Ipc, Inquirer); -Mgr::Inquirer::RequestsMap Mgr::Inquirer::TheRequestsMap; -unsigned int Mgr::Inquirer::LastRequestId = 0; +Ipc::Inquirer::RequestsMap Ipc::Inquirer::TheRequestsMap; +unsigned int Ipc::Inquirer::LastRequestId = 0; /// compare Ipc::StrandCoord using kidId, for std::sort() below static bool LesserStrandByKidId(const Ipc::StrandCoord &c1, const Ipc::StrandCoord &c2) { return c1.kidId < c2.kidId; } -Mgr::Inquirer::Inquirer(Action::Pointer anAction, int aFd, - const Request &aCause, const Ipc::StrandCoords &coords): - AsyncJob("Mgr::Inquirer"), - aggrAction(anAction), - cause(aCause), - fd(aFd), - strands(coords), pos(strands.begin()), - requestId(0), closer(NULL), timeout(aggrAction->atomic() ? 10 : 100) +Ipc::Inquirer::Inquirer(Request::Pointer aRequest, const StrandCoords& coords, + double aTimeout): + AsyncJob("Ipc::Inquirer"), + request(aRequest), strands(coords), pos(strands.begin()), timeout(aTimeout) { - debugs(16, 5, HERE << "FD " << aFd << " action: " << aggrAction); + debugs(54, 5, HERE); // order by ascending kid IDs; useful for non-aggregatable stats std::sort(strands.begin(), strands.end(), LesserStrandByKidId); - - closer = asyncCall(16, 5, "Mgr::Inquirer::noteCommClosed", - CommCbMemFunT(this, &Inquirer::noteCommClosed)); - comm_add_close_handler(fd, closer); } -Mgr::Inquirer::~Inquirer() +Ipc::Inquirer::~Inquirer() { - debugs(16, 5, HERE); - close(); + debugs(54, 5, HERE); + cleanup(); } -/// closes our copy of the client HTTP connection socket void -Mgr::Inquirer::close() +Ipc::Inquirer::cleanup() { - if (fd >= 0) { - removeCloseHandler(); - comm_close(fd); - fd = -1; - } } void -Mgr::Inquirer::removeCloseHandler() +Ipc::Inquirer::start() { - if (closer != NULL) { - comm_remove_close_handler(fd, closer); - closer = NULL; - } + request->requestId = 0; } void -Mgr::Inquirer::start() -{ - debugs(16, 5, HERE); - Must(fd >= 0); - Must(aggrAction != NULL); - - std::auto_ptr reply(new HttpReply); - reply->setHeaders(HTTP_OK, NULL, "text/plain", -1, squid_curtime, squid_curtime); - reply->header.putStr(HDR_CONNECTION, "close"); // until we chunk response - std::auto_ptr replyBuf(reply->pack()); - writer = asyncCall(16, 5, "Mgr::Inquirer::noteWroteHeader", - CommCbMemFunT(this, &Inquirer::noteWroteHeader)); - Comm::Write(fd, replyBuf.get(), writer); -} - -/// called when we wrote the response header -void -Mgr::Inquirer::noteWroteHeader(const CommIoCbParams& params) -{ - debugs(16, 5, HERE); - writer = NULL; - Must(params.flag == COMM_OK); - Must(params.fd == fd); - Must(params.size != 0); - // start inquiries at the initial pos - inquire(); -} - -void -Mgr::Inquirer::inquire() +Ipc::Inquirer::inquire() { if (pos == strands.end()) { Must(done()); return; } - Must(requestId == 0); - AsyncCall::Pointer callback = asyncCall(16, 5, "Mgr::Inquirer::handleRemoteAck", - HandleAckDialer(this, &Inquirer::handleRemoteAck, Response())); - if (++LastRequestId == 0) // don't use zero value as requestId + Must(request->requestId == 0); + AsyncCall::Pointer callback = asyncCall(54, 5, "Mgr::Inquirer::handleRemoteAck", + HandleAckDialer(this, &Inquirer::handleRemoteAck, NULL)); + if (++LastRequestId == 0) // don't use zero value as request->requestId ++LastRequestId; - requestId = LastRequestId; + request->requestId = LastRequestId; const int kidId = pos->kidId; - debugs(16, 4, HERE << "inquire kid: " << kidId << status()); - TheRequestsMap[requestId] = callback; - Request mgrRequest(KidIdentifier, requestId, fd, - aggrAction->command().params); - Ipc::TypedMsgHdr message; - mgrRequest.pack(message); - Ipc::SendMessage(Ipc::Port::MakeAddr(Ipc::strandAddrPfx, kidId), message); - eventAdd("Mgr::Inquirer::requestTimedOut", &Inquirer::RequestTimedOut, + debugs(54, 4, HERE << "inquire kid: " << kidId << status()); + TheRequestsMap[request->requestId] = callback; + TypedMsgHdr message; + request->pack(message); + SendMessage(Port::MakeAddr(strandAddrPfx, kidId), message); + eventAdd("Ipc::Inquirer::requestTimedOut", &Inquirer::RequestTimedOut, this, timeout, 0, false); } /// called when a strand is done writing its output void -Mgr::Inquirer::handleRemoteAck(const Response& response) +Ipc::Inquirer::handleRemoteAck(Response::Pointer response) { - debugs(16, 4, HERE << status()); - requestId = 0; + debugs(54, 4, HERE << status()); + request->requestId = 0; removeTimeoutEvent(); - if (response.hasAction()) - aggrAction->add(response.getAction()); - Must(!done()); // or we should not be called - ++pos; // advance after a successful inquiry - inquire(); + if (aggregate(response)) { + Must(!done()); // or we should not be called + ++pos; // advance after a successful inquiry + inquire(); + } else { + mustStop("error"); + } } -/// called when the HTTP client or some external force closed our socket void -Mgr::Inquirer::noteCommClosed(const CommCloseCbParams& params) +Ipc::Inquirer::swanSong() { - debugs(16, 5, HERE); - Must(fd < 0 || fd == params.fd); - fd = -1; - mustStop("commClosed"); + debugs(54, 5, HERE); + removeTimeoutEvent(); + if (request->requestId > 0) { + DequeueRequest(request->requestId); + request->requestId = 0; + } + sendResponse(); + cleanup(); +} + +bool +Ipc::Inquirer::doneAll() const +{ + return pos == strands.end(); } void -Mgr::Inquirer::swanSong() +Ipc::Inquirer::handleException(const std::exception& e) { - debugs(16, 5, HERE); - removeTimeoutEvent(); - if (requestId > 0) { - DequeueRequest(requestId); - requestId = 0; - } - if (aggrAction->aggregatable()) { - removeCloseHandler(); - AsyncJob::Start(new ActionWriter(aggrAction, fd)); - fd = -1; // should not close fd because we passed it to ActionWriter - } - close(); + debugs(54, 3, HERE << e.what()); + mustStop("exception"); } -bool -Mgr::Inquirer::doneAll() const +void +Ipc::Inquirer::callException(const std::exception& e) { - return !writer && pos == strands.end(); + debugs(54, 3, HERE); + try { + handleException(e); + } catch (const std::exception& ex) { + debugs(54, DBG_CRITICAL, HERE << ex.what()); + } + AsyncJob::callException(e); } /// returns and forgets the right Inquirer callback for strand request AsyncCall::Pointer -Mgr::Inquirer::DequeueRequest(unsigned int requestId) +Ipc::Inquirer::DequeueRequest(unsigned int requestId) { - debugs(16, 3, HERE << " requestId " << requestId); + debugs(54, 3, HERE << " requestId " << requestId); Must(requestId != 0); AsyncCall::Pointer call; RequestsMap::iterator request = TheRequestsMap.find(requestId); if (request != TheRequestsMap.end()) { call = request->second; Must(call != NULL); TheRequestsMap.erase(request); } return call; } void -Mgr::Inquirer::HandleRemoteAck(const Mgr::Response& response) +Ipc::Inquirer::HandleRemoteAck(const Response& response) { Must(response.requestId != 0); AsyncCall::Pointer call = DequeueRequest(response.requestId); if (call != NULL) { HandleAckDialer* dialer = dynamic_cast(call->getDialer()); Must(dialer); - dialer->arg1 = response; + dialer->arg1 = response.clone(); ScheduleCallHere(call); } } /// called when we are no longer waiting for the strand to respond void -Mgr::Inquirer::removeTimeoutEvent() +Ipc::Inquirer::removeTimeoutEvent() { if (eventFind(&Inquirer::RequestTimedOut, this)) eventDelete(&Inquirer::RequestTimedOut, this); } -/// Mgr::Inquirer::requestTimedOut wrapper +/// Ipc::Inquirer::requestTimedOut wrapper void -Mgr::Inquirer::RequestTimedOut(void* param) +Ipc::Inquirer::RequestTimedOut(void* param) { - debugs(16, 3, HERE); + debugs(54, 3, HERE); Must(param != NULL); Inquirer* cmi = static_cast(param); // use async call to enable job call protection that time events lack - CallJobHere(16, 5, cmi, Mgr::Inquirer, requestTimedOut); + CallJobHere(54, 5, cmi, Inquirer, requestTimedOut); } /// called when the strand failed to respond (or finish responding) in time void -Mgr::Inquirer::requestTimedOut() +Ipc::Inquirer::requestTimedOut() { - debugs(16, 3, HERE); - if (requestId != 0) { - DequeueRequest(requestId); - requestId = 0; + debugs(54, 3, HERE); + if (request->requestId != 0) { + DequeueRequest(request->requestId); + request->requestId = 0; Must(!done()); // or we should not be called ++pos; // advance after a failed inquiry inquire(); } } const char* -Mgr::Inquirer::status() const +Ipc::Inquirer::status() const { static MemBuf buf; buf.reset(); - buf.Printf(" [FD %d, requestId %u]", fd, requestId); + buf.Printf(" [request->requestId %u]", request->requestId); buf.terminate(); return buf.content(); } === renamed file 'src/mgr/Inquirer.h' => 'src/ipc/Inquirer.h' --- src/mgr/Inquirer.h 2010-10-29 00:12:28 +0000 +++ src/ipc/Inquirer.h 2011-01-17 15:10:36 +0000 @@ -1,87 +1,85 @@ /* * $Id$ * - * DEBUG: section 16 Cache Manager API + * DEBUG: section 54 Interprocess Communication * */ -#ifndef SQUID_MGR_INQUIRER_H -#define SQUID_MGR_INQUIRER_H +#ifndef SQUID_IPC_INQUIRER_H +#define SQUID_IPC_INQUIRER_H #include "base/AsyncJobCalls.h" #include "base/AsyncJob.h" +#include "ipc/forward.h" +#include "ipc/Request.h" +#include "ipc/Response.h" #include "ipc/StrandCoords.h" -#include "MemBuf.h" -#include "mgr/Action.h" -#include "mgr/Request.h" #include -class CommIoCbParams; -class CommCloseCbParams; -namespace Mgr +namespace Ipc { /// Coordinator's job that sends a cache manage request to each strand, /// aggregating individual strand responses and dumping the result if needed class Inquirer: public AsyncJob { public: - Inquirer(Action::Pointer anAction, int aFd, const Request &aCause, - const Ipc::StrandCoords &coords); + Inquirer(Request::Pointer aRequest, const Ipc::StrandCoords& coords, double aTimeout); virtual ~Inquirer(); /// finds and calls the right Inquirer upon strand's response - static void HandleRemoteAck(const Mgr::Response& response); + static void HandleRemoteAck(const Response& response); + + /* has-to-be-public AsyncJob API */ + virtual void callException(const std::exception& e); protected: /* AsyncJob API */ virtual void start(); virtual void swanSong(); virtual bool doneAll() const; virtual const char *status() const; -private: - typedef UnaryMemFunT HandleAckDialer; + /// inquire the next strand + virtual void inquire(); + /// perform cleanup actions on completion of job + virtual void cleanup(); + /// do specific exception handling + virtual void handleException(const std::exception& e); + /// send response to client + virtual void sendResponse() = 0; + /// perform aggregating of responses and returns true if need to continue + virtual bool aggregate(Response::Pointer aResponse) = 0; - void inquire(); - void noteWroteHeader(const CommIoCbParams& params); - void noteCommClosed(const CommCloseCbParams& params); +private: + typedef UnaryMemFunT HandleAckDialer; - void handleRemoteAck(const Response& response); + void handleRemoteAck(Response::Pointer response); static AsyncCall::Pointer DequeueRequest(unsigned int requestId); static void RequestTimedOut(void* param); void requestTimedOut(); void removeTimeoutEvent(); - void close(); - void removeCloseHandler(); - -private: - Action::Pointer aggrAction; //< action to aggregate - - Request cause; ///< cache manager request received from HTTP client - int fd; ///< HTTP client socket descriptor +protected: + Request::Pointer request; ///< cache manager request received from client Ipc::StrandCoords strands; ///< all strands we want to query, in order Ipc::StrandCoords::const_iterator pos; ///< strand we should query now - unsigned int requestId; ///< ID of our outstanding request to strand - AsyncCall::Pointer writer; ///< comm_write callback - AsyncCall::Pointer closer; ///< comm_close handler const double timeout; ///< number of seconds to wait for strand response - /// maps requestId to Inquirer::handleRemoteAck callback + /// maps request->id to Inquirer::handleRemoteAck callback typedef std::map RequestsMap; static RequestsMap TheRequestsMap; ///< pending strand requests static unsigned int LastRequestId; ///< last requestId used CBDATA_CLASS2(Inquirer); }; -} // namespace Mgr +} // namespace Ipc -#endif /* SQUID_MGR_INQUIRER_H */ +#endif /* SQUID_IPC_INQUIRER_H */ === modified file 'src/ipc/Makefile.am' --- src/ipc/Makefile.am 2010-10-28 18:52:59 +0000 +++ src/ipc/Makefile.am 2011-01-28 13:59:51 +0000 @@ -11,24 +11,29 @@ Kids.cc \ Kids.h \ Messages.h \ StartListening.cc \ StartListening.h \ StrandCoord.cc \ StrandCoord.h \ StrandCoords.h \ SharedListen.cc \ SharedListen.h \ TypedMsgHdr.cc \ TypedMsgHdr.h \ Coordinator.cc \ Coordinator.h \ UdsOp.cc \ UdsOp.h \ Port.cc \ Port.h \ Strand.cc \ Strand.h \ - \ - forward.h + forward.h \ + Forwarder.cc \ + Forwarder.h \ + Inquirer.cc \ + Inquirer.h \ + Request.h \ + Response.h DEFS += -DDEFAULT_PREFIX=\"$(prefix)\" === modified file 'src/ipc/Messages.h' --- src/ipc/Messages.h 2010-10-28 18:52:59 +0000 +++ src/ipc/Messages.h 2011-01-28 16:36:48 +0000 @@ -1,28 +1,28 @@ /* * $Id$ * * DEBUG: section 54 Interprocess Communication * */ #ifndef SQUID_IPC_MESSAGES_H #define SQUID_IPC_MESSAGES_H -#include "ipc/forward.h" -#include - -/** Declarations used by varios IPC messages */ +/** Declarations used by various IPC messages */ namespace Ipc { /// message class identifier typedef enum { mtNone = 0, mtRegistration, mtSharedListenRequest, mtSharedListenResponse, - mtCacheMgrRequest, mtCacheMgrResponse + mtCacheMgrRequest, mtCacheMgrResponse, +#if SQUID_SNMP + mtSnmpRequest, mtSnmpResponse +#endif } MessageType; } // namespace Ipc; #endif /* SQUID_IPC_MESSAGES_H */ === renamed file 'src/mgr/Request.h' => 'src/ipc/Request.h' --- src/mgr/Request.h 2010-10-29 00:12:28 +0000 +++ src/ipc/Request.h 2011-01-17 15:10:36 +0000 @@ -1,39 +1,43 @@ /* * $Id$ * - * DEBUG: section 16 Cache Manager API + * DEBUG: section 54 Interprocess Communication * */ -#ifndef SQUID_MGR_REQUEST_H -#define SQUID_MGR_REQUEST_H +#ifndef SQUID_IPC_REQUEST_H +#define SQUID_IPC_REQUEST_H -#include "ipc/TypedMsgHdr.h" -#include "mgr/ActionParams.h" +#include "ipc/forward.h" +#include "RefCount.h" -namespace Mgr +namespace Ipc { -/// cache manager request -class Request +/// IPC request +class Request: public RefCountable { public: - Request(int aRequestorId, unsigned int aRequestId, int aFd, - const ActionParams &aParams); + typedef RefCount Pointer; - explicit Request(const Ipc::TypedMsgHdr& msg); ///< from recvmsg() - void pack(Ipc::TypedMsgHdr& msg) const; ///< prepare for sendmsg() +public: + Request(int aRequestorId, unsigned int aRequestId): + requestorId(aRequestorId), requestId(aRequestId) {} + + virtual void pack(TypedMsgHdr& msg) const = 0; ///< prepare for sendmsg() + virtual Pointer clone() const = 0; ///< returns a copy of this + +private: + Request(const Request&); // not implemented + Request& operator= (const Request&); // not implemented public: int requestorId; ///< kidId of the requestor; used for response destination unsigned int requestId; ///< unique for sender; matches request w/ response - int fd; ///< HTTP client connection descriptor - - ActionParams params; ///< action name and parameters }; -} // namespace Mgr +} // namespace Ipc -#endif /* SQUID_MGR_REQUEST_H */ +#endif /* SQUID_IPC_REQUEST_H */ === renamed file 'src/mgr/Response.h' => 'src/ipc/Response.h' --- src/mgr/Response.h 2010-10-28 18:52:59 +0000 +++ src/ipc/Response.h 2011-01-28 15:17:56 +0000 @@ -1,38 +1,49 @@ /* * $Id$ * - * DEBUG: section 16 Cache Manager API + * DEBUG: section 54 Interprocess Communication * */ -#ifndef SQUID_MGR_RESPONSE_H -#define SQUID_MGR_RESPONSE_H +#ifndef SQUID_IPC_RESPONSE_H +#define SQUID_IPC_RESPONSE_H -#include "mgr/Action.h" +#include "ipc/forward.h" +#include "RefCount.h" -namespace Mgr +namespace Ipc { -/// A response to Mgr::Request. -/// May carry strand action data to be aggregated with data from other strands. -class Response +/// A response to Ipc::Request. +class Response: public RefCountable { public: - Response(unsigned int aRequestId = 0, Action::Pointer anAction = NULL); + typedef RefCount Pointer; - explicit Response(const Ipc::TypedMsgHdr& msg); ///< from recvmsg() - void pack(Ipc::TypedMsgHdr& msg) const; ///< prepare for sendmsg() - bool hasAction() const; ///< whether response contain action object - const Action& getAction() const; ///< returns action object +public: + explicit Response(unsigned int aRequestId): + requestId(aRequestId) {} + + virtual void pack(TypedMsgHdr& msg) const = 0; ///< prepare for sendmsg() + virtual Pointer clone() const = 0; ///< returns a copy of this + +private: + Response(const Response&); // not implemented + Response& operator= (const Response&); // not implemented public: unsigned int requestId; ///< ID of request we are responding to - Action::Pointer action; ///< action relating to response }; -extern std::ostream& operator <<(std::ostream &os, const Response &response); +inline +std::ostream& operator << (std::ostream &os, const Response& response) +{ + os << "[response.requestId %u]" << response.requestId << '}'; + return os; +} + -} // namespace Mgr +} // namespace Ipc -#endif /* SQUID_MGR_RESPONSE_H */ +#endif /* SQUID_IPC_RESPONSE_H */ === modified file 'src/ipc/Strand.cc' --- src/ipc/Strand.cc 2010-10-28 18:52:59 +0000 +++ src/ipc/Strand.cc 2011-01-28 16:39:10 +0000 @@ -1,39 +1,43 @@ /* * $Id$ * * DEBUG: section 54 Interprocess Communication * */ #include "config.h" #include "base/TextException.h" #include "ipc/Strand.h" #include "ipc/StrandCoord.h" #include "ipc/Messages.h" #include "ipc/SharedListen.h" #include "ipc/Kids.h" #include "mgr/Request.h" #include "mgr/Response.h" #include "mgr/Forwarder.h" #include "CacheManager.h" - +#if SQUID_SNMP +#include "snmpx/Forwarder.h" +#include "snmpx/Request.h" +#include "snmpx/Response.h" +#endif CBDATA_NAMESPACED_CLASS_INIT(Ipc, Strand); Ipc::Strand::Strand(): Port(MakeAddr(strandAddrPfx, KidIdentifier)), isRegistered(false) { } void Ipc::Strand::start() { Port::start(); registerSelf(); } void Ipc::Strand::registerSelf() { debugs(54, 6, HERE); Must(!isRegistered); @@ -47,57 +51,81 @@ { debugs(54, 6, HERE << message.type()); switch (message.type()) { case mtRegistration: handleRegistrationResponse(StrandCoord(message)); break; case mtSharedListenResponse: SharedListenJoined(SharedListenResponse(message)); break; case mtCacheMgrRequest: handleCacheMgrRequest(Mgr::Request(message)); break; case mtCacheMgrResponse: handleCacheMgrResponse(Mgr::Response(message)); break; +#if SQUID_SNMP + case mtSnmpRequest: + handleSnmpRequest(Snmp::Request(message)); + break; + + case mtSnmpResponse: + handleSnmpResponse(Snmp::Response(message)); + break; +#endif + default: debugs(54, 1, HERE << "Unhandled message type: " << message.type()); break; } } void Ipc::Strand::handleRegistrationResponse(const StrandCoord &strand) { // handle registration response from the coordinator; it could be stale if (strand.kidId == KidIdentifier && strand.pid == getpid()) { debugs(54, 6, "kid" << KidIdentifier << " registered"); clearTimeout(); // we are done } else { // could be an ACK to the registration message of our dead predecessor debugs(54, 6, "kid" << KidIdentifier << " is not yet registered"); // keep listening, with a timeout } } void Ipc::Strand::handleCacheMgrRequest(const Mgr::Request& request) { Mgr::Action::Pointer action = CacheManager::GetInstance()->createRequestedAction(request.params); action->respond(request); } void Ipc::Strand::handleCacheMgrResponse(const Mgr::Response& response) { Mgr::Forwarder::HandleRemoteAck(response.requestId); } +#if SQUID_SNMP +void Ipc::Strand::handleSnmpRequest(const Snmp::Request& request) +{ + debugs(54, 6, HERE); + Snmp::SendResponse(request.requestId, request.pdu); +} + +void Ipc::Strand::handleSnmpResponse(const Snmp::Response& response) +{ + debugs(54, 6, HERE); + Snmp::Forwarder::HandleRemoteAck(response.requestId); +} +#endif + void Ipc::Strand::timedout() { debugs(54, 6, HERE << isRegistered); if (!isRegistered) fatalf("kid%d registration timed out", KidIdentifier); } === modified file 'src/ipc/Strand.h' --- src/ipc/Strand.h 2010-10-28 18:52:59 +0000 +++ src/ipc/Strand.h 2011-01-28 16:38:38 +0000 @@ -1,52 +1,58 @@ /* * $Id$ * * DEBUG: section 54 Interprocess Communication * */ #ifndef SQUID_IPC_STRAND_H #define SQUID_IPC_STRAND_H #include "ipc/Port.h" #include "mgr/forward.h" - +#if SQUID_SNMP +#include "snmpx/forward.h" +#endif namespace Ipc { class StrandCoord; /// Receives coordination messages on behalf of its process or thread class Strand: public Port { public: Strand(); virtual void start(); // Port (AsyncJob) API protected: virtual void timedout(); // Port (UsdOp) API virtual void receive(const TypedMsgHdr &message); // Port API private: void registerSelf(); /// let Coordinator know this strand exists void handleRegistrationResponse(const StrandCoord &strand); void handleCacheMgrRequest(const Mgr::Request& request); void handleCacheMgrResponse(const Mgr::Response& response); +#if SQUID_SNMP + void handleSnmpRequest(const Snmp::Request& request); + void handleSnmpResponse(const Snmp::Response& response); +#endif private: bool isRegistered; ///< whether Coordinator ACKed registration (unused) private: Strand(const Strand&); // not implemented Strand& operator =(const Strand&); // not implemented CBDATA_CLASS2(Strand); }; } #endif /* SQUID_IPC_STRAND_H */ === modified file 'src/ipc/UdsOp.cc' --- src/ipc/UdsOp.cc 2010-11-27 01:46:22 +0000 +++ src/ipc/UdsOp.cc 2011-01-27 11:17:44 +0000 @@ -115,20 +115,40 @@ { debugs(54, 5, HERE << "FD " << params.fd << " flag " << params.flag << " [" << this << ']'); writing = false; if (params.flag != COMM_OK && retries-- > 0) { sleep(1); // do not spend all tries at once; XXX: use an async timed event instead of blocking here; store the time when we started writing so that we do not sleep if not needed? write(); // XXX: should we close on error so that fd() reopens? } } void Ipc::UdsSender::timedout() { debugs(54, 5, HERE); mustStop("timedout"); } void Ipc::SendMessage(const String& toAddress, const TypedMsgHdr &message) { AsyncJob::Start(new UdsSender(toAddress, message)); } + +int Ipc::ImportFdIntoComm(int fd, int socktype, int protocol, Ipc::FdNoteId noteId) +{ + struct sockaddr_in addr; + socklen_t len = sizeof(addr); + if (getsockname(fd, reinterpret_cast(&addr), &len) == 0) { + Ip::Address ipAddr(addr); + struct addrinfo* addr_info = NULL; + ipAddr.GetAddrInfo(addr_info); + addr_info->ai_socktype = socktype; + addr_info->ai_protocol = protocol; + comm_import_opened(fd, ipAddr, COMM_NONBLOCKING, Ipc::FdNote(noteId), addr_info); + ipAddr.FreeAddrInfo(addr_info); + } else { + debugs(54, DBG_CRITICAL, HERE << "ERROR: FD " << fd << ' ' << xstrerror()); + ::close(fd); + fd = -1; + } + return fd; +} === modified file 'src/ipc/UdsOp.h' --- src/ipc/UdsOp.h 2010-07-06 18:58:38 +0000 +++ src/ipc/UdsOp.h 2011-01-17 15:10:36 +0000 @@ -1,34 +1,35 @@ /* * $Id$ * * DEBUG: section 54 Interprocess Communication * */ #ifndef SQUID_IPC_ASYNCUDSOP_H #define SQUID_IPC_ASYNCUDSOP_H #include "SquidString.h" #include "base/AsyncJob.h" #include "ipc/TypedMsgHdr.h" +#include "ipc/FdNotes.h" class CommTimeoutCbParams; class CommIoCbParams; namespace Ipc { /// code shared by unix-domain socket senders (e.g., UdsSender or Coordinator) /// and receivers (e.g. Port or Coordinator) class UdsOp: public AsyncJob { public: UdsOp(const String &pathAddr); virtual ~UdsOp(); public: struct sockaddr_un address; ///< UDS address from path; treat as read-only protected: virtual void timedout() {} ///< called after setTimeout() if timed out @@ -73,25 +74,27 @@ private: void write(); ///< schedule writing void wrote(const CommIoCbParams& params); ///< done writing or error private: TypedMsgHdr message; ///< what to send int retries; ///< how many times to try after a write error int timeout; ///< total time to send the message bool writing; ///< whether Comm started and did not finish writing private: UdsSender(const UdsSender&); // not implemented UdsSender& operator= (const UdsSender&); // not implemented CBDATA_CLASS2(UdsSender); }; void SendMessage(const String& toAddress, const TypedMsgHdr& message); +/// import socket fd from another strand into our Comm state +int ImportFdIntoComm(int fd, int socktype, int protocol, FdNoteId noteId); } #endif /* SQUID_IPC_ASYNCUDSOP_H */ === modified file 'src/ipc/forward.h' --- src/ipc/forward.h 2010-11-21 04:40:05 +0000 +++ src/ipc/forward.h 2011-01-17 15:10:36 +0000 @@ -1,19 +1,23 @@ /* * $Id$ * * DEBUG: section 54 Interprocess Communication * */ #ifndef SQUID_IPC_FORWARD_H #define SQUID_IPC_FORWARD_H namespace Ipc { class TypedMsgHdr; class StrandCoord; +class Forwarder; +class Inquirer; +class Request; +class Response; } // namespace Ipc #endif /* SQUID_IPC_FORWARD_H */ === added file 'src/mgr/Forwarder.cc' --- src/mgr/Forwarder.cc 1970-01-01 00:00:00 +0000 +++ src/mgr/Forwarder.cc 2011-01-17 15:10:36 +0000 @@ -0,0 +1,130 @@ +/* + * $Id$ + * + * DEBUG: section 16 Cache Manager API + * + */ + +#include "config.h" +#include "base/AsyncJobCalls.h" +#include "base/TextException.h" +#include "CommCalls.h" +#include "errorpage.h" +#include "HttpReply.h" +#include "HttpRequest.h" +#include "ipc/Port.h" +#include "mgr/Forwarder.h" +#include "mgr/Request.h" +#include "SquidTime.h" +#include "Store.h" + + +CBDATA_NAMESPACED_CLASS_INIT(Mgr, Forwarder); + + +Mgr::Forwarder::Forwarder(int aFd, const ActionParams &aParams, + HttpRequest* aRequest, StoreEntry* anEntry): + Ipc::Forwarder(new Request(KidIdentifier, 0, aFd, aParams), 10), + httpRequest(aRequest), entry(anEntry), fd(aFd) +{ + debugs(16, 5, HERE << "FD " << fd); + Must(fd >= 0); + Must(httpRequest != NULL); + Must(entry != NULL); + + HTTPMSGLOCK(httpRequest); + entry->lock(); + EBIT_SET(entry->flags, ENTRY_FWD_HDR_WAIT); + + closer = asyncCall(16, 5, "Mgr::Forwarder::noteCommClosed", + CommCbMemFunT(this, &Forwarder::noteCommClosed)); + comm_add_close_handler(fd, closer); +} + +Mgr::Forwarder::~Forwarder() +{ + debugs(16, 5, HERE); + Must(httpRequest != NULL); + Must(entry != NULL); + + HTTPMSGUNLOCK(httpRequest); + entry->unregisterAbort(); + entry->unlock(); + cleanup(); +} + +/// closes our copy of the client HTTP connection socket +void +Mgr::Forwarder::cleanup() +{ + if (fd >= 0) { + if (closer != NULL) { + comm_remove_close_handler(fd, closer); + closer = NULL; + } + comm_close(fd); + fd = -1; + } +} + +void +Mgr::Forwarder::handleError() +{ + debugs(16, DBG_CRITICAL, "ERROR: uri " << entry->url() << " exceeds buffer size"); + sendError(errorCon(ERR_INVALID_URL, HTTP_REQUEST_URI_TOO_LARGE, httpRequest)); + mustStop("long URI"); +} + +void +Mgr::Forwarder::handleTimeout() +{ + sendError(errorCon(ERR_LIFETIME_EXP, HTTP_REQUEST_TIMEOUT, httpRequest)); + Ipc::Forwarder::handleTimeout(); +} + +void +Mgr::Forwarder::handleException(const std::exception& e) +{ + if (entry != NULL && httpRequest != NULL && fd >= 0) + sendError(errorCon(ERR_INVALID_RESP, HTTP_INTERNAL_SERVER_ERROR, httpRequest)); + Ipc::Forwarder::handleException(e); +} + +/// called when the client socket gets closed by some external force +void +Mgr::Forwarder::noteCommClosed(const CommCloseCbParams& params) +{ + debugs(16, 5, HERE); + Must(fd == params.fd); + fd = -1; + mustStop("commClosed"); +} + +/// called when Coordinator starts processing the request +void +Mgr::Forwarder::handleRemoteAck() +{ + Ipc::Forwarder::handleRemoteAck(); + + Must(entry != NULL); + EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT); + entry->complete(); +} + +/// send error page +void +Mgr::Forwarder::sendError(ErrorState *error) +{ + debugs(16, 3, HERE); + Must(error != NULL); + Must(entry != NULL); + Must(httpRequest != NULL); + + EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT); + entry->buffer(); + entry->replaceHttpReply(error->BuildHttpReply()); + entry->expires = squid_curtime; + errorStateFree(error); + entry->flush(); + entry->complete(); +} === added file 'src/mgr/Forwarder.h' --- src/mgr/Forwarder.h 1970-01-01 00:00:00 +0000 +++ src/mgr/Forwarder.h 2011-01-17 15:10:36 +0000 @@ -0,0 +1,57 @@ +/* + * $Id$ + * + * DEBUG: section 16 Cache Manager API + * + */ + +#ifndef SQUID_MGR_FORWARDER_H +#define SQUID_MGR_FORWARDER_H + +#include "ipc/Forwarder.h" +#include "mgr/ActionParams.h" + + +class CommCloseCbParams; +class HttpRequest; +class StoreEntry; +class ErrorState; + +namespace Mgr +{ + +/** Forwards a single client cache manager request to Coordinator. + * Waits for an ACK from Coordinator while holding the Store entry. + * Fills the store entry with an error response if forwarding fails. + */ +class Forwarder: public Ipc::Forwarder +{ +public: + Forwarder(int aFd, const ActionParams &aParams, HttpRequest* aRequest, + StoreEntry* anEntry); + virtual ~Forwarder(); + +protected: + /* Ipc::Forwarder API */ + virtual void cleanup(); ///< perform cleanup actions + virtual void handleError(); + virtual void handleTimeout(); + virtual void handleException(const std::exception& e); + virtual void handleRemoteAck(); + +private: + void noteCommClosed(const CommCloseCbParams& params); + void sendError(ErrorState* error); + +private: + HttpRequest* httpRequest; ///< HTTP client request for detailing errors + StoreEntry* entry; ///< Store entry expecting the response + int fd; ///< HTTP client connection descriptor + AsyncCall::Pointer closer; ///< comm_close handler for the HTTP connection + + CBDATA_CLASS2(Forwarder); +}; + +} // namespace Mgr + +#endif /* SQUID_MGR_FORWARDER_H */ === modified file 'src/mgr/FunAction.cc' --- src/mgr/FunAction.cc 2010-10-29 00:12:28 +0000 +++ src/mgr/FunAction.cc 2011-01-17 15:10:36 +0000 @@ -1,50 +1,51 @@ /* * $Id$ * * DEBUG: section 16 Cache Manager API * */ #include "config.h" #include "base/TextException.h" +#include "ipc/UdsOp.h" #include "mgr/Command.h" #include "mgr/Filler.h" #include "mgr/FunAction.h" #include "mgr/Request.h" #include "Store.h" Mgr::FunAction::Pointer Mgr::FunAction::Create(const Command::Pointer &aCmd, OBJH* aHandler) { return new FunAction(aCmd, aHandler); } Mgr::FunAction::FunAction(const Command::Pointer &aCmd, OBJH* aHandler): Action(aCmd), handler(aHandler) { Must(handler != NULL); debugs(16, 5, HERE); } void Mgr::FunAction::respond(const Request& request) { debugs(16, 5, HERE); - const int fd = ImportHttpFdIntoComm(request.fd); + const int fd = Ipc::ImportFdIntoComm(request.fd, SOCK_STREAM, IPPROTO_TCP, Ipc::fdnHttpSocket); Must(fd >= 0); Must(request.requestId != 0); AsyncJob::Start(new Mgr::Filler(this, fd, request.requestId)); } void Mgr::FunAction::dump(StoreEntry* entry) { debugs(16, 5, HERE); Must(entry != NULL); if (UsingSmp() && IamWorkerProcess()) storeAppendPrintf(entry, "by kid%d {\n", KidIdentifier); handler(entry); if (atomic() && UsingSmp() && IamWorkerProcess()) storeAppendPrintf(entry, "} by kid%d\n\n", KidIdentifier); } === modified file 'src/mgr/InfoAction.cc' --- src/mgr/InfoAction.cc 2010-10-29 00:12:28 +0000 +++ src/mgr/InfoAction.cc 2011-01-17 15:10:36 +0000 @@ -1,31 +1,32 @@ /* * $Id$ * * DEBUG: section 16 Cache Manager API * */ #include "config.h" #include "base/TextException.h" #include "HttpReply.h" #include "ipc/Messages.h" +#include "ipc/UdsOp.h" #include "ipc/TypedMsgHdr.h" #include "mgr/Filler.h" #include "mgr/InfoAction.h" #include "mgr/Request.h" #include "mgr/Response.h" #include "SquidTime.h" #include "Store.h" extern void GetInfo(Mgr::InfoActionData& stats); extern void DumpInfo(Mgr::InfoActionData& stats, StoreEntry* sentry); extern void DumpMallocStatistics(StoreEntry* sentry); Mgr::InfoActionData::InfoActionData() { xmemset(this, 0, sizeof(*this)); } Mgr::InfoActionData& Mgr::InfoActionData::operator += (const InfoActionData& stats) @@ -138,41 +139,41 @@ return new InfoAction(cmd); } Mgr::InfoAction::InfoAction(const CommandPointer &cmd): Action(cmd), data() { debugs(16, 5, HERE); } void Mgr::InfoAction::add(const Action& action) { debugs(16, 5, HERE); data += dynamic_cast(action).data; } void Mgr::InfoAction::respond(const Request& request) { debugs(16, 5, HERE); - int fd = ImportHttpFdIntoComm(request.fd); + int fd = Ipc::ImportFdIntoComm(request.fd, SOCK_STREAM, IPPROTO_TCP, Ipc::fdnHttpSocket); Must(fd >= 0); Must(request.requestId != 0); AsyncJob::Start(new Mgr::Filler(this, fd, request.requestId)); } void Mgr::InfoAction::collect() { GetInfo(data); } void Mgr::InfoAction::dump(StoreEntry* entry) { debugs(16, 5, HERE); Must(entry != NULL); #if XMALLOC_STATISTICS if (UsingSmp() && IamWorkerProcess()) storeAppendPrintf(entry, "by kid%d {\n", KidIdentifier); === added file 'src/mgr/Inquirer.cc' --- src/mgr/Inquirer.cc 1970-01-01 00:00:00 +0000 +++ src/mgr/Inquirer.cc 2011-01-17 16:57:44 +0000 @@ -0,0 +1,121 @@ +/* + * $Id$ + * + * DEBUG: section 16 Cache Manager API + * + */ + +#include "config.h" +#include "base/TextException.h" +#include "comm/Write.h" +#include "CommCalls.h" +#include "HttpReply.h" +#include "ipc/UdsOp.h" +#include "mgr/ActionWriter.h" +#include "mgr/Inquirer.h" +#include "mgr/Request.h" +#include "mgr/Response.h" +#include "SquidTime.h" +#include + + +CBDATA_NAMESPACED_CLASS_INIT(Mgr, Inquirer); + + +Mgr::Inquirer::Inquirer(Action::Pointer anAction, + const Request &aCause, const Ipc::StrandCoords &coords): + Ipc::Inquirer(aCause.clone(), coords, anAction->atomic() ? 10 : 100), + aggrAction(anAction), + fd(Ipc::ImportFdIntoComm(aCause.fd, SOCK_STREAM, IPPROTO_TCP, Ipc::fdnHttpSocket)) +{ + debugs(16, 5, HERE << "FD " << fd << " action: " << aggrAction); + + closer = asyncCall(16, 5, "Mgr::Inquirer::noteCommClosed", + CommCbMemFunT(this, &Inquirer::noteCommClosed)); + comm_add_close_handler(fd, closer); +} + +/// closes our copy of the client HTTP connection socket +void +Mgr::Inquirer::cleanup() +{ + if (fd >= 0) { + removeCloseHandler(); + comm_close(fd); + fd = -1; + } +} + +void +Mgr::Inquirer::removeCloseHandler() +{ + if (closer != NULL) { + comm_remove_close_handler(fd, closer); + closer = NULL; + } +} + +void +Mgr::Inquirer::start() +{ + debugs(16, 5, HERE); + Ipc::Inquirer::start(); + Must(fd >= 0); + Must(aggrAction != NULL); + + std::auto_ptr reply(new HttpReply); + reply->setHeaders(HTTP_OK, NULL, "text/plain", -1, squid_curtime, squid_curtime); + reply->header.putStr(HDR_CONNECTION, "close"); // until we chunk response + std::auto_ptr replyBuf(reply->pack()); + writer = asyncCall(16, 5, "Mgr::Inquirer::noteWroteHeader", + CommCbMemFunT(this, &Inquirer::noteWroteHeader)); + Comm::Write(fd, replyBuf.get(), writer); +} + +/// called when we wrote the response header +void +Mgr::Inquirer::noteWroteHeader(const CommIoCbParams& params) +{ + debugs(16, 5, HERE); + writer = NULL; + Must(params.flag == COMM_OK); + Must(params.fd == fd); + Must(params.size != 0); + // start inquiries at the initial pos + inquire(); +} + +/// called when the HTTP client or some external force closed our socket +void +Mgr::Inquirer::noteCommClosed(const CommCloseCbParams& params) +{ + debugs(16, 5, HERE); + Must(fd < 0 || fd == params.fd); + fd = -1; + mustStop("commClosed"); +} + +bool +Mgr::Inquirer::aggregate(Ipc::Response::Pointer aResponse) +{ + Mgr::Response& response = static_cast(*aResponse); + if (response.hasAction()) + aggrAction->add(response.getAction()); + return true; +} + +void +Mgr::Inquirer::sendResponse() +{ + if (aggrAction->aggregatable()) { + removeCloseHandler(); + AsyncJob::Start(new ActionWriter(aggrAction, fd)); + fd = -1; // should not close fd because we passed it to ActionWriter + } +} + +bool +Mgr::Inquirer::doneAll() const +{ + return !writer && Ipc::Inquirer::doneAll(); +} === added file 'src/mgr/Inquirer.h' --- src/mgr/Inquirer.h 1970-01-01 00:00:00 +0000 +++ src/mgr/Inquirer.h 2011-01-17 15:10:36 +0000 @@ -0,0 +1,56 @@ +/* + * $Id$ + * + * DEBUG: section 16 Cache Manager API + * + */ + +#ifndef SQUID_MGR_INQUIRER_H +#define SQUID_MGR_INQUIRER_H + +#include "ipc/Inquirer.h" +#include "mgr/Action.h" + +class CommIoCbParams; +class CommCloseCbParams; + +namespace Mgr +{ + +/// Coordinator's job that sends a cache manage request to each strand, +/// aggregating individual strand responses and dumping the result if needed +class Inquirer: public Ipc::Inquirer +{ +public: + Inquirer(Action::Pointer anAction, const Request &aCause, + const Ipc::StrandCoords &coords); + +protected: + /* AsyncJob API */ + virtual void start(); + virtual bool doneAll() const; + + /* Ipc::Inquirer API */ + virtual void cleanup(); + virtual void sendResponse(); + virtual bool aggregate(Ipc::Response::Pointer aResponse); + +private: + void noteWroteHeader(const CommIoCbParams& params); + void noteCommClosed(const CommCloseCbParams& params); + void removeCloseHandler(); + +private: + Action::Pointer aggrAction; //< action to aggregate + + int fd; ///< HTTP client socket descriptor + + AsyncCall::Pointer writer; ///< comm_write callback + AsyncCall::Pointer closer; ///< comm_close handler + + CBDATA_CLASS2(Inquirer); +}; + +} // namespace Mgr + +#endif /* SQUID_MGR_INQUIRER_H */ === added file 'src/mgr/Request.cc' --- src/mgr/Request.cc 1970-01-01 00:00:00 +0000 +++ src/mgr/Request.cc 2011-01-17 15:10:36 +0000 @@ -0,0 +1,56 @@ +/* + * $Id$ + * + * DEBUG: section 16 Cache Manager API + * + */ + +#include "config.h" +#include "base/TextException.h" +#include "ipc/Messages.h" +#include "ipc/TypedMsgHdr.h" +#include "mgr/ActionParams.h" +#include "mgr/Request.h" + + +Mgr::Request::Request(int aRequestorId, unsigned int aRequestId, int aFd, + const ActionParams &aParams): + Ipc::Request(aRequestorId, aRequestId), + fd(aFd), params(aParams) +{ + Must(requestorId > 0); +} + +Mgr::Request::Request(const Request& request): + Ipc::Request(request.requestorId, request.requestId), + fd(request.fd), params(request.params) +{ +} + +Mgr::Request::Request(const Ipc::TypedMsgHdr& msg): + Ipc::Request(0, 0) +{ + msg.checkType(Ipc::mtCacheMgrRequest); + msg.getPod(requestorId); + msg.getPod(requestId); + params = ActionParams(msg); + + fd = msg.getFd(); +} + +void +Mgr::Request::pack(Ipc::TypedMsgHdr& msg) const +{ + msg.setType(Ipc::mtCacheMgrRequest); + msg.putPod(requestorId); + msg.putPod(requestId); + params.pack(msg); + + msg.putFd(fd); +} + +Ipc::Request::Pointer +Mgr::Request::clone() const +{ + return new Request(*this); +} === removed file 'src/mgr/Request.cc' --- src/mgr/Request.cc 2010-10-29 00:12:28 +0000 +++ src/mgr/Request.cc 1970-01-01 00:00:00 +0000 @@ -1,43 +0,0 @@ -/* - * $Id$ - * - * DEBUG: section 16 Cache Manager API - * - */ - -#include "config.h" -#include "base/TextException.h" -#include "ipc/Messages.h" -#include "mgr/ActionParams.h" -#include "mgr/Request.h" - - -Mgr::Request::Request(int aRequestorId, unsigned int aRequestId, int aFd, - const ActionParams &aParams): - requestorId(aRequestorId), requestId(aRequestId), - fd(aFd), params(aParams) -{ - Must(requestorId > 0); - Must(requestId != 0); -} - -Mgr::Request::Request(const Ipc::TypedMsgHdr& msg) -{ - msg.checkType(Ipc::mtCacheMgrRequest); - msg.getPod(requestorId); - msg.getPod(requestId); - params = ActionParams(msg); - - fd = msg.getFd(); -} - -void -Mgr::Request::pack(Ipc::TypedMsgHdr& msg) const -{ - msg.setType(Ipc::mtCacheMgrRequest); - msg.putPod(requestorId); - msg.putPod(requestId); - params.pack(msg); - - msg.putFd(fd); -} === added file 'src/mgr/Request.h' --- src/mgr/Request.h 1970-01-01 00:00:00 +0000 +++ src/mgr/Request.h 2011-01-17 15:10:36 +0000 @@ -0,0 +1,43 @@ +/* + * $Id$ + * + * DEBUG: section 16 Cache Manager API + * + */ + +#ifndef SQUID_MGR_REQUEST_H +#define SQUID_MGR_REQUEST_H + +#include "ipc/forward.h" +#include "ipc/Request.h" +#include "mgr/ActionParams.h" + + +namespace Mgr +{ + +/// cache manager request +class Request: public Ipc::Request +{ +public: + Request(int aRequestorId, unsigned int aRequestId, int aFd, + const ActionParams &aParams); + + explicit Request(const Ipc::TypedMsgHdr& msg); ///< from recvmsg() + /* Ipc::Request API */ + virtual void pack(Ipc::TypedMsgHdr& msg) const; + virtual Pointer clone() const; + +private: + Request(const Request& request); + +public: + int fd; ///< HTTP client connection descriptor + + ActionParams params; ///< action name and parameters +}; + + +} // namespace Mgr + +#endif /* SQUID_MGR_REQUEST_H */ === added file 'src/mgr/Response.cc' --- src/mgr/Response.cc 1970-01-01 00:00:00 +0000 +++ src/mgr/Response.cc 2011-01-17 15:10:36 +0000 @@ -0,0 +1,74 @@ +/* + * $Id$ + * + * DEBUG: section 16 Cache Manager API + * + */ + +#include "config.h" +#include "base/TextException.h" +#include "CacheManager.h" +#include "ipc/Messages.h" +#include "ipc/TypedMsgHdr.h" +#include "mgr/ActionCreator.h" +#include "mgr/ActionProfile.h" +#include "mgr/Response.h" + + +Mgr::Response::Response(unsigned int aRequestId, Action::Pointer anAction): + Ipc::Response(aRequestId), action(anAction) +{ + Must(!action || action->name()); // if there is an action, it must be named +} + +Mgr::Response::Response(const Response& response): + Ipc::Response(response.requestId), action(response.action) +{ +} + +Mgr::Response::Response(const Ipc::TypedMsgHdr& msg): + Ipc::Response(0) +{ + msg.checkType(Ipc::mtCacheMgrResponse); + msg.getPod(requestId); + Must(requestId != 0); + + if (msg.hasMoreData()) { + String actionName; + msg.getString(actionName); + action = CacheManager::GetInstance()->createNamedAction(actionName.termedBuf()); + Must(hasAction()); + action->unpack(msg); + } +} + +void +Mgr::Response::pack(Ipc::TypedMsgHdr& msg) const +{ + Must(requestId != 0); + msg.setType(Ipc::mtCacheMgrResponse); + msg.putPod(requestId); + if (hasAction()) { + msg.putString(action->name()); + action->pack(msg); + } +} + +Ipc::Response::Pointer +Mgr::Response::clone() const +{ + return new Response(*this); +} + +bool +Mgr::Response::hasAction() const +{ + return action != NULL; +} + +const Mgr::Action& +Mgr::Response::getAction() const +{ + Must(hasAction()); + return *action; +} === removed file 'src/mgr/Response.cc' --- src/mgr/Response.cc 2010-10-29 00:12:28 +0000 +++ src/mgr/Response.cc 1970-01-01 00:00:00 +0000 @@ -1,68 +0,0 @@ -/* - * $Id$ - * - * DEBUG: section 16 Cache Manager API - * - */ - -#include "config.h" -#include "base/TextException.h" -#include "CacheManager.h" -#include "ipc/Messages.h" -#include "ipc/TypedMsgHdr.h" -#include "mgr/ActionCreator.h" -#include "mgr/ActionProfile.h" -#include "mgr/Response.h" - - -std::ostream& Mgr::operator << (std::ostream &os, const Response& response) -{ - os << "response: {requestId: " << response.requestId << '}'; - return os; -} - -Mgr::Response::Response(unsigned int aRequestId, Action::Pointer anAction): - requestId(aRequestId), action(anAction) -{ - Must(!action || action->name()); // if there is an action, it must be named -} - -Mgr::Response::Response(const Ipc::TypedMsgHdr& msg) -{ - msg.checkType(Ipc::mtCacheMgrResponse); - msg.getPod(requestId); - Must(requestId != 0); - - if (msg.hasMoreData()) { - String actionName; - msg.getString(actionName); - action = CacheManager::GetInstance()->createNamedAction(actionName.termedBuf()); - Must(hasAction()); - action->unpack(msg); - } -} - -void -Mgr::Response::pack(Ipc::TypedMsgHdr& msg) const -{ - Must(requestId != 0); - msg.setType(Ipc::mtCacheMgrResponse); - msg.putPod(requestId); - if (hasAction()) { - msg.putString(action->name()); - action->pack(msg); - } -} - -bool -Mgr::Response::hasAction() const -{ - return action != NULL; -} - -const Mgr::Action& -Mgr::Response::getAction() const -{ - Must(hasAction()); - return *action; -} === added file 'src/mgr/Response.h' --- src/mgr/Response.h 1970-01-01 00:00:00 +0000 +++ src/mgr/Response.h 2011-01-17 15:10:36 +0000 @@ -0,0 +1,44 @@ +/* + * $Id$ + * + * DEBUG: section 16 Cache Manager API + * + */ + +#ifndef SQUID_MGR_RESPONSE_H +#define SQUID_MGR_RESPONSE_H + +#include "ipc/forward.h" +#include "ipc/Response.h" +#include "mgr/Action.h" + + +namespace Mgr +{ + +/// A response to Mgr::Request. +/// May carry strand action data to be aggregated with data from other strands. +class Response: public Ipc::Response +{ +public: + Response(unsigned int aRequestId, Action::Pointer anAction = NULL); + + explicit Response(const Ipc::TypedMsgHdr& msg); ///< from recvmsg() + + /* Ipc::Response API */ + virtual void pack(Ipc::TypedMsgHdr& msg) const; + virtual Ipc::Response::Pointer clone() const; + + bool hasAction() const; ///< whether response contain action object + const Action& getAction() const; ///< returns action object + +private: + Response(const Response& response); + +public: + Action::Pointer action; ///< action relating to response +}; + +} // namespace Mgr + +#endif /* SQUID_MGR_RESPONSE_H */ === modified file 'src/mgr/StoreToCommWriter.cc' --- src/mgr/StoreToCommWriter.cc 2010-11-27 01:46:22 +0000 +++ src/mgr/StoreToCommWriter.cc 2011-01-17 15:10:36 +0000 @@ -147,42 +147,20 @@ entry = NULL; } close(); } bool Mgr::StoreToCommWriter::doneAll() const { return entry && entry->store_status == STORE_OK && // the action is over writeOffset >= entry->objectLen(); // we wrote all the results } void Mgr::StoreToCommWriter::Abort(void* param) { StoreToCommWriter* mgrWriter = static_cast(param); if (mgrWriter->fd >= 0) comm_close(mgrWriter->fd); } - - -int -Mgr::ImportHttpFdIntoComm(int fd) -{ - struct sockaddr_in addr; - socklen_t len = sizeof(addr); - if (getsockname(fd, reinterpret_cast(&addr), &len) == 0) { - Ip::Address ipAddr(addr); - struct addrinfo* addr_info = NULL; - ipAddr.GetAddrInfo(addr_info); - addr_info->ai_socktype = SOCK_STREAM; - addr_info->ai_protocol = IPPROTO_TCP; - comm_import_opened(fd, ipAddr, COMM_NONBLOCKING, Ipc::FdNote(Ipc::fdnHttpSocket), addr_info); - ipAddr.FreeAddrInfo(addr_info); - } else { - debugs(16, DBG_CRITICAL, HERE << "ERROR: FD " << fd << ' ' << xstrerror()); - ::close(fd); - fd = -1; - } - return fd; -} === modified file 'src/mgr/StoreToCommWriter.h' --- src/mgr/StoreToCommWriter.h 2010-10-28 18:52:59 +0000 +++ src/mgr/StoreToCommWriter.h 2011-01-17 15:10:36 +0000 @@ -48,26 +48,23 @@ void noteCommWrote(const CommIoCbParams& params); /// called by Comm if the client socket got closed void noteCommClosed(const CommCloseCbParams& params); /// closes the local connection to the HTTP client, if any void close(); protected: int fd; ///< HTTP client descriptor StoreEntry* entry; ///< store entry with the cache manager response store_client* sc; ///< our registration with the store int64_t writeOffset; ///< number of bytes written to the client AsyncCall::Pointer closer; ///< comm_close handler char buffer[HTTP_REQBUF_SZ]; ///< action results; Store fills, Comm writes CBDATA_CLASS2(StoreToCommWriter); }; -/// import HTTP socket fd from another strand into our Comm state -extern int ImportHttpFdIntoComm(int fd); - } // namespace Mgr #endif /* SQUID_MGR_STORE_TO_COMM_WRITER_H */ === modified file 'src/snmp_core.cc' --- src/snmp_core.cc 2011-01-10 09:43:43 +0000 +++ src/snmp_core.cc 2011-01-28 16:13:31 +0000 @@ -14,260 +14,244 @@ * incorporates software developed and/or copyrighted by other * sources; see the CREDITS file for full details. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. * */ #include "squid.h" #include "acl/FilledChecklist.h" -#include "cache_snmp.h" +#include "base/CbcPointer.h" #include "comm.h" #include "comm/Loops.h" #include "ipc/StartListening.h" #include "ip/Address.h" #include "ip/tools.h" +#include "snmp_core.h" +#include "snmpx/Forwarder.h" -#define SNMP_REQUEST_SIZE 4096 -#define MAX_PROTOSTAT 5 /// dials snmpConnectionOpened call class SnmpListeningStartedDialer: public CallDialer, public Ipc::StartListeningCb { public: typedef void (*Handler)(int fd, int errNo); SnmpListeningStartedDialer(Handler aHandler): handler(aHandler) {} virtual void print(std::ostream &os) const { startPrint(os) << ')'; } virtual bool canDial(AsyncCall &) const { return true; } virtual void dial(AsyncCall &) { (handler)(fd, errNo); } public: Handler handler; }; Ip::Address theOutSNMPAddr; -typedef struct _mib_tree_entry mib_tree_entry; -typedef oid *(instance_Fn) (oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn); - -struct _mib_tree_entry { - oid *name; - int len; - oid_ParseFn *parsefunction; - instance_Fn *instancefunction; - int children; - - struct _mib_tree_entry **leaves; - - struct _mib_tree_entry *parent; -}; - mib_tree_entry *mib_tree_head; mib_tree_entry *mib_tree_last; static void snmpIncomingConnectionOpened(int fd, int errNo); static void snmpOutgoingConnectionOpened(int fd, int errNo); -static mib_tree_entry * snmpAddNodeStr(const char *base_str, int o, oid_ParseFn * parsefunction, instance_Fn * instancefunction); -static mib_tree_entry *snmpAddNode(oid * name, int len, oid_ParseFn * parsefunction, instance_Fn * instancefunction, int children,...); +static mib_tree_entry * snmpAddNodeStr(const char *base_str, int o, oid_ParseFn * parsefunction, instance_Fn * instancefunction, AggrType aggrType = atNone); +static mib_tree_entry *snmpAddNode(oid * name, int len, oid_ParseFn * parsefunction, instance_Fn * instancefunction, AggrType aggrType, int children,...); static oid *snmpCreateOid(int length,...); mib_tree_entry * snmpLookupNodeStr(mib_tree_entry *entry, const char *str); int snmpCreateOidFromStr(const char *str, oid **name, int *nl); SQUIDCEXTERN void (*snmplib_debug_hook) (int, char *); static oid *static_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn); static oid *time_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn); static oid *peer_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn); static oid *client_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn); static void snmpDecodePacket(snmp_request_t * rq); static void snmpConstructReponse(snmp_request_t * rq); -static struct snmp_pdu *snmpAgentResponse(struct snmp_pdu *PDU); static oid_ParseFn *snmpTreeNext(oid * Current, snint CurrentLen, oid ** Next, snint * NextLen); static oid_ParseFn *snmpTreeGet(oid * Current, snint CurrentLen); static mib_tree_entry *snmpTreeEntry(oid entry, snint len, mib_tree_entry * current); static mib_tree_entry *snmpTreeSiblingEntry(oid entry, snint len, mib_tree_entry * current); extern "C" void snmpSnmplibDebug(int lvl, char *buf); /* * The functions used during startup: * snmpInit * snmpConnectionOpen * snmpConnectionShutdown * snmpConnectionClose */ /* * Turns the MIB into a Tree structure. Called during the startup process. */ void snmpInit(void) { debugs(49, 5, "snmpInit: Building SNMP mib tree structure"); snmplib_debug_hook = snmpSnmplibDebug; /* * This following bit of evil is to get the final node in the "squid" mib * without having a "search" function. A search function should be written * to make this and the other code much less evil. */ - mib_tree_head = snmpAddNode(snmpCreateOid(1, 1), 1, NULL, NULL, 0); + mib_tree_head = snmpAddNode(snmpCreateOid(1, 1), 1, NULL, NULL, atNone, 0); assert(mib_tree_head); debugs(49, 5, "snmpInit: root is " << mib_tree_head); snmpAddNodeStr("1", 3, NULL, NULL); snmpAddNodeStr("1.3", 6, NULL, NULL); snmpAddNodeStr("1.3.6", 1, NULL, NULL); snmpAddNodeStr("1.3.6.1", 4, NULL, NULL); snmpAddNodeStr("1.3.6.1.4", 1, NULL, NULL); snmpAddNodeStr("1.3.6.1.4.1", 3495, NULL, NULL); mib_tree_entry *m2 = snmpAddNodeStr("1.3.6.1.4.1.3495", 1, NULL, NULL); mib_tree_entry *n = snmpLookupNodeStr(NULL, "1.3.6.1.4.1.3495.1"); assert(m2 == n); /* SQ_SYS - 1.3.6.1.4.1.3495.1.1 */ snmpAddNodeStr("1.3.6.1.4.1.3495.1", 1, NULL, NULL); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.1", SYSVMSIZ, snmp_sysFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.1", SYSSTOR, snmp_sysFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.1", SYS_UPTIME, snmp_sysFn, static_Inst); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.1", SYSVMSIZ, snmp_sysFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.1", SYSSTOR, snmp_sysFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.1", SYS_UPTIME, snmp_sysFn, static_Inst, atMax); /* SQ_CONF - 1.3.6.1.4.1.3495.1.2 */ snmpAddNodeStr("1.3.6.1.4.1.3495.1", 2, NULL, NULL); snmpAddNodeStr("1.3.6.1.4.1.3495.1.2", CONF_ADMIN, snmp_confFn, static_Inst); snmpAddNodeStr("1.3.6.1.4.1.3495.1.2", CONF_VERSION, snmp_confFn, static_Inst); snmpAddNodeStr("1.3.6.1.4.1.3495.1.2", CONF_VERSION_ID, snmp_confFn, static_Inst); snmpAddNodeStr("1.3.6.1.4.1.3495.1.2", CONF_LOG_FAC, snmp_confFn, static_Inst); /* SQ_CONF + CONF_STORAGE - 1.3.6.1.4.1.3495.1.5 */ snmpAddNodeStr("1.3.6.1.4.1.3495.1.2", CONF_STORAGE, NULL, NULL); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.2.5", CONF_ST_MMAXSZ, snmp_confFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.2.5", CONF_ST_SWMAXSZ, snmp_confFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.2.5", CONF_ST_SWHIWM, snmp_confFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.2.5", CONF_ST_SWLOWM, snmp_confFn, static_Inst); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.2.5", CONF_ST_MMAXSZ, snmp_confFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.2.5", CONF_ST_SWMAXSZ, snmp_confFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.2.5", CONF_ST_SWHIWM, snmp_confFn, static_Inst, atMin); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.2.5", CONF_ST_SWLOWM, snmp_confFn, static_Inst, atMax); snmpAddNodeStr("1.3.6.1.4.1.3495.1.2", CONF_UNIQNAME, snmp_confFn, static_Inst); /* SQ_PRF - 1.3.6.1.4.1.3495.1.3 */ snmpAddNodeStr("1.3.6.1.4.1.3495.1", 3, NULL, NULL); /* SQ_PRF */ /* PERF_SYS - 1.3.6.1.4.1.3495.1.3.1 */ snmpAddNodeStr("1.3.6.1.4.1.3495.1.3", PERF_SYS, NULL, NULL); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_PF, snmp_prfSysFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_NUMR, snmp_prfSysFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_MEMUSAGE, snmp_prfSysFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CPUTIME, snmp_prfSysFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CPUUSAGE, snmp_prfSysFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_MAXRESSZ, snmp_prfSysFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_NUMOBJCNT, snmp_prfSysFn, static_Inst); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_PF, snmp_prfSysFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_NUMR, snmp_prfSysFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_MEMUSAGE, snmp_prfSysFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CPUTIME, snmp_prfSysFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CPUUSAGE, snmp_prfSysFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_MAXRESSZ, snmp_prfSysFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_NUMOBJCNT, snmp_prfSysFn, static_Inst, atSum); snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURLRUEXP, snmp_prfSysFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURUNLREQ, snmp_prfSysFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURUNUSED_FD, snmp_prfSysFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURRESERVED_FD, snmp_prfSysFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURUSED_FD, snmp_prfSysFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURMAX_FD, snmp_prfSysFn, static_Inst); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURUNLREQ, snmp_prfSysFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURUNUSED_FD, snmp_prfSysFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURRESERVED_FD, snmp_prfSysFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURUSED_FD, snmp_prfSysFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURMAX_FD, snmp_prfSysFn, static_Inst, atMax); /* PERF_PROTO - 1.3.6.1.4.1.3495.1.3.2 */ snmpAddNodeStr("1.3.6.1.4.1.3495.1.3", PERF_PROTO, NULL, NULL); snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2", PERF_PROTOSTAT_AGGR, NULL, NULL); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_HTTP_REQ, snmp_prfProtoFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_HTTP_HITS, snmp_prfProtoFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_HTTP_ERRORS, snmp_prfProtoFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_HTTP_KBYTES_IN, snmp_prfProtoFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_HTTP_KBYTES_OUT, snmp_prfProtoFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_ICP_S, snmp_prfProtoFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_ICP_R, snmp_prfProtoFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_ICP_SKB, snmp_prfProtoFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_ICP_RKB, snmp_prfProtoFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_REQ, snmp_prfProtoFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_ERRORS, snmp_prfProtoFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_KBYTES_IN, snmp_prfProtoFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_KBYTES_OUT, snmp_prfProtoFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_CURSWAP, snmp_prfProtoFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_CLIENTS, snmp_prfProtoFn, static_Inst); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_HTTP_REQ, snmp_prfProtoFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_HTTP_HITS, snmp_prfProtoFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_HTTP_ERRORS, snmp_prfProtoFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_HTTP_KBYTES_IN, snmp_prfProtoFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_HTTP_KBYTES_OUT, snmp_prfProtoFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_ICP_S, snmp_prfProtoFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_ICP_R, snmp_prfProtoFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_ICP_SKB, snmp_prfProtoFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_ICP_RKB, snmp_prfProtoFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_REQ, snmp_prfProtoFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_ERRORS, snmp_prfProtoFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_KBYTES_IN, snmp_prfProtoFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_KBYTES_OUT, snmp_prfProtoFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_CURSWAP, snmp_prfProtoFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_CLIENTS, snmp_prfProtoFn, static_Inst, atSum); /* Note this is time-series rather than 'static' */ /* cacheMedianSvcTable */ snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2", PERF_PROTOSTAT_MEDIAN, NULL, NULL); /* cacheMedianSvcEntry */ snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2", 1, NULL, NULL); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_TIME, snmp_prfProtoFn, time_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_HTTP_ALL, snmp_prfProtoFn, time_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_HTTP_MISS, snmp_prfProtoFn, time_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_HTTP_NM, snmp_prfProtoFn, time_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_HTTP_HIT, snmp_prfProtoFn, time_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_ICP_QUERY, snmp_prfProtoFn, time_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_ICP_REPLY, snmp_prfProtoFn, time_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_DNS, snmp_prfProtoFn, time_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_RHR, snmp_prfProtoFn, time_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_BHR, snmp_prfProtoFn, time_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_HTTP_NH, snmp_prfProtoFn, time_Inst); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_TIME, snmp_prfProtoFn, time_Inst, atAverage); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_HTTP_ALL, snmp_prfProtoFn, time_Inst, atAverage); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_HTTP_MISS, snmp_prfProtoFn, time_Inst, atAverage); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_HTTP_NM, snmp_prfProtoFn, time_Inst, atAverage); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_HTTP_HIT, snmp_prfProtoFn, time_Inst, atAverage); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_ICP_QUERY, snmp_prfProtoFn, time_Inst, atAverage); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_ICP_REPLY, snmp_prfProtoFn, time_Inst, atAverage); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_DNS, snmp_prfProtoFn, time_Inst, atAverage); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_RHR, snmp_prfProtoFn, time_Inst, atAverage); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_BHR, snmp_prfProtoFn, time_Inst, atAverage); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_HTTP_NH, snmp_prfProtoFn, time_Inst, atAverage); /* SQ_NET - 1.3.6.1.4.1.3495.1.4 */ snmpAddNodeStr("1.3.6.1.4.1.3495.1", 4, NULL, NULL); snmpAddNodeStr("1.3.6.1.4.1.3495.1.4", NET_IP_CACHE, NULL, NULL); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_ENT, snmp_netIpFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_REQ, snmp_netIpFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_HITS, snmp_netIpFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_PENDHIT, snmp_netIpFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_NEGHIT, snmp_netIpFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_MISS, snmp_netIpFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_GHBN, snmp_netIpFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_LOC, snmp_netIpFn, static_Inst); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_ENT, snmp_netIpFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_REQ, snmp_netIpFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_HITS, snmp_netIpFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_PENDHIT, snmp_netIpFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_NEGHIT, snmp_netIpFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_MISS, snmp_netIpFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_GHBN, snmp_netIpFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_LOC, snmp_netIpFn, static_Inst, atSum); snmpAddNodeStr("1.3.6.1.4.1.3495.1.4", NET_FQDN_CACHE, NULL, NULL); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_ENT, snmp_netFqdnFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_REQ, snmp_netFqdnFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_HITS, snmp_netFqdnFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_PENDHIT, snmp_netFqdnFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_NEGHIT, snmp_netFqdnFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_MISS, snmp_netFqdnFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_GHBN, snmp_netFqdnFn, static_Inst); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_ENT, snmp_netFqdnFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_REQ, snmp_netFqdnFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_HITS, snmp_netFqdnFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_PENDHIT, snmp_netFqdnFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_NEGHIT, snmp_netFqdnFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_MISS, snmp_netFqdnFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_GHBN, snmp_netFqdnFn, static_Inst, atSum); snmpAddNodeStr("1.3.6.1.4.1.3495.1.4", NET_DNS_CACHE, NULL, NULL); #if USE_DNSSERVERS - snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.3", DNS_REQ, snmp_netDnsFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.3", DNS_REP, snmp_netDnsFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.3", DNS_SERVERS, snmp_netDnsFn, static_Inst); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.3", DNS_REQ, snmp_netDnsFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.3", DNS_REP, snmp_netDnsFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.3", DNS_SERVERS, snmp_netDnsFn, static_Inst, atSum); #else - snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.3", DNS_REQ, snmp_netIdnsFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.3", DNS_REP, snmp_netIdnsFn, static_Inst); - snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.3", DNS_SERVERS, snmp_netIdnsFn, static_Inst); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.3", DNS_REQ, snmp_netIdnsFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.3", DNS_REP, snmp_netIdnsFn, static_Inst, atSum); + snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.3", DNS_SERVERS, snmp_netIdnsFn, static_Inst, atSum); #endif /* SQ_MESH - 1.3.6.1.4.1.3495.1.5 */ snmpAddNodeStr("1.3.6.1.4.1.3495.1", 5, NULL, NULL); /* cachePeerTable - 1.3.6.1.4.1.3495.1.5.1 */ snmpAddNodeStr("1.3.6.1.4.1.3495.1.5", MESH_PTBL, NULL, NULL); /* CachePeerTableEntry (version 3) - 1.3.6.1.4.1.3495.1.5.1.3 */ snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1", 3, NULL, NULL); snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_INDEX, snmp_meshPtblFn, peer_Inst); snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_NAME, snmp_meshPtblFn, peer_Inst); snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_ADDR_TYPE, snmp_meshPtblFn, peer_Inst); snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_ADDR, snmp_meshPtblFn, peer_Inst); snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_HTTP, snmp_meshPtblFn, peer_Inst); snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_ICP, snmp_meshPtblFn, peer_Inst); snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_TYPE, snmp_meshPtblFn, peer_Inst); snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_STATE, snmp_meshPtblFn, peer_Inst); snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_SENT, snmp_meshPtblFn, peer_Inst); snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_PACKED, snmp_meshPtblFn, peer_Inst); @@ -520,56 +504,64 @@ snmpConstructReponse(rq); } else { debugs(49, 1, HERE << "Failed SNMP agent query from : " << rq->from); snmp_free_pdu(PDU); } if (Community) xfree(Community); } /* * Packet OK, ACL Check OK, Create reponse. */ static void snmpConstructReponse(snmp_request_t * rq) { struct snmp_pdu *RespPDU; debugs(49, 5, "snmpConstructReponse: Called."); + + if (UsingSmp() && IamWorkerProcess()) { + AsyncJob::Start(new Snmp::Forwarder(static_cast(*rq->PDU), + static_cast(rq->session), rq->sock, rq->from)); + snmp_free_pdu(rq->PDU); + return; + } + RespPDU = snmpAgentResponse(rq->PDU); snmp_free_pdu(rq->PDU); if (RespPDU != NULL) { snmp_build(&rq->session, RespPDU, rq->outbuf, &rq->outlen); comm_udp_sendto(rq->sock, rq->from, rq->outbuf, rq->outlen); snmp_free_pdu(RespPDU); } } /* * Decide how to respond to the request, construct a response and * return the response to the requester. */ -static struct snmp_pdu * +struct snmp_pdu * snmpAgentResponse(struct snmp_pdu *PDU) { struct snmp_pdu *Answer = NULL; debugs(49, 5, "snmpAgentResponse: Called."); if ((Answer = snmp_pdu_create(SNMP_PDU_RESPONSE))) { Answer->reqid = PDU->reqid; Answer->errindex = 0; if (PDU->command == SNMP_PDU_GET || PDU->command == SNMP_PDU_GETNEXT) { /* Indirect way */ int get_next = (PDU->command == SNMP_PDU_GETNEXT); variable_list *VarPtr_; variable_list **RespVars = &(Answer->variables); oid_ParseFn *ParseFn; int index = 0; /* Loop through all variables */ for (VarPtr_ = PDU->variables; VarPtr_; VarPtr_ = VarPtr_->next_variable) { @@ -648,40 +640,63 @@ mibTreeEntry = mib_tree_head; if (Current[count] == mibTreeEntry->name[count]) { count++; while ((mibTreeEntry) && (count < CurrentLen) && (!mibTreeEntry->parsefunction)) { mibTreeEntry = snmpTreeEntry(Current[count], count, mibTreeEntry); count++; } } if (mibTreeEntry && mibTreeEntry->parsefunction) Fn = mibTreeEntry->parsefunction; debugs(49, 5, "snmpTreeGet: return"); return (Fn); } +AggrType +snmpAggrType(oid* Current, snint CurrentLen) +{ + debugs(49, 5, HERE); + + mib_tree_entry* mibTreeEntry = mib_tree_head; + AggrType type = atNone; + int count = 0; + + if (Current[count] == mibTreeEntry->name[count]) { + count++; + + while (mibTreeEntry != NULL && count < CurrentLen) { + mibTreeEntry = snmpTreeEntry(Current[count], count, mibTreeEntry); + if (mibTreeEntry != NULL) + type = mibTreeEntry->aggrType; + count++; + } + } + + return type; +} + static oid_ParseFn * snmpTreeNext(oid * Current, snint CurrentLen, oid ** Next, snint * NextLen) { oid_ParseFn *Fn = NULL; mib_tree_entry *mibTreeEntry = NULL, *nextoid = NULL; int count = 0; debugs(49, 5, "snmpTreeNext: Called"); MemBuf tmp; debugs(49, 6, "snmpTreeNext: Current : " << snmpDebugOid(Current, CurrentLen, tmp)); mibTreeEntry = mib_tree_head; if (Current[count] == mibTreeEntry->name[count]) { count++; while ((mibTreeEntry) && (count < CurrentLen) && (!mibTreeEntry->parsefunction)) { mib_tree_entry *nextmibTreeEntry = snmpTreeEntry(Current[count], count, mibTreeEntry); @@ -1015,91 +1030,92 @@ *nl = 0; char *s = xstrdup(str); char *s_ = s; /* Parse the OID string into oid bits */ while ( (p = strsep(&s_, delim)) != NULL) { *name = (oid*)xrealloc(*name, sizeof(oid) * ((*nl) + 1)); (*name)[*nl] = atoi(p); (*nl)++; } xfree(s); return 1; } /* * Create an entry. Return a pointer to the newly created node, or NULL * on failure. */ static mib_tree_entry * -snmpAddNodeStr(const char *base_str, int o, oid_ParseFn * parsefunction, instance_Fn * instancefunction) +snmpAddNodeStr(const char *base_str, int o, oid_ParseFn * parsefunction, instance_Fn * instancefunction, AggrType aggrType) { mib_tree_entry *m, *b; oid *n; int nl; char s[1024]; /* Find base node */ b = snmpLookupNodeStr(mib_tree_head, base_str); if (! b) return NULL; debugs(49, 5, "snmpAddNodeStr: " << base_str << ": -> " << b); /* Create OID string for new entry */ snprintf(s, 1024, "%s.%d", base_str, o); if (! snmpCreateOidFromStr(s, &n, &nl)) return NULL; /* Create a node */ - m = snmpAddNode(n, nl, parsefunction, instancefunction, 0); + m = snmpAddNode(n, nl, parsefunction, instancefunction, aggrType, 0); /* Link it into the existing tree */ snmpAddNodeChild(b, m); /* Return the node */ return m; } /* * Adds a node to the MIB tree structure and adds the appropriate children */ static mib_tree_entry * -snmpAddNode(oid * name, int len, oid_ParseFn * parsefunction, instance_Fn * instancefunction, int children,...) +snmpAddNode(oid * name, int len, oid_ParseFn * parsefunction, instance_Fn * instancefunction, AggrType aggrType, int children,...) { va_list args; int loop; mib_tree_entry *entry = NULL; va_start(args, children); MemBuf tmp; debugs(49, 6, "snmpAddNode: Children : " << children << ", Oid : " << snmpDebugOid(name, len, tmp)); va_start(args, children); entry = (mib_tree_entry *)xmalloc(sizeof(mib_tree_entry)); entry->name = name; entry->len = len; entry->parsefunction = parsefunction; entry->instancefunction = instancefunction; entry->children = children; entry->leaves = NULL; + entry->aggrType = aggrType; if (children > 0) { entry->leaves = (mib_tree_entry **)xmalloc(sizeof(mib_tree_entry *) * children); for (loop = 0; loop < children; loop++) { entry->leaves[loop] = va_arg(args, mib_tree_entry *); entry->leaves[loop]->parent = entry; } } return (entry); } /* End of tree utility functions */ /* * Returns the list of parameters in an oid */ static oid * snmpCreateOid(int length,...) { === added file 'src/snmp_core.h' --- src/snmp_core.h 1970-01-01 00:00:00 +0000 +++ src/snmp_core.h 2011-01-17 15:10:36 +0000 @@ -0,0 +1,38 @@ +/* + * $Id$ + * + * DEBUG: section 49 SNMP Interface + * + */ + +#ifndef SQUID_SNMP_CORE_H +#define SQUID_SNMP_CORE_H + +#include "config.h" +#include "cache_snmp.h" + +#define SNMP_REQUEST_SIZE 4096 +#define MAX_PROTOSTAT 5 + + +typedef struct _mib_tree_entry mib_tree_entry; +typedef oid *(instance_Fn) (oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn); +typedef enum {atNone = 0, atSum, atAverage, atMax, atMin} AggrType; + +struct _mib_tree_entry { + oid *name; + int len; + oid_ParseFn *parsefunction; + instance_Fn *instancefunction; + int children; + + struct _mib_tree_entry **leaves; + + struct _mib_tree_entry *parent; + AggrType aggrType; +}; + +extern struct snmp_pdu* snmpAgentResponse(struct snmp_pdu* PDU); +extern AggrType snmpAggrType(oid* Current, snint CurrentLen); + +#endif /* SQUID_SNMP_CORE_H */ === added directory 'src/snmpx' === added file 'src/snmpx/Forwarder.cc' --- src/snmpx/Forwarder.cc 1970-01-01 00:00:00 +0000 +++ src/snmpx/Forwarder.cc 2011-01-27 11:19:05 +0000 @@ -0,0 +1,107 @@ +/* + * $Id$ + * + * DEBUG: section 49 SNMP Interface + * + */ + +#include "config.h" +#include "base/TextException.h" +#include "CommCalls.h" +#include "ipc/Port.h" +#include "snmp_core.h" +#include "snmpx/Forwarder.h" +#include "snmpx/Request.h" +#include "snmpx/Response.h" + + +CBDATA_NAMESPACED_CLASS_INIT(Snmp, Forwarder); + + +Snmp::Forwarder::Forwarder(const Pdu& aPdu, const Session& aSession, int aFd, + const Ip::Address& anAddress): + Ipc::Forwarder(new Request(KidIdentifier, 0, aPdu, aSession, aFd, anAddress), 2), + fd(aFd) +{ + debugs(49, 5, HERE << "FD " << aFd); + Must(fd >= 0); + closer = asyncCall(49, 5, "Snmp::Forwarder::noteCommClosed", + CommCbMemFunT(this, &Forwarder::noteCommClosed)); + comm_add_close_handler(fd, closer); +} + +/// removes our cleanup handler of the client connection socket +void +Snmp::Forwarder::cleanup() +{ + if (fd >= 0) { + if (closer != NULL) { + comm_remove_close_handler(fd, closer); + closer = NULL; + } + fd = -1; + } +} + +/// called when the client socket gets closed by some external force +void +Snmp::Forwarder::noteCommClosed(const CommCloseCbParams& params) +{ + debugs(49, 5, HERE); + Must(fd == params.fd); + fd = -1; + mustStop("commClosed"); +} + +void +Snmp::Forwarder::handleTimeout() +{ + sendError(SNMP_ERR_RESOURCEUNAVAILABLE); + Ipc::Forwarder::handleTimeout(); +} + +void +Snmp::Forwarder::handleException(const std::exception& e) +{ + debugs(49, 3, HERE << e.what()); + if (fd >= 0) + sendError(SNMP_ERR_GENERR); + Ipc::Forwarder::handleException(e); +} + +/// send error SNMP response +void +Snmp::Forwarder::sendError(int error) +{ + debugs(49, 3, HERE); + Snmp::Request& req = static_cast(*request); + req.pdu.command = SNMP_PDU_RESPONSE; + req.pdu.errstat = error; + u_char buffer[SNMP_REQUEST_SIZE]; + int len = sizeof(buffer); + snmp_build(&req.session, &req.pdu, buffer, &len); + comm_udp_sendto(fd, req.address, buffer, len); +} + +void +Snmp::SendResponse(unsigned int requestId, const Pdu& pdu) +{ + debugs(49, 5, HERE); + // snmpAgentResponse() can modify arg + Pdu tmp = pdu; + Snmp::Response response(requestId); + snmp_pdu* response_pdu = NULL; + try { + response_pdu = snmpAgentResponse(&tmp); + Must(response_pdu != NULL); + response.pdu = static_cast(*response_pdu); + snmp_free_pdu(response_pdu); + } catch (const std::exception& e) { + debugs(49, DBG_CRITICAL, HERE << e.what()); + response.pdu.command = SNMP_PDU_RESPONSE; + response.pdu.errstat = SNMP_ERR_GENERR; + } + Ipc::TypedMsgHdr message; + response.pack(message); + Ipc::SendMessage(Ipc::coordinatorAddr, message); +} === added file 'src/snmpx/Forwarder.h' --- src/snmpx/Forwarder.h 1970-01-01 00:00:00 +0000 +++ src/snmpx/Forwarder.h 2011-01-17 15:10:36 +0000 @@ -0,0 +1,52 @@ +/* + * $Id$ + * + * DEBUG: section 49 SNMP Interface + * + */ + +#ifndef SQUID_SNMPX_FORWARDER_H +#define SQUID_SNMPX_FORWARDER_H + +#include "ipc/Forwarder.h" +#include "snmpx/Pdu.h" +#include "snmpx/Session.h" + + +class CommCloseCbParams; + +namespace Snmp +{ + +/** Forwards a single client SNMP request to Coordinator. + * Waits for an ACK from Coordinator + * Send the data unit with an error response if forwarding fails. + */ +class Forwarder: public Ipc::Forwarder +{ +public: + Forwarder(const Pdu& aPdu, const Session& aSession, int aFd, + const Ip::Address& anAddress); + +protected: + /* Ipc::Forwarder API */ + virtual void cleanup(); ///< perform cleanup actions + virtual void handleTimeout(); + virtual void handleException(const std::exception& e); + +private: + void noteCommClosed(const CommCloseCbParams& params); + void sendError(int error); + +private: + int fd; ///< client connection descriptor + AsyncCall::Pointer closer; ///< comm_close handler for the connection + + CBDATA_CLASS2(Forwarder); +}; + +extern void SendResponse(unsigned int requestId, const Pdu& pdu); + +} // namespace Snmp + +#endif /* SQUID_SNMPX_FORWARDER_H */ === added file 'src/snmpx/Inquirer.cc' --- src/snmpx/Inquirer.cc 1970-01-01 00:00:00 +0000 +++ src/snmpx/Inquirer.cc 2011-01-27 11:19:24 +0000 @@ -0,0 +1,102 @@ +/* + * $Id$ + * + * DEBUG: section 49 SNMP Interface + * + */ + +#include "config.h" +#include "base/TextException.h" +#include "CommCalls.h" +#include "ipc/UdsOp.h" +#include "snmp_core.h" +#include "snmpx/Inquirer.h" +#include "snmpx/Response.h" +#include "snmpx/Request.h" + + +CBDATA_NAMESPACED_CLASS_INIT(Snmp, Inquirer); + + +Snmp::Inquirer::Inquirer(const Request& aRequest, const Ipc::StrandCoords& coords): + Ipc::Inquirer(aRequest.clone(), coords, 2), + aggrPdu(aRequest.pdu), + fd(ImportFdIntoComm(aRequest.fd, SOCK_DGRAM, IPPROTO_UDP, Ipc::fdnInSnmpSocket)) +{ + debugs(49, 5, HERE); + closer = asyncCall(49, 5, "Snmp::Inquirer::noteCommClosed", + CommCbMemFunT(this, &Inquirer::noteCommClosed)); + comm_add_close_handler(fd, closer); +} + +/// closes our copy of the client connection socket +void +Snmp::Inquirer::cleanup() +{ + if (fd >= 0) { + if (closer != NULL) { + comm_remove_close_handler(fd, closer); + closer = NULL; + } + comm_close(fd); + fd = -1; + } +} + +void +Snmp::Inquirer::start() +{ + debugs(49, 5, HERE); + Ipc::Inquirer::start(); + Must(fd >= 0); + inquire(); +} + +void +Snmp::Inquirer::handleException(const std::exception& e) +{ + aggrPdu.errstat = SNMP_ERR_GENERR; + Ipc::Inquirer::handleException(e); +} + +bool +Snmp::Inquirer::aggregate(Response::Pointer aResponse) +{ + Snmp::Response& response = static_cast(*aResponse); + bool error = response.pdu.errstat != SNMP_ERR_NOERROR; + if (error) { + aggrPdu = response.pdu; + } else { + aggrPdu.aggregate(response.pdu); + } + return !error; +} + +/// called when the some external force closed our socket +void +Snmp::Inquirer::noteCommClosed(const CommCloseCbParams& params) +{ + debugs(49, 5, HERE); + Must(fd < 0 || fd == params.fd); + fd = -1; + mustStop("commClosed"); +} + +bool +Snmp::Inquirer::doneAll() const +{ + return !writer && Ipc::Inquirer::doneAll(); +} + +void +Snmp::Inquirer::sendResponse() +{ + debugs(49, 5, HERE); + aggrPdu.fixAggregate(); + aggrPdu.command = SNMP_PDU_RESPONSE; + u_char buffer[SNMP_REQUEST_SIZE]; + int len = sizeof(buffer); + Snmp::Request& req = static_cast(*request); + snmp_build(&req.session, &aggrPdu, buffer, &len); + comm_udp_sendto(fd, req.address, buffer, len); +} === added file 'src/snmpx/Inquirer.h' --- src/snmpx/Inquirer.h 1970-01-01 00:00:00 +0000 +++ src/snmpx/Inquirer.h 2011-01-17 15:10:36 +0000 @@ -0,0 +1,54 @@ +/* + * $Id$ + * + * DEBUG: section 49 SNMP Interface + * + */ + +#ifndef SQUID_SNMPX_INQUIRER_H +#define SQUID_SNMPX_INQUIRER_H + +#include "ipc/Inquirer.h" +#include "snmpx/forward.h" +#include "snmpx/Pdu.h" + + +class CommCloseCbParams; + +namespace Snmp +{ + +/// Coordinator's job that sends a PDU request to each strand, +/// aggregates strand responses and send back the result to client +class Inquirer: public Ipc::Inquirer +{ +public: + Inquirer(const Request& aRequest, const Ipc::StrandCoords& coords); + +protected: + /* AsyncJob API */ + virtual void start(); + virtual bool doneAll() const; + + /* Ipc::Inquirer API */ + virtual void cleanup(); + virtual void handleException(const std::exception& e); + virtual void sendResponse(); + virtual bool aggregate(Ipc::Response::Pointer aResponse); + +private: + void noteCommClosed(const CommCloseCbParams& params); + +private: + Pdu aggrPdu; ///< aggregated pdu + int fd; ///< client connection descriptor + + AsyncCall::Pointer writer; ///< comm_write callback + AsyncCall::Pointer closer; ///< comm_close handler + + CBDATA_CLASS2(Inquirer); +}; + +} // namespace Snmp + +#endif /* SQUID_SNMPX_INQUIRER_H */ === added file 'src/snmpx/Pdu.cc' --- src/snmpx/Pdu.cc 1970-01-01 00:00:00 +0000 +++ src/snmpx/Pdu.cc 2011-01-28 14:09:38 +0000 @@ -0,0 +1,239 @@ +/* + * $Id$ + * + * DEBUG: section 49 SNMP Interface + * + */ + +#include "config.h" +#include "base/TextException.h" +#include "ipc/TypedMsgHdr.h" +#include "protos.h" +#include "snmp_core.h" +#include "snmpx/Pdu.h" +#include "snmpx/Var.h" + + +Snmp::Pdu::Pdu() +{ + init(); +} + +Snmp::Pdu::Pdu(const Pdu& pdu) +{ + init(); + assign(pdu); +} + +Snmp::Pdu::~Pdu() +{ + clear(); +} + +Snmp::Pdu& +Snmp::Pdu::operator = (const Pdu& pdu) +{ + clear(); + assign(pdu); + return *this; +} + +void +Snmp::Pdu::init() +{ + xmemset(this, 0, sizeof(*this)); + errstat = SNMP_DEFAULT_ERRSTAT; + errindex = SNMP_DEFAULT_ERRINDEX; +} + +void +Snmp::Pdu::aggregate(const Pdu& pdu) +{ + Must(varCount() == pdu.varCount()); + aggrCount++; + for (variable_list* p_aggr = variables, *p_var = pdu.variables; p_var != NULL; + p_aggr = p_aggr->next_variable, p_var = p_var->next_variable) + { + Must(p_aggr != NULL); + Var& aggr = static_cast(*p_aggr); + Var& var = static_cast(*p_var); + if (aggr.isNull()) { + aggr.setName(var.getName()); + aggr.copyValue(var); + } else { + switch(snmpAggrType(aggr.name, aggr.name_length)) + { + case atSum: + case atAverage: + // The mean-average division is done later + // when the Snmp::Pdu::fixAggregate() called + aggr += var; + break; + case atMax: + if (var > aggr) + aggr.copyValue(var); + break; + case atMin: + if (var < aggr) + aggr.copyValue(var); + break; + default: + break; + } + } + } +} + +void +Snmp::Pdu::clear() +{ + clearSystemOid(); + clearVars(); + init(); +} + +void +Snmp::Pdu::assign(const Pdu& pdu) +{ + command = pdu.command; + address.sin_addr.s_addr = pdu.address.sin_addr.s_addr; + reqid = pdu.reqid; + errstat = pdu.errstat; + errindex = pdu.errindex; + non_repeaters = pdu.non_repeaters; + max_repetitions = pdu.max_repetitions; + agent_addr.sin_addr.s_addr = pdu.agent_addr.sin_addr.s_addr; + trap_type = pdu.trap_type; + specific_type = pdu.specific_type; + time = pdu.time; + aggrCount = pdu.aggrCount; + setSystemOid(pdu.getSystemOid()); + setVars(pdu.variables); +} + +void +Snmp::Pdu::clearVars() +{ + variable_list* var = variables; + while (var != NULL) { + variable_list* tmp = var; + var = var->next_variable; + snmp_var_free(tmp); + } + variables = NULL; +} + +void +Snmp::Pdu::setVars(variable_list* vars) +{ + clearVars(); + for (variable_list** p_var = &variables; vars != NULL; + vars = vars->next_variable, p_var = &(*p_var)->next_variable) + { + *p_var = new Var(static_cast(*vars)); + } +} + +void +Snmp::Pdu::clearSystemOid() +{ + if (enterprise != NULL) { + xfree(enterprise); + enterprise = NULL; + } + enterprise_length = 0; +} + +Range +Snmp::Pdu::getSystemOid() const +{ + return Range(enterprise, enterprise + enterprise_length); +} + +void +Snmp::Pdu::setSystemOid(const Range& systemOid) +{ + clearSystemOid(); + if (systemOid.start != NULL && systemOid.size() != 0) { + enterprise_length = systemOid.size(); + enterprise = static_cast(xmalloc(enterprise_length * sizeof(oid))); + std::copy(systemOid.start, systemOid.end, enterprise); + } +} + +void +Snmp::Pdu::pack(Ipc::TypedMsgHdr& msg) const +{ + msg.putPod(command); + msg.putPod(address); + msg.putPod(reqid); + msg.putPod(errstat); + msg.putPod(errindex); + msg.putPod(non_repeaters); + msg.putPod(max_repetitions); + msg.putInt(enterprise_length); + if (enterprise_length > 0) { + Must(enterprise != NULL); + msg.putFixed(enterprise, enterprise_length * sizeof(oid)); + } + msg.putPod(agent_addr); + msg.putPod(trap_type); + msg.putPod(specific_type); + msg.putPod(time); + msg.putInt(varCount()); + for (variable_list* var = variables; var != NULL; var = var->next_variable) + static_cast(var)->pack(msg); +} + +void +Snmp::Pdu::unpack(const Ipc::TypedMsgHdr& msg) +{ + clear(); + msg.getPod(command); + msg.getPod(address); + msg.getPod(reqid); + msg.getPod(errstat); + msg.getPod(errindex); + msg.getPod(non_repeaters); + msg.getPod(max_repetitions); + enterprise_length = msg.getInt(); + if (enterprise_length > 0) { + enterprise = static_cast(xmalloc(enterprise_length * sizeof(oid))); + msg.getFixed(enterprise, enterprise_length * sizeof(oid)); + } + msg.getPod(agent_addr); + msg.getPod(trap_type); + msg.getPod(specific_type); + msg.getPod(time); + int count = msg.getInt(); + for (variable_list** p_var = &variables; count > 0; + p_var = &(*p_var)->next_variable, --count) + { + Var* var = new Var(); + var->unpack(msg); + *p_var = var; + } +} + +int +Snmp::Pdu::varCount() const +{ + int count = 0; + for (variable_list* var = variables; var != NULL; var = var->next_variable) + ++count; + return count; +} + +void +Snmp::Pdu::fixAggregate() +{ + if (aggrCount < 2) + return; + for (variable_list* p_aggr = variables; p_aggr != NULL; p_aggr = p_aggr->next_variable) { + Var& aggr = static_cast(*p_aggr); + if(snmpAggrType(aggr.name, aggr.name_length) == atAverage) { + aggr /= aggrCount; + } + } + aggrCount = 0; +} === added file 'src/snmpx/Pdu.h' --- src/snmpx/Pdu.h 1970-01-01 00:00:00 +0000 +++ src/snmpx/Pdu.h 2011-01-28 14:06:18 +0000 @@ -0,0 +1,50 @@ +/* + * $Id$ + * + * DEBUG: section 49 SNMP Interface + * + */ + +#ifndef SQUID_SNMPX_PDU_H +#define SQUID_SNMPX_PDU_H + +#include "config.h" +#include "ipc/forward.h" +#include "Range.h" +#include "snmp.h" + + +namespace Snmp +{ + +/// snmp_pdu wrapper introduce the feature +/// to aggregate variables and to pack/unpack message +class Pdu: public snmp_pdu +{ +public: + Pdu(); + Pdu(const Pdu& pdu); + Pdu& operator = (const Pdu& pdu); + ~Pdu(); + + void aggregate(const Pdu& pdu); + void fixAggregate(); + void pack(Ipc::TypedMsgHdr& msg) const; ///< prepare for sendmsg() + void unpack(const Ipc::TypedMsgHdr& msg); ///< restore struct from the message + int varCount() const; ///< size of variables list + void clear(); ///< clear all internal members + void setVars(variable_list* vars); ///< perform assignment of variables list + void clearVars(); ///< clear variables list + Range getSystemOid() const; + void setSystemOid(const Range& systemOid); + void clearSystemOid(); + +private: + void init(); ///< initialize members + void assign(const Pdu& pdu); ///< perform full assignment + unsigned int aggrCount; ///< The number of other Pdus merged into +}; + +} // namespace Snmp + +#endif /* SQUID_SNMPX_PDU_H */ === added file 'src/snmpx/Request.cc' --- src/snmpx/Request.cc 1970-01-01 00:00:00 +0000 +++ src/snmpx/Request.cc 2011-01-17 15:10:36 +0000 @@ -0,0 +1,59 @@ +/* + * $Id$ + * + * DEBUG: section 49 SNMP Interface + * + */ + +#include "config.h" +#include "ipc/Messages.h" +#include "ipc/TypedMsgHdr.h" +#include "snmpx/Request.h" + + +Snmp::Request::Request(int aRequestorId, unsigned int aRequestId, + const Pdu& aPdu, const Session& aSession, + int aFd, const Ip::Address& anAddress): + Ipc::Request(aRequestorId, aRequestId), + pdu(aPdu), session(aSession), fd(aFd), address(anAddress) +{ +} + +Snmp::Request::Request(const Request& request): + Ipc::Request(request.requestorId, request.requestId), + pdu(request.pdu), session(request.session), + fd(request.fd), address(request.address) +{ +} + +Snmp::Request::Request(const Ipc::TypedMsgHdr& msg): + Ipc::Request(0, 0) +{ + msg.checkType(Ipc::mtSnmpRequest); + msg.getPod(requestorId); + msg.getPod(requestId); + pdu.unpack(msg); + session.unpack(msg); + msg.getPod(address); + + fd = msg.getFd(); +} + +void +Snmp::Request::pack(Ipc::TypedMsgHdr& msg) const +{ + msg.setType(Ipc::mtSnmpRequest); + msg.putPod(requestorId); + msg.putPod(requestId); + pdu.pack(msg); + session.pack(msg); + msg.putPod(address); + + msg.putFd(fd); +} + +Ipc::Request::Pointer +Snmp::Request::clone() const +{ + return new Request(*this); +} === added file 'src/snmpx/Request.h' --- src/snmpx/Request.h 1970-01-01 00:00:00 +0000 +++ src/snmpx/Request.h 2011-01-17 15:10:36 +0000 @@ -0,0 +1,46 @@ +/* + * $Id$ + * + * DEBUG: section 49 SNMP Interface + * + */ + +#ifndef SQUID_SNMPX_REQUEST_H +#define SQUID_SNMPX_REQUEST_H + +#include "ip/Address.h" +#include "ipc/forward.h" +#include "ipc/Request.h" +#include "snmpx/Pdu.h" +#include "snmpx/Session.h" + + +namespace Snmp +{ + +/// SNMP request +class Request: public Ipc::Request +{ +public: + Request(int aRequestorId, unsigned int aRequestId, const Pdu& aPdu, + const Session& aSession, int aFd, const Ip::Address& anAddress); + + explicit Request(const Ipc::TypedMsgHdr& msg); ///< from recvmsg() + /* Ipc::Request API */ + virtual void pack(Ipc::TypedMsgHdr& msg) const; + virtual Pointer clone() const; + +private: + Request(const Request& request); + +public: + Pdu pdu; ///< SNMP protocol data unit + Session session; ///< SNMP session + int fd; ///< client connection descriptor + Ip::Address address; ///< client address +}; + + +} // namespace Snmp + +#endif /* SQUID_SNMPX_REQUEST_H */ === added file 'src/snmpx/Response.cc' --- src/snmpx/Response.cc 1970-01-01 00:00:00 +0000 +++ src/snmpx/Response.cc 2011-01-17 15:10:36 +0000 @@ -0,0 +1,51 @@ +/* + * $Id$ + * + * DEBUG: section 49 SNMP Interface + * + */ + +#include "config.h" +#include "base/TextException.h" +#include "ipc/Messages.h" +#include "ipc/TypedMsgHdr.h" +#include "snmpx/Response.h" + + +std::ostream& Snmp::operator << (std::ostream& os, const Response& response) +{ + os << "response: {requestId: " << response.requestId << '}'; + return os; +} + +Snmp::Response::Response(unsigned int aRequestId): + Ipc::Response(aRequestId), pdu() +{ +} + +Snmp::Response::Response(const Response& response): + Ipc::Response(response.requestId), pdu(response.pdu) +{ +} + +Snmp::Response::Response(const Ipc::TypedMsgHdr& msg): + Ipc::Response(0) +{ + msg.checkType(Ipc::mtSnmpResponse); + msg.getPod(requestId); + pdu.unpack(msg); +} + +void +Snmp::Response::pack(Ipc::TypedMsgHdr& msg) const +{ + msg.setType(Ipc::mtSnmpResponse); + msg.putPod(requestId); + pdu.pack(msg); +} + +Ipc::Response::Pointer +Snmp::Response::clone() const +{ + return new Response(*this); +} === added file 'src/snmpx/Response.h' --- src/snmpx/Response.h 1970-01-01 00:00:00 +0000 +++ src/snmpx/Response.h 2011-01-17 15:10:36 +0000 @@ -0,0 +1,40 @@ +/* + * $Id$ + * + * DEBUG: section 49 SNMP Interface + * + */ + +#ifndef SQUID_SNMPX_RESPONSE_H +#define SQUID_SNMPX_RESPONSE_H + +#include "ipc/forward.h" +#include "ipc/Response.h" +#include "snmpx/Pdu.h" +#include + +namespace Snmp +{ + +/// +class Response: public Ipc::Response +{ +public: + Response(unsigned int aRequestId); + explicit Response(const Ipc::TypedMsgHdr& msg); ///< from recvmsg() + /* Ipc::Response API */ + virtual void pack(Ipc::TypedMsgHdr& msg) const; + virtual Ipc::Response::Pointer clone() const; + +private: + Response(const Response& response); + +public: + Pdu pdu; ///< SNMP protocol data unit +}; + +extern std::ostream& operator << (std::ostream& os, const Response& response); + +} // namespace Snmp + +#endif /* SQUID_SNMPX_RESPONSE_H */ === added file 'src/snmpx/Session.cc' --- src/snmpx/Session.cc 1970-01-01 00:00:00 +0000 +++ src/snmpx/Session.cc 2011-01-17 17:11:25 +0000 @@ -0,0 +1,112 @@ +/* + * $Id$ + * + * DEBUG: section 49 SNMP Interface + * + */ + +#include "config.h" +#include "base/TextException.h" +#include "ipc/TypedMsgHdr.h" +#include "protos.h" +#include "snmpx/Session.h" + + +Snmp::Session::Session() +{ + clear(); +} + +Snmp::Session::Session(const Session& session) +{ + assign(session); +} + +Snmp::Session::~Session() +{ + free(); +} + +Snmp::Session& +Snmp::Session::operator = (const Session& session) +{ + free(); + assign(session); + return *this; +} + +void +Snmp::Session::clear() +{ + xmemset(this, 0, sizeof(*this)); +} + +void +Snmp::Session::free() +{ + if (community_len > 0) { + Must(community != NULL); + xfree(community); + } + if (peername != NULL) + xfree(peername); + clear(); +} + +void +Snmp::Session::assign(const Session& session) +{ + memcpy(this, &session, sizeof(*this)); + if (session.community != NULL) { + community = (u_char*)xstrdup((char*)session.community); + Must(community != NULL); + } + if (session.peername != NULL) { + peername = xstrdup(session.peername); + Must(peername != NULL); + } +} + +void +Snmp::Session::pack(Ipc::TypedMsgHdr& msg) const +{ + msg.putPod(Version); + msg.putInt(community_len); + if (community_len > 0) { + Must(community != NULL); + msg.putFixed(community, community_len); + } + msg.putPod(retries); + msg.putPod(timeout); + int len = peername != NULL ? strlen(peername) : 0; + msg.putInt(len); + if (len > 0) + msg.putFixed(peername, len); + msg.putPod(remote_port); + msg.putPod(local_port); +} + +void +Snmp::Session::unpack(const Ipc::TypedMsgHdr& msg) +{ + free(); + msg.getPod(Version); + community_len = msg.getInt(); + if (community_len > 0) { + community = static_cast(xmalloc(community_len + 1)); + Must(community != NULL); + msg.getFixed(community, community_len); + community[community_len] = 0; + } + msg.getPod(retries); + msg.getPod(timeout); + int len = msg.getInt(); + if (len > 0) { + peername = static_cast(xmalloc(len + 1)); + Must(peername != NULL); + msg.getFixed(peername, len); + peername[len] = 0; + } + msg.getPod(remote_port); + msg.getPod(local_port); +} === added file 'src/snmpx/Session.h' --- src/snmpx/Session.h 1970-01-01 00:00:00 +0000 +++ src/snmpx/Session.h 2011-01-17 15:10:36 +0000 @@ -0,0 +1,40 @@ +/* + * $Id$ + * + * DEBUG: section 49 SNMP Interface + * + */ + +#ifndef SQUID_SNMPX_SESSION_H +#define SQUID_SNMPX_SESSION_H + +#include "config.h" +#include "ipc/forward.h" +#include "snmp.h" +#include "snmp_session.h" + + +namespace Snmp +{ + +/// snmp_session wrapper add pack/unpack feature +class Session: public snmp_session +{ +public: + Session(); + Session(const Session& session); + Session& operator = (const Session& session); + ~Session(); + + void pack(Ipc::TypedMsgHdr& msg) const; ///< prepare for sendmsg() + void unpack(const Ipc::TypedMsgHdr& msg); ///< restore struct from the message + void clear(); ///< clear internal members + +private: + void free(); ///< free internal members + void assign(const Session& session); ///< perform full assignment +}; + +} // namespace Snmp + +#endif /* SQUID_SNMPX_SESSION_H */ === added file 'src/snmpx/Var.cc' --- src/snmpx/Var.cc 1970-01-01 00:00:00 +0000 +++ src/snmpx/Var.cc 2011-01-28 15:08:50 +0000 @@ -0,0 +1,360 @@ +/* + * $Id$ + * + * DEBUG: section 49 SNMP Interface + * + */ + +#include "config.h" +#include "base/TextException.h" +#include "ipc/TypedMsgHdr.h" +#include "protos.h" +#include "snmpx/Var.h" + + +Snmp::Var::Var() +{ + init(); +} + +Snmp::Var::Var(const Var& var) +{ + init(); + assign(var); +} + +Snmp::Var::~Var() +{ + clear(); +} + +Snmp::Var& +Snmp::Var::operator = (const Var& var) +{ + clear(); + assign(var); + return *this; +} + +void +Snmp::Var::init() +{ + xmemset(this, 0, sizeof(*this)); +} + +Snmp::Var& +Snmp::Var::operator += (const Var& var) +{ + switch(type) + { + case SMI_INTEGER: + setInt(asInt() + var.asInt()); + break; + case SMI_GAUGE32: + setGauge(asGauge() + var.asGauge()); + break; + case SMI_COUNTER32: + setCounter(asCounter() + var.asCounter()); + break; + case SMI_COUNTER64: + setCounter64(asCounter64() + var.asCounter64()); + break; + case SMI_TIMETICKS: + setTimeTicks(asTimeTicks() + var.asTimeTicks()); + break; + default: + debugs(49, DBG_CRITICAL, HERE << "Unsupported type: " << type); + throw TexcHere("Unsupported type"); + break; + } + return *this; +} + +Snmp::Var& +Snmp::Var::operator /= (int num) +{ + Must(num != 0); + switch(type) + { + case SMI_INTEGER: + setInt(asInt() / num); + break; + case SMI_GAUGE32: + setGauge(asGauge() / num); + break; + case SMI_COUNTER32: + setCounter(asCounter() / num); + break; + case SMI_COUNTER64: + setCounter64(asCounter64() / num); + break; + case SMI_TIMETICKS: + setTimeTicks(asTimeTicks() / num); + break; + default: + debugs(49, DBG_CRITICAL, HERE << "Unsupported type: " << type); + throw TexcHere("Unsupported type"); + break; + } + return *this; +} + +bool +Snmp::Var::operator < (const Var& var) const +{ + switch(type) + { + case SMI_INTEGER: + return asInt() < var.asInt(); + case SMI_GAUGE32: + return asGauge() < var.asGauge(); + case SMI_COUNTER32: + return asCounter() < var.asCounter(); + case SMI_COUNTER64: + return asCounter64() < var.asCounter64(); + case SMI_TIMETICKS: + return asTimeTicks() < var.asTimeTicks(); + default: + debugs(49, DBG_CRITICAL, HERE << "Unsupported type: " << type); + throw TexcHere("Unsupported type"); + break; + } + return false; // unreachable +} + +bool +Snmp::Var::operator > (const Var& var) const +{ + switch(type) + { + case SMI_INTEGER: + return asInt() > var.asInt(); + case SMI_GAUGE32: + return asGauge() > var.asGauge(); + case SMI_COUNTER32: + return asCounter() > var.asCounter(); + case SMI_COUNTER64: + return asCounter64() > var.asCounter64(); + case SMI_TIMETICKS: + return asTimeTicks() > var.asTimeTicks(); + default: + debugs(49, DBG_CRITICAL, HERE << "Unsupported type: " << type); + throw TexcHere("Unsupported type"); + break; + } + return false; // unreachable +} + +void +Snmp::Var::assign(const Var& var) +{ + setName(var.getName()); + copyValue(var); +} + +void +Snmp::Var::clearName() +{ + if (name != NULL) { + xfree(name); + name = NULL; + } + name_length = 0; +} + +Range +Snmp::Var::getName() const +{ + return Range(name, name + name_length); +} + +void +Snmp::Var::setName(const Range& aName) +{ + clearName(); + if (aName.start != NULL && aName.size() != 0) { + name_length = aName.size(); + name = static_cast(xmalloc(name_length * sizeof(oid))); + std::copy(aName.start, aName.end, name); + } +} + +void +Snmp::Var::clearValue() +{ + if (val.string != NULL) { + xfree(val.string); + val.string = NULL; + } + val_len = 0; + type = 0; +} + +bool +Snmp::Var::isNull() const +{ + return type == SMI_NULLOBJ; +} + +int +Snmp::Var::asInt() const +{ + Must(type == SMI_INTEGER); + Must(val.integer != NULL && val_len == sizeof(int)); + return *val.integer; +} + +unsigned int +Snmp::Var::asGauge() const +{ + Must(type == SMI_GAUGE32); + Must(val.integer != NULL && val_len == 4); + return *reinterpret_cast(val.integer); +} + +int +Snmp::Var::asCounter() const +{ + Must(type == SMI_COUNTER32); + Must(val.integer != NULL && val_len == 4); + return *reinterpret_cast(val.integer); +} + +long long int +Snmp::Var::asCounter64() const +{ + Must(type == SMI_COUNTER64); + Must(val.integer != NULL && val_len == 8); + return *reinterpret_cast(val.integer); +} + +unsigned int +Snmp::Var::asTimeTicks() const +{ + Must(type == SMI_TIMETICKS); + Must(val.integer != NULL && val_len == sizeof(unsigned int)); + return *reinterpret_cast(val.integer); +} + +Range +Snmp::Var::asObject() const +{ + Must(type == SMI_OBJID); + Must(val_len % sizeof(oid) == 0); + int length = val_len / sizeof(oid); + Must(val.objid != NULL && length > 0); + return Range(val.objid, val.objid + length); +} + +Range +Snmp::Var::asString() const +{ + Must(type == SMI_STRING); + Must(val.string != NULL && val_len > 0); + return Range(val.string, val.string + val_len); +} + +void +Snmp::Var::setInt(int value) +{ + setValue(&value, sizeof(value), SMI_INTEGER); +} + +void +Snmp::Var::setCounter(int value) +{ + setValue(&value, sizeof(value), SMI_COUNTER32); +} + +void +Snmp::Var::setGauge(unsigned int value) +{ + setValue(&value, sizeof(value), SMI_GAUGE32); +} + +void +Snmp::Var::setString(const Range& string) +{ + setValue(string.start, string.size(), SMI_STRING); +} + +void +Snmp::Var::setObject(const Range& object) +{ + setValue(object.start, object.size() * sizeof(oid), SMI_OBJID); +} + +void +Snmp::Var::setCounter64(long long int counter) +{ + setValue(&counter, sizeof(counter), SMI_COUNTER64); +} + +void +Snmp::Var::setTimeTicks(unsigned int ticks) +{ + setValue(&ticks, sizeof(ticks), SMI_TIMETICKS); +} + +void +Snmp::Var::copyValue(const Var& var) +{ + setValue(var.val.string, var.val_len, var.type); +} + +void +Snmp::Var::setValue(const void* value, int length, int aType) +{ + clearValue(); + if (value != NULL) { + Must(length > 0 && aType > 0); + val.string = static_cast(xmalloc(length)); + memcpy(val.string, value, length); + } + val_len = length; + type = aType; +} + +void +Snmp::Var::clear() +{ + clearName(); + clearValue(); + init(); +} + +void +Snmp::Var::pack(Ipc::TypedMsgHdr& msg) const +{ + msg.putInt(name_length); + if (name_length > 0) { + Must(name != NULL); + msg.putFixed(name, name_length * sizeof(oid)); + } + msg.putPod(type); + msg.putPod(val_len); + if (val_len > 0) { + Must(val.string != NULL); + msg.putFixed(val.string, val_len); + } +} + +void +Snmp::Var::unpack(const Ipc::TypedMsgHdr& msg) +{ + clearName(); + clearValue(); + name_length = msg.getInt(); + Must(name_length >= 0); + if (name_length > 0) { + name = static_cast(xmalloc(name_length * sizeof(oid))); + msg.getFixed(name, name_length * sizeof(oid)); + } + msg.getPod(type); + val_len = msg.getInt(); + Must(val_len >= 0); + if (val_len > 0) { + val.string = static_cast(xmalloc(val_len)); + msg.getFixed(val.string, val_len); + } +} === added file 'src/snmpx/Var.h' --- src/snmpx/Var.h 1970-01-01 00:00:00 +0000 +++ src/snmpx/Var.h 2011-01-28 15:08:06 +0000 @@ -0,0 +1,72 @@ +/* + * $Id$ + * + * DEBUG: section 49 SNMP Interface + * + */ + +#ifndef SQUID_SNMPX_VAR_H +#define SQUID_SNMPX_VAR_H + +#include "config.h" +#include "ipc/forward.h" +#include "Range.h" +#include "snmp_vars.h" + + +namespace Snmp +{ + +/// variable_list wrapper implement the feature to change +/// the name/value of variable and to pack/unpack message +class Var: public variable_list +{ +public: + Var(); + Var(const Var& var); + Var& operator = (const Var& var); + ~Var(); + + Var& operator += (const Var& var); + Var& operator /= (int num); + bool operator < (const Var& var) const; + bool operator > (const Var& var) const; + + void pack(Ipc::TypedMsgHdr& msg) const; ///< prepare for sendmsg() + void unpack(const Ipc::TypedMsgHdr& msg); ///< restore struct from the message + + Range getName() const; ///< returns variable name + void setName(const Range& aName); ///< set new variable name + void clearName(); ///< clear variable name + + bool isNull() const; + + int asInt() const; ///< returns variable value as integer + unsigned int asGauge() const; ///< returns variable value as unsigned int + int asCounter() const; ///< returns variable value as Counter32 + long long int asCounter64() const; ///< returns variable value as Counter64 + unsigned int asTimeTicks() const; ///< returns variable value as time ticks + Range asObject() const; ///< returns variable value as object oid + Range asString() const; ///< returns variable value as chars string + + void setInt(int value); ///< assign int value to variable + void setCounter(int value); ///< assign Counter32 value to variable + void setGauge(unsigned int value); ///< assign unsigned int value to variable + void setString(const Range& string); ///< assign string to variable + void setObject(const Range& object); ///< assign object oid to variable + void setTimeTicks(unsigned int ticks); ///