added new method rsGetHostByName to use gethostbyname_r for re-entrant calls. Updated dnsresolver and extaddrfinder to use it. Suggestion by GuessWho #125

This commit is contained in:
csoler 2015-10-07 21:24:31 -04:00
parent f1f722a767
commit e776effc0d
5 changed files with 90 additions and 39 deletions

View File

@ -62,25 +62,33 @@ void *solveDNSEntries(void *p)
if(!next_call.empty())
{
hostent *pHost = gethostbyname(next_call.c_str());
in_addr in ;
bool succeed = rsGetHostByName(next_call.c_str(),in);
{
RsStackMutex mut(dnsr->_rdnsMtx) ;
{
RsStackMutex mut(dnsr->_rdnsMtx) ;
DNSResolver::AddrInfo &info = (*dnsr->_addr_map)[next_call];
DNSResolver::AddrInfo &info = (*dnsr->_addr_map)[next_call];
if(pHost)
if(succeed)
{
info.state = DNSResolver::DNS_HAVE ;
// IPv4 for the moment.
struct sockaddr_in *addrv4p = (struct sockaddr_in *) &(info.addr);
addrv4p->sin_family = AF_INET;
addrv4p->sin_addr= in ;
addrv4p->sin_port = htons(0);
std::cerr << "LOOKUP succeeded: " << next_call.c_str() << " => " << rs_inet_ntoa(addrv4p->sin_addr) << std::endl;
}
else
{
info.state = DNSResolver::DNS_HAVE ;
// IPv4 for the moment.
struct sockaddr_in *addrv4p = (struct sockaddr_in *) &(info.addr);
addrv4p->sin_family = AF_INET;
addrv4p->sin_addr.s_addr = *(unsigned long*) (pHost->h_addr);
addrv4p->sin_port = htons(0);
}
else
info.state = DNSResolver::DNS_LOOKUP_ERROR ;
}
std::cerr << "DNSResolver: lookup error for address \"" << next_call.c_str() << "\"" << std::endl;
}
}
}
}

View File

@ -2,6 +2,7 @@
#include "pqi/pqinetwork.h"
#include "util/rsstring.h"
#include "util/rsmemory.h"
#ifndef WIN32
#include <netdb.h>
@ -58,7 +59,6 @@ static void getPage(const std::string& server_name,std::string& page)
int sockfd,n=0; // socket descriptor
struct sockaddr_in serveur; // server's parameters
memset(&serveur.sin_zero, 0, sizeof(serveur.sin_zero));
struct hostent *hostinfo=NULL; // structure for storing the server's ip
char buf[1024];
char request[1024];
@ -78,20 +78,21 @@ static void getPage(const std::string& server_name,std::string& page)
// get server's ipv4 adress
hostinfo = gethostbyname(server_name.c_str());
if (hostinfo == NULL) /* l'hôte n'existe pas */
in_addr in ;
if(!rsGetHostByName(server_name.c_str(),in)) /* l'hôte n'existe pas */
{
std::cerr << "ExtAddrFinder: Unknown host " << server_name << std::endl;
unix_close(sockfd);
return ;
}
serveur.sin_addr = *(struct in_addr*) hostinfo->h_addr;
serveur.sin_addr = in ;
serveur.sin_port = htons(80);
#ifdef EXTADDRSEARCH_DEBUG
printf("Connection attempt\n");
#endif
std::cerr << "ExtAddrFinder: resolved hostname " << server_name << " to " << rs_inet_ntoa(in) << std::endl;
if(unix_connect(sockfd,(struct sockaddr *)&serveur, sizeof(serveur)) == -1)
{

View File

@ -21,29 +21,37 @@
//
class RsTemporaryMemory
{
public:
RsTemporaryMemory(size_t s)
{
_mem = (unsigned char *)malloc(s) ;
}
public:
RsTemporaryMemory(size_t s)
{
_mem = (unsigned char *)malloc(s) ;
operator unsigned char *() { return _mem ; }
if(_mem)
_size = s ;
else
_size = 0 ;
}
~RsTemporaryMemory()
{
if(_mem != NULL)
{
free(_mem) ;
_mem = NULL ;
}
}
operator unsigned char *() { return _mem ; }
size_t size() const { return _size ; }
private:
unsigned char *_mem ;
~RsTemporaryMemory()
{
if(_mem != NULL)
{
free(_mem) ;
_mem = NULL ;
}
}
// make it noncopyable
RsTemporaryMemory& operator=(const RsTemporaryMemory&) { return *this ;}
RsTemporaryMemory(const RsTemporaryMemory&) {}
private:
unsigned char *_mem ;
size_t _size ;
// make it noncopyable
RsTemporaryMemory& operator=(const RsTemporaryMemory&) { return *this ;}
RsTemporaryMemory(const RsTemporaryMemory&) {}
};

View File

@ -26,6 +26,7 @@
#include "util/rsnet.h"
#include "util/rsthreads.h"
#include "util/rsstring.h"
#include "util/rsmemory.h"
#ifdef WINDOWS_SYS
#else
@ -72,6 +73,36 @@ void sockaddr_clear(struct sockaddr_in *addr)
addr->sin_family = AF_INET;
}
bool rsGetHostByName(const std::string& hostname, in_addr& returned_addr)
{
RsTemporaryMemory mem(8192) ;
if(!mem)
{
std::cerr << __PRETTY_FUNCTION__ << ": Cannot allocate memory!" << std::endl;
return false; // Do something.
}
int error = 0;
struct hostent pHost;
struct hostent *result;
if(gethostbyname_r(hostname.c_str(), &pHost, (char*)(unsigned char*)mem, mem.size(), &result, &error) != 0)
{
std::cerr << __PRETTY_FUNCTION__ << ": cannot call gethostname_r. Internal error reported. Check buffer size." << std::endl;
return false ;
}
if(!result)
{
std::cerr << __PRETTY_FUNCTION__ << ": gethostname_r returned null result." << std::endl;
return false ;
}
// Use contents of result.
returned_addr.s_addr = *(unsigned long*) (result->h_addr);
return true ;
}
bool isValidNet(const struct in_addr *addr)
{

View File

@ -70,6 +70,9 @@ bool isLoopbackNet(const struct in_addr *addr);
bool isPrivateNet(const struct in_addr *addr);
bool isExternalNet(const struct in_addr *addr);
// uses a re-entrant version of gethostbyname
bool rsGetHostByName(const std::string& hostname, in_addr& returned_addr) ;
std::ostream& operator<<(std::ostream& o,const struct sockaddr_in&) ;
/* thread-safe version of inet_ntoa */