From d6a8b099ede9aec517c8206070c741269bbf2328 Mon Sep 17 00:00:00 2001 From: Vincent Richard Date: Thu, 5 Aug 2010 10:30:22 +0000 Subject: [PATCH] Connection time out. --- src/net/imap/IMAPConnection.cpp | 2 +- src/net/pop3/POP3Store.cpp | 2 +- src/net/smtp/SMTPTransport.cpp | 2 +- src/platforms/posix/posixSocket.cpp | 125 ++++++++++++++++++++++++-- tests/testUtils.hpp | 5 ++ vmime/net/socket.hpp | 13 +++ vmime/platforms/posix/posixSocket.hpp | 5 +- 7 files changed, 143 insertions(+), 11 deletions(-) diff --git a/src/net/imap/IMAPConnection.cpp b/src/net/imap/IMAPConnection.cpp index 825a002b..e2b60ed9 100644 --- a/src/net/imap/IMAPConnection.cpp +++ b/src/net/imap/IMAPConnection.cpp @@ -99,7 +99,7 @@ void IMAPConnection::connect() m_timeoutHandler = store->getTimeoutHandlerFactory()->create(); // Create and connect the socket - m_socket = store->getSocketFactory()->create(); + m_socket = store->getSocketFactory()->create(m_timeoutHandler); #if VMIME_HAVE_TLS_SUPPORT if (store->isIMAPS()) // dedicated port/IMAPS diff --git a/src/net/pop3/POP3Store.cpp b/src/net/pop3/POP3Store.cpp index e5e8ba75..9d554c6d 100644 --- a/src/net/pop3/POP3Store.cpp +++ b/src/net/pop3/POP3Store.cpp @@ -138,7 +138,7 @@ void POP3Store::connect() m_timeoutHandler = getTimeoutHandlerFactory()->create(); // Create and connect the socket - m_socket = getSocketFactory()->create(); + m_socket = getSocketFactory()->create(m_timeoutHandler); #if VMIME_HAVE_TLS_SUPPORT if (m_isPOP3S) // dedicated port/POP3S diff --git a/src/net/smtp/SMTPTransport.cpp b/src/net/smtp/SMTPTransport.cpp index 917a56c8..71f166bc 100644 --- a/src/net/smtp/SMTPTransport.cpp +++ b/src/net/smtp/SMTPTransport.cpp @@ -100,7 +100,7 @@ void SMTPTransport::connect() m_timeoutHandler = getTimeoutHandlerFactory()->create(); // Create and connect the socket - m_socket = getSocketFactory()->create(); + m_socket = getSocketFactory()->create(m_timeoutHandler); #if VMIME_HAVE_TLS_SUPPORT if (m_isSMTPS) // dedicated port/SMTPS diff --git a/src/platforms/posix/posixSocket.cpp b/src/platforms/posix/posixSocket.cpp index 807ec47c..b8bb8b18 100644 --- a/src/platforms/posix/posixSocket.cpp +++ b/src/platforms/posix/posixSocket.cpp @@ -49,8 +49,8 @@ namespace posix { // posixSocket // -posixSocket::posixSocket() - : m_desc(-1) +posixSocket::posixSocket(ref th) + : m_timeoutHandler(th), m_desc(-1) { } @@ -105,11 +105,115 @@ void posixSocket::connect(const vmime::string& address, const vmime::port_t port if (sock < 0) continue; // try next - if (::connect(sock, res->ai_addr, res->ai_addrlen) < 0) + if (m_timeoutHandler != NULL) { - ::close(sock); - sock = -1; - continue; // try next + ::fcntl(sock, F_SETFL, ::fcntl(sock, F_GETFL) | O_NONBLOCK); + + if (::connect(sock, res->ai_addr, res->ai_addrlen) < 0) + { + switch (errno) + { + case 0: + case EINPROGRESS: + case EINTR: +#if defined(EAGAIN) + case EAGAIN: +#endif // EAGAIN +#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) + case EWOULDBLOCK: +#endif // EWOULDBLOCK + + // Connection in progress + break; + + default: + + ::close(sock); + sock = -1; + continue; // try next + } + + // Wait for socket to be connected. + // We will check for time out every second. + fd_set fds; + FD_ZERO(&fds); + FD_SET(sock, &fds); + + fd_set fdsError; + FD_ZERO(&fdsError); + FD_SET(sock, &fdsError); + + struct timeval tm; + tm.tv_sec = 1; + tm.tv_usec = 0; + + m_timeoutHandler->resetTimeOut(); + + bool connected = false; + + do + { + const int ret = select(sock + 1, NULL, &fds, &fdsError, &tm); + + // Success + if (ret > 0) + { + connected = true; + break; + } + // Error + else if (ret < -1) + { + if (errno != EINTR) + { + // Cancel connection + break; + } + } + // 1-second timeout + else if (ret == 0) + { + if (m_timeoutHandler->isTimeOut()) + { + if (!m_timeoutHandler->handleTimeOut()) + { + // Cancel connection + break; + } + else + { + // Reset timeout and keep waiting for connection + m_timeoutHandler->resetTimeOut(); + } + } + else + { + // Keep waiting for connection + } + } + + ::sched_yield(); + + } while (true); + + if (!connected) + { + ::close(sock); + sock = -1; + continue; // try next + } + + break; + } + } + else + { + if (::connect(sock, res->ai_addr, res->ai_addrlen) < 0) + { + ::close(sock); + sock = -1; + continue; // try next + } } } @@ -325,7 +429,14 @@ void posixSocket::throwSocketError(const int err) ref posixSocketFactory::create() { - return vmime::create (); + ref th = NULL; + return vmime::create (th); +} + + +ref posixSocketFactory::create(ref th) +{ + return vmime::create (th); } diff --git a/tests/testUtils.hpp b/tests/testUtils.hpp index 9aee153c..aee50dc7 100644 --- a/tests/testUtils.hpp +++ b/tests/testUtils.hpp @@ -260,6 +260,11 @@ public: { return vmime::create (); } + + vmime::ref create(vmime::ref /* th */) + { + return vmime::create (); + } }; diff --git a/vmime/net/socket.hpp b/vmime/net/socket.hpp index ec6a9d37..b3946494 100644 --- a/vmime/net/socket.hpp +++ b/vmime/net/socket.hpp @@ -27,6 +27,8 @@ #include "vmime/base.hpp" +#include "vmime/net/timeoutHandler.hpp" + namespace vmime { namespace net { @@ -117,7 +119,18 @@ public: virtual ~socketFactory() { } + /** Creates a socket without timeout handler. + * + * @return a new socket + */ virtual ref create() = 0; + + /** Creates a socket with the specified timeout handler. + * + * @param th timeout handler + * @return a new socket + */ + virtual ref create(ref th) = 0; }; diff --git a/vmime/platforms/posix/posixSocket.hpp b/vmime/platforms/posix/posixSocket.hpp index 9cd49d4a..7e0c2d39 100644 --- a/vmime/platforms/posix/posixSocket.hpp +++ b/vmime/platforms/posix/posixSocket.hpp @@ -40,7 +40,7 @@ class posixSocket : public vmime::net::socket { public: - posixSocket(); + posixSocket(ref th); ~posixSocket(); void connect(const vmime::string& address, const vmime::port_t port); @@ -61,6 +61,8 @@ protected: private: + ref m_timeoutHandler; + char m_buffer[65536]; int m_desc; }; @@ -72,6 +74,7 @@ class posixSocketFactory : public vmime::net::socketFactory public: ref create(); + ref create(ref th); };