mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-07-30 01:38:51 -04:00
made the DNS calls in a separate thread, using new DNSResolver class. Added test program for that class as well. Moved extaddrfinder to util/
git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@3980 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
parent
dddc9c383c
commit
40f4009ca7
10 changed files with 328 additions and 53 deletions
159
libretroshare/src/util/dnsresolver.cc
Normal file
159
libretroshare/src/util/dnsresolver.cc
Normal file
|
@ -0,0 +1,159 @@
|
|||
#include "dnsresolver.h"
|
||||
|
||||
#include "pqi/pqinetwork.h"
|
||||
|
||||
#ifndef WIN32
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <stdio.h>
|
||||
|
||||
const time_t MAX_TIME_BEFORE_RETRY = 300 ; /* seconds before retrying an ip address */
|
||||
const time_t MAX_KEEP_DNS_ENTRY = 3600 ; /* seconds during which a DNS entry is considered valid */
|
||||
|
||||
static const std::string ADDR_AGENT = "Mozilla/5.0";
|
||||
|
||||
void *solveDNSEntries(void *p)
|
||||
{
|
||||
bool more_to_go = true ;
|
||||
DNSResolver *dnsr = (DNSResolver*)p ;
|
||||
|
||||
while(more_to_go)
|
||||
{
|
||||
// get an address request
|
||||
time_t now = time(NULL) ;
|
||||
|
||||
std::string next_call = "" ;
|
||||
|
||||
{
|
||||
RsStackMutex mut(dnsr->_rdnsMtx) ;
|
||||
|
||||
if(dnsr->_addr_map != NULL)
|
||||
for(std::map<std::string, DNSResolver::AddrInfo>::iterator it(dnsr->_addr_map->begin());it!=dnsr->_addr_map->end() && next_call.empty();++it)
|
||||
{
|
||||
switch(it->second.state)
|
||||
{
|
||||
case DNSResolver::DNS_SEARCHING:
|
||||
case DNSResolver::DNS_HAVE: break ;
|
||||
|
||||
case DNSResolver::DNS_LOOKUP_ERROR: if(it->second.last_lookup_time + MAX_TIME_BEFORE_RETRY > now)
|
||||
continue ;
|
||||
|
||||
case DNSResolver::DNS_DONT_HAVE: next_call = it->first ;
|
||||
it->second.state = DNSResolver::DNS_SEARCHING ;
|
||||
it->second.last_lookup_time = now ;
|
||||
more_to_go = true ;
|
||||
break ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!next_call.empty())
|
||||
{
|
||||
hostent *pHost = gethostbyname(next_call.c_str());
|
||||
|
||||
if(pHost)
|
||||
{
|
||||
RsStackMutex mut(dnsr->_rdnsMtx) ;
|
||||
|
||||
(*dnsr->_addr_map)[next_call].state = DNSResolver::DNS_HAVE ;
|
||||
(*dnsr->_addr_map)[next_call].addr.s_addr = *(unsigned long*) (pHost->h_addr);
|
||||
}
|
||||
else
|
||||
(*dnsr->_addr_map)[next_call].state = DNSResolver::DNS_LOOKUP_ERROR ;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
RsStackMutex mut(dnsr->_rdnsMtx) ;
|
||||
dnsr->_thread_running = false ;
|
||||
}
|
||||
return NULL ;
|
||||
}
|
||||
|
||||
void DNSResolver::start_request()
|
||||
{
|
||||
{
|
||||
RsStackMutex mut(_rdnsMtx) ;
|
||||
*_thread_running = true ;
|
||||
}
|
||||
|
||||
void *data = (void *)this;
|
||||
pthread_t tid ;
|
||||
pthread_create(&tid, 0, &solveDNSEntries, data);
|
||||
pthread_detach(tid); /* so memory is reclaimed in linux */
|
||||
}
|
||||
|
||||
void DNSResolver::reset()
|
||||
{
|
||||
RsStackMutex mut(_rdnsMtx) ;
|
||||
|
||||
*_thread_running = false ;
|
||||
_addr_map->clear();
|
||||
}
|
||||
|
||||
bool DNSResolver::getIPAddressFromString(const std::string& server_name,struct in_addr& addr)
|
||||
{
|
||||
addr.s_addr = 0 ;
|
||||
bool running = false;
|
||||
{
|
||||
RsStackMutex mut(_rdnsMtx) ;
|
||||
|
||||
std::map<std::string, AddrInfo>::iterator it(_addr_map->find(server_name)) ;
|
||||
time_t now = time(NULL) ;
|
||||
AddrInfo *addr_info ;
|
||||
|
||||
if(it != _addr_map->end())
|
||||
{
|
||||
// check that the address record is not too old
|
||||
|
||||
if(it->second.last_lookup_time + MAX_KEEP_DNS_ENTRY > now && it->second.state == DNSResolver::DNS_HAVE)
|
||||
{
|
||||
addr = it->second.addr ;
|
||||
return true ;
|
||||
}
|
||||
else
|
||||
addr_info = &it->second ;
|
||||
}
|
||||
else
|
||||
addr_info = &(*_addr_map)[server_name] ;
|
||||
|
||||
// We don't have it. Let's push it into the names to lookup for, except if we're already into it.
|
||||
|
||||
if(addr_info->state != DNSResolver::DNS_SEARCHING)
|
||||
addr_info->state = DNSResolver::DNS_DONT_HAVE ;
|
||||
|
||||
running = *_thread_running ;
|
||||
}
|
||||
|
||||
if(!running)
|
||||
start_request();
|
||||
|
||||
return false ;
|
||||
}
|
||||
|
||||
DNSResolver::~DNSResolver()
|
||||
{
|
||||
RsStackMutex mut(_rdnsMtx) ;
|
||||
|
||||
delete _addr_map ;
|
||||
_addr_map = NULL ;
|
||||
delete _thread_running ;
|
||||
}
|
||||
|
||||
DNSResolver::DNSResolver()
|
||||
{
|
||||
RsStackMutex mut(_rdnsMtx) ;
|
||||
|
||||
_addr_map = new std::map<std::string, AddrInfo>() ;
|
||||
_thread_running = new bool ;
|
||||
*_thread_running = false ;
|
||||
}
|
||||
|
40
libretroshare/src/util/dnsresolver.h
Normal file
40
libretroshare/src/util/dnsresolver.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
#pragma once
|
||||
|
||||
#include "pqi/pqinetwork.h"
|
||||
|
||||
#ifndef WIN32
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include "util/rsthreads.h"
|
||||
|
||||
struct sockaddr ;
|
||||
|
||||
class DNSResolver
|
||||
{
|
||||
public:
|
||||
DNSResolver() ;
|
||||
~DNSResolver() ;
|
||||
|
||||
bool getIPAddressFromString(const std::string& server_name,struct in_addr& addr) ;
|
||||
|
||||
void start_request() ;
|
||||
void reset() ;
|
||||
|
||||
private:
|
||||
enum { DNS_DONT_HAVE,DNS_SEARCHING, DNS_HAVE, DNS_LOOKUP_ERROR } ;
|
||||
|
||||
struct AddrInfo
|
||||
{
|
||||
uint32_t state ; // state: Looked-up, not found, have
|
||||
time_t last_lookup_time ; // last lookup time
|
||||
struct in_addr addr ;
|
||||
};
|
||||
friend void *solveDNSEntries(void *p) ;
|
||||
|
||||
RsMutex _rdnsMtx ;
|
||||
bool *_thread_running ;
|
||||
std::map<std::string, AddrInfo> *_addr_map ;
|
||||
};
|
297
libretroshare/src/util/extaddrfinder.cc
Normal file
297
libretroshare/src/util/extaddrfinder.cc
Normal file
|
@ -0,0 +1,297 @@
|
|||
#include "extaddrfinder.h"
|
||||
|
||||
#include "pqi/pqinetwork.h"
|
||||
|
||||
#ifndef WIN32
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <stdio.h>
|
||||
|
||||
const uint32_t MAX_IP_STORE = 300; /* seconds ip address timeout */
|
||||
|
||||
static const std::string ADDR_AGENT = "Mozilla/5.0";
|
||||
|
||||
static std::string scan_ip(const std::string& text)
|
||||
{
|
||||
std::set<unsigned char> digits ;
|
||||
digits.insert('0') ; digits.insert('3') ; digits.insert('6') ;
|
||||
digits.insert('1') ; digits.insert('4') ; digits.insert('7') ;
|
||||
digits.insert('2') ; digits.insert('5') ; digits.insert('8') ;
|
||||
digits.insert('9') ;
|
||||
|
||||
for(int i=0;i<(int)text.size();++i)
|
||||
{
|
||||
while(i < (int)text.size() && digits.find(text[i])==digits.end()) ++i ;
|
||||
|
||||
if(i>=(int)text.size())
|
||||
return "" ;
|
||||
|
||||
unsigned int a,b,c,d ;
|
||||
|
||||
if(sscanf(text.c_str()+i,"%u.%u.%u.%u",&a,&b,&c,&d) != 4)
|
||||
continue ;
|
||||
|
||||
if(a < 256 && b<256 && c<256 && d<256)
|
||||
{
|
||||
std::ostringstream o ;
|
||||
o << a << "." << b << "." << c << "." << d ;
|
||||
return o.str();
|
||||
}
|
||||
}
|
||||
return "" ;
|
||||
}
|
||||
|
||||
static void getPage(const std::string& server_name,std::string& page)
|
||||
{
|
||||
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];
|
||||
#ifdef EXTADDRSEARCH_DEBUG
|
||||
std::cout << "ExtAddrFinder: connecting to " << server_name << std::endl ;
|
||||
#endif
|
||||
// socket creation
|
||||
|
||||
sockfd = unix_socket(PF_INET,SOCK_STREAM,0);
|
||||
|
||||
serveur.sin_family = AF_INET;
|
||||
|
||||
// get server's ipv4 adress
|
||||
|
||||
hostinfo = gethostbyname(server_name.c_str());
|
||||
|
||||
if (hostinfo == NULL) /* l'hôte n'existe pas */
|
||||
{
|
||||
std::cerr << "ExtAddrFinder: Unknown host " << server_name << std::endl;
|
||||
return ;
|
||||
}
|
||||
serveur.sin_addr = *(struct in_addr*) hostinfo->h_addr;
|
||||
serveur.sin_port = htons(80);
|
||||
|
||||
#ifdef EXTADDRSEARCH_DEBUG
|
||||
printf("Connexion attempt\n");
|
||||
#endif
|
||||
|
||||
if(unix_connect(sockfd,(struct sockaddr *)&serveur, sizeof(serveur)) == -1)
|
||||
{
|
||||
std::cerr << "ExtAddrFinder: Connexion error to " << server_name << std::endl ;
|
||||
return ;
|
||||
}
|
||||
#ifdef EXTADDRSEARCH_DEBUG
|
||||
std::cerr << "ExtAddrFinder: Connexion established to " << server_name << std::endl ;
|
||||
#endif
|
||||
|
||||
// envoi
|
||||
sprintf( request,
|
||||
"GET / HTTP/1.0\r\n"
|
||||
"Host: %s:%d\r\n"
|
||||
"Connection: Close\r\n"
|
||||
"\r\n",
|
||||
server_name.c_str(), 80);
|
||||
|
||||
if(send(sockfd,request,strlen(request),0)== -1)
|
||||
{
|
||||
std::cerr << "ExtAddrFinder: Could not send request to " << server_name << std::endl ;
|
||||
return ;
|
||||
}
|
||||
// recéption
|
||||
|
||||
while((n = recv(sockfd, buf, sizeof buf - 1, 0)) > 0)
|
||||
{
|
||||
buf[n] = '\0';
|
||||
page += std::string(buf,n) ;
|
||||
}
|
||||
// fermeture de la socket
|
||||
|
||||
unix_close(sockfd);
|
||||
#ifdef EXTADDRSEARCH_DEBUG
|
||||
std::cerr << "ExtAddrFinder: Got full page from " << server_name << std::endl ;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void* doExtAddrSearch(void *p)
|
||||
{
|
||||
|
||||
std::vector<std::string> res ;
|
||||
|
||||
ExtAddrFinder *af = (ExtAddrFinder*)p ;
|
||||
|
||||
for(std::list<std::string>::const_iterator it(af->_ip_servers.begin());it!=af->_ip_servers.end();++it)
|
||||
{
|
||||
std::string page ;
|
||||
|
||||
getPage(*it,page) ;
|
||||
std::string ip = scan_ip(page) ;
|
||||
|
||||
if(ip != "")
|
||||
res.push_back(ip) ;
|
||||
#ifdef EXTADDRSEARCH_DEBUG
|
||||
std::cout << "ip found through " << *it << ": \"" << ip << "\"" << std::endl ;
|
||||
#endif
|
||||
}
|
||||
|
||||
if(res.empty())
|
||||
{
|
||||
// thread safe copy results.
|
||||
//
|
||||
{
|
||||
RsStackMutex mtx(af->_addrMtx) ;
|
||||
|
||||
*(af->_found) = false ;
|
||||
*(af->mFoundTS) = time(NULL) ;
|
||||
*(af->_searching) = false ;
|
||||
}
|
||||
pthread_exit(NULL);
|
||||
return NULL ;
|
||||
}
|
||||
|
||||
sort(res.begin(),res.end()) ; // eliminates outliers.
|
||||
|
||||
|
||||
if(!inet_aton(res[res.size()/2].c_str(),af->_addr))
|
||||
{
|
||||
std::cerr << "ExtAddrFinder: Could not convert " << res[res.size()/2] << " into an address." << std::endl ;
|
||||
{
|
||||
RsStackMutex mtx(af->_addrMtx) ;
|
||||
*(af->_found) = false ;
|
||||
*(af->mFoundTS) = time(NULL) ;
|
||||
*(af->_searching) = false ;
|
||||
}
|
||||
pthread_exit(NULL);
|
||||
return NULL ;
|
||||
}
|
||||
|
||||
{
|
||||
RsStackMutex mtx(af->_addrMtx) ;
|
||||
*(af->_found) = true ;
|
||||
*(af->mFoundTS) = time(NULL) ;
|
||||
*(af->_searching) = false ;
|
||||
}
|
||||
|
||||
pthread_exit(NULL);
|
||||
return NULL ;
|
||||
}
|
||||
|
||||
|
||||
void ExtAddrFinder::start_request()
|
||||
{
|
||||
void *data = (void *)this;
|
||||
pthread_t tid ;
|
||||
pthread_create(&tid, 0, &doExtAddrSearch, data);
|
||||
pthread_detach(tid); /* so memory is reclaimed in linux */
|
||||
}
|
||||
|
||||
bool ExtAddrFinder::hasValidIP(struct in_addr *addr)
|
||||
{
|
||||
#ifdef EXTADDRSEARCH_DEBUG
|
||||
std::cerr << "ExtAddrFinder: Getting ip." << std::endl ;
|
||||
#endif
|
||||
|
||||
if(*_found)
|
||||
{
|
||||
#ifdef EXTADDRSEARCH_DEBUG
|
||||
std::cerr << "ExtAddrFinder: Has stored ip: responding with this ip." << std::endl ;
|
||||
#endif
|
||||
*addr = *_addr;
|
||||
}
|
||||
|
||||
//timeout the current ip
|
||||
time_t delta = time(NULL) - *mFoundTS;
|
||||
if((uint32_t)delta > MAX_IP_STORE) {//launch a research
|
||||
if( _addrMtx.trylock())
|
||||
{
|
||||
if(!*_searching)
|
||||
{
|
||||
#ifdef EXTADDRSEARCH_DEBUG
|
||||
std::cerr << "ExtAddrFinder: No stored ip: Initiating new search." << std::endl ;
|
||||
#endif
|
||||
*_searching = true ;
|
||||
start_request() ;
|
||||
}
|
||||
#ifdef EXTADDRSEARCH_DEBUG
|
||||
else
|
||||
std::cerr << "ExtAddrFinder: Already searching." << std::endl ;
|
||||
#endif
|
||||
_addrMtx.unlock();
|
||||
}
|
||||
#ifdef EXTADDRSEARCH_DEBUG
|
||||
else
|
||||
std::cerr << "ExtAddrFinder: (Note) Could not acquire lock. Busy." << std::endl ;
|
||||
#endif
|
||||
}
|
||||
|
||||
return *_found ;
|
||||
}
|
||||
|
||||
void ExtAddrFinder::reset()
|
||||
{
|
||||
// while(*_searching)
|
||||
//#ifdef WIN32
|
||||
// Sleep(1000) ;
|
||||
//#else
|
||||
// sleep(1) ;
|
||||
//#endif
|
||||
|
||||
RsStackMutex mut(_addrMtx) ;
|
||||
|
||||
*_found = false ;
|
||||
*_searching = false ;
|
||||
*mFoundTS = time(NULL) - MAX_IP_STORE;
|
||||
}
|
||||
|
||||
ExtAddrFinder::~ExtAddrFinder()
|
||||
{
|
||||
#ifdef EXTADDRSEARCH_DEBUG
|
||||
std::cerr << "ExtAddrFinder: Deleting ExtAddrFinder." << std::endl ;
|
||||
#endif
|
||||
// while(*_searching)
|
||||
//#ifdef WIN32
|
||||
// Sleep(1000) ;
|
||||
//#else
|
||||
// sleep(1) ;
|
||||
//#endif
|
||||
|
||||
RsStackMutex mut(_addrMtx) ;
|
||||
|
||||
delete _found ;
|
||||
delete _searching ;
|
||||
free (_addr) ;
|
||||
}
|
||||
|
||||
ExtAddrFinder::ExtAddrFinder()
|
||||
{
|
||||
#ifdef EXTADDRSEARCH_DEBUG
|
||||
std::cerr << "ExtAddrFinder: Creating new ExtAddrFinder." << std::endl ;
|
||||
#endif
|
||||
RsStackMutex mut(_addrMtx) ;
|
||||
|
||||
_found = new bool ;
|
||||
*_found = false ;
|
||||
|
||||
_searching = new bool ;
|
||||
*_searching = false ;
|
||||
|
||||
mFoundTS = new time_t;
|
||||
*mFoundTS = time(NULL) - MAX_IP_STORE;
|
||||
|
||||
_addr = (in_addr*)malloc(sizeof(in_addr)) ;
|
||||
|
||||
_ip_servers.push_back(std::string( "checkip.dyndns.org" )) ;
|
||||
_ip_servers.push_back(std::string( "www.showmyip.com" )) ;
|
||||
_ip_servers.push_back(std::string( "showip.net" )) ;
|
||||
_ip_servers.push_back(std::string( "www.displaymyip.com")) ;
|
||||
}
|
||||
|
31
libretroshare/src/util/extaddrfinder.h
Normal file
31
libretroshare/src/util/extaddrfinder.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include "util/rsthreads.h"
|
||||
|
||||
struct sockaddr ;
|
||||
|
||||
class ExtAddrFinder
|
||||
{
|
||||
public:
|
||||
ExtAddrFinder() ;
|
||||
~ExtAddrFinder() ;
|
||||
|
||||
bool hasValidIP(struct in_addr *addr) ;
|
||||
void getIPServersList(std::list<std::string>& ip_servers) { ip_servers = _ip_servers ; }
|
||||
|
||||
void start_request() ;
|
||||
|
||||
void reset() ;
|
||||
|
||||
private:
|
||||
friend void* doExtAddrSearch(void *p) ;
|
||||
|
||||
time_t *mFoundTS;
|
||||
RsMutex _addrMtx ;
|
||||
struct in_addr *_addr ;
|
||||
bool *_found ;
|
||||
bool *_searching ;
|
||||
std::list<std::string> _ip_servers ;
|
||||
};
|
|
@ -129,22 +129,6 @@ bool isExternalNet(const struct in_addr *addr)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool getIPAddressFromString (const char *addr_str, struct in_addr *addr)
|
||||
{
|
||||
if (addr_str && addr) {
|
||||
static RsMutex mtx;
|
||||
RsStackMutex stack(mtx);
|
||||
|
||||
hostent *pHost = gethostbyname (addr_str);
|
||||
if (pHost) {
|
||||
addr->s_addr = *(unsigned long*) (pHost->h_addr);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const struct sockaddr_in &addr)
|
||||
{
|
||||
out << "[" << inet_ntoa(addr.sin_addr) << ":";
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue