]> granicus.if.org Git - pdns/commitdiff
rec: Respect the timeout when connecting to a protobuf server
authorRemi Gacogne <remi.gacogne@powerdns.com>
Fri, 5 Aug 2016 13:06:10 +0000 (15:06 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Fri, 19 Aug 2016 15:29:43 +0000 (17:29 +0200)
pdns/iputils.cc
pdns/iputils.hh
pdns/misc.cc
pdns/misc.hh
pdns/remote_logger.cc

index 1fe0872449a30fea41a54b8cce1d031895e82afe..c470b843b55d8c0365d7cf680112ef606ebc1ded 100644 (file)
@@ -30,6 +30,47 @@ int SConnect(int sockfd, const ComboAddress& remote)
   return ret;
 }
 
+int SConnectWithTimeout(int sockfd, const ComboAddress& remote, int timeout)
+{
+  int ret = connect(sockfd, (struct sockaddr*)&remote, remote.getSocklen());
+  if(ret < 0) {
+    int savederrno = errno;
+    if (savederrno == EINPROGRESS) {
+      /* we wait until the connection has been established */
+      bool error = false;
+      bool disconnected = false;
+      int res = waitForRWData(sockfd, false, timeout, 0, &error, &disconnected);
+      if (res == 1) {
+        if (error) {
+          savederrno = 0;
+          socklen_t errlen = sizeof(savederrno);
+          if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&savederrno, &errlen) == 0) {
+            RuntimeError(boost::format("connecting to %s failed: %s") % remote.toStringWithPort() % string(strerror(savederrno)));
+          }
+          else {
+            RuntimeError(boost::format("connecting to %s failed") % remote.toStringWithPort());
+          }
+        }
+        if (disconnected) {
+          RuntimeError(boost::format("%s closed the connection") % remote.toStringWithPort());
+        }
+        return 0;
+      }
+      else if (res == 0) {
+        RuntimeError(boost::format("timeout while connecting to %s") % remote.toStringWithPort());
+      } else if (res < 0) {
+        savederrno = errno;
+        RuntimeError(boost::format("waiting to connect to %s: %s") % remote.toStringWithPort() % string(strerror(savederrno)));
+      }
+    }
+    else {
+      RuntimeError(boost::format("connecting to %s: %s") % remote.toStringWithPort() % string(strerror(savederrno)));
+    }
+  }
+
+  return ret;
+}
+
 int SBind(int sockfd, const ComboAddress& local)
 {
   int ret = bind(sockfd, (struct sockaddr*)&local, local.getSocklen());
index 1cc3798ba5db851bac765a584b4020a3e8c4c98e..3c42277c0a81dc5d93456215773f2d251ec78ce7 100644 (file)
@@ -863,6 +863,11 @@ struct SComboAddress
 
 int SSocket(int family, int type, int flags);
 int SConnect(int sockfd, const ComboAddress& remote);
+/* tries to connect to remote for a maximum of timeout seconds.
+   sockfd should be set to non-blocking beforehand.
+   returns 0 on success (the socket is writable), throw a
+   runtime_error otherwise */
+int SConnectWithTimeout(int sockfd, const ComboAddress& remote, int timeout);
 int SBind(int sockfd, const ComboAddress& local);
 int SAccept(int sockfd, ComboAddress& remote);
 int SListen(int sockfd, int limit);
index bca2bbd80eec94e9c26fcfb28cfea0df64f64a4f..cfd8428233753a8fce96d498a721d3b6d0c5e753 100644 (file)
@@ -303,7 +303,7 @@ int waitForData(int fd, int seconds, int useconds)
   return waitForRWData(fd, true, seconds, useconds);
 }
 
-int waitForRWData(int fd, bool waitForRead, int seconds, int useconds)
+int waitForRWData(int fd, bool waitForRead, int seconds, int useconds, bool* error, bool* disconnected)
 {
   int ret;
 
@@ -317,8 +317,17 @@ int waitForRWData(int fd, bool waitForRead, int seconds, int useconds)
     pfd.events=POLLOUT;
 
   ret = poll(&pfd, 1, seconds * 1000 + useconds/1000);
-  if ( ret == -1 )
+  if ( ret == -1 ) {
     errno = ETIMEDOUT; // ???
+  }
+  else if (ret > 0) {
+    if (error && (pfd.revents & POLLERR)) {
+      *error = true;
+    }
+    if (disconnected && (pfd.revents & POLLHUP)) {
+      *disconnected = true;
+    }
+  }
 
   return ret;
 }
index d14f3a9c4e102d39ae9be77f197b885685bc7b53..1bf4e32619fdd6095e397babe0c59eff725a46dc 100644 (file)
@@ -62,7 +62,7 @@ string getHostname();
 string urlEncode(const string &text);
 int waitForData(int fd, int seconds, int useconds=0);
 int waitFor2Data(int fd1, int fd2, int seconds, int useconds, int* fd);
-int waitForRWData(int fd, bool waitForRead, int seconds, int useconds);
+int waitForRWData(int fd, bool waitForRead, int seconds, int useconds, bool* error=nullptr, bool* disconnected=nullptr);
 uint16_t getShort(const unsigned char *p);
 uint16_t getShort(const char *p);
 uint32_t getLong(const unsigned char *p);
index 86835782c162d897d8c98721bc89e04fec754280..b1e18ed99616ae6033a66eea0e5d5689061a4141 100644 (file)
@@ -15,8 +15,8 @@ bool RemoteLogger::reconnect()
   }
   try {
     d_socket = SSocket(d_remote.sin4.sin_family, SOCK_STREAM, 0);
-    SConnect(d_socket, d_remote);
     setNonBlocking(d_socket);
+    SConnectWithTimeout(d_socket, d_remote, d_timeout);
   }
   catch(const std::exception& e) {
 #ifdef WE_ARE_RECURSOR