From: Remi Gacogne Date: Fri, 5 Aug 2016 13:06:10 +0000 (+0200) Subject: rec: Respect the timeout when connecting to a protobuf server X-Git-Tag: rec-4.0.2~6^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=51959320964300402ba13cd23398e60143ce9fc5;p=thirdparty%2Fpdns.git rec: Respect the timeout when connecting to a protobuf server --- diff --git a/pdns/iputils.cc b/pdns/iputils.cc index 1fe0872449..c470b843b5 100644 --- a/pdns/iputils.cc +++ b/pdns/iputils.cc @@ -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()); diff --git a/pdns/iputils.hh b/pdns/iputils.hh index 1cc3798ba5..3c42277c0a 100644 --- a/pdns/iputils.hh +++ b/pdns/iputils.hh @@ -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); diff --git a/pdns/misc.cc b/pdns/misc.cc index bca2bbd80e..cfd8428233 100644 --- a/pdns/misc.cc +++ b/pdns/misc.cc @@ -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; } diff --git a/pdns/misc.hh b/pdns/misc.hh index d14f3a9c4e..1bf4e32619 100644 --- a/pdns/misc.hh +++ b/pdns/misc.hh @@ -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); diff --git a/pdns/remote_logger.cc b/pdns/remote_logger.cc index 86835782c1..b1e18ed996 100644 --- a/pdns/remote_logger.cc +++ b/pdns/remote_logger.cc @@ -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