diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index 491ff347f..e02d28855 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -382,8 +382,6 @@ HEADERS += services/p3channels.h \ services/p3tunnel.h # services/p3blogs.h \ -HEADERS += tcponudp/extaddrfinder.h \ - HEADERS += turtle/p3turtle.h \ turtle/rsturtleitem.h \ turtle/turtletypes.h @@ -395,6 +393,8 @@ HEADERS += util/folderiterator.h \ util/rsdir.h \ util/rsdiscspace.h \ util/rsnet.h \ + util/extaddrfinder.h \ + util/dnsresolver.h \ util/rsprint.h \ util/rsthreads.h \ util/rsversion.h \ @@ -498,8 +498,6 @@ SOURCES += services/p3channels.cc \ services/p3statusservice.cc # removed because getPeer() doesn t exist services/p3tunnel.cc -SOURCES += tcponudp/extaddrfinder.cc \ - SOURCES += turtle/p3turtle.cc \ turtle/rsturtleitem.cc @@ -514,6 +512,8 @@ SOURCES += util/folderiterator.cc \ util/rsdir.cc \ util/rsdiscspace.cc \ util/rsnet.cc \ + util/extaddrfinder.cc \ + util/dnsresolver.cc \ util/rsprint.cc \ util/rsthreads.cc \ util/rsversion.cc \ diff --git a/libretroshare/src/pqi/p3connmgr.cc b/libretroshare/src/pqi/p3connmgr.cc index a1f238812..0418af93e 100644 --- a/libretroshare/src/pqi/p3connmgr.cc +++ b/libretroshare/src/pqi/p3connmgr.cc @@ -27,7 +27,8 @@ #include "pqi/p3connmgr.h" #include "pqi/p3dhtmgr.h" // Only need it for constants. #include "tcponudp/tou.h" -#include "tcponudp/extaddrfinder.h" +#include "util/extaddrfinder.h" +#include "util/dnsresolver.h" #include "util/rsnet.h" #include "pqi/authgpg.h" @@ -195,6 +196,7 @@ p3ConnectMgr::p3ConnectMgr() mUseExtAddrFinder = true; mAllowTunnelConnection = false; mExtAddrFinder = new ExtAddrFinder; + mDNSResolver = new DNSResolver; mNetInitTS = 0; mRetryPeriod = MIN_RETRY_PERIOD; @@ -2607,8 +2609,8 @@ bool p3ConnectMgr::locked_CheckPotentialAddr(struct sockaddr_in *addr, time_t a } bool isValid = isValidNet(&(addr->sin_addr)); -// bool isLoopback = isLoopbackNet(&(addr->sin_addr)); -// bool isPrivate = isPrivateNet(&(addr->sin_addr)); + // bool isLoopback = isLoopbackNet(&(addr->sin_addr)); + // bool isPrivate = isPrivateNet(&(addr->sin_addr)); bool isExternal = isExternalNet(&(addr->sin_addr)); /* if invalid - quick rejection */ @@ -2782,39 +2784,41 @@ void p3ConnectMgr::locked_ConnectAttempt_HistoricalAddresses(peerConnectState * void p3ConnectMgr::locked_ConnectAttempt_AddDynDNS(peerConnectState *peer) { /* try dyndns address too */ - if (!peer->dyndns.empty()) { - struct in_addr addr; - u_short port = peer->currentserveraddr.sin_port ? peer->currentserveraddr.sin_port : peer->currentlocaladdr.sin_port; + if (!peer->dyndns.empty()) + { + struct in_addr addr; + u_short port = peer->currentserveraddr.sin_port ? peer->currentserveraddr.sin_port : peer->currentlocaladdr.sin_port; #ifdef CONN_DEBUG - std::cerr << "Looking up DynDNS address" << std::endl; + std::cerr << "Looking up DynDNS address" << std::endl; #endif - if (port) { - if (getIPAddressFromString (peer->dyndns.c_str (), &addr)) + if (port) { -#ifdef CONN_DEBUG - std::cerr << "Adding tcp connection attempt: "; - std::cerr << "DynDNS Addr: " << rs_inet_ntoa(addr); - std::cerr << ":" << ntohs(port); - std::cerr << std::endl; -#endif - peerConnectAddress pca; - pca.addr.sin_family = AF_INET; - pca.addr.sin_addr.s_addr = addr.s_addr; - pca.addr.sin_port = port; - pca.type = RS_NET_CONN_TCP_EXTERNAL; - //for the delay, we add a random time and some more time when the friend list is big - pca.delay = P3CONNMGR_TCP_DEFAULT_DELAY; - pca.ts = time(NULL); - pca.period = P3CONNMGR_TCP_DEFAULT_PERIOD; - - /* check address validity */ - if (locked_CheckPotentialAddr(&(pca.addr), 0)) + if(mDNSResolver->getIPAddressFromString (std::string(peer->dyndns.c_str()), addr)) { - addAddressIfUnique(peer->connAddrs, pca); +#ifdef CONN_DEBUG + std::cerr << "Adding tcp connection attempt: "; + std::cerr << "DynDNS Addr: " << rs_inet_ntoa(addr); + std::cerr << ":" << ntohs(port); + std::cerr << std::endl; +#endif + peerConnectAddress pca; + pca.addr.sin_family = AF_INET; + pca.addr.sin_addr.s_addr = addr.s_addr; + pca.addr.sin_port = port; + pca.type = RS_NET_CONN_TCP_EXTERNAL; + //for the delay, we add a random time and some more time when the friend list is big + pca.delay = P3CONNMGR_TCP_DEFAULT_DELAY; + pca.ts = time(NULL); + pca.period = P3CONNMGR_TCP_DEFAULT_PERIOD; + + /* check address validity */ + if (locked_CheckPotentialAddr(&(pca.addr), 0)) + { + addAddressIfUnique(peer->connAddrs, pca); + } } - } - } - } + } + } } diff --git a/libretroshare/src/pqi/p3connmgr.h b/libretroshare/src/pqi/p3connmgr.h index 943be55cb..082b0dc0d 100644 --- a/libretroshare/src/pqi/p3connmgr.h +++ b/libretroshare/src/pqi/p3connmgr.h @@ -38,6 +38,7 @@ #include "util/rsthreads.h" class ExtAddrFinder ; +class DNSResolver ; /* RS_VIS_STATE_XXXX * determines how public this peer wants to be... @@ -402,6 +403,7 @@ private: // These should have there own Mutex Protection, //p3tunnel *mP3tunnel; ExtAddrFinder *mExtAddrFinder ; + DNSResolver *mDNSResolver ; /* These are considered static from a MUTEX perspective */ std::map mFwAgents; diff --git a/libretroshare/src/tests/pqi/Makefile b/libretroshare/src/tests/pqi/Makefile index 05e315e56..fe7ccfaac 100644 --- a/libretroshare/src/tests/pqi/Makefile +++ b/libretroshare/src/tests/pqi/Makefile @@ -12,11 +12,11 @@ TESTOBJ = conn_harness.o ppg_harness.o TESTOBJ += net_test.o dht_test.o net_test1.o netiface_test.o dht_test.o TESTOBJ += pkt_test.o pqiarchive_test.o pqiperson_test.o -TESTOBJ += extaddrfinder_test.o pqiipset_test.o +TESTOBJ += extaddrfinder_test.o dnsresolver_test.o pqiipset_test.o TESTOBJ += p3connmgr_reset_test.o p3connmgr_connect_test.o #conn_test.o -TESTS = net_test net_test1 netiface_test pqiarchive_test pqiperson_test extaddrfinder_test +TESTS = net_test net_test1 netiface_test pqiarchive_test pqiperson_test dnsresolver_test extaddrfinder_test TESTS += pqiipset_test TESTS += p3connmgr_reset_test p3connmgr_connect_test #TESTS = p3connmgr_test1 @@ -56,6 +56,9 @@ pqiperson_test: pqiperson_test.o testconnect.o extaddrfinder_test: extaddrfinder_test.o $(CC) $(CFLAGS) -o extaddrfinder_test extaddrfinder_test.o $(LIBS) +dnsresolver_test: dnsresolver_test.o + $(CC) $(CFLAGS) -o dnsresolver_test dnsresolver_test.o $(LIBS) + pqiipset_test: pqiipset_test.o $(CC) $(CFLAGS) -o pqiipset_test pqiipset_test.o $(LIBS) diff --git a/libretroshare/src/tests/pqi/dnsresolver_test.cc b/libretroshare/src/tests/pqi/dnsresolver_test.cc new file mode 100644 index 000000000..2a20ecc90 --- /dev/null +++ b/libretroshare/src/tests/pqi/dnsresolver_test.cc @@ -0,0 +1,83 @@ + +/* + * "$Id:$" + * + * RetroShare C++ Interface. + * + * Copyright 2010-2011 by Cyril Soler + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License Version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + * + * Please report all bugs and problems to "retroshare@lunamutt.com". + * + */ + + + +#include "util/dnsresolver.h" + +#include +#include +#include + +int main() +{ + std::list names; + + DNSResolver *r = new DNSResolver ; + + names.push_back("cortinaire.inrialpes.fr") ; + names.push_back("www.google.com") ; + names.push_back("www.ego.cn") ; + names.push_back("free.fr") ; + + for(int i=0;i<5;++i) + { + for(std::list::const_iterator it = names.begin(); it != names.end(); it++) + { + in_addr addr ; + bool res = r->getIPAddressFromString(*it,addr) ; + + if(res) + std::cerr << "Lookup of " << *it << ": " << (res?"done":"pending") << ": addr = " << (void*)addr.s_addr << std::endl; + else + std::cerr << "Lookup of " << *it << ": " << (res?"done":"pending") << std::endl; + } + + std::cerr << std::endl; + usleep(200000) ; + } + + r->reset() ; + + for(int i=0;i<5;++i) + { + for(std::list::const_iterator it = names.begin(); it != names.end(); it++) + { + in_addr addr ; + bool res = r->getIPAddressFromString(*it,addr) ; + + if(res) + std::cerr << "Lookup of " << *it << ": " << (res?"done":"pending") << ": addr = " << (void*)addr.s_addr << std::endl; + else + std::cerr << "Lookup of " << *it << ": " << (res?"done":"pending") << std::endl ; + } + std::cerr << std::endl; + usleep(200000) ; + } + + delete r ; +} + diff --git a/libretroshare/src/util/dnsresolver.cc b/libretroshare/src/util/dnsresolver.cc new file mode 100644 index 000000000..3982afa20 --- /dev/null +++ b/libretroshare/src/util/dnsresolver.cc @@ -0,0 +1,159 @@ +#include "dnsresolver.h" + +#include "pqi/pqinetwork.h" + +#ifndef WIN32 +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +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::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::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() ; + _thread_running = new bool ; + *_thread_running = false ; +} + diff --git a/libretroshare/src/util/dnsresolver.h b/libretroshare/src/util/dnsresolver.h new file mode 100644 index 000000000..51aa77dc2 --- /dev/null +++ b/libretroshare/src/util/dnsresolver.h @@ -0,0 +1,40 @@ +#pragma once + +#include "pqi/pqinetwork.h" + +#ifndef WIN32 +#include +#endif + +#include +#include +#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 *_addr_map ; +}; diff --git a/libretroshare/src/tcponudp/extaddrfinder.cc b/libretroshare/src/util/extaddrfinder.cc similarity index 100% rename from libretroshare/src/tcponudp/extaddrfinder.cc rename to libretroshare/src/util/extaddrfinder.cc diff --git a/libretroshare/src/tcponudp/extaddrfinder.h b/libretroshare/src/util/extaddrfinder.h similarity index 100% rename from libretroshare/src/tcponudp/extaddrfinder.h rename to libretroshare/src/util/extaddrfinder.h diff --git a/libretroshare/src/util/rsnet.cc b/libretroshare/src/util/rsnet.cc index bc7e7f944..33c80a81c 100644 --- a/libretroshare/src/util/rsnet.cc +++ b/libretroshare/src/util/rsnet.cc @@ -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) << ":";