]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
SNMP: Use our FDMultiplexer instead of select()
authorRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 30 May 2017 20:34:26 +0000 (22:34 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 27 Jun 2017 12:51:54 +0000 (14:51 +0200)
17 files changed:
m4/pdns_with_net_snmp.m4
pdns/devpollmplexer.cc
pdns/dnsdistdist/Makefile.am
pdns/dnsdistdist/devpollmplexer.cc [new symlink]
pdns/dnsdistdist/epollmplexer.cc [new symlink]
pdns/dnsdistdist/kqueuemplexer.cc [new symlink]
pdns/dnsdistdist/mplexer.hh [new symlink]
pdns/dnsdistdist/portsmplexer.cc [new symlink]
pdns/dnsdistdist/selectmplexer.cc [new symlink]
pdns/epollmplexer.cc
pdns/kqueuemplexer.cc
pdns/mplexer.hh
pdns/pollmplexer.cc
pdns/portsmplexer.cc
pdns/selectmplexer.cc
pdns/snmp-agent.cc
pdns/snmp-agent.hh

index 4134fc454e1173c0d5a925ba56bbf0540be19dba..8040672e6cb5850709b5fb1c4d0baa4a8c354ad1 100644 (file)
@@ -11,6 +11,15 @@ AC_DEFUN([PDNS_WITH_NET_SNMP], [
     AS_IF([test "x$with_net_snmp" = "xyes" -o "x$with_net_snmp" = "xauto"], [
       AC_CHECK_PROG([NET_SNMP_CFLAGS], [net-snmp-config], [`net-snmp-config --cflags`])
       AC_CHECK_PROG([NET_SNMP_LIBS], [net-snmp-config], [`net-snmp-config --agent-libs`])
+      AC_CHECK_DECLS([snmp_select_info2], [ : ], [ : ],
+        [AC_INCLUDES_DEFAULT
+          #include <net-snmp/net-snmp-config.h>
+          #include <net-snmp/definitions.h>
+          #include <net-snmp/types.h>
+          #include <net-snmp/utilities.h>
+          #include <net-snmp/config_api.h>
+          #include <net-snmp/session_api.h>
+      ])
     ])
   ])
   AS_IF([test "x$with_net_snmp" = "xyes"], [
index 54543787a6dfad0c30a8602f1c8a7ab217239114..5e11404d1c6448946f338b28fee9593be6c6608e 100644 (file)
@@ -35,7 +35,6 @@
 #include "misc.hh"
 #include "syncres.hh"
 
-#include "namespaces.hh"
 #include "namespaces.hh"
 
 class DevPollFDMultiplexer : public FDMultiplexer
@@ -47,7 +46,7 @@ public:
     close(d_devpollfd);
   }
 
-  virtual int run(struct timeval* tv);
+  virtual int run(struct timeval* tv, int timeout=500);
 
   virtual void addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter);
   virtual void removeFD(callbackmap_t& cbmap, int fd);
@@ -113,7 +112,7 @@ void DevPollFDMultiplexer::removeFD(callbackmap_t& cbmap, int fd)
   }
 }
 
-int DevPollFDMultiplexer::run(struct timeval* now)
+int DevPollFDMultiplexer::run(struct timeval* now, int timeout)
 {
   if(d_inrun) {
     throw FDMultiplexerException("FDMultiplexer::run() is not reentrant!\n");
@@ -121,7 +120,7 @@ int DevPollFDMultiplexer::run(struct timeval* now)
   struct dvpoll dvp;
   dvp.dp_nfds = d_readCallbacks.size() + d_writeCallbacks.size();
   dvp.dp_fds = new pollfd[dvp.dp_nfds];
-  dvp.dp_timeout = 500;
+  dvp.dp_timeout = timeout;
   int ret=ioctl(d_devpollfd, DP_POLL, &dvp); 
   gettimeofday(now,0); // MANDATORY!
   
@@ -151,7 +150,7 @@ int DevPollFDMultiplexer::run(struct timeval* now)
   }
   delete[] dvp.dp_fds;
   d_inrun=false;
-  return 0;
+  return ret;
 }
 
 #if 0
index 5ae8da3154b4cd8e3f64af70cc246fd613d4ab1e..3193fc1a88d3f4fbf81743e449927d0fefe487d2 100644 (file)
@@ -47,7 +47,11 @@ EXTRA_DIST=dnslabeltext.rl \
           bpf-filter.main.ebpf \
           bpf-filter.qname.ebpf \
           bpf-filter.ebpf.src \
-          DNSDIST-MIB.txt
+          DNSDIST-MIB.txt \
+          devpollmplexer.cc \
+          epollmplexer.cc \
+          kqueuemplexer.cc \
+          portsmplexer.cc
 
 bin_PROGRAMS = dnsdist
 
@@ -93,15 +97,17 @@ dnsdist_SOURCES = \
        ednscookies.cc ednscookies.hh \
        ednssubnet.cc ednssubnet.hh \
        gettime.cc gettime.hh \
+       htmlfiles.h \
        iputils.cc iputils.hh \
        lock.hh \
        misc.cc misc.hh \
-       htmlfiles.h \
+       mplexer.hh \
        namespaces.hh \
        pdnsexception.hh \
        protobuf.cc protobuf.hh \
        qtype.cc qtype.hh \
        remote_logger.cc remote_logger.hh \
+       selectmplexer.cc \
        sholder.hh \
        snmp-agent.cc snmp-agent.hh \
        sodcrypto.cc sodcrypto.hh \
@@ -152,6 +158,20 @@ dnsdist.$(OBJEXT): dnsmessage.pb.cc
 endif
 endif
 
+if HAVE_FREEBSD
+dnsdist_SOURCES += kqueuemplexer.cc
+endif
+
+if HAVE_LINUX
+dnsdist_SOURCES += epollmplexer.cc
+endif
+
+if HAVE_SOLARIS
+dnsdist_SOURCES += \
+        devpollmplexer.cc \
+        portsmplexer.cc
+endif
+
 testrunner_SOURCES = \
        base64.hh \
        dns.hh \
diff --git a/pdns/dnsdistdist/devpollmplexer.cc b/pdns/dnsdistdist/devpollmplexer.cc
new file mode 120000 (symlink)
index 0000000..ab43785
--- /dev/null
@@ -0,0 +1 @@
+../devpollmplexer.cc
\ No newline at end of file
diff --git a/pdns/dnsdistdist/epollmplexer.cc b/pdns/dnsdistdist/epollmplexer.cc
new file mode 120000 (symlink)
index 0000000..b796a57
--- /dev/null
@@ -0,0 +1 @@
+../epollmplexer.cc
\ No newline at end of file
diff --git a/pdns/dnsdistdist/kqueuemplexer.cc b/pdns/dnsdistdist/kqueuemplexer.cc
new file mode 120000 (symlink)
index 0000000..0824bd9
--- /dev/null
@@ -0,0 +1 @@
+../kqueuemplexer.cc
\ No newline at end of file
diff --git a/pdns/dnsdistdist/mplexer.hh b/pdns/dnsdistdist/mplexer.hh
new file mode 120000 (symlink)
index 0000000..abb3c51
--- /dev/null
@@ -0,0 +1 @@
+../mplexer.hh
\ No newline at end of file
diff --git a/pdns/dnsdistdist/portsmplexer.cc b/pdns/dnsdistdist/portsmplexer.cc
new file mode 120000 (symlink)
index 0000000..d5e7107
--- /dev/null
@@ -0,0 +1 @@
+../portsmplexer.cc
\ No newline at end of file
diff --git a/pdns/dnsdistdist/selectmplexer.cc b/pdns/dnsdistdist/selectmplexer.cc
new file mode 120000 (symlink)
index 0000000..85b38bc
--- /dev/null
@@ -0,0 +1 @@
+../selectmplexer.cc
\ No newline at end of file
index 9ab4ebf48efd73b62dc41109d17a771e6392197d..2deae83b768af571f155bf210d2107dc235920c9 100644 (file)
@@ -31,7 +31,6 @@
 #include <sys/epoll.h>
 #endif
 
-#include "namespaces.hh"
 #include "namespaces.hh"
 
 class EpollFDMultiplexer : public FDMultiplexer
@@ -43,7 +42,7 @@ public:
     close(d_epollfd);
   }
 
-  virtual int run(struct timeval* tv);
+  virtual int run(struct timeval* tv, int timeout=500);
 
   virtual void addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter);
   virtual void removeFD(callbackmap_t& cbmap, int fd);
@@ -124,13 +123,13 @@ void EpollFDMultiplexer::removeFD(callbackmap_t& cbmap, int fd)
     throw FDMultiplexerException("Removing fd from epoll set: "+stringerror());
 }
 
-int EpollFDMultiplexer::run(struct timeval* now)
+int EpollFDMultiplexer::run(struct timeval* now, int timeout)
 {
   if(d_inrun) {
     throw FDMultiplexerException("FDMultiplexer::run() is not reentrant!\n");
   }
   
-  int ret=epoll_wait(d_epollfd, d_eevents.get(), s_maxevents, 500);
+  int ret=epoll_wait(d_epollfd, d_eevents.get(), s_maxevents, timeout);
   gettimeofday(now,0); // MANDATORY
   
   if(ret < 0 && errno!=EINTR)
@@ -154,7 +153,7 @@ int EpollFDMultiplexer::run(struct timeval* now)
     }
   }
   d_inrun=false;
-  return 0;
+  return ret;
 }
 
 #if 0
index e0eefc87657ba8649e939bb1bd343da1773bb452..b3510c501fe1880c86bf9594f8007ffc8c383669 100644 (file)
 #include <iostream>
 #include <unistd.h>
 #include "misc.hh"
-#include "syncres.hh"
 #include <sys/types.h>
 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
 #include <sys/event.h>
 #endif
 #include <sys/time.h>
 
-#include "namespaces.hh"
 #include "namespaces.hh"
 
 class KqueueFDMultiplexer : public FDMultiplexer
@@ -46,7 +44,7 @@ public:
     close(d_kqueuefd);
   }
 
-  virtual int run(struct timeval* tv);
+  virtual int run(struct timeval* tv, int timeout=500);
 
   virtual void addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const boost::any& parameter);
   virtual void removeFD(callbackmap_t& cbmap, int fd);
@@ -105,15 +103,15 @@ void KqueueFDMultiplexer::removeFD(callbackmap_t& cbmap, int fd)
     throw FDMultiplexerException("Removing fd from kqueue set: "+stringerror());
 }
 
-int KqueueFDMultiplexer::run(struct timeval* now)
+int KqueueFDMultiplexer::run(struct timeval* now, int timeout)
 {
   if(d_inrun) {
     throw FDMultiplexerException("FDMultiplexer::run() is not reentrant!\n");
   }
   
   struct timespec ts;
-  ts.tv_sec=0;
-  ts.tv_nsec=500000000U;
+  ts.tv_sec=timeout/1000;
+  ts.tv_nsec=(timeout % 1000) * 1000000;
 
   int ret=kevent(d_kqueuefd, 0, 0, d_kevents.get(), s_maxevents, &ts);
   gettimeofday(now,0); // MANDATORY!
@@ -141,7 +139,7 @@ int KqueueFDMultiplexer::run(struct timeval* now)
   }
 
   d_inrun=false;
-  return 0;
+  return ret;
 }
 
 #if 0
index 7ab348151bb6886bb82a7f2660c85a0913bc3923..3e9c8cd3eb7cc6dfd27ba3fcf3c1637a1d409f00 100644 (file)
@@ -30,7 +30,6 @@
 #include <map>
 #include <stdexcept>
 #include <string>
-#include "utility.hh"
 
 class FDMultiplexerException : public std::runtime_error
 {
@@ -50,7 +49,6 @@ public:
 class FDMultiplexer
 {
 public:
-  //  typedef boost::variant<PacketID, TCPConnection> funcparam_t;
   typedef boost::any funcparam_t;
 protected:
 
@@ -68,7 +66,9 @@ public:
   virtual ~FDMultiplexer()
   {}
 
-  virtual int run(struct timeval* tv) = 0;
+  /* tv will be updated to 'now' before run returns */
+  /* timeout is in ms */
+  virtual int run(struct timeval* tv, int timeout=500) = 0;
 
   //! Add an fd to the read watch list - currently an fd can only be on one list at a time!
   virtual void addReadFD(int fd, callbackfunc_t toDo, const funcparam_t& parameter=funcparam_t())
@@ -131,7 +131,6 @@ public:
   
   virtual std::string getName() = 0;
 
-
 protected:
   typedef std::map<int, Callback> callbackmap_t;
   callbackmap_t d_readCallbacks, d_writeCallbacks;
@@ -168,7 +167,7 @@ public:
   virtual ~SelectFDMultiplexer()
   {}
 
-  virtual int run(struct timeval* tv);
+  virtual int run(struct timeval* tv, int timeout=500);
 
   virtual void addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter);
   virtual void removeFD(callbackmap_t& cbmap, int fd);
index 08f126eb4e770e4b2a2ccd117d9490589156c534..5f1a6ffb8eaeffebcc0d31c5dcb5aea3a1cde6b4 100644 (file)
@@ -6,9 +6,6 @@
 #include <iostream>
 #include <poll.h>
 #include "misc.hh"
-#include "syncres.hh"
-#include "utility.hh" 
-#include "namespaces.hh"
 #include "namespaces.hh"
 
 
@@ -49,7 +46,7 @@ bool pollfdcomp(const struct pollfd& a, const struct pollfd& b)
   return a.fd < b.fd;
 }
 
-int PollFDMultiplexer::run(struct timeval* now)
+int PollFDMultiplexer::run(struct timeval* now, int timeout=500)
 {
   if(d_inrun) {
     throw FDMultiplexerException("FDMultiplexer::run() is not reentrant!\n");
@@ -70,15 +67,15 @@ int PollFDMultiplexer::run(struct timeval* now)
     pollfds.push_back(pollfd);
   }
 
-  int ret=poll(&pollfds[0], pollfds.size(), 500);
-  Utility::gettimeofday(now, 0); // MANDATORY!
+  int ret=poll(&pollfds[0], pollfds.size(), timeout);
+  gettimeofday(now, 0); // MANDATORY!
   
   if(ret < 0 && errno!=EINTR)
     throw FDMultiplexerException("poll returned error: "+stringerror());
 
   d_iter=d_readCallbacks.end();
   d_inrun=true;
-  
+
   for(unsigned int n = 0; n < pollfds.size(); ++n) {  
     if(pollfds[n].revents == POLLIN) {
       d_iter=d_readCallbacks.find(pollfds[n].fd);
@@ -97,7 +94,7 @@ int PollFDMultiplexer::run(struct timeval* now)
     }
   }
   d_inrun=false;
-  return 0;
+  return ret;
 }
 
 #if 0
index 58d05f7eeed4059ea01331cc6d9442d77c007000..c6e91e60fc25d71e7a55e11890c36e8a59706120 100644 (file)
@@ -11,9 +11,7 @@
 #include <iostream>
 
 #include "misc.hh"
-#include "syncres.hh"
 
-#include "namespaces.hh"
 #include "namespaces.hh"
 
 class PortsFDMultiplexer : public FDMultiplexer
@@ -25,7 +23,7 @@ public:
     close(d_portfd);
   }
 
-  virtual int run(struct timeval* tv);
+  virtual int run(struct timeval* tv, int timeout=500);
 
   virtual void addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const boost::any& parameter);
   virtual void removeFD(callbackmap_t& cbmap, int fd);
@@ -80,16 +78,17 @@ void PortsFDMultiplexer::removeFD(callbackmap_t& cbmap, int fd)
     throw FDMultiplexerException("Removing fd from port set: "+stringerror());
 }
 
-int PortsFDMultiplexer::run(struct timeval* now)
+int PortsFDMultiplexer::run(struct timeval* now, int timeout)
 {
   if(d_inrun) {
     throw FDMultiplexerException("FDMultiplexer::run() is not reentrant!\n");
   }
   
-  struct timespec timeout;
-  timeout.tv_sec=0; timeout.tv_nsec=500000000;
+  struct timespec timeoutspec;
+  timeoutspec.tv_sec = time / 1000;
+  timeoutspec.tv_nsec = (time % 1000) * 1000000;
   unsigned int numevents=1;
-  int ret= port_getn(d_portfd, d_pevents.get(), min(PORT_MAX_LIST, s_maxevents), &numevents, &timeout);
+  int ret= port_getn(d_portfd, d_pevents.get(), min(PORT_MAX_LIST, s_maxevents), &numevents, &timeoutspec);
   
   /* port_getn has an unusual API - (ret == -1, errno == ETIME) can
      mean partial success; you must check (*numevents) in this case
@@ -133,7 +132,7 @@ int PortsFDMultiplexer::run(struct timeval* now)
   }
 
   d_inrun=false;
-  return 0;
+  return numevents;
 }
 
 #if 0
index 857dec6570003fa1d2214057da3fb00db3636376..9e3d6f7c900a3a903942b5ed725cd11c888a11aa 100644 (file)
@@ -5,10 +5,7 @@
 #include "sstuff.hh"
 #include <iostream>
 #include "misc.hh"
-#include "utility.hh" 
 
-
-#include "namespaces.hh"
 #include "namespaces.hh"
 
 static FDMultiplexer* make()
@@ -43,7 +40,7 @@ void SelectFDMultiplexer::removeFD(callbackmap_t& cbmap, int fd)
     throw FDMultiplexerException("Tried to remove unlisted fd "+std::to_string(fd)+ " from multiplexer");
 }
 
-int SelectFDMultiplexer::run(struct timeval* now)
+int SelectFDMultiplexer::run(struct timeval* now, int timeout)
 {
   if(d_inrun) {
     throw FDMultiplexerException("FDMultiplexer::run() is not reentrant!\n");
@@ -64,9 +61,9 @@ int SelectFDMultiplexer::run(struct timeval* now)
     fdmax=max(i->first, fdmax);
   }
   
-  struct timeval tv={0,500000};
+  struct timeval tv={timeout / 1000 , (timeout % 1000) * 1000};
   int ret=select(fdmax + 1, &readfds, &writefds, 0, &tv);
-  Utility::gettimeofday(now, 0); // MANDATORY!
+  gettimeofday(now, 0); // MANDATORY!
   
   if(ret < 0 && errno!=EINTR)
     throw FDMultiplexerException("select returned error: "+stringerror());
@@ -76,12 +73,14 @@ int SelectFDMultiplexer::run(struct timeval* now)
 
   d_iter=d_readCallbacks.end();
   d_inrun=true;
-  
+
+  int got = 0;
   for(callbackmap_t::iterator i=d_readCallbacks.begin(); i != d_readCallbacks.end() && i->first <= fdmax; ) {
     d_iter=i++;
 
     if(FD_ISSET(d_iter->first, &readfds)) {
       d_iter->second.d_callback(d_iter->first, d_iter->second.d_parameter);
+      got++;
       continue;  // so we don't refind ourselves as writable
     }
   }
@@ -90,11 +89,12 @@ int SelectFDMultiplexer::run(struct timeval* now)
     d_iter=i++;
     if(FD_ISSET(d_iter->first, &writefds)) {
       d_iter->second.d_callback(d_iter->first, d_iter->second.d_parameter);
+      got++;
     }
   }
 
   d_inrun=false;
-  return 0;
+  return got;
 }
 
 #if 0
index ad76f1d87ad215d425645c47be2d82e4ef6b654e..eecb36ebf82e0b84fe0ad52c5049dac66de5a467 100644 (file)
@@ -3,6 +3,22 @@
 
 #ifdef HAVE_NET_SNMP
 
+#ifndef HAVE_SNMP_SELECT_INFO2
+/* that's terrible, because it means we are going to have trouble with large
+   FD numbers at some point.. */
+# define netsnmp_large_fd_set fd_set
+# define snmp_read2 snmp_read
+# define snmp_select_info2 snmp_select_info
+# define netsnmp_large_fd_set_init(...)
+# define netsnmp_large_fd_set_cleanup(...)
+# define NETSNMP_LARGE_FD_SET FD_SET
+# define NETSNMP_LARGE_FD_CLR FD_CLR
+# define NETSNMP_LARGE_FD_ZERO FD_ZERO
+# define NETSNMP_LARGE_FD_ISSET FD_ISSET
+#else
+# include <net-snmp/library/large_fd_set.h>
+#endif
+
 const oid SNMPAgent::snmpTrapOID[] = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 };
 const size_t SNMPAgent::snmpTrapOIDLen = OID_LENGTH(SNMPAgent::snmpTrapOID);
 
@@ -31,7 +47,7 @@ bool SNMPAgent::sendTrap(int fd,
   return true;
 }
 
-void SNMPAgent::handleTraps()
+void SNMPAgent::handleTrapsEvent()
 {
   netsnmp_variable_list* varList = nullptr;
   ssize_t got = 0;
@@ -46,44 +62,104 @@ void SNMPAgent::handleTraps()
   }
   while (got > 0);
 }
+
+void SNMPAgent::handleSNMPQueryEvent(int fd)
+{
+  netsnmp_large_fd_set fdset;
+  netsnmp_large_fd_set_init(&fdset, FD_SETSIZE);
+  NETSNMP_LARGE_FD_ZERO(&fdset);
+  NETSNMP_LARGE_FD_SET(fd, &fdset);
+  snmp_read2(&fdset);
+}
+
+void SNMPAgent::handleTrapsCB(int fd, FDMultiplexer::funcparam_t& var)
+{
+  SNMPAgent** agent = boost::any_cast<SNMPAgent*>(&var);
+  if (!agent || !*agent)
+    throw std::runtime_error("Invalid value received in SNMP trap callback");
+
+  (*agent)->handleTrapsEvent();
+}
+
+void SNMPAgent::handleSNMPQueryCB(int fd, FDMultiplexer::funcparam_t& var)
+{
+  SNMPAgent** agent = boost::any_cast<SNMPAgent*>(&var);
+  if (!agent || !*agent)
+    throw std::runtime_error("Invalid value received in SNMP trap callback");
+
+  (*agent)->handleSNMPQueryEvent(fd);
+}
+
+static FDMultiplexer* getMultiplexer()
+{
+  FDMultiplexer* ret = nullptr;
+  for(const auto& i : FDMultiplexer::getMultiplexerMap()) {
+    try {
+      ret = i.second();
+      return ret;
+    }
+    catch(const FDMultiplexerException& fe) {
+    }
+    catch(...) {
+    }
+  }
+  return ret;
+}
+
 #endif /* HAVE_NET_SNMP */
 
 void SNMPAgent::worker()
 {
 #ifdef HAVE_NET_SNMP
-  int numfds = 0;
+  FDMultiplexer* mplexer = getMultiplexer();
+  if (mplexer == nullptr) {
+    throw std::runtime_error("No FD multiplexer found for the SNMP agent!");
+  }
+
+  int maxfd = 0;
   int block = 1;
-  fd_set fdset;
+  netsnmp_large_fd_set fdset;
   struct timeval timeout = { 0, 0 };
+  struct timeval now;
+
+  /* we want to be notified if a trap is waiting
+   to be sent */
+  mplexer->addReadFD(d_trapPipe[0], &handleTrapsCB, this);
 
   while(true) {
-    numfds = FD_SETSIZE;
+    netsnmp_large_fd_set_init(&fdset, FD_SETSIZE);
+    NETSNMP_LARGE_FD_ZERO(&fdset);
 
-    FD_ZERO(&fdset);
-    FD_SET(d_trapPipe[0], &fdset);
     block = 1;
     timeout = { 0, 0 };
-    snmp_select_info(&numfds, &fdset, &timeout, &block);
+    snmp_select_info2(&maxfd, &fdset, &timeout, &block);
 
-    int res = select(FD_SETSIZE, &fdset, nullptr, nullptr, block ? nullptr : &timeout);
-
-    if (res == 2) {
-      FD_CLR(d_trapPipe[0], &fdset);
-      snmp_read(&fdset);
-      handleTraps();
-    }
-    else if (res == 1)
-    {
-      if (FD_ISSET(d_trapPipe[0], &fdset)) {
-        handleTraps();
-      } else {
-        snmp_read(&fdset);
+    for (int fd = 0; fd < maxfd; fd++) {
+      if (NETSNMP_LARGE_FD_ISSET(fd, &fdset)) {
+        mplexer->addReadFD(fd, &handleSNMPQueryCB, this);
       }
     }
-    else if (res == 0) {
+
+    /* run updates now */
+    int res = mplexer->run(&now, (timeout.tv_sec * 1000) + (timeout.tv_usec / 1000));
+
+    /* we handle timeouts here, the rest has already been handled by callbacks */
+    if (res == 0) {
       snmp_timeout();
       run_alarms();
     }
+
+    for (int fd = 0; fd < maxfd; fd++) {
+      if (NETSNMP_LARGE_FD_ISSET(fd, &fdset)) {
+        try {
+          mplexer->removeReadFD(fd);
+        }
+        catch(const FDMultiplexerException& e) {
+          /* we might get an exception when removing a closed file descriptor,
+             just ignore it */
+        }
+      }
+    }
   }
 #endif /* HAVE_NET_SNMP */
 }
index 4e2afe24662f977571ee0ca2c364f49e5eb08784..5d693bb6bc100a8500e7d9a60fda68ac750b3f7d 100644 (file)
@@ -17,6 +17,8 @@
 #undef INET6 /* SRSLY? */
 #endif /* HAVE_NET_SNMP */
 
+#include "mplexer.hh"
+
 class SNMPAgent
 {
 public:
@@ -49,12 +51,14 @@ protected:
   static bool sendTrap(int fd,
                        netsnmp_variable_list* varList);
 
-  void handleTraps();
-
   int d_trapPipe[2] = { -1, -1};
 #endif /* HAVE_NET_SNMP */
 private:
   void worker();
+  static void handleTrapsCB(int fd, FDMultiplexer::funcparam_t& var);
+  static void handleSNMPQueryCB(int fd, FDMultiplexer::funcparam_t& var);
+  void handleTrapsEvent();
+  void handleSNMPQueryEvent(int fd);
 
   std::thread d_thread;
 };