]> git.ipfire.org Git - thirdparty/pdns.git/blobdiff - pdns/portsmplexer.cc
Merge pull request #7908 from omoerbeek/rec-4.1.14-changelog
[thirdparty/pdns.git] / pdns / portsmplexer.cc
index daa5c735074520ac6ef9a0a79175785a67fa5039..39939b2f4fbc437f491ed0a7561613a18f00e657 100644 (file)
@@ -1,18 +1,18 @@
-#include "mplexer.hh"
-#include "sstuff.hh"
-#include <iostream>
-#include <unistd.h>
-#include "misc.hh"
-#include <boost/lexical_cast.hpp>
-#include "syncres.hh"
-
 #if defined(__sun__) && defined(__svr4__)
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
 #include <port.h>
 #include <sys/port_impl.h>
 #endif
+#include <unistd.h>
+#include "mplexer.hh"
+#include "sstuff.hh"
+#include <iostream>
+
+#include "misc.hh"
 
-using namespace boost;
-using namespace std;
+#include "namespaces.hh"
 
 class PortsFDMultiplexer : public FDMultiplexer
 {
@@ -23,9 +23,9 @@ 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 addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const boost::any& parameter, const struct timeval* ttd=nullptr);
   virtual void removeFD(callbackmap_t& cbmap, int fd);
   string getName()
   {
@@ -59,9 +59,9 @@ PortsFDMultiplexer::PortsFDMultiplexer() : d_pevents(new port_event_t[s_maxevent
     throw FDMultiplexerException("Setting up port: "+stringerror());
 }
 
-void PortsFDMultiplexer::addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const boost::any& parameter)
+void PortsFDMultiplexer::addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const boost::any& parameter, const struct timeval* ttd)
 {
-  accountingAddFD(cbmap, fd, toDo, parameter);
+  accountingAddFD(cbmap, fd, toDo, parameter, ttd);
 
   if(port_associate(d_portfd, PORT_SOURCE_FD, fd, (&cbmap == &d_readCallbacks) ? POLLIN : POLLOUT, 0) < 0) {
     cbmap.erase(fd);
@@ -72,32 +72,38 @@ void PortsFDMultiplexer::addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo
 void PortsFDMultiplexer::removeFD(callbackmap_t& cbmap, int fd)
 {
   if(!cbmap.erase(fd))
-    throw FDMultiplexerException("Tried to remove unlisted fd "+lexical_cast<string>(fd)+ " from multiplexer");
+    throw FDMultiplexerException("Tried to remove unlisted fd "+std::to_string(fd)+ " from multiplexer");
 
-  if(port_dissociate(d_portfd, PORT_SOURCE_FD, fd) < 0)
+  if(port_dissociate(d_portfd, PORT_SOURCE_FD, fd) < 0 && errno != ENOENT) // it appears under some circumstances, ENOENT will be returned, without this being an error. Apache has this same "fix"
     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);
-
-  gettimeofday(now,0);
+  int ret= port_getn(d_portfd, d_pevents.get(), min(PORT_MAX_LIST, s_maxevents), &numevents, &timeoutspec);
   
-  if(ret < 0) {
-    if(errno!=EINTR && errno!=ETIME)
+  /* port_getn has an unusual API - (ret == -1, errno == ETIME) can
+     mean partial success; you must check (*numevents) in this case
+     and process anything in there, otherwise you'll never see any
+     events from that object again. We don't care about pure timeouts
+     (ret == -1, errno == ETIME, *numevents == 0) so we don't bother
+     with that case. */
+  if(ret == -1 && errno!=ETIME) {
+    if(errno!=EINTR)
       throw FDMultiplexerException("completion port_getn returned error: "+stringerror());
-    // EINTR and ETIME are not really errors
+    // EINTR is not really an error
+    gettimeofday(now,0);
     return 0;
   }
-
+  gettimeofday(now,0);
   if(!numevents) // nothing
     return 0;
 
@@ -107,25 +113,26 @@ int PortsFDMultiplexer::run(struct timeval* now)
     d_iter=d_readCallbacks.find(d_pevents[n].portev_object);
     
     if(d_iter != d_readCallbacks.end()) {
-      d_iter->second.d_callback(d_iter->first, d_iter->second.d_parameter);
+      d_iter->d_callback(d_iter->d_fd, d_iter->d_parameter);
       if(d_readCallbacks.count(d_pevents[n].portev_object) && port_associate(d_portfd, PORT_SOURCE_FD, d_pevents[n].portev_object, 
-                       POLLIN, 0) < 0)
-       throw FDMultiplexerException("Unable to add fd back to ports (read): "+stringerror());
+                        POLLIN, 0) < 0)
+        throw FDMultiplexerException("Unable to add fd back to ports (read): "+stringerror());
+      continue; // so we don't find ourselves as writable again
     }
 
     d_iter=d_writeCallbacks.find(d_pevents[n].portev_object);
     
     if(d_iter != d_writeCallbacks.end()) {
-      d_iter->second.d_callback(d_iter->first, d_iter->second.d_parameter);
+      d_iter->d_callback(d_iter->d_fd, d_iter->d_parameter);
       if(d_writeCallbacks.count(d_pevents[n].portev_object) && port_associate(d_portfd, PORT_SOURCE_FD, d_pevents[n].portev_object, 
-                       POLLOUT, 0) < 0)
-       throw FDMultiplexerException("Unable to add fd back to ports (write): "+stringerror());
+                        POLLOUT, 0) < 0)
+        throw FDMultiplexerException("Unable to add fd back to ports (write): "+stringerror());
     }
 
   }
 
   d_inrun=false;
-  return 0;
+  return numevents;
 }
 
 #if 0
@@ -142,7 +149,7 @@ void acceptData(int fd, boost::any& parameter)
 
 int main()
 {
-  Socket s(InterNetwork, Datagram);
+  Socket s(AF_INET, SOCK_DGRAM);
   
   IPEndpoint loc("0.0.0.0", 2000);
   s.bind(loc);