]> granicus.if.org Git - pdns/commitdiff
ixfrdist: safely exit, ensure sockets can be reused
authorPieter Lexis <pieter.lexis@powerdns.com>
Fri, 19 Jan 2018 12:00:44 +0000 (13:00 +0100)
committerPieter Lexis <pieter.lexis@powerdns.com>
Mon, 29 Jan 2018 08:20:14 +0000 (09:20 +0100)
pdns/ixfrdist.cc
pdns/misc.cc
pdns/misc.hh
pdns/sstuff.hh

index 83da30159fa6b2c8b66e10645611ad05d84d90de..824e68a47d96eb2bfc3024752b81f8ad19837ca2 100644 (file)
@@ -66,6 +66,12 @@ ComboAddress g_master;
 bool g_verbose = false;
 bool g_debug = false;
 
+bool g_exiting = false;
+
+void handleSignal(int signum) {
+  g_exiting = true;
+}
+
 void usage(po::options_description &desc) {
   cerr << "Usage: ixfrdist [OPTION]... DOMAIN [DOMAIN]..."<<endl;
   cerr << desc << "\n";
@@ -104,18 +110,22 @@ void* updateThread(void*) {
   }
 
   while (true) {
+    if (g_exiting) {
+      break;
+    }
     time_t now = time(nullptr);
     for (const auto &domain : g_domains) {
-      string dir = g_workdir + "/" + domain.toString();
-      if (now - lastCheck[domain] < 30) { // YOLO 30 seconds
+      if (now - lastCheck[domain] < g_soas[domain]->d_st.refresh) {
         continue;
       }
+      string dir = g_workdir + "/" + domain.toString();
       if (g_verbose) {
         cerr<<"[INFO] Attempting to retrieve SOA Serial update for '"<<domain<<"' from '"<<g_master.toStringWithPort()<<"'"<<endl;
       }
       shared_ptr<SOARecordContent> sr;
       try {
         auto newSerial = getSerialFromMaster(g_master, domain, sr); // TODO TSIG
+        lastCheck[domain] = now;
         if(g_soas.find(domain) != g_soas.end() && g_verbose) {
           cerr<<"[INFO] Got SOA Serial for "<<domain<<" from "<<g_master.toStringWithPort()<<": "<< newSerial<<", had Serial: "<<g_soas[domain]->d_st.serial;
           if (newSerial == g_soas[domain]->d_st.serial) {
@@ -171,13 +181,12 @@ void* updateThread(void*) {
       } catch (runtime_error &e) {
         cerr<<"[WARNING] Could not save zone '"<<domain<<"' to disk: "<<e.what()<<endl;
       }
-      lastCheck[domain] = now;
       {
         std::lock_guard<std::mutex> guard(g_soas_mutex);
         g_soas[domain] = soa;
       }
     } /* for (const auto &domain : domains) */
-    sleep(10);
+    sleep(1);
   } /* while (true) */
 } /* updateThread */
 
@@ -644,6 +653,7 @@ int main(int argc, char** argv) {
     }
   }
 
+  set<int> allSockets;
   for (const auto addr : listen_addresses) {
     // Create UDP socket
     int s = socket(addr.sin4.sin_family, SOCK_DGRAM, 0);
@@ -654,6 +664,7 @@ int main(int argc, char** argv) {
     }
 
     setNonBlocking(s);
+    setReuseAddr(s);
 
     if (bind(s, (sockaddr*) &addr, addr.getSocklen()) < 0) {
       cerr<<"[ERROR] Unable to bind to "<<addr.toStringWithPort()<<": "<<strerror(errno)<<endl;
@@ -673,6 +684,7 @@ int main(int argc, char** argv) {
     }
 
     setNonBlocking(t);
+    setReuseAddr(t);
 
     if (bind(t, (sockaddr*) &addr, addr.getSocklen()) < 0) {
       cerr<<"[ERROR] Unable to bind to "<<addr.toStringWithPort()<<": "<<strerror(errno)<<endl;
@@ -687,6 +699,7 @@ int main(int argc, char** argv) {
     }
 
     g_fdm.addReadFD(t, handleTCPRequest);
+    allSockets.insert(t);
   }
 
   g_workdir = g_vm["work-dir"].as<string>();
@@ -697,6 +710,10 @@ int main(int argc, char** argv) {
   }
 
   // It all starts here
+  signal(SIGTERM, handleSignal);
+  signal(SIGINT, handleSignal);
+  signal(SIGSTOP, handleSignal);
+
   // Init the things we need
   reportAllTypes();
 
@@ -713,5 +730,19 @@ int main(int argc, char** argv) {
   for(;;) {
     gettimeofday(&now, 0);
     g_fdm.run(&now);
+    if (g_exiting) {
+      cerr<<"Shutting down!"<<endl;
+      for (const int& fd : allSockets) {
+        try {
+          closesocket(fd);
+        } catch(PDNSException &e) {
+          cerr<<"[ERROR] "<<e.reason<<endl;
+        }
+      }
+      break;
+    }
   }
+  char* x;
+  pthread_join(qtid, (void**)&x);
+  return EXIT_SUCCESS;
 }
index 8dc5d4b360e3db1d1dca0a59c65c1ee24689cd19..80fecccd26c0e0a3597085f771b66fdf964bbf14 100644 (file)
@@ -1051,6 +1051,14 @@ bool setBlocking(int sock)
   return true;
 }
 
+bool setReuseAddr(int sock)
+{
+  int tmp = 1;
+  if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&tmp, static_cast<unsigned>(sizeof tmp))<0)
+    throw PDNSException(string("Setsockopt failed: ")+strerror(errno));
+  return true;
+}
+
 bool isNonBlocking(int sock)
 {
   int flags=fcntl(sock,F_GETFL,0);
index f9db931a7cf0ae1260eb8d6f03f18b6ca8a3b737..00056ff1c5e62c5b454b07cd362b9b17e6f3a321 100644 (file)
@@ -534,6 +534,7 @@ bool setBlocking( int sock );
 //! Sets the socket into non-blocking mode.
 bool setNonBlocking( int sock );
 bool setTCPNoDelay(int sock);
+bool setReuseAddr(int sock);
 bool isNonBlocking(int sock);
 int closesocket(int fd);
 bool setCloseOnExec(int sock);
index 707b1ad12b2b23da3ebe03a482e4dab49ff8de1c..0eec38487e91bd993b3497e84dfe43a635e24a55 100644 (file)
@@ -133,9 +133,11 @@ public:
 
   void setReuseAddr()
   {
-    int tmp = 1;
-    if (setsockopt(d_socket, SOL_SOCKET, SO_REUSEADDR, (char*)&tmp, static_cast<unsigned>(sizeof tmp))<0)
-      throw NetworkError(string("Setsockopt failed: ")+strerror(errno));
+    try {
+      ::setReuseAddr(d_socket);
+    } catch (PDNSException &e) {
+      throw NetworkError(e.reason);
+    }
   }
 
   //! Bind the socket to a specified endpoint