Fixed issue #23. Avoid additional queries if gethostname() is already a FQDN. Use getaddrinfo() instead of gethostbyname() for IPv6 compatibility.

This commit is contained in:
Vincent Richard 2013-02-10 20:59:14 +01:00
parent 3829cc2f86
commit 4457dec512
2 changed files with 74 additions and 56 deletions

View File

@ -31,6 +31,8 @@
#include "vmime/platforms/posix/posixCriticalSection.hpp"
#include "vmime/utility/stringUtils.hpp"
#include <time.h>
#include <fcntl.h>
#include <unistd.h>
@ -174,47 +176,55 @@ const vmime::charset posixHandler::getLocaleCharset() const
}
static inline bool isFQDN(const vmime::string& str)
{
if (utility::stringUtils::isStringEqualNoCase(str, "localhost", 9))
return false;
const vmime::string::size_type p = str.find_first_of(".");
return p != vmime::string::npos && p > 0 && p != str.length() - 1;
}
const vmime::string posixHandler::getHostName() const
{
std::vector <vmime::string> hostnames;
char buffer[256];
char hostname[256];
// Try with 'gethostname'
::gethostname(buffer, sizeof(buffer));
buffer[sizeof(buffer) - 1] = '\0';
::gethostname(hostname, sizeof(hostname));
hostname[sizeof(hostname) - 1] = '\0';
if (::strlen(buffer) == 0)
::strcpy(buffer, "localhost");
// If this is a Fully-Qualified Domain Name (FQDN), return immediately
if (isFQDN(hostname))
return hostname;
hostnames.push_back(buffer);
if (::strlen(hostname) == 0)
::strcpy(hostname, "localhost");
// And with 'gethostbyname'
struct hostent* he = ::gethostbyname(buffer);
// Try to get canonical name for the hostname
struct addrinfo hints;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; // either IPV4 or IPV6
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_CANONNAME;
if (he != NULL)
struct addrinfo* info;
if (getaddrinfo(hostname, "http", &hints, &info) == 0)
{
if (::strlen(he->h_name) != 0)
hostnames.push_back(he->h_name);
char** alias = he->h_aliases;
while (alias && *alias)
for (struct addrinfo* p = info ; p != NULL ; p = p->ai_next)
{
if (::strlen(*alias) != 0)
hostnames.push_back(*alias);
++alias;
if (isFQDN(p->ai_canonname))
{
freeaddrinfo(info);
return p->ai_canonname;
}
}
freeaddrinfo(info);
}
// Find a Fully-Qualified Domain Name (FQDN)
for (unsigned int i = 0 ; i < hostnames.size() ; ++i)
{
if (hostnames[i].find_first_of(".") != vmime::string::npos)
return (hostnames[i]);
}
return (hostnames[0]);
return hostname;
}

View File

@ -198,47 +198,55 @@ const vmime::charset windowsHandler::getLocaleCharset() const
}
static inline bool isFQDN(const vmime::string& str)
{
if (utility::stringUtils::isStringEqualNoCase(str, "localhost", 9))
return false;
const vmime::string::size_type p = str.find_first_of(".");
return p != vmime::string::npos && p > 0 && p != str.length() - 1;
}
const vmime::string windowsHandler::getHostName() const
{
std::vector <vmime::string> hostnames;
char buffer[256];
char hostname[256];
// Try with 'gethostname'
::gethostname(buffer, sizeof(buffer));
buffer[sizeof(buffer) - 1] = '\0';
::gethostname(hostname, sizeof(hostname));
hostname[sizeof(hostname) - 1] = '\0';
if (::strlen(buffer) == 0)
::strcpy(buffer, "localhost");
// If this is a Fully-Qualified Domain Name (FQDN), return immediately
if (isFQDN(hostname))
return hostname;
hostnames.push_back(buffer);
if (::strlen(hostname) == 0)
::strcpy(hostname, "localhost");
// And with 'gethostbyname'
struct hostent* he = ::gethostbyname(buffer);
// Try to get canonical name for the hostname
struct addrinfo hints;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; // either IPV4 or IPV6
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_CANONNAME;
if (he != NULL)
struct addrinfo* info;
if (getaddrinfo(hostname, "http", &hints, &info) == 0)
{
if (::strlen(he->h_name) != 0)
hostnames.push_back(he->h_name);
char** alias = he->h_aliases;
while (alias && *alias)
for (struct addrinfo* p = info ; p != NULL ; p = p->ai_next)
{
if (::strlen(*alias) != 0)
hostnames.push_back(*alias);
++alias;
if (isFQDN(p->ai_canonname))
{
freeaddrinfo(info);
return p->ai_canonname;
}
}
freeaddrinfo(info);
}
// Find a Fully-Qualified Domain Name (FQDN)
for (unsigned int i = 0 ; i < hostnames.size() ; ++i)
{
if (hostnames[i].find_first_of(".") != vmime::string::npos)
return (hostnames[i]);
}
return (hostnames[0]);
return hostname;
}