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());
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);
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;
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;
}
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);
}
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