From 247e583a35b17eb4076120425dbca43d9eface62 Mon Sep 17 00:00:00 2001 From: drbob Date: Fri, 21 Mar 2008 19:06:34 +0000 Subject: [PATCH] Addition of a new Automatic DHT Bootstrap system. This will need to be tweaked as the numbers of users increase. * hashed keys are posted to specific DHT entries, to create a series of bootstrap lists. * these are fetched as needed to bootstrap new clients. * Modified Bootstrap monitor program. Created a minimal backup bootstrap list (temporary) Added "-e" option to commandline to force 'external port' mode Bugfix for multiple connection methods, could kill an active connection. git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@397 b45a01b8-16f6-495d-af2f-9b41ad6348cc --- libretroshare/src/dht/dht_bootstrap.cc | 102 +--- libretroshare/src/dht/dht_check_peers.cc | 500 +++++++++++++++++++ libretroshare/src/pqi/p3connmgr.cc | 13 - libretroshare/src/pqi/p3dhtmgr.cc | 218 +++++++- libretroshare/src/pqi/p3dhtmgr.h | 23 +- libretroshare/src/pqi/pqiperson.cc | 18 +- libretroshare/src/rsserver/p3face-startup.cc | 12 +- libretroshare/src/rsserver/p3face.h | 1 + 8 files changed, 783 insertions(+), 104 deletions(-) create mode 100644 libretroshare/src/dht/dht_check_peers.cc diff --git a/libretroshare/src/dht/dht_bootstrap.cc b/libretroshare/src/dht/dht_bootstrap.cc index a82ff54fc..84c6c7ead 100644 --- a/libretroshare/src/dht/dht_bootstrap.cc +++ b/libretroshare/src/dht/dht_bootstrap.cc @@ -129,31 +129,6 @@ virtual void peerStatus(std::string id, struct sockaddr_in laddr, struct sockaddr_in raddr, uint32_t type, uint32_t mode, uint32_t source) { - - { - RsStackMutex stack(peerMtx); /**** LOCK MUTEX ***/ - - std::map::iterator it; - it = peerMap.find(id); - if (it == peerMap.end()) - { - std::cerr << "peerStatus() for unknown Peer id: " << id; - std::cerr << std::endl; - return; - } - it->second.laddr = laddr; - it->second.raddr = raddr; - it->second.type = type; - it->second.mode = mode; - it->second.source= source; - - it->second.lastStatus = time(NULL); - - it->second.stunAttempts++; /* as we are about to try! */ - } - - printPeerStatus(); - stunPeer(id, raddr); } void printPeerStatus() @@ -165,7 +140,7 @@ void printPeerStatus() std::cerr << "BootstrapStatus: " << timestr; std::cerr << "BootstrapStatus: " << peerMap.size() << " Peers"; std::cerr << std::endl; - std::cerr << "BootstrapStatus: ID ---------- DHT ENTRY ---"; + std::cerr << "BootstrapStatus: ID --------------------- DHT ENTRY ---"; std::cerr << " EXT PORT -- STUN OK -- %AVAIL -- LAST DHT TS"; std::cerr << std::endl; @@ -173,7 +148,7 @@ void printPeerStatus() for(it = peerMap.begin(); it != peerMap.end(); it++) { - std::cerr << it->first; + std::cerr << RsUtil::BinToHex(it->first); bool dhtActive = (time(NULL) - it->second.lastStatus < 1900); bool stunActive = (time(NULL) - it->second.lastStunResult < 1900); @@ -228,7 +203,8 @@ void printPeerStatus() void stunPeer(std::string id, struct sockaddr_in peeraddr) { - std::cerr << "Should Stun Peer: " << id; + std::cerr << "stunPeer: 0x" << RsUtil::BinToHex(id); + std::cerr << std::endl; /* launch a publishThread */ @@ -256,6 +232,27 @@ virtual void peerConnectRequest(std::string id, virtual void stunStatus(std::string id, struct sockaddr_in raddr, uint32_t type, uint32_t flags) { + addPeer(id); + { + RsStackMutex stack(peerMtx); /**** LOCK MUTEX ***/ + + std::map::iterator it; + it = peerMap.find(id); + if (it == peerMap.end()) + { + std::cerr << "peerStatus() for unknown Peer id: 0x" << RsUtil::BinToHex(id); + std::cerr << std::endl; + return; + } + it->second.raddr = raddr; + it->second.type = type; + it->second.lastStatus = time(NULL); + + it->second.stunAttempts++; /* as we are about to try! */ + } + + printPeerStatus(); + stunPeer(id, raddr); return; } @@ -268,11 +265,11 @@ virtual void stunSuccess(std::string id, struct sockaddr_in toaddr, struct so it = peerMap.find(id); if (it == peerMap.end()) { - std::cerr << "stunSuccess() for unknown Peer id: " << id; + std::cerr << "stunSuccess() for unknown Peer id: 0x" << RsUtil::BinToHex(id); std::cerr << std::endl; return; } - std::cerr << "stunSuccess() for id: " << id; + std::cerr << "stunSuccess() for id: 0x" << RsUtil::BinToHex(id); std::cerr << std::endl; it->second.lastStunResult = time(NULL); @@ -374,13 +371,6 @@ int main(int argc, char **argv) ownId = "dummyOwnId"; } - if (peerIds.size() < 1) - { - std::cerr << "No PeerIds, loading bootstrap Ids"; - std::cerr << std::endl; - loadBootStrapIds(peerIds); - } - pqiConnectCbStun cbStun; OpenDHTMgr dhtTester(ownId, &cbStun, "."); @@ -401,15 +391,6 @@ int main(int argc, char **argv) std::cerr << "Switching on DhtTester()" << std::endl; dhtTester.setDhtOn(true); - std::cerr << "Adding a List of Peers" << std::endl; - std::list::iterator it; - for(it = peerIds.begin(); it != peerIds.end(); it++) - { - cbStun.addPeer(*it); - dhtTester.findPeer(*it); - } - - /* wait loop */ while(1) { @@ -426,35 +407,6 @@ int main(int argc, char **argv) }; -void loadBootStrapIds(std::list &peerIds) -{ - std::string id; - - // Two Defaults for The Initial Release. - id = "7ad672ea4d4af8560d5230aff3c88b59"; - peerIds.push_back(id); - - id = "8ad7c08e7778e0289de04843bf57a6ae"; - peerIds.push_back(id); - - // Donated by public. - id = "8523688347027884059506005618ae74"; /* tm */ - peerIds.push_back(id); - - id = "1bd15b320269fa1561ceb1162fd042f0"; /* cp */ - peerIds.push_back(id); - - id = "2cf2361f2afcd6d871159714bbbfc502"; /* cc */ - peerIds.push_back(id); - - id = "128646cdf761970376a62c52c372c931"; /* rf */ - peerIds.push_back(id); - - id = "86d5d94474a4b8ac4386686eff31aeb9"; /* bn */ - peerIds.push_back(id); - - return; -} bool stunPeer(struct sockaddr_in toaddr, struct sockaddr_in &ansaddr) diff --git a/libretroshare/src/dht/dht_check_peers.cc b/libretroshare/src/dht/dht_check_peers.cc new file mode 100644 index 000000000..153e15df9 --- /dev/null +++ b/libretroshare/src/dht/dht_check_peers.cc @@ -0,0 +1,500 @@ +/* + * libretroshare/src/dht: odhtmgr_test.cc + * + * Interface with OpenDHT for RetroShare. + * + * Copyright 2007-2008 by Robert Fernie. + * + * 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". + * + */ + + + +/***** Test for the new DHT system *****/ + +#include "pqi/p3dhtmgr.h" +#include "pqi/p3connmgr.h" +#include "pqi/pqimonitor.h" +#include "dht/opendhtmgr.h" + +#include "util/rsnet.h" +#include "util/rsthreads.h" +#include "util/rsprint.h" + +#include "tcponudp/tou_net.h" +#include "tcponudp/udpsorter.h" + +#include +#include +#include +#include + +#define BOOTSTRAP_DEBUG 1 + +void usage(char *name) +{ + std::cerr << "USAGE: " << name << " -o OwnId [ -p PeerId1 [ -p PeerId2 [ ... ] ] ] "; + std::cerr << std::endl; + exit(1); +} + +bool stunPeer(struct sockaddr_in toaddr, struct sockaddr_in &ansaddr); + +class pqiConnectCbStun; + +class dhtStunData +{ + public: + pqiConnectCbStun *stunCb; + std::string id; + struct sockaddr_in toaddr; + struct sockaddr_in ansaddr; +}; + +extern "C" void* doStunPeer(void* p); + + + +class StunDetails +{ + public: + StunDetails() +{ + lastStatus = 0; + lastStunResult = 0; + stunAttempts = 0; + stunResults = 0; +} + + std::string id; + + /* peerStatus details */ + struct sockaddr_in laddr, raddr; + uint32_t type, mode, source; + + /* stun response */ + uint32_t stunAttempts; + uint32_t stunResults; + struct sockaddr_in stunaddr; + + /* timestamps */ + time_t lastStatus; + time_t lastStunResult; + +}; + +class pqiConnectCbStun: public pqiConnectCb +{ + public: + pqiConnectCbStun() +{ + return; +} + +virtual ~pqiConnectCbStun() +{ + return; +} + +void addPeer(std::string id) +{ + RsStackMutex stack(peerMtx); /**** LOCK MUTEX ***/ + std::map::iterator it; + it = peerMap.find(id); + if (it == peerMap.end()) + { + StunDetails sd; + sd.id = id; + peerMap[id] = sd; + } +} + +virtual void peerStatus(std::string id, + struct sockaddr_in laddr, struct sockaddr_in raddr, + uint32_t type, uint32_t mode, uint32_t source) +{ + + { + RsStackMutex stack(peerMtx); /**** LOCK MUTEX ***/ + + std::map::iterator it; + it = peerMap.find(id); + if (it == peerMap.end()) + { + std::cerr << "peerStatus() for unknown Peer id: " << id; + std::cerr << std::endl; + return; + } + it->second.laddr = laddr; + it->second.raddr = raddr; + it->second.type = type; + it->second.mode = mode; + it->second.source= source; + + it->second.lastStatus = time(NULL); + + it->second.stunAttempts++; /* as we are about to try! */ + } + + printPeerStatus(); + stunPeer(id, raddr); +} + +void printPeerStatus() +{ + RsStackMutex stack(peerMtx); /**** LOCK MUTEX ***/ + + time_t t = time(NULL); + std::string timestr = ctime(&t); + std::cerr << "BootstrapStatus: " << timestr; + std::cerr << "BootstrapStatus: " << peerMap.size() << " Peers"; + std::cerr << std::endl; + std::cerr << "BootstrapStatus: ID ---------- DHT ENTRY ---"; + std::cerr << " EXT PORT -- STUN OK -- %AVAIL -- LAST DHT TS"; + std::cerr << std::endl; + + std::map::iterator it; + + for(it = peerMap.begin(); it != peerMap.end(); it++) + { + std::cerr << it->first; + + bool dhtActive = (time(NULL) - it->second.lastStatus < 1900); + bool stunActive = (time(NULL) - it->second.lastStunResult < 1900); + bool extPort = it->second.type & RS_NET_CONN_TCP_EXTERNAL; + float percentAvailable = it->second.stunResults * 100.0 / (it->second.stunAttempts + 0.0001); + + if (dhtActive) + { + std::cerr << " Yes --->"; + } + else + { + std::cerr << " No "; + } + + if (extPort) + { + std::cerr << " Yes --->"; + } + else + { + std::cerr << " No "; + } + + if (stunActive) + { + std::cerr << " Yes --->"; + } + else + { + std::cerr << " No "; + } + + std::cerr << " " << std::setw(4) << percentAvailable; + std::cerr << " "; + + if (it->second.lastStatus == 0) + { + std::cerr << " NEVER "; + } + else + { + std::cerr << " " << time(NULL) - it->second.lastStatus; + std::cerr << " secs ago "; + } + std::cerr << std::endl; + } +} + + + + +void stunPeer(std::string id, struct sockaddr_in peeraddr) +{ + std::cerr << "Should Stun Peer: " << id; + std::cerr << std::endl; + + /* launch a publishThread */ + pthread_t tid; + + dhtStunData *pub = new dhtStunData; + pub->stunCb = this; + pub->id = id; + pub->toaddr = peeraddr; + + void *data = (void *) pub; + pthread_create(&tid, 0, &doStunPeer, data); + + return; + +} + + +virtual void peerConnectRequest(std::string id, + struct sockaddr_in raddr, uint32_t source) +{ + return; +} + + +virtual void stunStatus(std::string id, struct sockaddr_in raddr, uint32_t type, uint32_t flags) +{ + return; +} + +virtual void stunSuccess(std::string id, struct sockaddr_in toaddr, struct sockaddr_in ansaddr) +{ + { + RsStackMutex stack(peerMtx); /**** LOCK MUTEX ***/ + + std::map::iterator it; + it = peerMap.find(id); + if (it == peerMap.end()) + { + std::cerr << "stunSuccess() for unknown Peer id: " << id; + std::cerr << std::endl; + return; + } + std::cerr << "stunSuccess() for id: " << id; + std::cerr << std::endl; + + it->second.lastStunResult = time(NULL); + it->second.stunResults++; + } + + printPeerStatus(); +} + + private: + + RsMutex peerMtx; + std::map peerMap; +}; + + + +extern "C" void* doStunPeer(void* p) +{ + dhtStunData *data = (dhtStunData *) p; + if ((!data) || (!data->stunCb)) + { + pthread_exit(NULL); + } + + /* stun it! */ + if (stunPeer(data->toaddr, data->ansaddr)) + { + data->stunCb->stunSuccess(data->id, data->toaddr, data->ansaddr); + } + + delete data; + + pthread_exit(NULL); + + return NULL; +} + + + + +int main(int argc, char **argv) +{ + int c; + bool setOwnId = false; + std::string ownId; + std::list peerIds; + + while(-1 != (c = getopt(argc, argv, "o:p:"))) + { + switch (c) + { + case 'o': + ownId = optarg; + setOwnId = true; + break; + case 'p': + peerIds.push_back(std::string(optarg)); + break; + default: + usage(argv[0]); + break; + } + } +/******************************** WINDOWS/UNIX SPECIFIC PART ******************/ +#ifndef WINDOWS_SYS +/********************************** WINDOWS/UNIX SPECIFIC PART ******************/ +#else +/* for static PThreads under windows... we need to init the library... + */ + #ifdef PTW32_STATIC_LIB + pthread_win32_process_attach_np(); + #endif + + // Windows Networking Init. + WORD wVerReq = MAKEWORD(2,2); + WSADATA wsaData; + + if (0 != WSAStartup(wVerReq, &wsaData)) + { + std::cerr << "Failed to Startup Windows Networking"; + std::cerr << std::endl; + } + else + { + std::cerr << "Started Windows Networking"; + std::cerr << std::endl; + } + +#endif + + + if (!setOwnId) + { + std::cerr << "Missing OwnId: Setting dummy Id"; + std::cerr << std::endl; + + setOwnId = true; + ownId = "dummyOwnId"; + } + + pqiConnectCbStun cbStun; + OpenDHTMgr dhtTester(ownId, &cbStun, "."); + + /* startup dht */ + std::cerr << "Starting up DhtTester()" << std::endl; + dhtTester.start(); + + /* wait for a little before switching on */ +/********************************** WINDOWS/UNIX SPECIFIC PART ******************/ +#ifndef WINDOWS_SYS + sleep(1); +#else + Sleep(1000); +#endif +/********************************** WINDOWS/UNIX SPECIFIC PART ******************/ + + + std::cerr << "Switching on DhtTester()" << std::endl; + dhtTester.setDhtOn(true); + + std::cerr << "Adding a List of Peers" << std::endl; + std::list::iterator it; + for(it = peerIds.begin(); it != peerIds.end(); it++) + { + cbStun.addPeer(*it); + dhtTester.findPeer(*it); + } + + /* switch off Stun/Bootstrap stuff */ + dht.doneStun(); + dht.setBootstrapAllowed(false); + + + /* wait loop */ + while(1) + { + cbStun.printPeerStatus(); + std::cerr << "Main waiting..." << std::endl; +/********************************** WINDOWS/UNIX SPECIFIC PART ******************/ +#ifndef WINDOWS_SYS + sleep(30); +#else + Sleep(30000); +#endif +/********************************** WINDOWS/UNIX SPECIFIC PART ******************/ + } +}; + + +bool stunPeer(struct sockaddr_in toaddr, struct sockaddr_in &ansaddr) +{ +#ifdef BOOTSTRAP_DEBUG + std::cerr << "stunPeer: " << toaddr << std::endl; +#endif + /* open a socket */ + int sockfd = tounet_socket(PF_INET, SOCK_DGRAM, 0); + if (-1 == tounet_fcntl(sockfd, F_SETFL, O_NONBLOCK)) + { +#ifdef BOOTSTRAP_DEBUG + std::cerr << "Failed to Make Non-Blocking" << std::endl; +#endif + } + + /* create a stun packet */ + char stunpkt[100]; + int maxlen = 100; + int len = maxlen; + + UdpStun_generate_stun_pkt((void *) stunpkt, &len); + +#ifdef BOOTSTRAP_DEBUG + std::cerr << "stunPeer() Send packet length: " << len << std::endl; +#endif + + /* send stun packet */ + tounet_sendto(sockfd, stunpkt, len, 0, + (struct sockaddr *) &(toaddr), + sizeof(toaddr)); + + /* wait */ +/********************************** WINDOWS/UNIX SPECIFIC PART ******************/ +#ifndef WINDOWS_SYS + sleep(2); +#else + Sleep(2000); +#endif +/********************************** WINDOWS/UNIX SPECIFIC PART ******************/ + + /* check for response */ + struct sockaddr_in fromaddr; + socklen_t fromsize = sizeof(fromaddr); + int insize = maxlen; + + insize = tounet_recvfrom(sockfd,stunpkt,insize,0, + (struct sockaddr*)&fromaddr,&fromsize); + + tounet_close(sockfd); + + if (0 >= insize) + { +#ifdef BOOTSTRAP_DEBUG + std::cerr << "No Stun response from: " << toaddr; + std::cerr << std::endl; +#endif + return false; + } + + if (UdpStun_response(stunpkt, insize, ansaddr)) + { +#ifdef BOOTSTRAP_DEBUG + std::cerr << "received Stun Reply from : " << fromaddr; + std::cerr << std::endl; + std::cerr << "External Address is: " << ansaddr; + std::cerr << std::endl; +#endif + return true; + } + +#ifdef BOOTSTRAP_DEBUG + std::cerr << "received Data (not Stun Reply) from : " << fromaddr; + std::cerr << std::endl; +#endif + return false; +} + diff --git a/libretroshare/src/pqi/p3connmgr.cc b/libretroshare/src/pqi/p3connmgr.cc index 8b49e2873..8b84eb37e 100644 --- a/libretroshare/src/pqi/p3connmgr.cc +++ b/libretroshare/src/pqi/p3connmgr.cc @@ -2781,19 +2781,6 @@ bool p3ConnectMgr::addBootstrapStunPeers() id = "8ad7c08e7778e0289de04843bf57a6ae"; stunCollect(RsUtil::HashId(id, false), dummyaddr, flags); - // Donated by public. - id = "8523688347027884059506005618ae74"; /* tm */ - stunCollect(RsUtil::HashId(id, false), dummyaddr, flags); - - id = "1bd15b320269fa1561ceb1162fd042f0"; /* cp */ - stunCollect(RsUtil::HashId(id, false), dummyaddr, flags); - - id = "2cf2361f2afcd6d871159714bbbfc502"; /* cc */ - stunCollect(RsUtil::HashId(id, false), dummyaddr, flags); - - id = "128646cdf761970376a62c52c372c931"; /* rf */ - stunCollect(RsUtil::HashId(id, false), dummyaddr, flags); - return true; } diff --git a/libretroshare/src/pqi/p3dhtmgr.cc b/libretroshare/src/pqi/p3dhtmgr.cc index 5f6ec24bd..3ff7b71cc 100644 --- a/libretroshare/src/pqi/p3dhtmgr.cc +++ b/libretroshare/src/pqi/p3dhtmgr.cc @@ -36,6 +36,8 @@ * #define P3DHTMGR_USE_LOCAL_UDP_CONN 1 // For Testing only ****/ +#define DHT_DEBUG 1 + /**** DHT State Variables **** * TODO: * (1) notify call in. @@ -57,9 +59,12 @@ #define DHT_RESTART_PERIOD 300 /* 5 min */ #define DHT_DEFAULT_PERIOD 300 /* Default period if no work to do */ #define DHT_MIN_PERIOD 1 /* to ensure we don't get too many requests */ +#define DHT_SHORT_PERIOD 10 /* a short period */ #define DHT_DEFAULT_WAITTIME 1 /* Std sleep break period */ +#define DHT_NUM_BOOTSTRAP_BINS 1 +#define DHT_MIN_BOOTSTRAP_REQ_PERIOD 30 void printDhtPeerEntry(dhtPeerEntry *ent, std::ostream &out); @@ -102,6 +107,9 @@ p3DhtMgr::p3DhtMgr(std::string id, pqiConnectCb *cb) mDhtOn = false; mDhtState = DHT_STATE_OFF; + mBootstrapAllowed = true; + mLastBootstrapListTS = 0; + dhtMtx.unlock(); /* UNLOCK MUTEX */ return; @@ -139,6 +147,26 @@ bool p3DhtMgr::getDhtActive() return act; } +void p3DhtMgr::setBootstrapAllowed(bool on) +{ + dhtMtx.lock(); /* LOCK MUTEX */ + + mBootstrapAllowed = on; + + dhtMtx.unlock(); /* UNLOCK MUTEX */ +} + +bool p3DhtMgr::getBootstrapAllowed() +{ + dhtMtx.lock(); /* LOCK MUTEX */ + + bool on = mBootstrapAllowed; + + dhtMtx.unlock(); /* UNLOCK MUTEX */ + + return on; +} + /******************************** PEER MANAGEMENT ********************************** * */ @@ -391,7 +419,6 @@ void p3DhtMgr::run() #ifdef DHT_DEBUG std::cerr << "p3DhtMgr::run() state = ACTIVE -> do stuff" << std::endl; #endif - doStun(); period = checkOwnDHTKeys(); #ifdef DHT_DEBUG @@ -409,6 +436,15 @@ void p3DhtMgr::run() period = tmpperiod; if (tmpperiod2 < period) period = tmpperiod2; + + /* finally we need to keep stun going */ + if (checkStunState_Active()) + { + /* still more stun to do */ + period = DHT_SHORT_PERIOD; + doStun(); + } + } break; default: @@ -528,6 +564,21 @@ int p3DhtMgr::checkOwnDHTKeys() dhtMtx.unlock(); /* UNLOCK MUTEX */ } + /* dhtBootstrap -> if allowed and EXT port */ + if (peer.type & RS_NET_CONN_TCP_EXTERNAL) + { + dhtMtx.lock(); /* LOCK MUTEX */ + + bool doBootstrapPub = mBootstrapAllowed; + + dhtMtx.unlock(); /* UNLOCK MUTEX */ + + if (doBootstrapPub) + { + dhtBootstrap(randomBootstrapId(), peer.hash1, ""); + } + } + /* restart immediately */ repubPeriod = DHT_MIN_PERIOD; return repubPeriod; @@ -868,11 +919,17 @@ int p3DhtMgr::checkStunState() } else if (mDhtState == DHT_STATE_FIND_STUN) { - /* if we run out of stun peers -> just go to active */ + /* if we run out of stun peers -> get some more */ if (stunIds.size() < 1) { - std::cerr << "WARNING: out of Stun Peers - without getting id" << std::endl; + std::cerr << "WARNING: out of Stun Peers - switching to Active Now" << std::endl; mDhtState = DHT_STATE_ACTIVE; + dhtMtx.unlock(); /* UNLOCK MUTEX */ + + /* this is a locked function */ + getDhtBootstrapList(); + + dhtMtx.lock(); /* LOCK MUTEX */ } } @@ -880,6 +937,103 @@ int p3DhtMgr::checkStunState() return 1; } +int p3DhtMgr::checkStunState_Active() +{ +#ifdef DHT_DEBUG + std::cerr << "p3DhtMgr::checkStunState_Active()" << std::endl; +#endif + dhtMtx.lock(); /* LOCK MUTEX */ + + bool stunReq = mStunRequired; + bool moreIds = ((mStunRequired) && (stunIds.size() < 1)); + + dhtMtx.unlock(); /* UNLOCK MUTEX */ + + if (moreIds) + /* if we run out of stun peers -> get some more */ + { + std::cerr << "WARNING: out of Stun Peers - getting more" << std::endl; + getDhtBootstrapList(); + } + + return stunReq; +} + +bool p3DhtMgr::getDhtBootstrapList() +{ +#ifdef DHT_DEBUG + std::cerr << "p3DhtMgr::getDHTBootstrapList()" << std::endl; +#endif + dhtMtx.lock(); /* LOCK MUTEX */ + + time_t now = time(NULL); + if (now - mLastBootstrapListTS < DHT_MIN_BOOTSTRAP_REQ_PERIOD) + { +#ifdef DHT_DEBUG + std::cerr << "p3DhtMgr::getDHTBootstrapList() Waiting: "; + std::cerr << DHT_MIN_BOOTSTRAP_REQ_PERIOD-(now-mLastBootstrapListTS); + std::cerr << " secs" << std::endl; +#endif + dhtMtx.unlock(); /* UNLOCK MUTEX */ + + return false; + } + + mLastBootstrapListTS = now; + std::string bootId = randomBootstrapId(); + + + dhtMtx.unlock(); /* UNLOCK MUTEX */ + +#ifdef DHT_DEBUG + std::cerr << "p3DhtMgr::getDHTBootstrapList() bootId: 0x"; + std::cerr << RsUtil::BinToHex(bootId) << std::endl; +#endif + + dhtSearch(bootId, DHT_MODE_SEARCH); + + return true; +} + + +std::string p3DhtMgr::BootstrapId(uint32_t bin) +{ + /* generate these from an equation! (makes it easy) + * Make sure that NUM_BOOTSTRAP_BINS doesn't affect ids + */ + + std::ostringstream genId; + genId << "BootstrapId"; + + uint32_t id = (bin % DHT_NUM_BOOTSTRAP_BINS) * 1234; + + genId << id; + +#ifdef DHT_DEBUG + std::cerr << "p3DhtMgr::BootstrapId() generatedId: "; + std::cerr << genId.str() << std::endl; +#endif + + /* now hash this to create a bootstrap Bin Id */ + std::string bootId = RsUtil::HashId(genId.str(), false); + +#ifdef DHT_DEBUG + std::cerr << "p3DhtMgr::BootstrapId() bootId: 0x"; + std::cerr << RsUtil::BinToHex(bootId) << std::endl; +#endif + + return bootId; +} + +std::string p3DhtMgr::randomBootstrapId() +{ + uint32_t rnd = DHT_NUM_BOOTSTRAP_BINS * (rand() / (RAND_MAX + 1.0)); + + return BootstrapId(rnd); +} + + + void p3DhtMgr::checkDHTStatus() { dhtMtx.lock(); /* LOCK MUTEX */ @@ -1157,7 +1311,17 @@ bool p3DhtMgr::dhtSearch(std::string idhash, uint32_t mode) } +bool p3DhtMgr::dhtBootstrap(std::string storehash, std::string ownIdHash, std::string sign) +{ + std::cerr << "p3DhtMgr::dhtBootstrap()" << std::endl; + std::ostringstream value; + value << "RSDHT:" << std::setw(2) << std::setfill('0') << DHT_MODE_BOOTSTRAP << ":"; + value << ownIdHash; + + /* call to the real DHT */ + return publishDHT(storehash, value.str(), DHT_TTL_BOOTSTRAP); +} /****************************** DHT FEEDBACK INTERFACE ********************************* @@ -1280,6 +1444,23 @@ bool p3DhtMgr::resultDHT(std::string key, std::string value) break; } + case DHT_MODE_BOOTSTRAP: + { +#ifdef DHT_DEBUG + std::cerr << "p3DhtMgr::resultDHT() BOOTSTRAP msg" << std::endl; +#endif + + /* get the hash */ + std::string bootId = value.substr(loc); +#ifdef DHT_DEBUG + std::cerr << "p3DhtMgr::resultDHT() BOOTSTRAP msg, IdHash:->" << RsUtil::BinToHex(bootId) << "<-" << std::endl; +#endif + /* call out */ + dhtResultBootstrap(bootId); + + break; + } + default: return false; @@ -1292,6 +1473,37 @@ bool p3DhtMgr::resultDHT(std::string key, std::string value) +bool p3DhtMgr::dhtResultBootstrap(std::string idhash) +{ + RsStackMutex stack(dhtMtx); /***** LOCK MUTEX *****/ + +#ifdef DHT_DEBUG + std::cerr << "p3DhtMgr::dhtResultBootstrap() from idhash: "; + std::cerr << RsUtil::BinToHex(idhash) << std::endl; +#endif + + /* Temp - to avoid duplication during testing */ + if (stunIds.end() == std::find(stunIds.begin(), stunIds.end(), idhash)) + { + stunIds.push_back(idhash); +#ifdef DHT_DEBUG + std::cerr << "p3DhtMgr::dhtResultBootstrap() adding to StunList"; + std::cerr << std::endl; +#endif + } + else + { +#ifdef DHT_DEBUG + std::cerr << "p3DhtMgr::dhtResultBootstrap() DUPLICATE not adding to List"; + std::cerr << std::endl; +#endif + } + + + return true; +} + + bool p3DhtMgr::dhtResultNotify(std::string idhash) diff --git a/libretroshare/src/pqi/p3dhtmgr.h b/libretroshare/src/pqi/p3dhtmgr.h index 7730a19c8..a9ee2ef1e 100644 --- a/libretroshare/src/pqi/p3dhtmgr.h +++ b/libretroshare/src/pqi/p3dhtmgr.h @@ -55,7 +55,7 @@ #define DHT_MODE_SEARCH 1 #define DHT_MODE_PUBLISH 1 #define DHT_MODE_NOTIFY 2 - +#define DHT_MODE_BOOTSTRAP 3 /* TIMEOUTS: Reference Values are set here... */ @@ -68,9 +68,7 @@ /* TTLs for DHTs posts */ #define DHT_TTL_PUBLISH (DHT_PUBLISH_PERIOD + 120) // for a little overlap. #define DHT_TTL_NOTIFY (DHT_NOTIFY_PERIOD + 60) // for time to find it... - - - +#define DHT_TTL_BOOTSTRAP (DHT_PUBLISH_PERIOD) // To start with. class dhtPeerEntry { @@ -107,6 +105,9 @@ void setDhtOn(bool on); bool getDhtOn(); bool getDhtActive(); +void setBootstrapAllowed(bool on); +bool getBootstrapAllowed(); + /* set key data */ bool setExternalInterface(struct sockaddr_in laddr, struct sockaddr_in raddr, uint32_t type); @@ -139,6 +140,8 @@ virtual bool dhtResultSearch(std::string id, struct sockaddr_in &laddr, struct sockaddr_in &raddr, uint32_t type, std::string sign); +virtual bool dhtResultBootstrap(std::string idhash); + protected: /* can block briefly (called only from thread) */ @@ -149,8 +152,13 @@ virtual bool dhtPublish(std::string id, virtual bool dhtNotify(std::string peerid, std::string ownId, std::string sign); + virtual bool dhtSearch(std::string id, uint32_t mode); +virtual bool dhtBootstrap(std::string storehash, std::string ownIdHash, + std::string sign); /* to publish bootstrap */ + + /********** Actual DHT Work Functions ************************ * These involve a very simple LOW-LEVEL interface ... @@ -191,6 +199,7 @@ virtual void run(); /* search scheduling */ void checkDHTStatus(); int checkStunState(); +int checkStunState_Active(); /* when in active state */ int doStun(); int checkPeerDHTKeys(); int checkOwnDHTKeys(); @@ -198,6 +207,10 @@ int checkNotifyDHT(); void clearDhtData(); + /* IP Bootstrap */ +bool getDhtBootstrapList(); +std::string BootstrapId(uint32_t bin); +std::string randomBootstrapId(); /* other feedback through callback */ pqiConnectCb *connCb; @@ -218,6 +231,8 @@ void clearDhtData(); uint32_t mDhtState; time_t mDhtActiveTS; + bool mBootstrapAllowed; + time_t mLastBootstrapListTS; }; diff --git a/libretroshare/src/pqi/pqiperson.cc b/libretroshare/src/pqi/pqiperson.cc index 0c3a99821..3529094f3 100644 --- a/libretroshare/src/pqi/pqiperson.cc +++ b/libretroshare/src/pqi/pqiperson.cc @@ -216,9 +216,6 @@ int pqiperson::notifyEvent(NetInterface *ni, int newState) case CONNECT_FIREWALLED: case CONNECT_FAILED: - /* notify up */ - if (pqipg) - pqipg->notifyConnect(PeerId(), false); if (active) { @@ -228,13 +225,13 @@ int pqiperson::notifyEvent(NetInterface *ni, int newState) "CONNECT_FAILED->marking so!"); active = false; activepqi = NULL; - return 1; } else { pqioutput(PQL_WARNING, pqipersonzone, "CONNECT_FAIL+not activepqi->strange!"); - // something strange! + // probably UDP connect has failed, + // TCP connection has been made since attempt started. return -1; } } @@ -242,10 +239,14 @@ int pqiperson::notifyEvent(NetInterface *ni, int newState) { pqioutput(PQL_WARNING, pqipersonzone, "CONNECT_FAILED+NOT active -> try connect again"); - - //connectattempt(pqi); - return 1; } + + /* notify up (But not if we are actually active: rtn -1 case above) */ + if (pqipg) + pqipg->notifyConnect(PeerId(), false); + + return 1; + break; default: break; @@ -361,6 +362,7 @@ int pqiperson::connect(uint32_t type, struct sockaddr_in raddr, uint32_t delay, } /* set the parameters */ + (it->second)->reset(); (it->second)->connect_parameter(NET_PARAM_CONNECT_DELAY, delay); (it->second)->connect_parameter(NET_PARAM_CONNECT_PERIOD, period); (it->second)->connect(raddr); diff --git a/libretroshare/src/rsserver/p3face-startup.cc b/libretroshare/src/rsserver/p3face-startup.cc index 08dd4fdd2..e528ab028 100644 --- a/libretroshare/src/rsserver/p3face-startup.cc +++ b/libretroshare/src/rsserver/p3face-startup.cc @@ -237,7 +237,7 @@ int InitRetroShare(int argcIgnored, char **argvIgnored, RsInit *config) /******************************** WINDOWS/UNIX SPECIFIC PART ******************/ int c; - while((c = getopt(argc, argv,"ai:p:c:sw:l:d:u")) != -1) + while((c = getopt(argc, argv,"ai:p:ec:sw:l:d:u")) != -1) { switch (c) { @@ -292,6 +292,11 @@ int InitRetroShare(int argcIgnored, char **argvIgnored, RsInit *config) std::cerr << "Opt for only udpListener"; std::cerr << std::endl; break; + case 'e': + config->forceExtPort = true; + std::cerr << "Opt for External Port Mode"; + std::cerr << std::endl; + break; default: std::cerr << "Unknown Option!"; exit(1); @@ -616,6 +621,11 @@ int RsServer::StartupRetroShare(RsInit *config) mConnMgr->setLocalAddress(ownId, laddr); } + if (config->forceExtPort) + { + mConnMgr->setOwnNetConfig(RS_NET_MODE_EXT, RS_VIS_STATE_STD); + } + #if 0 /* must load the trusted_peer before setting up the pqipersongrp */ if (config->firsttime_run) diff --git a/libretroshare/src/rsserver/p3face.h b/libretroshare/src/rsserver/p3face.h index 51cf3a064..c609be79c 100644 --- a/libretroshare/src/rsserver/p3face.h +++ b/libretroshare/src/rsserver/p3face.h @@ -318,6 +318,7 @@ class RsInit std::string homePath; /* Listening Port */ + bool forceExtPort; bool forceLocalAddr; unsigned short port; char inet[256];