diff --git a/ChangeLog b/ChangeLog index 0a6ad965..260d1e5b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,11 @@ VERSION 0.8.1cvs ================ +2005-12-26 Vincent Richard + + * posixSocket.cpp: use getaddrinfo() if available. This should bring + thread-safe DNS resolution and IPv6 support. + 2005-12-18 Vincent Richard * IMAPParser.hpp: compatibility bugs + enhanced debugging trace. diff --git a/SConstruct b/SConstruct index 01e293d0..dd7847fb 100644 --- a/SConstruct +++ b/SConstruct @@ -827,6 +827,10 @@ if IsProtocolSupported(messaging_protocols, 'sendmail'): config_hpp.write(""" +// Additional defines +#define VMIME_HAVE_GETADDRINFO 1 + + #endif // VMIME_CONFIG_HPP_INCLUDED """) @@ -1661,10 +1665,17 @@ AC_PATH_PROG(SENDMAIL, sendmail, /usr/sbin/sendmail, /usr/sbin:/usr/lib) # Detect some platform-specific stuff # +# -- MLang (Windows) if test "x$VMIME_DETECT_PLATFORM" = "xwindows"; then AC_CHECK_HEADER(mlang.h, [VMIME_ADDITIONAL_DEFINES="$VMIME_ADDITIONAL_DEFINES HAVE_MLANG_H"]) fi +# -- getaddrinfo (POSIX) +if test "x$VMIME_DETECT_PLATFORM" = "xposix"; then + AC_CHECK_HEADERS(netdb.h sys/types.h sys/socket.h,) + AC_CHECK_FUNC(getaddrinfo, [VMIME_ADDITIONAL_DEFINES="$VMIME_ADDITIONAL_DEFINES HAVE_GETADDRINFO"]) +fi + """) diff --git a/src/platforms/posix/posixSocket.cpp b/src/platforms/posix/posixSocket.cpp index 5585492a..d514a1a6 100644 --- a/src/platforms/posix/posixSocket.cpp +++ b/src/platforms/posix/posixSocket.cpp @@ -67,6 +67,65 @@ void posixSocket::connect(const vmime::string& address, const vmime::port_t port m_desc = -1; } +#if VMIME_HAVE_GETADDRINFO // use thread-safe and IPv6-aware getaddrinfo() if available + + // Resolve address, if needed + struct ::addrinfo hints; + memset(&hints, 0, sizeof(hints)); + + hints.ai_flags = AI_CANONNAME; + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + std::ostringstream portStr; + portStr << port; + + struct ::addrinfo* res0; + + if (::getaddrinfo(address.c_str(), portStr.str().c_str(), &hints, &res0) != 0) + { + // Error: cannot resolve address + throw vmime::exceptions::connection_error("Cannot resolve address."); + } + + // Connect to host + int sock = -1; + struct ::addrinfo* res = res0; + + for ( ; sock == -1 && res != NULL ; res = res->ai_next) + { + sock = ::socket(res->ai_family, res->ai_socktype, res->ai_protocol); + + if (sock < 0) + continue; // try next + + if (::connect(sock, res->ai_addr, res->ai_addrlen) < 0) + { + ::close(sock); + sock = -1; + continue; // try next + } + } + + ::freeaddrinfo(res0); + + if (sock == -1) + { + try + { + throwSocketError(errno); + } + catch (exceptions::socket_exception& e) + { + throw vmime::exceptions::connection_error + ("Error while connecting socket.", e); + } + } + + m_desc = sock; + +#else // !VMIME_HAVE_GETADDRINFO + // Resolve address ::sockaddr_in addr; @@ -123,6 +182,8 @@ void posixSocket::connect(const vmime::string& address, const vmime::port_t port } } +#endif // VMIME_HAVE_GETADDRINFO + ::fcntl(m_desc, F_SETFL, ::fcntl(m_desc, F_GETFL) | O_NONBLOCK); }