diff options
Diffstat (limited to 'src/platforms/posix/posixSocket.cpp')
| -rw-r--r-- | src/platforms/posix/posixSocket.cpp | 125 |
1 files changed, 118 insertions, 7 deletions
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 <vmime::net::timeoutHandler> 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 <vmime::net::socket> posixSocketFactory::create() { - return vmime::create <posixSocket>(); + ref <vmime::net::timeoutHandler> th = NULL; + return vmime::create <posixSocket>(th); +} + + +ref <vmime::net::socket> posixSocketFactory::create(ref <vmime::net::timeoutHandler> th) +{ + return vmime::create <posixSocket>(th); } |
