RetroShare/libretroshare/src/pqi/p3connmgr.cc

3564 lines
103 KiB
C++
Raw Normal View History

/*
* libretroshare/src/pqi: p3connmgr.cc
*
* 3P/PQI network interface 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".
*
*/
#include "pqi/p3connmgr.h"
#include "pqi/p3dhtmgr.h" // Only need it for constants.
#include "tcponudp/tou.h"
#include "tcponudp/extaddrfinder.h"
#include "util/rsnet.h"
#include "pqi/authgpg.h"
#include "util/rsprint.h"
#include "util/rsdebug.h"
const int p3connectzone = 3431;
#include "serialiser/rsconfigitems.h"
#include "pqi/pqinotify.h"
#include <sstream>
/* Network setup States */
const uint32_t RS_NET_NEED_RESET = 0x0000;
const uint32_t RS_NET_UNKNOWN = 0x0001;
const uint32_t RS_NET_UPNP_INIT = 0x0002;
const uint32_t RS_NET_UPNP_SETUP = 0x0004;
const uint32_t RS_NET_DONE = 0x0005;
const uint32_t RS_NET_LOOPBACK = 0x0006;
const uint32_t RS_NET_MODE_DOWN = 0x0007;
/* Stun modes (TODO) */
const uint32_t RS_STUN_DHT = 0x0001;
const uint32_t RS_STUN_DONE = 0x0002;
const uint32_t RS_STUN_LIST_MIN = 100;
const uint32_t RS_STUN_FOUND_MIN = 10;
const uint32_t MAX_UPNP_INIT = 60; /* seconds UPnP timeout */
const uint32_t MAX_NETWORK_INIT = 70; /* timeout before network reset */
const uint32_t MIN_TIME_BETWEEN_NET_RESET = 5;
const uint32_t PEER_IP_CONNECT_STATE_MAX_LIST_SIZE = 6;
/****
* #define CONN_DEBUG 1
***/
/****
* #define P3CONNMGR_NO_TCP_CONNECTIONS 1
***/
/****
* #define P3CONNMGR_NO_AUTO_CONNECTION 1
***/
const uint32_t P3CONNMGR_TCP_DEFAULT_DELAY = 3; /* 2 Seconds? is it be enough! */
const uint32_t P3CONNMGR_UDP_DEFAULT_DELAY = 3; /* 2 Seconds? is it be enough! */
const uint32_t P3CONNMGR_UDP_DEFAULT_PERIOD = 40; //a random timeout is set between P3CONNMGR_UDP_DEFAULT_PERIOD and 2 * P3CONNMGR_UDP_DEFAULT_PERIOD in the implementation
#define MAX_AVAIL_PERIOD 230 //times a peer stay in available state when not connected
#define MIN_RETRY_PERIOD 140
void printConnectState(peerConnectState &peer);
peerConnectAddress::peerConnectAddress()
:delay(0), period(0), type(0), ts(0)
{
sockaddr_clear(&addr);
}
peerAddrInfo::peerAddrInfo()
:found(false), type(0), ts(0)
{
sockaddr_clear(&laddr);
sockaddr_clear(&raddr);
}
peerConnectState::peerConnectState()
:id("unknown"),
gpg_id("unknown"),
netMode(RS_NET_MODE_UNKNOWN), visState(RS_VIS_STATE_STD),
lastcontact(0),
connecttype(0),
lastavailable(0),
lastattempt(time(NULL) - MIN_RETRY_PERIOD + MIN_TIME_BETWEEN_NET_RESET + 6 + rand() % 6), //start connection few seconds after the possible next one net reset
name(""), location(""),
state(0), actions(0),
source(0),
inConnAttempt(0)
{
sockaddr_clear(&currentlocaladdr);
sockaddr_clear(&currentserveraddr);
return;
}
std::string textPeerConnectState(peerConnectState &state)
{
std::ostringstream out;
out << "Id: " << state.id << std::endl;
out << "NetMode: " << state.netMode << std::endl;
out << "VisState: " << state.visState << std::endl;
out << "laddr: " << inet_ntoa(state.currentlocaladdr.sin_addr)
<< ":" << ntohs(state.currentlocaladdr.sin_port) << std::endl;
out << "eaddr: " << inet_ntoa(state.currentserveraddr.sin_addr)
<< ":" << ntohs(state.currentserveraddr.sin_port) << std::endl;
std::string output = out.str();
return output;
}
p3ConnectMgr::p3ConnectMgr()
:p3Config(CONFIG_TYPE_PEERS),
mNetStatus(RS_NET_UNKNOWN),
mStunStatus(0), mStunFound(0), mStunMoreRequired(true),
mStatusChanged(false)
{
/* setup basics of own state */
ownState.id = AuthSSL::getAuthSSL()->OwnId();
ownState.gpg_id = AuthGPG::getAuthGPG()->getGPGOwnId();
ownState.name = AuthGPG::getAuthGPG()->getGPGOwnName();
ownState.location = AuthSSL::getAuthSSL()->getOwnLocation();
ownState.netMode = RS_NET_MODE_UDP;
ownState.netMode |= RS_NET_MODE_TRY_UPNP;
//use_extr_addr_finder = true ;
use_extr_addr_finder = false;
allow_tunnel_connection = true;
mExtAddrFinder = new ExtAddrFinder;
mNetInitTS = 0;
netFlagLocalOk = false;
netFlagUpnpOk = false;
netFlagDhtOk = false;
netFlagStunOk = false;
netFlagExtraAddressCheckOk = false;
oldnetFlagLocalOk = false;
oldnetFlagUpnpOk = false;
oldnetFlagDhtOk = false;
oldnetFlagStunOk = false;
oldnetFlagExtraAddressCheckOk = false;
netReset();
return;
}
void p3ConnectMgr::getIPServersList(std::list<std::string>& ip_servers)
{
mExtAddrFinder->getIPServersList(ip_servers);
}
void p3ConnectMgr::setIPServersEnabled(bool b)
{
use_extr_addr_finder = b ;
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
std::cerr << "p3ConnectMgr: setIPServers to " << b << std::endl ;
}
void p3ConnectMgr::setTunnelConnection(bool b)
{
allow_tunnel_connection = b ;
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
}
void p3ConnectMgr::setOwnNetConfig(uint32_t netMode, uint32_t visState)
{
/* only change TRY flags */
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::setOwnNetConfig()" << std::endl;
std::cerr << "Existing netMode: " << ownState.netMode << " vis: " << ownState.visState;
std::cerr << std::endl;
std::cerr << "Input netMode: " << netMode << " vis: " << visState;
std::cerr << std::endl;
#endif
ownState.netMode &= ~(RS_NET_MODE_TRYMODE);
#ifdef CONN_DEBUG
std::cerr << "After Clear netMode: " << ownState.netMode << " vis: " << ownState.visState;
std::cerr << std::endl;
#endif
switch(netMode & RS_NET_MODE_ACTUAL)
{
case RS_NET_MODE_EXT:
ownState.netMode |= RS_NET_MODE_TRY_EXT;
break;
case RS_NET_MODE_UPNP:
ownState.netMode |= RS_NET_MODE_TRY_UPNP;
break;
default:
case RS_NET_MODE_UDP:
ownState.netMode |= RS_NET_MODE_TRY_UDP;
break;
}
ownState.visState = visState;
#ifdef CONN_DEBUG
std::cerr << "Final netMode: " << ownState.netMode << " vis: " << ownState.visState;
std::cerr << std::endl;
#endif
/* if we've started up - then tweak Dht On/Off */
if (mNetStatus != RS_NET_UNKNOWN)
{
//enableNetAssistConnect(!(ownState.visState & RS_VIS_STATE_NODHT));
//DHT disabled
}
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
}
/***** Framework / initial implementation for a connection manager.
*
* This needs a state machine for Initialisation.
*
* Network state:
* RS_NET_UNKNOWN
* RS_NET_EXT_UNKNOWN * forwarded port (but Unknown Ext IP) *
* RS_NET_EXT_KNOWN * forwarded port with known IP/Port. *
*
* RS_NET_UPNP_CHECK * checking for UPnP *
* RS_NET_UPNP_KNOWN * confirmed UPnP ext Ip/port *
*
* RS_NET_UDP_UNKNOWN * not Ext/UPnP - to determine Ext IP/Port *
* RS_NET_UDP_KNOWN * have Stunned for Ext Addr *
*
* Transitions:
*
* RS_NET_UNKNOWN -(config)-> RS_NET_EXT_UNKNOWN
* RS_NET_UNKNOWN -(config)-> RS_NET_UPNP_UNKNOWN
* RS_NET_UNKNOWN -(config)-> RS_NET_UDP_UNKNOWN
*
* RS_NET_EXT_UNKNOWN -(DHT(ip)/Stun)-> RS_NET_EXT_KNOWN
*
* RS_NET_UPNP_UNKNOWN -(Upnp)-> RS_NET_UPNP_KNOWN
* RS_NET_UPNP_UNKNOWN -(timout/Upnp)-> RS_NET_UDP_UNKNOWN
*
* RS_NET_UDP_UNKNOWN -(stun)-> RS_NET_UDP_KNOWN
*
*
* STUN state:
* RS_STUN_INIT * done nothing *
* RS_STUN_DHT * looking up peers *
* RS_STUN_DONE * found active peer and stunned *
*
*
* Steps.
*******************************************************************
* (1) Startup.
* - UDP port setup.
* - DHT setup.
* - Get Stun Keys -> add to DHT.
* - Feedback from DHT -> ask UDP to stun.
*
* (1) determine Network mode.
* If external Port.... Done:
* (2)
*******************************************************************
* Stable operation:
* (1) tick and check peers.
* (2) handle callback.
* (3) notify of new/failed connections.
*
*
*/
/* Called to reseet the whole network stack. this call is
* triggered by udp stun address tracking.
*
* must:
* - reset UPnP and DHT.
* -
*/
void p3ConnectMgr::netReset()
{
//don't do a net reset if the MIN_TIME_BETWEEN_NET_RESET is not reached
time_t delta = time(NULL) - mNetInitTS;
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr time since last reset : " << delta << std::endl;
#endif
if (delta < MIN_TIME_BETWEEN_NET_RESET) {
{
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
mNetStatus = RS_NET_NEED_RESET;
}
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::netStartup() don't do a net reset if the MIN_TIME_BETWEEN_NET_RESET is not reached" << std::endl;
#endif
return;
}
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::netReset() shutdown" << std::endl;
#endif
shutdown(); /* blocking shutdown call */
// Will initiate a new call for determining the external ip.
mExtAddrFinder->reset() ;
{
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
mNetStatus = RS_NET_UNKNOWN;
netStatusReset();
}
/* check Network Address */
checkNetAddress();
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::netReset() done" << std::endl;
#endif
}
/* to allow resets of network stuff */
void p3ConnectMgr::addNetListener(pqiNetListener *listener)
{
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
mNetListeners.push_back(listener);
}
void p3ConnectMgr::startListeners() {
/* NOTE: nNetListeners should be protected via the Mutex.
* HOWEVER, as we NEVER change this list - once its setup
* we can get away without it - and assume its constant.
*
* NB: (*it)->reset_listener must be out of the mutex,
* as it calls back to p3ConnMgr.
*/
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::netReset() resetting listeners" << std::endl;
#endif
std::list<pqiNetListener *>::const_iterator it;
for(it = mNetListeners.begin(); it != mNetListeners.end(); it++)
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::netReset() reset listener" << std::endl;
#endif
(*it)->reset_listener();
}
mListenerActive = true;
}
void p3ConnectMgr::stopListeners() {
//TODO implement it
mListenerActive = false;
}
void p3ConnectMgr::netStatusReset()
{
//std::cerr << "p3ConnectMgr::netStatusReset()" << std::endl;;
netFlagExtraAddressCheckOk = false;
netFlagLocalOk = false;
netFlagUpnpOk = false;
netFlagDhtOk = false;
netFlagStunOk = false;
for(std::map<std::string, peerConnectState>::iterator it = mFriendList.begin(); it != mFriendList.end(); it++)
{
it->second.state &= ~RS_PEER_S_CONNECTED ;
// forces immediate re-connexion in 6 seconds, don't start all connection immediately
it->second.lastattempt = time(NULL) - MIN_RETRY_PERIOD + 6 + rand() % 6;
}
IndicateConfigChanged();
}
void p3ConnectMgr::netStartup()
{
/* startup stuff */
/* StunInit gets a list of peers, and asks the DHT to find them...
* This is needed for all systems so startup straight away
*/
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::netStartup()" << std::endl;
#endif
//netDhtInit(); //DHT disabled
netUdpInit();
netStunInit();
/* decide which net setup mode we're going into
*/
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
netStatusReset();
mNetInitTS = time(NULL);
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::netStartup() resetting mNetInitTS timestamp" << std::endl;
std::cerr << "p3ConnectMgr::netStartup() tou_stunkeepalive() enabled" << std::endl;
#endif
tou_stunkeepalive(1);
mStunMoreRequired = true;
ownState.netMode &= ~(RS_NET_MODE_ACTUAL);
switch(ownState.netMode & RS_NET_MODE_TRYMODE)
{
case RS_NET_MODE_TRY_EXT: /* v similar to UDP */
ownState.netMode |= RS_NET_MODE_EXT;
mNetStatus = RS_NET_DONE;
break;
case RS_NET_MODE_TRY_UDP:
ownState.netMode |= RS_NET_MODE_UDP;
mNetStatus = RS_NET_DONE;
break;
case RS_NET_MODE_TRY_UPNP:
default:
/* Force it here (could be default!) */
ownState.netMode |= RS_NET_MODE_TRY_UPNP;
ownState.netMode |= RS_NET_MODE_UDP; /* set to UDP, upgraded is UPnP is Okay */
mNetStatus = RS_NET_UPNP_INIT;
break;
}
}
void p3ConnectMgr::tick()
{
netTick();
statusTick();
tickMonitors();
}
bool p3ConnectMgr::shutdown() /* blocking shutdown call */
{
{
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
mNetStatus = RS_NET_UNKNOWN;
mNetInitTS = time(NULL);
netStatusReset();
}
netAssistFirewallShutdown();
netAssistConnectShutdown();
stopListeners(); //not implemented yet
return true;
}
void p3ConnectMgr::statusTick()
{
/* iterate through peers ...
* if been available for long time ... remove flag
* if last attempt a while - retryConnect.
* etc.
*/
#ifdef CONN_DEBUG_TICK
std::cerr << "p3ConnectMgr::statusTick()" << std::endl;
#endif
std::list<std::string> retryIds;
std::list<std::string>::iterator it2;
std::list<std::string> dummyToRemove;
time_t now = time(NULL);
time_t oldavail = now - MAX_AVAIL_PERIOD;
time_t retry = now - MIN_RETRY_PERIOD;
{
RsStackMutex stack(connMtx); /****** LOCK MUTEX ******/
std::map<std::string, peerConnectState>::iterator it;
for(it = mFriendList.begin(); it != mFriendList.end(); it++)
{
if (it->second.id == ("dummy" + it->second.gpg_id)) {
//if there is other friends for the same gpg key (that obviously are not "dummy"), we will remove this useless dummy friend
std::map<std::string, peerConnectState>::iterator it2;
for(it2 = mFriendList.begin(); it2 != mFriendList.end(); it2++) {
if ((it->second.id != it2->second.id) && (it->second.gpg_id == it2->second.gpg_id)) {
dummyToRemove.push_back(it->first);
break;
}
}
continue;
}
if (it->second.state & RS_PEER_S_CONNECTED)
{
continue;
}
if ((it->second.state & RS_PEER_S_ONLINE) &&
(it->second.lastavailable < oldavail))
{
#ifdef CONN_DEBUG_TICK
std::cerr << "p3ConnectMgr::statusTick() ONLINE TIMEOUT for: ";
std::cerr << it->first;
std::cerr << std::endl;
#endif
it->second.state &= (~RS_PEER_S_ONLINE);
}
if (it->second.lastattempt < retry)
{
retryIds.push_back(it->first);
}
}
}
for (std::list<std::string>::iterator dummyIt = dummyToRemove.begin(); dummyIt != dummyToRemove.end(); dummyIt++) {
removeFriend(*dummyIt);
}
#ifndef P3CONNMGR_NO_AUTO_CONNECTION
for(it2 = retryIds.begin(); it2 != retryIds.end(); it2++)
{
#ifdef CONN_DEBUG_TICK
std::cerr << "p3ConnectMgr::statusTick() RETRY TIMEOUT for: ";
std::cerr << *it2;
std::cerr << std::endl;
#endif
/* retry it! */
retryConnectTCP(*it2);
}
#endif
}
void p3ConnectMgr::netTick()
{
#ifdef CONN_DEBUG_TICK
//std::cerr << "p3ConnectMgr::netTick()" << std::endl;
#endif
// Check whether we are stuck on loopback. This happens if RS starts when
// the computer is not yet connected to the internet. In such a case we
// periodically check for a local net address.
//
checkNetAddress() ;
networkConsistencyCheck(); /* check consistency. If not consistent, do a reset inside networkConsistencyCheck() */
connMtx.lock(); /* LOCK MUTEX */
uint32_t netStatus = mNetStatus;
connMtx.unlock(); /* UNLOCK MUTEX */
/* start tcp network - if necessary */
//TODO : implement stop listeners in net reset
if (!mListenerActive && netStatus != RS_NET_NEED_RESET && (time(NULL) - mNetInitTS) > (MIN_TIME_BETWEEN_NET_RESET + 2)) {//start connection 2 second after the possible next one net reset
startListeners();
}
switch(netStatus)
{
case RS_NET_NEED_RESET:
#ifdef CONN_DEBUG_TICK
std::cerr << "p3ConnectMgr::netTick() STATUS: NEED_RESET" << std::endl;
#endif
netReset();
break;
case RS_NET_UNKNOWN:
#ifdef CONN_DEBUG_TICK
std::cerr << "p3ConnectMgr::netTick() STATUS: UNKNOWN" << std::endl;
#endif
netStartup();
break;
case RS_NET_UPNP_INIT:
#ifdef CONN_DEBUG_TICK
std::cerr << "p3ConnectMgr::netTick() STATUS: UPNP_INIT" << std::endl;
#endif
netExtFinderAddressCheck();
netUpnpInit();
break;
case RS_NET_UPNP_SETUP:
#ifdef CONN_DEBUG_TICK
std::cerr << "p3ConnectMgr::netTick() STATUS: UPNP_SETUP" << std::endl;
#endif
netUpnpCheck();
break;
case RS_NET_DONE:
#ifdef CONN_DEBUG_TICK
//std::cerr << "p3ConnectMgr::netTick() STATUS: DONE" << std::endl;
#endif
break;
case RS_NET_LOOPBACK:
//don't do a shutdown because a client in a computer without local network might be usefull for debug.
//shutdown();
#ifdef CONN_DEBUG_TICK
std::cerr << "p3ConnectMgr::netTick() STATUS: RS_NET_LOOPBACK" << std::endl;
#endif
default:
break;
}
return;
}
void p3ConnectMgr::netUdpInit()
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::netUdpInit()" << std::endl;
#endif
connMtx.lock(); /* LOCK MUTEX */
struct sockaddr_in iaddr = ownState.currentlocaladdr;
connMtx.unlock(); /* UNLOCK MUTEX */
/* open our udp port */
tou_init((struct sockaddr *) &iaddr, sizeof(iaddr));
}
void p3ConnectMgr::netDhtInit()
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::netDhtInit()" << std::endl;
#endif
connMtx.lock(); /* LOCK MUTEX */
uint32_t vs = ownState.visState;
connMtx.unlock(); /* UNLOCK MUTEX */
//enableNetAssistConnect(!(vs & RS_VIS_STATE_NODHT));
//DHT disabled
}
void p3ConnectMgr::netUpnpInit()
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::netUpnpInit()" << std::endl;
#endif
uint16_t eport, iport;
connMtx.lock(); /* LOCK MUTEX */
/* get the ports from the configuration */
mNetStatus = RS_NET_UPNP_SETUP;
iport = ntohs(ownState.currentlocaladdr.sin_port);
eport = ntohs(ownState.currentserveraddr.sin_port);
if ((eport < 1000) || (eport > 30000))
{
eport = iport;
}
connMtx.unlock(); /* UNLOCK MUTEX */
netAssistFirewallPorts(iport, eport);
enableNetAssistFirewall(true);
}
void p3ConnectMgr::netUpnpCheck()
{
/* grab timestamp */
connMtx.lock(); /* LOCK MUTEX */
time_t delta = time(NULL) - mNetInitTS;
#ifdef CONN_DEBUG_TICK
std::cerr << "p3ConnectMgr time since last reset : " << delta << std::endl;
#endif
connMtx.unlock(); /* UNLOCK MUTEX */
struct sockaddr_in extAddr;
int upnpState = netAssistFirewallActive();
if ((upnpState == 0) && (delta > MAX_UPNP_INIT))
{
#ifdef CONN_DEBUG_TICK
std::cerr << "p3ConnectMgr::netUpnpCheck() ";
std::cerr << "Upnp Check failed." << std::endl;
#endif
/* fallback to UDP startup */
connMtx.lock(); /* LOCK MUTEX */
/* UPnP Failed us! */
mNetStatus = RS_NET_DONE;
connMtx.unlock(); /* UNLOCK MUTEX */
}
else if ((upnpState > 0) && netAssistExtAddress(extAddr))
{
#ifdef CONN_DEBUG_TICK
std::cerr << "p3ConnectMgr::netUpnpCheck() ";
std::cerr << "Upnp Check successed." << std::endl;
#endif
/* switch to UDP startup */
connMtx.lock(); /* LOCK MUTEX */
/* Set Net Status flags ....
* we now have external upnp address. Golden!
* don't set netOk flag until have seen some traffic.
*/
netFlagUpnpOk = true;
mNetStatus = RS_NET_DONE;
/* Fix netMode & Clear others! */
ownState.netMode = RS_NET_MODE_TRY_UPNP | RS_NET_MODE_UPNP;
connMtx.unlock(); /* UNLOCK MUTEX */
}
}
void p3ConnectMgr::networkConsistencyCheck()
{
time_t delta;
#ifdef CONN_DEBUG_TICK
delta = time(NULL) - mNetInitTS;
std::cerr << "p3ConnectMgr::networkConsistencyCheck() time since last reset : " << delta << std::endl;
#endif
bool doNetReset = false;
//if one of the flag is degrated from true to false during last tick, let's do a reset
#ifdef CONN_DEBUG_TICK
std::cerr << "p3ConnectMgr::networkConsistencyCheck() net flags : " << std::endl;
std::cerr << " oldnetFlagLocalOk : " << oldnetFlagLocalOk << ". netFlagLocalOk : " << netFlagLocalOk << "." << std::endl;
std::cerr << " oldnetFlagUpnpOk : " << oldnetFlagUpnpOk << ". netFlagUpnpOk : " << netFlagUpnpOk << "." << std::endl;
std::cerr << " oldnetFlagDhtOk : " << oldnetFlagDhtOk << ". netFlagDhtOk : " << netFlagDhtOk << "." << std::endl;
std::cerr << " oldnetFlagStunOk : " << oldnetFlagStunOk << ". netFlagStunOk : " << netFlagStunOk << "." << std::endl;
std::cerr << " oldnetFlagExtraAddressCheckOk : " << oldnetFlagExtraAddressCheckOk << ". netFlagExtraAddressCheckOk : " << netFlagExtraAddressCheckOk << "." << std::endl;
#endif
if ( !netFlagLocalOk
|| (!netFlagUpnpOk && oldnetFlagUpnpOk)
|| (!netFlagDhtOk && oldnetFlagDhtOk)
|| (!netFlagStunOk && oldnetFlagStunOk)
|| (!netFlagExtraAddressCheckOk && oldnetFlagExtraAddressCheckOk)
) {
#ifdef CONN_DEBUG_TICK
std::cerr << "p3ConnectMgr::networkConsistencyCheck() A net flag went down." << std::endl;
#endif
//don't do a normal shutdown for upnp as it might hang up.
//With a 0 port it will just dereference and not attemps to communicate for shutting down upnp session.
netAssistFirewallPorts(0, 0);
doNetReset = true;
}
connMtx.lock(); /* LOCK MUTEX */
//storing old flags
oldnetFlagLocalOk = netFlagLocalOk;
oldnetFlagUpnpOk = netFlagUpnpOk;
oldnetFlagDhtOk = netFlagDhtOk;
oldnetFlagStunOk = netFlagStunOk;
oldnetFlagExtraAddressCheckOk = netFlagExtraAddressCheckOk;
if (!doNetReset) {//set an external address. if ip adresses are different, let's use the stun address, then the extaddrfinder and then the upnp address.
struct sockaddr_in extAddr;
if (getExtFinderExtAddress(extAddr)) {
netExtFinderAddressCheck(); //so we put the extra address flag ok.
#ifdef CONN_DEBUG_TICK
std::cerr << "p3ConnectMgr::networkConsistencyCheck() using getExtFinderExtAddress for ownState.serveraddr." << std::endl;
#endif
ownState.currentserveraddr = extAddr;
} else if (getUpnpExtAddress(extAddr)) {
#ifdef CONN_DEBUG_TICK
std::cerr << "p3ConnectMgr::networkConsistencyCheck() using getUpnpExtAddress for ownState.serveraddr." << std::endl;
#endif
ownState.currentserveraddr = extAddr;
} else {
//try to extract ext address from our own ip address list
IpAddressTimed extractedAddress;
if (peerConnectState::extractExtAddress(ownState.getIpAddressList(), extractedAddress)) {
ownState.currentserveraddr = extractedAddress.ipAddr;
}
//check if a peer is connected, if yes don't do a net reset
bool is_connected = false;
std::map<std::string, peerConnectState>::iterator it;
for(it = mFriendList.begin(); it != mFriendList.end() && !is_connected; it++)
{
/* get last contact detail */
is_connected = it->second.state & RS_PEER_S_CONNECTED;
}
#ifdef CONN_DEBUG_TICK
if (is_connected) {
std::cerr << "p3ConnectMgr::networkConsistencyCheck() not doing a net reset because a peer is connected." << std::endl;
} else {
std::cerr << "p3ConnectMgr::networkConsistencyCheck() no peer is connected." << std::endl;
}
#endif
doNetReset = !is_connected;
}
}
connMtx.unlock(); /* UNLOCK MUTEX */
if (!doNetReset) {
//extAddr found,update ip address list
IpAddressTimed ipAddressTimed;
ipAddressTimed.ipAddr = ownState.currentserveraddr;
ipAddressTimed.seenTime = time(NULL);
ownState.updateIpAddressList(ipAddressTimed);
}
//let's do a net reset
if (doNetReset) {
//don't do a reset it if the network init is not finished
delta = time(NULL) - mNetInitTS;
if (delta > MAX_NETWORK_INIT) {
#ifdef CONN_DEBUG_TICK
std::cerr << "p3ConnectMgr::networkConsistencyCheck() doing a net reset." << std::endl;
#endif
netReset();
} else {
#ifdef CONN_DEBUG_TICK
std::cerr << "p3ConnectMgr::networkConsistencyCheck() reset delayed : p3ConnectMgr time since last reset : " << delta;
std::cerr << ". Cannot reset before : " << MAX_NETWORK_INIT << " sec" << std::endl;
#endif
}
}
}
void p3ConnectMgr::netExtFinderAddressCheck()
{ struct sockaddr_in tmpip;
if (getExtFinderExtAddress(tmpip)) {
#ifdef CONN_DEBUG_TICK
std::cerr << "p3ConnectMgr::netExtraAddressCheck() return true" << std::endl;
#endif
netFlagExtraAddressCheckOk = true;
} else {
#ifdef CONN_DEBUG_TICK
std::cerr << "p3ConnectMgr::netExtraAddressCheck() return false" << std::endl;
#endif
netFlagExtraAddressCheckOk = false;
}
}
void p3ConnectMgr::netUnreachableCheck()
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::netUnreachableCheck()" << std::endl;
#endif
std::map<std::string, peerConnectState>::iterator it;
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
for(it = mFriendList.begin(); it != mFriendList.end(); it++)
{
/* get last contact detail */
if (it->second.state & RS_PEER_S_CONNECTED)
{
#ifdef CONN_DEBUG
std::cerr << "NUC() Ignoring Connected Peer" << std::endl;
#endif
continue;
}
peerAddrInfo details;
switch(it->second.source)
{
case RS_CB_DHT:
details = it->second.dht;
#ifdef CONN_DEBUG
std::cerr << "NUC() Using DHT data" << std::endl;
#endif
break;
case RS_CB_DISC:
details = it->second.disc;
#ifdef CONN_DEBUG
std::cerr << "NUC() Using DISC data" << std::endl;
#endif
break;
case RS_CB_PERSON:
details = it->second.peer;
#ifdef CONN_DEBUG
std::cerr << "NUC() Using PEER data" << std::endl;
#endif
break;
default:
continue;
break;
}
std::cerr << "NUC() Peer: " << it->first << std::endl;
/* Determine Reachability (only advisory) */
// if (ownState.netMode == RS_NET_MODE_UNREACHABLE) // MUST BE TRUE!
{
if (details.type & RS_NET_CONN_TCP_EXTERNAL)
{
/* reachable! */
it->second.state &= (~RS_PEER_S_UNREACHABLE);
#ifdef CONN_DEBUG
std::cerr << "NUC() Peer EXT TCP - reachable" << std::endl;
#endif
}
else
{
/* unreachable */
it->second.state |= RS_PEER_S_UNREACHABLE;
#ifdef CONN_DEBUG
std::cerr << "NUC() Peer !EXT TCP - unreachable" << std::endl;
#endif
}
}
}
}
/******************************* UDP MAINTAINANCE ********************************
* Interaction with the UDP is mainly for determining the External Port.
*
*/
void p3ConnectMgr::udpStunPeer(std::string id, struct sockaddr_in &addr)
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::udpStunPeer()" << std::endl;
#endif
/* add it into udp stun list */
tou_stunpeer((struct sockaddr *) &addr, sizeof(addr), id.c_str());
}
/********************************** STUN SERVERS ***********************************
* We maintain a list of stun servers. This is initialised with a set of random keys.
*
* This is gradually rolled over with time. We update with friends/friends of friends,
* and the lists that they provide (part of AutoDisc).
*
* max 100 entries?
*/
void p3ConnectMgr::netStunInit()
{
stunInit();
}
void p3ConnectMgr::stunInit()
{
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
netAssistStun(true);
/* push stun list to DHT */
std::list<std::string>::iterator it;
for(it = mStunList.begin(); it != mStunList.end(); it++)
{
netAssistAddStun(*it);
}
mStunStatus = RS_STUN_DHT;
mStunFound = 0;
mStunMoreRequired = true;
}
/* This is continually called
*
* checks whether the ext address is consistent
*
* checks if UDP needs more stun peers - or not
* The status is passed onto the DHT.
*
*/
bool p3ConnectMgr::stunCheck()
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::stunCheck()" << std::endl;
#endif
/* check udp address stability */
bool netDone = false;
{
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
mStunStatus = RS_STUN_DHT;
netDone = (mNetStatus == RS_NET_DONE);
}
struct sockaddr_in raddr;
socklen_t rlen = sizeof(raddr);
uint8_t stable;
if (netDone)
{
if (0 < tou_extaddr((struct sockaddr *) &raddr, &rlen, &stable))
{
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::stunCheck() mStunExtAddr.sin_addr.s_addr : " << inet_ntoa(mStunExtAddr.sin_addr) << std::endl;
std::cerr << "p3ConnectMgr::stunCheck() raddr.sin_addr.s_addr : " << inet_ntoa(raddr.sin_addr) << std::endl;
std::cerr << "p3ConnectMgr::stunCheck() stable : " << (stable !=0) << std::endl;
#endif
if ((mStunExtAddr.sin_addr.s_addr != raddr.sin_addr.s_addr) ||
(stable == 0))
{
netFlagStunOk = false;
mStunExtAddr = raddr;
}
else
{
netFlagStunOk = true;
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::stunCheck() Stun ext : ok !" << std::endl;
#endif
}
}
else
{
netFlagStunOk = false;
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::stunCheck() Stun : No Ext Address." << std::endl;
#endif
}
}
//#ifdef CONN_DEBUG
// uint32_t failCount;
// time_t lastSent;
// time_t now = time(NULL);
// struct sockaddr_in eaddr;
// socklen_t elen = sizeof(eaddr);
// int i = 0;
// for(i = 0; tou_getstunpeer(i, (struct sockaddr *) &raddr, &rlen,
// (struct sockaddr *) &eaddr, &elen,
// &failCount, &lastSent); i++)
// {
// std::cerr << "STUN PEERS: ";
// std::cerr << " raddr: " << inet_ntoa(raddr.sin_addr) << ":" << ntohs(raddr.sin_port);
// std::cerr << " eaddr: " << inet_ntoa(eaddr.sin_addr) << ":" << ntohs(eaddr.sin_port);
// if (lastSent)
// {
// std::cerr << " failCount: " << failCount << " lastSent: " << now-lastSent;
// }
// else
// {
// std::cerr << " Unused ";
// }
// std::cerr << std::endl;
// }
//#endif
/* pass on udp status to dht */
if (tou_needstunpeers())
{
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
if (!mStunMoreRequired)
{
#ifdef CONN_DEBUG
std::cerr << "Telling DHT More Stun Required" << std::endl;
#endif
netAssistStun(true);
mStunMoreRequired = true;
}
}
else
{
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
if (mStunMoreRequired)
{
#ifdef CONN_DEBUG
std::cerr << "Telling DHT No More Stun Required" << std::endl;
#endif
netAssistStun(false);
mStunMoreRequired = false;
}
}
return true;
}
void p3ConnectMgr::stunStatus(std::string id, struct sockaddr_in raddr, uint32_t type, uint32_t flags)
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::stunStatus() id: " << RsUtil::BinToHex(id) << " raddr: " << inet_ntoa(raddr.sin_addr);
std::cerr << ":" << ntohs(raddr.sin_port) << std::endl;
#endif
connMtx.lock(); /* LOCK MUTEX */
bool stillStunning = (mStunStatus == RS_STUN_DHT);
connMtx.unlock(); /* UNLOCK MUTEX */
/* only useful if they have an exposed TCP/UDP port */
if (type & RS_NET_CONN_TCP_EXTERNAL)
{
if (stillStunning)
{
connMtx.lock(); /* LOCK MUTEX */
mStunFound++;
connMtx.unlock(); /* UNLOCK MUTEX */
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::stunStatus() Sending to UDP" << std::endl;
#endif
/* push to the UDP */
udpStunPeer(id, raddr);
}
/* push to the stunCollect */
stunCollect(id, raddr, flags);
}
}
/* FLAGS
ONLINE
EXT
UPNP
UDP
FRIEND
FRIEND_OF_FRIEND
OTHER
*/
void p3ConnectMgr::stunCollect(std::string id, struct sockaddr_in addr, uint32_t flags)
{
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::stunCollect() id: " << RsUtil::BinToHex(id) << std::endl;
#endif
std::list<std::string>::iterator it;
it = std::find(mStunList.begin(), mStunList.end(), id);
if (it == mStunList.end())
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::stunCollect() Id not in List" << std::endl;
#endif
/* add it in:
* if FRIEND / ONLINE or if list is short.
*/
if ((flags & RS_STUN_ONLINE) || (flags & RS_STUN_FRIEND))
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::stunCollect() Id added to Front" << std::endl;
#endif
/* push to the front */
mStunList.push_front(id);
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
}
else if (mStunList.size() < RS_STUN_LIST_MIN)
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::stunCollect() Id added to Back" << std::endl;
#endif
/* push to the front */
mStunList.push_back(id);
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
}
}
else
{
/* if they're online ... move to the front
*/
if (flags & RS_STUN_ONLINE)
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::stunCollect() Id moved to Front" << std::endl;
#endif
/* move to front */
mStunList.erase(it);
mStunList.push_front(id);
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
}
}
}
/******************************** Network Status *********************************
* Configuration Loading / Saving.
*/
void p3ConnectMgr::addMonitor(pqiMonitor *mon)
{
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
std::list<pqiMonitor *>::iterator it;
it = std::find(clients.begin(), clients.end(), mon);
if (it != clients.end())
{
return;
}
mon->setConnectionMgr(this);
clients.push_back(mon);
return;
}
void p3ConnectMgr::removeMonitor(pqiMonitor *mon)
{
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
std::list<pqiMonitor *>::iterator it;
it = std::find(clients.begin(), clients.end(), mon);
if (it == clients.end())
{
return;
}
(*it)->setConnectionMgr(NULL);
clients.erase(it);
return;
}
void p3ConnectMgr::tickMonitors()
{
bool doStatusChange = false;
std::list<pqipeer> actionList;
std::map<std::string, peerConnectState>::iterator it;
{
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
if (mStatusChanged)
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::tickMonitors() StatusChanged! List:" << std::endl;
#endif
/* assemble list */
for(it = mFriendList.begin(); it != mFriendList.end(); it++)
{
if (it->second.actions)
{
/* add in */
pqipeer peer;
peer.id = it->second.id;
peer.name = it->second.name;
peer.state = it->second.state;
peer.actions = it->second.actions;
/* reset action */
it->second.actions = 0;
actionList.push_back(peer);
#ifdef CONN_DEBUG
std::cerr << "Friend: " << peer.name << " Id: " << peer.id << " State: " << peer.state;
if (peer.state & RS_PEER_S_FRIEND)
std::cerr << " S:RS_PEER_S_FRIEND";
if (peer.state & RS_PEER_S_ONLINE)
std::cerr << " S:RS_PEER_S_ONLINE";
if (peer.state & RS_PEER_S_CONNECTED)
std::cerr << " S:RS_PEER_S_CONNECTED";
std::cerr << " Actions: " << peer.actions;
if (peer.actions & RS_PEER_NEW)
std::cerr << " A:RS_PEER_NEW";
if (peer.actions & RS_PEER_MOVED)
std::cerr << " A:RS_PEER_MOVED";
if (peer.actions & RS_PEER_CONNECTED)
std::cerr << " A:RS_PEER_CONNECTED";
if (peer.actions & RS_PEER_DISCONNECTED)
std::cerr << " A:RS_PEER_DISCONNECTED";
if (peer.actions & RS_PEER_CONNECT_REQ)
std::cerr << " A:RS_PEER_CONNECT_REQ";
std::cerr << std::endl;
#endif
/* notify GUI */
if (peer.actions & RS_PEER_CONNECTED)
{
pqiNotify *notify = getPqiNotify();
if (notify)
{
notify->AddPopupMessage(RS_POPUP_CONNECT,
peer.id, "Online: ");
notify->AddFeedItem(RS_FEED_ITEM_PEER_CONNECT, peer.id, "", "");
}
}
}
}
/* do the Others as well! */
for(it = mOthersList.begin(); it != mOthersList.end(); it++)
{
if (it->second.actions)
{
/* add in */
pqipeer peer;
peer.id = it->second.id;
peer.name = it->second.name;
peer.state = it->second.state;
peer.actions = it->second.actions;
/* reset action */
it->second.actions = 0;
#ifdef CONN_DEBUG
std::cerr << "Other: " << peer.name << " Id: " << peer.id << " State: " << peer.state;
if (peer.state & RS_PEER_S_FRIEND)
std::cerr << " S:RS_PEER_S_FRIEND";
if (peer.state & RS_PEER_S_ONLINE)
std::cerr << " S:RS_PEER_S_ONLINE";
if (peer.state & RS_PEER_S_CONNECTED)
std::cerr << " S:RS_PEER_S_CONNECTED";
std::cerr << " Actions: " << peer.actions;
if (peer.actions & RS_PEER_NEW)
std::cerr << " A:RS_PEER_NEW";
if (peer.actions & RS_PEER_MOVED)
std::cerr << " A:RS_PEER_MOVED";
if (peer.actions & RS_PEER_CONNECTED)
std::cerr << " A:RS_PEER_CONNECTED";
if (peer.actions & RS_PEER_DISCONNECTED)
std::cerr << " A:RS_PEER_DISCONNECTED";
if (peer.actions & RS_PEER_CONNECT_REQ)
std::cerr << " A:RS_PEER_CONNECT_REQ";
std::cerr << std::endl;
#endif
actionList.push_back(peer);
}
}
mStatusChanged = false;
doStatusChange = true;
}
} /****** UNLOCK STACK MUTEX ******/
/* NOTE - clients is accessed without mutex protection!!!!
* At the moment this is okay - as they are only added at the start.
* IF this changes ---- must fix with second Mutex.
*/
if (doStatusChange)
{
#ifdef CONN_DEBUG
std::cerr << "Sending to " << clients.size() << " monitorClients" << std::endl;
#endif
/* send to all monitors */
std::list<pqiMonitor *>::iterator mit;
for(mit = clients.begin(); mit != clients.end(); mit++)
{
(*mit)->statusChange(actionList);
}
}
}
const std::string p3ConnectMgr::getOwnId()
{
return AuthSSL::getAuthSSL()->OwnId();
}
bool p3ConnectMgr::getOwnNetStatus(peerConnectState &state)
{
//RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
state = ownState;
return true;
}
bool p3ConnectMgr::isFriend(std::string id)
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::isFriend(" << id << ") called" << std::endl;
#endif
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
bool ret = (mFriendList.end() != mFriendList.find(id));
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::isFriend(" << id << ") returning : " << ret << std::endl;
#endif
return ret;
}
bool p3ConnectMgr::isOnline(std::string id)
{
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
std::map<std::string, peerConnectState>::iterator it;
if (mFriendList.end() != (it = mFriendList.find(id)))
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::isOnline(" << id << ") is Friend, Online: " << (it->second.state & RS_PEER_S_CONNECTED) << std::endl;
#endif
return (it->second.state & RS_PEER_S_CONNECTED);
}
else
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::isOnline(" << id << ") is Not Friend" << std::endl << "p3ConnectMgr::isOnline() OwnId: " << AuthSSL::getAuthSSL()->OwnId() << std::endl;
#endif
/* not a friend */
}
return false;
}
bool p3ConnectMgr::getFriendNetStatus(std::string id, peerConnectState &state)
{
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
/* check for existing */
std::map<std::string, peerConnectState>::iterator it;
it = mFriendList.find(id);
if (it == mFriendList.end())
{
return false;
}
state = it->second;
return true;
}
bool p3ConnectMgr::getOthersNetStatus(std::string id, peerConnectState &state)
{
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
/* check for existing */
std::map<std::string, peerConnectState>::iterator it;
it = mOthersList.find(id);
if (it == mOthersList.end())
{
return false;
}
state = it->second;
return true;
}
void p3ConnectMgr::getOnlineList(std::list<std::string> &peers)
{
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
/* check for existing */
std::map<std::string, peerConnectState>::iterator it;
for(it = mFriendList.begin(); it != mFriendList.end(); it++)
{
if (it->second.state & RS_PEER_S_CONNECTED)
{
peers.push_back(it->first);
}
}
return;
}
void p3ConnectMgr::getFriendList(std::list<std::string> &peers)
{
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
/* check for existing */
std::map<std::string, peerConnectState>::iterator it;
for(it = mFriendList.begin(); it != mFriendList.end(); it++)
{
peers.push_back(it->first);
}
return;
}
//void p3ConnectMgr::getOthersList(std::list<std::string> &peers)
//{
// RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
//
// /* check for existing */
// std::map<std::string, peerConnectState>::iterator it;
// for(it = mOthersList.begin(); it != mOthersList.end(); it++)
// {
// peers.push_back(it->first);
// }
// return;
//}
bool p3ConnectMgr::connectAttempt(std::string id, struct sockaddr_in &addr,
uint32_t &delay, uint32_t &period, uint32_t &type)
{
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
/* check for existing */
std::map<std::string, peerConnectState>::iterator it;
it = mFriendList.find(id);
if (it == mFriendList.end())
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::connectAttempt() FAILED Not in FriendList! id: " << id << std::endl;
#endif
return false;
}
if (it->second.connAddrs.size() < 1)
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::connectAttempt() FAILED No ConnectAddresses id: " << id << std::endl;
#endif
return false;
}
if ((it->second.state & RS_PEER_S_CONNECTED) && it->second.connAddrs.front().type == RS_NET_CONN_TUNNEL) {
//don't do a tunnel atemp if already connected via tunnel
it->second.connAddrs.pop_front();
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::connectAttempt() avoiding tunnel connection attempt because already connected via tunnel. " << std::endl;
#endif
//returning next connect attempt.
if (it->second.connAddrs.size() < 1)
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::connectAttempt() FAILED No ConnectAddresses id: " << id << std::endl;
#endif
return false;
}
}
it->second.lastattempt = time(NULL) + rand() % 6;//add a random perturbation between 0 and 2 sec.
it->second.inConnAttempt = true;
it->second.currentConnAddrAttempt = it->second.connAddrs.front();
it->second.connAddrs.pop_front();
addr = it->second.currentConnAddrAttempt.addr;
delay = it->second.currentConnAddrAttempt.delay;
period = it->second.currentConnAddrAttempt.period;
type = it->second.currentConnAddrAttempt.type;
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::connectAttempt() found an address: id: " << id << std::endl;
std::cerr << " laddr: " << inet_ntoa(addr.sin_addr) << " lport: " << ntohs(addr.sin_port) << " delay: " << delay << " period: " << period;
std::cerr << " type: " << type << std::endl;
#endif
if (addr.sin_addr.s_addr == 0 || addr.sin_port == 0) {
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::connectAttempt() address or port is null, don't make the attempt." << std::endl;
std::cerr << " type: " << type << std::endl;
#endif
return false;
}
return true;
}
/****************************
* Update state,
* trigger retry if necessary,
*
* remove from DHT?
*
*/
bool p3ConnectMgr::connectResult(std::string id, bool success, uint32_t flags, struct sockaddr_in remote_peer_address)
{
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
rslog(RSL_WARNING, p3connectzone, "p3ConnectMgr::connectResult() called Connect!: id: " + id);
if (success) {
rslog(RSL_WARNING, p3connectzone, "p3ConnectMgr::connectResult() called with SUCCESS.");
} else {
rslog(RSL_WARNING, p3connectzone, "p3ConnectMgr::connectResult() called with FAILED.");
}
if (id == getOwnId()) {
#ifdef CONN_DEBUG
rslog(RSL_WARNING, p3connectzone, "p3ConnectMgr::connectResult() Failed, connecting to own id: ");
#endif
return false;
}
/* check for existing */
std::map<std::string, peerConnectState>::iterator it;
it = mFriendList.find(id);
if (it == mFriendList.end())
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::connectResult() Failed, missing Friend " << " id: " << id << std::endl;
#endif
return false;
}
if (success)
{
/* update address (will come although through from DISC) */
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::connectResult() Connect!: id: " << id << std::endl;
std::cerr << " Success: " << success << " flags: " << flags << std::endl;
#endif
rslog(RSL_WARNING, p3connectzone, "p3ConnectMgr::connectResult() Success");
/* change state */
it->second.state |= RS_PEER_S_CONNECTED;
it->second.actions |= RS_PEER_CONNECTED;
it->second.lastcontact = time(NULL); /* time of connect */
it->second.connecttype = flags;
//used to send back to the peer it's own ext address
it->second.currentserveraddr = remote_peer_address;
//add the ip address in the address list if we were in a connect attempt and the attempt address is the same as the connect result
if (it->second.inConnAttempt &&
it->second.currentConnAddrAttempt.addr.sin_addr.s_addr == remote_peer_address.sin_addr.s_addr &&
it->second.currentConnAddrAttempt.addr.sin_port == remote_peer_address.sin_port &&
remote_peer_address.sin_addr.s_addr != 0 &&
!(remote_peer_address.sin_addr.s_addr == ownState.currentlocaladdr.sin_addr.s_addr) &&
(!isLoopbackNet(&remote_peer_address.sin_addr))
) {
IpAddressTimed ipLocalAddressTimed;
ipLocalAddressTimed.ipAddr = remote_peer_address;
ipLocalAddressTimed.seenTime = time(NULL);
it->second.updateIpAddressList(ipLocalAddressTimed);
it->second.purgeIpAddressList();
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::connectResult() adding current peer adress in list." << std::endl;
it->second.printIpAddressList();
#endif
}
/* remove other attempts */
it->second.inConnAttempt = false;
it->second.connAddrs.clear();
netAssistFriend(id, false);
mStatusChanged = true;
return true;
}
it->second.inConnAttempt = false;
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::connectResult() Disconnect/Fail: id: " << id << std::endl;
std::cerr << " Success: " << success << " flags: " << flags << std::endl;
#endif
/* if currently connected -> flag as failed */
if (it->second.state & RS_PEER_S_CONNECTED)
{
it->second.state &= (~RS_PEER_S_CONNECTED);
it->second.actions |= RS_PEER_DISCONNECTED;
it->second.lastcontact = time(NULL); /* time of disconnect */
netAssistFriend(id, true);
}
if (it->second.connAddrs.size() < 1)
{
return true;
}
it->second.actions |= RS_PEER_CONNECT_REQ;
mStatusChanged = true;
return true;
}
bool p3ConnectMgr::doNextAttempt(std::string id)
{
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
rslog(RSL_WARNING, p3connectzone, "p3ConnectMgr::doNextAttempt() called id : " + id);
if (id == getOwnId()) {
#ifdef CONN_DEBUG
rslog(RSL_WARNING, p3connectzone, "p3ConnectMgr::doNextAttempt() Failed, connecting to own id: ");
#endif
return false;
}
/* check for existing */
std::map<std::string, peerConnectState>::iterator it;
it = mFriendList.find(id);
if (it == mFriendList.end())
{
rslog(RSL_WARNING, p3connectzone, "p3ConnectMgr::connectResult() Failed, missing Friend ");
return false;
}
it->second.inConnAttempt = false;
if ((it->second.state & RS_PEER_S_CONNECTED) && !(it->second.connecttype & RS_NET_CONN_TUNNEL)) {
rslog(RSL_WARNING, p3connectzone, "p3ConnectMgr::doNextAttempt() peer is already connected and not in tunnel mode, don't do next attempt.");
return true;
}
if (it->second.connAddrs.size() < 1)
{
return true;
}
it->second.actions |= RS_PEER_CONNECT_REQ;
mStatusChanged = true;
return true;
}
/******************************** Feedback ...... *********************************
* From various sources
*/
void p3ConnectMgr::peerStatus(std::string id,
struct sockaddr_in laddr, struct sockaddr_in raddr, std::list<IpAddressTimed> ipDiscAddressList,
uint32_t type, uint32_t flags, uint32_t source)
{
std::map<std::string, peerConnectState>::iterator it;
bool isFriend = true;
time_t now = time(NULL);
peerAddrInfo details;
details.type = type;
details.found = true;
details.laddr = laddr;
details.raddr = raddr;
details.ts = now;
{
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::peerStatus()" << " id: " << id << " laddr: " << inet_ntoa(laddr.sin_addr) << " lport: " << ntohs(laddr.sin_port);
std::cerr << " raddr: " << inet_ntoa(raddr.sin_addr) << " rport: " << ntohs(raddr.sin_port) << " type: " << type << " flags: " << flags;
std::cerr << " source: " << source << std::endl;
peerConnectState::printIpAddressList(ipDiscAddressList);
#endif
{
/* Log */
std::ostringstream out;
out << "p3ConnectMgr::peerStatus()" << " id: " << id << " laddr: " << inet_ntoa(laddr.sin_addr) << " lport: " << ntohs(laddr.sin_port);
out << " raddr: " << inet_ntoa(raddr.sin_addr) << " rport: " << ntohs(raddr.sin_port) << " type: " << type << " flags: " << flags << " source: " << source;
rslog(RSL_WARNING, p3connectzone, out.str());
}
/* look up the id */
it = mFriendList.find(id);
if (it == mFriendList.end())
{
/* check Others list */
isFriend = false;
it = mOthersList.find(id);
if (it == mOthersList.end())
{
/* not found - ignore */
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::peerStatus() Peer Not Found - Ignore" << std::endl;
#endif
return;
}
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::peerStatus() Peer is in mOthersList" << std::endl;
#endif
}
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::peerStatus() Current Peer State:" << std::endl;
printConnectState(it->second);
std::cerr << std::endl;
#endif
/* update the status */
/* if source is DHT */
if (source == RS_CB_DHT)
{
/* DHT can tell us about
* 1) connect type (UDP/TCP/etc)
* 2) local/external address
*/
it->second.source = RS_CB_DHT;
it->second.dht = details;
/* If we get a info -> then they are online */
it->second.state |= RS_PEER_S_ONLINE;
it->second.lastavailable = now;
/* if we are recieving these - the dht is definitely up.
*/
netFlagDhtOk = true;
}
else if (source == RS_CB_DISC)
{
/* DISC can tell us about
* 1) connect type (UDP/TCP/etc)
* 2) local/external addresses
*/
it->second.source = RS_CB_DISC;
it->second.disc = details;
it->second.updateIpAddressList(ipDiscAddressList);
it->second.currentlocaladdr = laddr;
it->second.currentserveraddr = raddr;
//add the given address to the address list
IpAddressTimed laddrTimed;
laddrTimed.ipAddr = laddr;
laddrTimed.seenTime = time(NULL);
it->second.updateIpAddressList(laddrTimed);
IpAddressTimed raddrTimed;
raddrTimed.ipAddr = raddr;
raddrTimed.seenTime = time(NULL);
it->second.updateIpAddressList(raddrTimed);
if (flags & RS_NET_FLAGS_ONLINE)
{
it->second.actions |= RS_PEER_ONLINE;
it->second.state |= RS_PEER_S_ONLINE;
it->second.lastavailable = now;
mStatusChanged = true;
}
/* not updating VIS status??? */
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
}
else if (source == RS_CB_PERSON)
{
/* PERSON can tell us about
* 1) online / offline
* 2) connect address
* -> update all!
*/
it->second.source = RS_CB_PERSON;
it->second.peer = details;
it->second.updateIpAddressList(ipDiscAddressList);
it->second.currentlocaladdr = laddr;
it->second.currentserveraddr = raddr;
//add the given address to the address list
IpAddressTimed laddrTimed;
laddrTimed.ipAddr = laddr;
laddrTimed.seenTime = time(NULL);
it->second.updateIpAddressList(laddrTimed);
IpAddressTimed raddrTimed;
raddrTimed.ipAddr = raddr;
raddrTimed.seenTime = time(NULL);
it->second.updateIpAddressList(raddrTimed);
it->second.state |= RS_PEER_S_ONLINE;
it->second.lastavailable = now;
/* must be online to recv info (should be connected too!)
* but no need for action as should be connected already
*/
it->second.netMode &= (~RS_NET_MODE_ACTUAL); /* clear actual flags */
if (flags & RS_NET_FLAGS_EXTERNAL_ADDR)
{
it->second.netMode = RS_NET_MODE_EXT;
}
else if (flags & RS_NET_FLAGS_STABLE_UDP)
{
it->second.netMode = RS_NET_MODE_UDP;
}
else
{
it->second.netMode = RS_NET_MODE_UNREACHABLE;
}
/* always update VIS status */
if (flags & RS_NET_FLAGS_USE_DISC)
{
it->second.visState &= (~RS_VIS_STATE_NODISC);
}
else
{
it->second.visState |= RS_VIS_STATE_NODISC;
}
if (flags & RS_NET_FLAGS_USE_DHT)
{
it->second.visState &= (~RS_VIS_STATE_NODHT);
}
else
{
it->second.visState |= RS_VIS_STATE_NODHT;
}
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
}
/* Determine Reachability (only advisory) */
if (ownState.netMode & RS_NET_MODE_UDP)
{
if ((details.type & RS_NET_CONN_UDP) ||
(details.type & RS_NET_CONN_TCP_EXTERNAL))
{
/* reachable! */
it->second.state &= (~RS_PEER_S_UNREACHABLE);
}
else
{
/* unreachable */
it->second.state |= RS_PEER_S_UNREACHABLE;
}
}
else if (ownState.netMode & RS_NET_MODE_UNREACHABLE)
{
if (details.type & RS_NET_CONN_TCP_EXTERNAL)
{
/* reachable! */
it->second.state &= (~RS_PEER_S_UNREACHABLE);
}
else
{
/* unreachable */
it->second.state |= RS_PEER_S_UNREACHABLE;
}
}
else
{
it->second.state &= (~RS_PEER_S_UNREACHABLE);
}
if (!isFriend)
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::peerStatus() NOT FRIEND " << " id: " << id << std::endl;
#endif
{
rslog(RSL_WARNING, p3connectzone, "p3ConnectMgr::peerStatus() NO CONNECT (not friend)");
}
return;
}
/* if already connected -> done */
if (it->second.state & RS_PEER_S_CONNECTED)
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::peerStatus() PEER ONLINE ALREADY " << " id: " << id << std::endl;
#endif
{
/* Log */
rslog(RSL_WARNING, p3connectzone, "p3ConnectMgr::peerStatus() NO CONNECT (already connected!)");
}
return;
}
} /****** STACK UNLOCK MUTEX *******/
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::peerStatus()" << " id: " << id << " laddr: " << inet_ntoa(laddr.sin_addr) << " lport: " << ntohs(laddr.sin_port);
std::cerr << " raddr: " << inet_ntoa(raddr.sin_addr) << " rport: " << ntohs(raddr.sin_port) << " type: " << type << " flags: " << flags;
std::cerr << " source: " << source << std::endl;
#endif
#ifndef P3CONNMGR_NO_AUTO_CONNECTION
#ifndef P3CONNMGR_NO_TCP_CONNECTIONS
retryConnectTCP(id);
#endif // P3CONNMGR_NO_TCP_CONNECTIONS
retryConnectNotify(id);
#else
#endif // P3CONNMGR_NO_AUTO_CONNECTION
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::peerStatus() Resulting Peer State:" << std::endl;
printConnectState(it->second);
std::cerr << std::endl;
#endif
}
void p3ConnectMgr::peerConnectRequest(std::string id, struct sockaddr_in raddr,
uint32_t source)
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::peerConnectRequest() id: " << id << " raddr: " << inet_ntoa(raddr.sin_addr) << ":" << ntohs(raddr.sin_port);
std::cerr << " source: " << source << std::endl;
#endif
{
/* Log */
std::ostringstream out;
out << "p3ConnectMgr::peerConnectRequest() id: " << id << " raddr: " << inet_ntoa(raddr.sin_addr);
out << ":" << ntohs(raddr.sin_port) << " source: " << source;
rslog(RSL_WARNING, p3connectzone, out.str());
}
/******************** TCP PART *****************************/
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::peerConnectRequest() Try TCP first" << std::endl;
#endif
retryConnect(id);
}
/*******************************************************************/
/*******************************************************************/
bool p3ConnectMgr::addFriend(std::string id, std::string gpg_id, uint32_t netMode, uint32_t visState, time_t lastContact)
{
if (id == AuthSSL::getAuthSSL()->OwnId()) {
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::addFriend() cannot add own id as a friend." << std::endl;
#endif
/* (1) already exists */
return false;
}
/* so four possibilities
* (1) already exists as friend -> do nothing.
* (2) is in others list -> move over.
* (3) is non-existant -> create new one.
*/
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::addFriend() " << id << "; gpg_id : " << gpg_id << std::endl;
#endif
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
std::map<std::string, peerConnectState>::iterator it;
if (mFriendList.end() != mFriendList.find(id))
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::addFriend() Already Exists" << std::endl;
#endif
/* (1) already exists */
return true;
}
//Authentication is now tested at connection time, we don't store the ssl cert anymore
if (!AuthGPG::getAuthGPG()->isGPGAccepted(gpg_id) && gpg_id != AuthGPG::getAuthGPG()->getGPGOwnId())
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::addFriend() gpg is not accepted" << std::endl;
#endif
/* no auth */
return false;
}
/* check if it is in others */
// if (mOthersList.end() != (it = mOthersList.find(id)))
if (false)
{
/* (2) in mOthersList -> move over */
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::addFriend() Move from Others" << std::endl;
#endif
mFriendList[id] = it->second;
mOthersList.erase(it);
it = mFriendList.find(id);
/* setup state */
it->second.state = RS_PEER_S_FRIEND;
it->second.actions = RS_PEER_NEW;
/* setup connectivity parameters */
it->second.visState = visState;
it->second.netMode = netMode;
it->second.lastcontact = lastContact;
mStatusChanged = true;
/* add peer to DHT (if not dark) */
if (it->second.visState & RS_VIS_STATE_NODHT)
{
/* hidden from DHT world */
netAssistFriend(id, false);
}
else
{
netAssistFriend(id, true);
}
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
return true;
}
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::addFriend() Creating New Entry" << std::endl;
#endif
/* create a new entry */
peerConnectState pstate;
pstate.id = id;
pstate.gpg_id = gpg_id;
pstate.name = AuthGPG::getAuthGPG()->getGPGName(gpg_id);
pstate.state = RS_PEER_S_FRIEND;
pstate.actions = RS_PEER_NEW;
pstate.visState = visState;
pstate.netMode = netMode;
pstate.lastcontact = lastContact;
/* addr & timestamps -> auto cleared */
mFriendList[id] = pstate;
mStatusChanged = true;
/* expect it to be a standard DHT */
netAssistFriend(id, true);
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
return true;
}
bool p3ConnectMgr::removeFriend(std::string id)
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::removeFriend() for id : " << id << std::endl;
std::cerr << "p3ConnectMgr::removeFriend() mFriendList.size() : " << mFriendList.size() << std::endl;
#endif
netAssistFriend(id, false);
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
/* move to othersList */
bool success = false;
std::list<std::string> toRemove;
std::map<std::string, peerConnectState>::iterator it;
//remove ssl and gpg_ids
for(it = mFriendList.begin(); it != mFriendList.end(); it++)
{
if (it->second.id == id || it->second.gpg_id == id) {
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::removeFriend() friend found in the list." << id << std::endl;
#endif
peerConnectState peer = it->second;
toRemove.push_back(it->second.id);
peer.state &= (~RS_PEER_S_FRIEND);
peer.state &= (~RS_PEER_S_CONNECTED);
peer.state &= (~RS_PEER_S_ONLINE);
peer.actions = RS_PEER_MOVED;
peer.inConnAttempt = false;
mOthersList[id] = peer;
mStatusChanged = true;
success = true;
}
}
std::list<std::string>::iterator toRemoveIt;
for(toRemoveIt = toRemove.begin(); toRemoveIt != toRemove.end(); toRemoveIt++) {
if (mFriendList.end() != (it = mFriendList.find(*toRemoveIt))) {
mFriendList.erase(it);
}
}
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::removeFriend() new mFriendList.size() : " << mFriendList.size() << std::endl;
#endif
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
return !toRemove.empty();
}
bool p3ConnectMgr::addNeighbour(std::string id)
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::addNeighbour() not implemented anymore." << id << std::endl;
#endif
/* so three possibilities
* (1) already exists as friend -> do nothing.
* (2) already in others list -> do nothing.
* (3) is non-existant -> create new one.
*/
// RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
//
// std::map<std::string, peerConnectState>::iterator it;
// if (mFriendList.end() == mFriendList.find(id))
// {
// /* (1) already exists */
// return false;
// }
//
// if (mOthersList.end() == mOthersList.find(id))
// {
// /* (2) already exists */
// return true;
// }
//
// /* check with the AuthMgr if its valid */
// if (!AuthSSL::getAuthSSL()->isAuthenticated(id))
// {
// /* no auth */
// return false;
// }
//
// /* get details from AuthMgr */
// sslcert detail;
// if (!AuthSSL::getAuthSSL()->getCertDetails(id, detail))
// {
// /* no details */
// return false;
// }
//
// /* create a new entry */
// peerConnectState pstate;
//
// pstate.id = id;
// pstate.name = detail.name;
//
// pstate.state = 0;
// pstate.actions = 0; //RS_PEER_NEW;
// pstate.visState = RS_VIS_STATE_STD;
// pstate.netMode = RS_NET_MODE_UNKNOWN;
//
// /* addr & timestamps -> auto cleared */
// mOthersList[id] = pstate;
return false;
}
/*******************************************************************/
/*******************************************************************/
/*************** External Control ****************/
bool p3ConnectMgr::retryConnect(std::string id)
{
retryConnectTCP(id);
retryConnectNotify(id);
return true;
}
bool p3ConnectMgr::retryConnectTCP(std::string id)
{
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
/* push addresses onto stack */
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::retryConnectTCP() id: " << id << std::endl;
#endif
if (id == getOwnId()) {
#ifdef CONN_DEBUG
rslog(RSL_WARNING, p3connectzone, "p3ConnectMgr::retryConnectTCP() Failed, connecting to own id: ");
#endif
return false;
}
/* look up the id */
std::map<std::string, peerConnectState>::iterator it;
if (mFriendList.end() == (it = mFriendList.find(id)))
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::retryConnectTCP() Peer is not Friend" << std::endl;
#endif
return false;
}
/* if already connected -> done */
if (it->second.state & RS_PEER_S_CONNECTED)
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::retryConnectTCP() Peer Already Connected" << std::endl;
#endif
if (it->second.connecttype & RS_NET_CONN_TUNNEL) {
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::retryConnectTCP() Peer Connected through a tunnel connection, let's try a normal connection." << std::endl;
#endif
} else {
return true;
}
}
//add the ips off the ipAdressList for TCP
std::list<IpAddressTimed> ipList = it->second.getIpAddressList();
for (std::list<IpAddressTimed>::iterator ipListIt = ipList.begin(); ipListIt!=(ipList.end()); ipListIt++) {
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::retryConnectTCP() adding ip : " << inet_ntoa(ipListIt->ipAddr.sin_addr);
std::cerr << ":" << ntohs(ipListIt->ipAddr.sin_port) << std::endl;
#endif
//check that the address doens't exist already in the connAddrs
bool found = false;
for (std::list<peerConnectAddress>::iterator cit = it->second.connAddrs.begin(); cit != it->second.connAddrs.end(); cit++) {
if (cit->addr.sin_addr.s_addr == ipListIt->ipAddr.sin_addr.s_addr &&
cit->addr.sin_port == ipListIt->ipAddr.sin_port &&
cit->type == RS_NET_CONN_TCP_UNKNOW_TOPOLOGY) {
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::retryConnectTCP() tcp attempt already in list." << std::endl;
#endif
found = true;
break;
}
}
if (!found) {
#ifdef CONN_DEBUG
std::cerr << "Adding tcp connection attempt list." << std::endl;
#endif
peerConnectAddress pca;
pca.addr = ipListIt->ipAddr;
pca.type = RS_NET_CONN_TCP_UNKNOW_TOPOLOGY;
//fir the delay, we add a random time and some more time when the friend list is big
pca.delay = P3CONNMGR_TCP_DEFAULT_DELAY + rand() % 3 + (mFriendList.size() / 5);
pca.ts = time(NULL);
pca.period = 0;
it->second.connAddrs.push_back(pca);
}
}
//add the supposed external address UDP
IpAddressTimed extractedAddress;
if (peerConnectState::extractExtAddress(it->second.getIpAddressList(), extractedAddress)) {
#ifdef CONN_DEBUG
rslog(RSL_DEBUG_BASIC, p3connectzone, "p3ConnectMgr::retryConnectTCP() got a valid external address for UDP connection");
#endif
//check that the UDP attempt doens't exist already in the connAddrs
bool found = false;
for (std::list<peerConnectAddress>::iterator cit = it->second.connAddrs.begin(); cit != it->second.connAddrs.end(); cit++) {
if ( cit->type == RS_NET_CONN_UDP) {
#ifdef CONN_DEBUG
rslog(RSL_DEBUG_BASIC, p3connectzone, "p3ConnectMgr::retryConnectTCP() udp attempt already in list.");
#endif
found = true;
break;
}
}
if (!found) {
#ifdef CONN_DEBUG
rslog(RSL_DEBUG_BASIC, p3connectzone, "p3ConnectMgr::retryConnectTCP() Adding udp connection attempt.");
#endif
peerConnectAddress pca;
pca.addr = extractedAddress.ipAddr;
pca.type = RS_NET_CONN_UDP;
pca.delay = P3CONNMGR_UDP_DEFAULT_DELAY;
pca.ts = time(NULL);
// pseudo random number generator from Wikipedia/Numerical Recipies.
pca.period = P3CONNMGR_UDP_DEFAULT_PERIOD + ((time(NULL)*1664525 + 1013904223) % P3CONNMGR_UDP_DEFAULT_PERIOD); //add a random period between 1 and 2 times P3CONNMGR_UDP_DEFAULT_PERIOD
it->second.connAddrs.push_back(pca);
}
} else {
#ifdef CONN_DEBUG
rslog(RSL_DEBUG_BASIC, p3connectzone, "p3ConnectMgr::retryConnectTCP() no valid external address found for udp connection.");
#endif
}
//ad the tunnel attempt
bool found = false;
for (std::list<peerConnectAddress>::iterator cit = it->second.connAddrs.begin(); cit != it->second.connAddrs.end(); cit++) {
if (cit->type == RS_NET_CONN_TUNNEL) {
#ifdef CONN_DEBUG
rslog(RSL_DEBUG_BASIC, p3connectzone, "p3ConnectMgr::retryConnectTCP() tunnel is already in the list.");
#endif
found = true;
break;
}
}
if (!(it->second.state & RS_PEER_S_CONNECTED) && !found && allow_tunnel_connection)
{
#ifdef CONN_DEBUG
rslog(RSL_DEBUG_BASIC, p3connectzone, "p3ConnectMgr::retryConnectTCP() Add the tunnel connection attempt.");
#endif
peerConnectAddress pca;
pca.type = RS_NET_CONN_TUNNEL;
pca.ts = time(NULL);
pca.period = 0;
//we've got to set an address to avoid null pointer or some other bug
if (peerConnectState::extractExtAddress(it->second.getIpAddressList(), extractedAddress)) {
pca.addr = extractedAddress.ipAddr;
} else {
sockaddr_clear(&pca.addr);
pca.addr.sin_addr.s_addr = 1;
pca.addr.sin_port = 1;
}
it->second.connAddrs.push_back(pca);
}
/* flag as last attempt to prevent loop */
it->second.lastattempt = time(NULL) + rand() % 6;//add a random perturbation between 0 and 2 sec.
if (it->second.inConnAttempt) {
/* -> it'll automatically use the addresses we added */
return true;
}
/* start a connection attempt */
if (it->second.connAddrs.size() > 0) {
#ifdef CONN_DEBUG
std::ostringstream out;
out << "p3ConnectMgr::retryConnectTCP() Started CONNECT ATTEMPT! " << " id: " << id ;
rslog(RSL_DEBUG_ALERT, p3connectzone, out.str());
#endif
it->second.actions |= RS_PEER_CONNECT_REQ;
mStatusChanged = true;
} else {
#ifdef CONN_DEBUG
std::ostringstream out;
out << "p3ConnectMgr::retryConnectTCP() No addr in the connect attempt list. Not suitable for CONNECT ATTEMPT! " << " id: " << id;
rslog(RSL_DEBUG_ALERT, p3connectzone, out.str());
#endif
}
return true;
}
bool p3ConnectMgr::retryConnectNotify(std::string id)
{
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
/* push addresses onto stack */
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::retryConnectNotify() id: " << id << std::endl;
#endif
/* look up the id */
std::map<std::string, peerConnectState>::iterator it;
if (mFriendList.end() == (it = mFriendList.find(id)))
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::retryConnectNotify() Peer is not Friend" << std::endl;
#endif
return false;
}
/* if already connected -> done */
if (it->second.state & RS_PEER_S_CONNECTED)
{
if (it->second.currentConnAddrAttempt.type & RS_NET_CONN_TUNNEL) {
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::retryConnectNotify() Peer Connected through a tunnel connection, let's try a normal connection." << std::endl;
#endif
} else {
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::retryConnectNotify() Peer Already Connected, aborting retryConnect" << std::endl;
#endif
return true;
}
}
/* flag as last attempt to prevent loop */
it->second.lastattempt = time(NULL) + rand() % 6;//add a random perturbation between 0 and 2 sec.
if (ownState.netMode & RS_NET_MODE_UNREACHABLE)
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::retryConnectNotify() UNREACHABLE so no Notify! id: " << id << std::endl;
#endif
}
else
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::retryConnectNotify() Notifying Peer id: " << id << std::endl;
#endif
{
/* Log */
std::ostringstream out;
out << "p3ConnectMgr::retryConnectNotify() Notifying Peer";
out << " id: " << id;
rslog(RSL_WARNING, p3connectzone, out.str());
}
/* attempt UDP connection */
netAssistNotify(id);
}
return true;
}
bool p3ConnectMgr::setLocalAddress(std::string id, struct sockaddr_in addr)
{
if (id == AuthSSL::getAuthSSL()->OwnId())
{
{
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
ownState.currentlocaladdr = addr;
//avoid 0 for port and address
if (ownState.currentlocaladdr.sin_addr.s_addr == 0) {
ownState.currentlocaladdr.sin_addr.s_addr = 1;
}
if (addr.sin_port == 0) {
ownState.currentlocaladdr.sin_port = 1;
}
}
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
if ((ownState.netMode & RS_NET_MODE_ACTUAL) == RS_NET_MODE_EXT ||
(ownState.netMode & RS_NET_MODE_ACTUAL) == RS_NET_MODE_UDP) {
netReset();
}
return true;
}
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
/* check if it is a friend */
std::map<std::string, peerConnectState>::iterator it;
if (mFriendList.end() == (it = mFriendList.find(id)))
{
if (mOthersList.end() == (it = mOthersList.find(id)))
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::setLocalAddress() cannot add addres info : peer id not found in friend list id: " << id << std::endl;
#endif
return false;
}
}
/* "it" points to peer */
it->second.currentlocaladdr = addr;
//update ip address list
IpAddressTimed ipAddressTimed;
ipAddressTimed.ipAddr = addr;
ipAddressTimed.seenTime = time(NULL);
it->second.updateIpAddressList(ipAddressTimed);
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
return true;
}
bool p3ConnectMgr::setExtAddress(std::string id, struct sockaddr_in addr)
{
if (id == AuthSSL::getAuthSSL()->OwnId())
{
if (ownState.currentserveraddr.sin_addr.s_addr != addr.sin_addr.s_addr ||
ownState.currentserveraddr.sin_port != addr.sin_port) {
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
ownState.currentserveraddr = addr;
//check port and address
if (ownState.currentserveraddr.sin_addr.s_addr == 0 || ownState.currentserveraddr.sin_port == 0 ||
ownState.currentserveraddr.sin_addr.s_addr == 1|| ownState.currentserveraddr.sin_port == 1 ||
std::string(inet_ntoa(ownState.currentserveraddr.sin_addr)) == "1.1.1.1") {
//try to extract ext address from the ip address list
IpAddressTimed extractedAddress;
if (peerConnectState::extractExtAddress(ownState.getIpAddressList(), extractedAddress)) {
ownState.currentserveraddr = extractedAddress.ipAddr;
} else {
ownState.currentserveraddr = ownState.currentlocaladdr;
}
}
}
return true;
}
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
/* check if it is a friend */
std::map<std::string, peerConnectState>::iterator it;
if (mFriendList.end() == (it = mFriendList.find(id)))
{
if (mOthersList.end() == (it = mOthersList.find(id)))
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::setLocalAddress() cannot add addres info : peer id not found in friend list id: " << id << std::endl;
#endif
return false;
}
}
/* "it" points to peer */
it->second.currentserveraddr = addr;
//update ip address list
IpAddressTimed ipAddressTimed;
ipAddressTimed.ipAddr = addr;
ipAddressTimed.seenTime = time(NULL);
it->second.updateIpAddressList(ipAddressTimed);
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
return true;
}
bool p3ConnectMgr::setAddressList(std::string id, std::list<IpAddressTimed> IpAddressTimedList)
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::setAddressList() called for id : " << id << std::endl;
#endif
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
/* check if it is our own ip */
if (id == getOwnId()) {
ownState.updateIpAddressList(IpAddressTimedList);
//if we have no ext address from upnp or extAdrFinder, we will use this list for ext ip detection
//useless, already done in network consistency check
// sockaddr_in extAddr;
// if (!getExtFinderExtAddress(extAddr) && !getUpnpExtAddress(extAddr)) { //TODO fix it
// IpAddressTimed extractedAddress;
// if (peerConnectState::extractExtAddress(IpAddressTimedList, extractedAddress)) {
// #ifdef CONN_DEBUG
// std::cerr << "p3ConnectMgr::setAddressList() using ip address list to set external addres." << std::endl;
// #endif
// ownState.currentserveraddr.sin_addr = extractedAddress.ipAddr.sin_addr;
// IndicateConfigChanged();
// } else {
// #ifdef CONN_DEBUG
// std::cerr << "p3ConnectMgr::setAddressList() no valuable ext adress found." << std::endl;
// #endif
// }
// }
return true;
}
/* check if it is a friend */
std::map<std::string, peerConnectState>::iterator it;
if (mFriendList.end() == (it = mFriendList.find(id)))
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::setLocalAddress() cannot add addres info : peer id not found in friend list. id: " << id << std::endl;
#endif
return false;
}
/* "it" points to peer */
it->second.updateIpAddressList(IpAddressTimedList);
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
return true;
}
bool p3ConnectMgr::setNetworkMode(std::string id, uint32_t netMode)
{
if (id == AuthSSL::getAuthSSL()->OwnId())
{
uint32_t visState = ownState.visState;
setOwnNetConfig(netMode, visState);
if ((netMode & RS_NET_MODE_ACTUAL) != (ownState.netMode & RS_NET_MODE_ACTUAL)) {
netReset();
}
return true;
}
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
/* check if it is a friend */
std::map<std::string, peerConnectState>::iterator it;
if (mFriendList.end() == (it = mFriendList.find(id)))
{
if (mOthersList.end() == (it = mOthersList.find(id)))
{
return false;
}
}
/* "it" points to peer */
it->second.netMode = netMode;
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
return false;
}
bool p3ConnectMgr::setLocation(std::string id, std::string location)
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::setLocation() called for id : " << id << "; with location " << location << std::endl;
#endif
if (id == AuthSSL::getAuthSSL()->OwnId())
{
ownState.location = location;
return true;
}
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
/* check if it is a friend */
std::map<std::string, peerConnectState>::iterator it;
bool isFriend = false;
if (mFriendList.end() == (it = mFriendList.find(id))) {
return false;
} else {
it->second.location = location;
return true;
}
}
bool p3ConnectMgr::setVisState(std::string id, uint32_t visState)
{
if (id == AuthSSL::getAuthSSL()->OwnId())
{
ownState.visState = visState;
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
return true;
}
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
/* check if it is a friend */
std::map<std::string, peerConnectState>::iterator it;
bool isFriend = false;
if (mFriendList.end() == (it = mFriendList.find(id)))
{
if (mOthersList.end() == (it = mOthersList.find(id)))
{
return false;
}
}
else
{
isFriend = true;
}
/* "it" points to peer */
it->second.visState = visState;
if (isFriend)
{
/* toggle DHT state */
if (it->second.visState & RS_VIS_STATE_NODHT)
{
/* hidden from DHT world */
netAssistFriend(id, false);
}
else
{
netAssistFriend(id, true);
}
}
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
return false;
}
/*******************************************************************/
bool p3ConnectMgr::checkNetAddress()
{
in_addr_t old_in_addr = ownState.currentlocaladdr.sin_addr.s_addr;
int old_in_port = ownState.currentlocaladdr.sin_port;
{
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
// GetPreferredInterface now chooses the best local ilterface for you. So it's the default function to use now.
//
ownState.currentlocaladdr.sin_addr = getPreferredInterface() ;
if(ownState.currentlocaladdr.sin_addr.s_addr != 0 && !isLoopbackNet(&(ownState.currentlocaladdr.sin_addr)))
{
if (netFlagLocalOk != true)
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::checkNetAddress() changing netFlagOk to true." << std::endl;
#endif
netFlagLocalOk = true;
IndicateConfigChanged();
}
} else {
if (netFlagLocalOk != false)
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::checkNetAddress() changing netFlagOk to false." << std::endl;
#endif
netFlagLocalOk = false;
netFlagExtraAddressCheckOk = false;
netFlagUpnpOk = false;
netFlagDhtOk = false;
netFlagStunOk = false;
IndicateConfigChanged();
}
}
if(isLoopbackNet(&(ownState.currentlocaladdr.sin_addr)))
mNetStatus = RS_NET_LOOPBACK;
int port = ntohs(ownState.currentlocaladdr.sin_port);
if ((port < PQI_MIN_PORT) || (port > PQI_MAX_PORT))
ownState.currentlocaladdr.sin_port = htons(PQI_DEFAULT_PORT);
/* if localaddr = serveraddr, then ensure that the ports
* are the same (modify server)... this mismatch can
* occur when the local port is changed....
*/
if (ownState.currentlocaladdr.sin_addr.s_addr == ownState.currentserveraddr.sin_addr.s_addr)
ownState.currentserveraddr.sin_port = ownState.currentlocaladdr.sin_port;
// ensure that address family is set, otherwise windows Barfs.
ownState.currentlocaladdr.sin_family = AF_INET;
ownState.currentserveraddr.sin_family = AF_INET;
//update ip address list
IpAddressTimed ipAddressTimed;
ipAddressTimed.ipAddr = ownState.currentlocaladdr;
ipAddressTimed.seenTime = time(NULL);
ownState.updateIpAddressList(ipAddressTimed);
#ifdef CONN_DEBUG_TICK
std::cerr << "p3ConnectMgr::checkNetAddress() Final Local Address: " << inet_ntoa(ownState.currentlocaladdr.sin_addr);
std::cerr << ":" << ntohs(ownState.currentlocaladdr.sin_port) << std::endl;
#endif
}
if ((old_in_addr != ownState.currentlocaladdr.sin_addr.s_addr) || (old_in_port != ownState.currentlocaladdr.sin_port))
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::checkNetAddress() local address changed, resetting network." << std::endl;
#endif
netReset();
}
return 1;
}
/************************* p3config functions **********************/
/*******************************************************************/
/* Key Functions to be overloaded for Full Configuration */
RsSerialiser *p3ConnectMgr::setupSerialiser()
{
RsSerialiser *rss = new RsSerialiser();
rss->addSerialType(new RsPeerConfigSerialiser());
rss->addSerialType(new RsGeneralConfigSerialiser()) ;
return rss;
}
std::list<RsItem *> p3ConnectMgr::saveList(bool &cleanup)
{
/* create a list of current peers */
std::list<RsItem *> saveData;
cleanup = true;
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
RsPeerNetItem *item = new RsPeerNetItem();
item->clear();
item->pid = getOwnId();
item->gpg_id = ownState.gpg_id;
item->location = ownState.location;
if (ownState.netMode & RS_NET_MODE_TRY_EXT)
{
item->netMode = RS_NET_MODE_EXT;
}
else if (ownState.netMode & RS_NET_MODE_TRY_UPNP)
{
item->netMode = RS_NET_MODE_UPNP;
}
else
{
item->netMode = RS_NET_MODE_UDP;
}
item->visState = ownState.visState;
item->lastContact = ownState.lastcontact;
item->currentlocaladdr = ownState.currentlocaladdr;
item->currentremoteaddr = ownState.currentserveraddr;
item->ipAddressList = ownState.getIpAddressList();
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::saveList() Own Config Item:" << std::endl;
item->print(std::cerr, 10);
std::cerr << std::endl;
#endif
saveData.push_back(item);
/* iterate through all friends and save */
std::map<std::string, peerConnectState>::iterator it;
for(it = mFriendList.begin(); it != mFriendList.end(); it++)
{
item = new RsPeerNetItem();
item->clear();
item->pid = it->first;
item->gpg_id = (it->second).gpg_id;
item->location = (it->second).location;
item->netMode = (it->second).netMode;
item->visState = (it->second).visState;
item->lastContact = (it->second).lastcontact;
item->currentlocaladdr = (it->second).currentlocaladdr;
item->currentremoteaddr = (it->second).currentserveraddr;
item->ipAddressList = (it->second).getIpAddressList();
saveData.push_back(item);
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::saveList() Peer Config Item:" << std::endl;
item->print(std::cerr, 10);
std::cerr << std::endl;
#endif
}
RsPeerStunItem *sitem = new RsPeerStunItem();
std::list<std::string>::iterator sit;
uint32_t count = 0;
for(sit = mStunList.begin(); (sit != mStunList.end()) &&
(count < RS_STUN_LIST_MIN); sit++, count++)
{
sitem->stunList.ids.push_back(*sit);
}
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::saveList() Peer Stun Item:" << std::endl;
sitem->print(std::cerr, 10);
std::cerr << std::endl;
#endif
saveData.push_back(sitem);
// Now save config for network digging strategies
RsConfigKeyValueSet *vitem = new RsConfigKeyValueSet ;
RsTlvKeyValue kv;
kv.key = "USE_EXTR_IP_FINDER" ;
kv.value = (use_extr_addr_finder)?"TRUE":"FALSE" ;
vitem->tlvkvs.pairs.push_back(kv) ;
#ifdef CONN_DEBUG
std::cout << "Pushing item for use_extr_addr_finder = " << use_extr_addr_finder << std::endl ;
#endif
saveData.push_back(vitem);
// Now save config for network digging strategies
RsConfigKeyValueSet *vitem2 = new RsConfigKeyValueSet ;
RsTlvKeyValue kv2;
kv2.key = "ALLOW_TUNNEL_CONNECTION" ;
kv2.value = (allow_tunnel_connection)?"TRUE":"FALSE" ;
vitem2->tlvkvs.pairs.push_back(kv2) ;
#ifdef CONN_DEBUG
std::cout << "Pushing item for allow_tunnel_connection = " << allow_tunnel_connection << std::endl ;
#endif
saveData.push_back(vitem2);
return saveData;
}
bool p3ConnectMgr::loadList(std::list<RsItem *> load)
{
if (load.size() == 0) {
std::cerr << "p3ConnectMgr::loadList() list is empty, it may be a configuration problem." << std::endl;
return false;
}
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::loadList() Item Count: " << load.size() << std::endl;
#endif
/* load the list of peers */
std::list<RsItem *>::iterator it;
for(it = load.begin(); it != load.end(); it++)
{
RsPeerNetItem *pitem = dynamic_cast<RsPeerNetItem *>(*it);
RsPeerStunItem *sitem = dynamic_cast<RsPeerStunItem *>(*it);
RsConfigKeyValueSet *vitem = dynamic_cast<RsConfigKeyValueSet *>(*it) ;
if (pitem)
{
if (pitem->pid == getOwnId())
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::loadList() Own Config Item:" << std::endl;
pitem->print(std::cerr, 10);
std::cerr << std::endl;
#endif
/* add ownConfig */
setOwnNetConfig(pitem->netMode, pitem->visState);
ownState.gpg_id = AuthGPG::getAuthGPG()->getGPGOwnId();
ownState.location = AuthSSL::getAuthSSL()->getOwnLocation();
}
else
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::loadList() Peer Config Item:" << std::endl;
pitem->print(std::cerr, 10);
std::cerr << std::endl;
#endif
/* ************* */
addFriend(pitem->pid, pitem->gpg_id, pitem->netMode, pitem->visState, pitem->lastContact);
setLocation(pitem->pid, pitem->location);
}
setLocalAddress(pitem->pid, pitem->currentlocaladdr);
setExtAddress(pitem->pid, pitem->currentremoteaddr);
setAddressList(pitem->pid, pitem->ipAddressList);
}
else if (sitem)
{
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::loadList() Stun Config Item:" << std::endl;
sitem->print(std::cerr, 10);
std::cerr << std::endl;
#endif
std::list<std::string>::iterator sit;
for(sit = sitem->stunList.ids.begin();
sit != sitem->stunList.ids.end(); sit++)
{
mStunList.push_back(*sit);
}
}
else if(vitem)
{
RsStackMutex stack(connMtx); /****** STACK LOCK MUTEX *******/
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::loadList() General Variable Config Item:" << std::endl;
vitem->print(std::cerr, 10);
std::cerr << std::endl;
#endif
std::list<RsTlvKeyValue>::iterator kit;
for(kit = vitem->tlvkvs.pairs.begin(); kit != vitem->tlvkvs.pairs.end(); kit++) {
if(kit->key == "USE_EXTR_IP_FINDER") {
use_extr_addr_finder = (kit->value == "TRUE");
std::cerr << "setting use_extr_addr_finder to " << use_extr_addr_finder << std::endl ;
} else if (kit->key == "ALLOW_TUNNEL_CONNECTION") {
allow_tunnel_connection = (kit->value == "TRUE");
std::cerr << "setting allow_tunnel_connection to " << allow_tunnel_connection << std::endl ;
}
}
}
delete (*it);
}
return true;
}
void printConnectState(peerConnectState &peer)
{
#ifdef CONN_DEBUG
std::cerr << "Friend: " << peer.name << " Id: " << peer.id << " State: " << peer.state;
if (peer.state & RS_PEER_S_FRIEND)
std::cerr << " S:RS_PEER_S_FRIEND";
if (peer.state & RS_PEER_S_ONLINE)
std::cerr << " S:RS_PEER_S_ONLINE";
if (peer.state & RS_PEER_S_CONNECTED)
std::cerr << " S:RS_PEER_S_CONNECTED";
std::cerr << " Actions: " << peer.actions;
if (peer.actions & RS_PEER_NEW)
std::cerr << " A:RS_PEER_NEW";
if (peer.actions & RS_PEER_MOVED)
std::cerr << " A:RS_PEER_MOVED";
if (peer.actions & RS_PEER_CONNECTED)
std::cerr << " A:RS_PEER_CONNECTED";
if (peer.actions & RS_PEER_DISCONNECTED)
std::cerr << " A:RS_PEER_DISCONNECTED";
if (peer.actions & RS_PEER_CONNECT_REQ)
std::cerr << " A:RS_PEER_CONNECT_REQ";
std::cerr << std::endl;
#endif
return;
}
bool p3ConnectMgr::addBootstrapStunPeers()
{
std::string id;
struct sockaddr_in dummyaddr;
uint32_t flags = 0;
/* only use the Bootstrap system now */
return true;
}
/************************ INTERFACES ***********************/
void p3ConnectMgr::addNetAssistFirewall(uint32_t id, pqiNetAssistFirewall *fwAgent)
{
mFwAgents[id] = fwAgent;
}
bool p3ConnectMgr::enableNetAssistFirewall(bool on)
{
std::map<uint32_t, pqiNetAssistFirewall *>::iterator it;
for(it = mFwAgents.begin(); it != mFwAgents.end(); it++)
{
(it->second)->enable(on);
}
return true;
}
bool p3ConnectMgr::netAssistFirewallEnabled()
{
std::map<uint32_t, pqiNetAssistFirewall *>::iterator it;
for(it = mFwAgents.begin(); it != mFwAgents.end(); it++)
{
if ((it->second)->getEnabled())
{
return true;
}
}
return false;
}
bool p3ConnectMgr::netAssistFirewallActive()
{
std::map<uint32_t, pqiNetAssistFirewall *>::iterator it;
for(it = mFwAgents.begin(); it != mFwAgents.end(); it++)
{
if ((it->second)->getActive())
{
return true;
}
}
return false;
}
bool p3ConnectMgr::netAssistFirewallShutdown()
{
std::map<uint32_t, pqiNetAssistFirewall *>::iterator it;
for(it = mFwAgents.begin(); it != mFwAgents.end(); it++)
{
(it->second)->shutdown();
}
return true;
}
bool p3ConnectMgr::netAssistFirewallPorts(uint16_t iport, uint16_t eport)
{
std::map<uint32_t, pqiNetAssistFirewall *>::iterator it;
for(it = mFwAgents.begin(); it != mFwAgents.end(); it++)
{
(it->second)->setInternalPort(iport);
(it->second)->setExternalPort(eport);
}
return true;
}
bool p3ConnectMgr::netAssistExtAddress(struct sockaddr_in &extAddr)
{
std::map<uint32_t, pqiNetAssistFirewall *>::iterator it;
for(it = mFwAgents.begin(); it != mFwAgents.end(); it++)
{
if ((it->second)->getActive())
{
if ((it->second)->getExternalAddress(extAddr))
{
return true;
}
}
}
return false;
}
void p3ConnectMgr::addNetAssistConnect(uint32_t id, pqiNetAssistConnect *dht)
{
mDhts[id] = dht;
}
bool p3ConnectMgr::enableNetAssistConnect(bool on)
{
std::map<uint32_t, pqiNetAssistConnect *>::iterator it;
for(it = mDhts.begin(); it != mDhts.end(); it++)
{
(it->second)->enable(on);
}
return true;
}
bool p3ConnectMgr::netAssistConnectEnabled()
{
std::map<uint32_t, pqiNetAssistConnect *>::iterator it;
for(it = mDhts.begin(); it != mDhts.end(); it++)
{
if ((it->second)->getEnabled())
{
return true;
}
}
return false;
}
bool p3ConnectMgr::netAssistConnectActive()
{
std::map<uint32_t, pqiNetAssistConnect *>::iterator it;
for(it = mDhts.begin(); it != mDhts.end(); it++)
{
if ((it->second)->getActive())
{
return true;
}
}
return false;
}
bool p3ConnectMgr::netAssistConnectShutdown()
{
std::map<uint32_t, pqiNetAssistConnect *>::iterator it;
for(it = mDhts.begin(); it != mDhts.end(); it++)
{
(it->second)->shutdown();
}
return true;
}
bool p3ConnectMgr::netAssistFriend(std::string id, bool on)
{
std::map<uint32_t, pqiNetAssistConnect *>::iterator it;
for(it = mDhts.begin(); it != mDhts.end(); it++)
{
if (on)
{
(it->second)->findPeer(id);
}
else
{
(it->second)->dropPeer(id);
}
}
return true;
}
bool p3ConnectMgr::netAssistAddStun(std::string id)
{
std::map<uint32_t, pqiNetAssistConnect *>::iterator it;
for(it = mDhts.begin(); it != mDhts.end(); it++)
{
(it->second)->addStun(id);
}
return true;
}
bool p3ConnectMgr::netAssistStun(bool on)
{
std::map<uint32_t, pqiNetAssistConnect *>::iterator it;
for(it = mDhts.begin(); it != mDhts.end(); it++)
{
(it->second)->enableStun(on);
}
return true;
}
bool p3ConnectMgr::netAssistNotify(std::string id)
{
std::map<uint32_t, pqiNetAssistConnect *>::iterator it;
for(it = mDhts.begin(); it != mDhts.end(); it++)
{
(it->second)->notifyPeer(id);
}
return true;
}
bool p3ConnectMgr::netAssistSetAddress( struct sockaddr_in &laddr,
struct sockaddr_in &eaddr,
uint32_t mode)
{
std::map<uint32_t, pqiNetAssistConnect *>::iterator it;
for(it = mDhts.begin(); it != mDhts.end(); it++)
{
(it->second)->setExternalInterface(laddr, eaddr, mode);
}
return true;
}
bool p3ConnectMgr::getUPnPState()
{
return netAssistFirewallActive();
}
bool p3ConnectMgr::getUPnPEnabled()
{
return netAssistFirewallEnabled();
}
bool p3ConnectMgr::getDHTEnabled()
{
return netAssistConnectEnabled();
}
bool p3ConnectMgr::getNetStatusLocalOk()
{
return netFlagLocalOk;
}
bool p3ConnectMgr::getNetStatusUpnpOk()
{
return netFlagUpnpOk;
}
bool p3ConnectMgr::getNetStatusDhtOk()
{
return netFlagDhtOk;
}
bool p3ConnectMgr::getNetStatusStunOk()
{
return netFlagStunOk;
}
bool p3ConnectMgr::getNetStatusExtraAddressCheckOk()
{
return netFlagExtraAddressCheckOk;
}
bool p3ConnectMgr::getUpnpExtAddress(struct sockaddr_in &addr) {
return netAssistExtAddress(addr);
}
bool p3ConnectMgr::getStunExtAddress(struct sockaddr_in &addr) {
struct sockaddr_in temp_addr;
socklen_t len = sizeof(temp_addr);
uint8_t stable;
if (0 < tou_extaddr((struct sockaddr *) &temp_addr, &len, &stable))
{
addr = temp_addr;
//#ifdef CONN_DEBUG
// std::cerr << "p3ConnectMgr::getStunExtAddress() Got ";
// std::cerr << " addr: " << inet_ntoa(addr.sin_addr);
// std::cerr << ":" << ntohs(addr.sin_port);
// std::cerr << std::endl;
//#endif
return true;
}
//#ifdef CONN_DEBUG
// std::cerr << "p3ConnectMgr::getStunExtAddress() No ext address found." << std::endl;
//#endif
return false;
}
bool p3ConnectMgr::getExtFinderExtAddress(struct sockaddr_in &addr) {
if ((use_extr_addr_finder && mExtAddrFinder->hasValidIP(&addr))) {
addr.sin_port = ownState.currentlocaladdr.sin_port;
return true;
} else {
return false;
}
}
bool peerConnectState::compare_seen_time (IpAddressTimed first, IpAddressTimed second) { //Sort the ip list ordering by seen time
return (first.seenTime < second.seenTime);
}
bool peerConnectState::is_same_address(IpAddressTimed first, IpAddressTimed second) { //Sort the ip list ordering by seen time
return (first.ipAddr.sin_addr.s_addr == second.ipAddr.sin_addr.s_addr && first.ipAddr.sin_port == second.ipAddr.sin_port);
}
void peerConnectState::sortIpAddressListBySeenTime() { //Sort the ip list ordering by seen time
sortIpAddressListBySeenTime(this->ipAddressList);
}
void peerConnectState::sortIpAddressListBySeenTime(std::list<IpAddressTimed> &ipTimedListInput) { //Sort the ip list ordering by seen time
ipTimedListInput.sort(peerConnectState::compare_seen_time);
ipTimedListInput.reverse();
}
std::list<IpAddressTimed> peerConnectState::getIpAddressList() {
purgeIpAddressList();
return ipAddressList;
}
void peerConnectState::purgeIpAddressList() {//purge old and useless addresses to keep a small list
std::list<IpAddressTimed>::iterator ipListIt;
for (ipListIt = ipAddressList.begin(); ipListIt!=(ipAddressList.end());) {
if (ipListIt->ipAddr.sin_addr.s_addr == 0 || ipListIt->ipAddr.sin_port == 0 ||
ipListIt->ipAddr.sin_addr.s_addr == 1|| ipListIt->ipAddr.sin_port == 1 ||
std::string(inet_ntoa(ipListIt->ipAddr.sin_addr)) == "1.1.1.1") {
ipAddressList.erase(ipListIt++);
} else {
++ipListIt;
}
}
//purge duplicates
for (ipListIt = ipAddressList.begin(); ipListIt!=(ipAddressList.end()); ipListIt++) {
std::list<IpAddressTimed>::iterator ipListIt2 = ipListIt;
++ipListIt2;
while (ipListIt2!=(ipAddressList.end())) {
if (is_same_address(*ipListIt2, *ipListIt)) {
ipAddressList.erase(ipListIt2++);
} else {
++ipListIt2;
}
}
}
sortIpAddressListBySeenTime();
//keep only a limited number of addresses
if (ipAddressList.size() > PEER_IP_CONNECT_STATE_MAX_LIST_SIZE) {
ipAddressList.resize(PEER_IP_CONNECT_STATE_MAX_LIST_SIZE);
}
}
void peerConnectState::updateIpAddressList(std::list<IpAddressTimed> ipTimedList) { //purge old addresses to keep a small list
std::list<IpAddressTimed>::iterator ipListIt;
for (ipListIt = ipTimedList.begin(); ipListIt!=(ipTimedList.end()); ipListIt++) {
updateIpAddressList(*ipListIt);
}
}
void peerConnectState::updateIpAddressList(IpAddressTimed ipTimed) { //purge old addresses to keep a small list
#ifdef CONN_DEBUG
std::cerr << "peerConnectState::updateIpAdressList() ip " << inet_ntoa(ipTimed.ipAddr.sin_addr);
std::cerr << ":" << ntohs(ipTimed.ipAddr.sin_port);
std::cerr << std::endl;
#endif
if (ipTimed.ipAddr.sin_addr.s_addr == 0 || ipTimed.ipAddr.sin_port == 0 ||
ipTimed.ipAddr.sin_addr.s_addr == 1|| ipTimed.ipAddr.sin_port == 1 ||
std::string(inet_ntoa(ipTimed.ipAddr.sin_addr)) == "1.1.1.1") {
#ifdef CONN_DEBUG
std::cerr << "peerConnectState::updateIpAdressList() ip parameter is 0.0.0.0, 1.1.1.1 or port is 0, ignoring." << std::endl;
#endif
return;
}
//check if the ip list contains the current remote address of the connected peer
bool found = false;
std::list<IpAddressTimed>::iterator ipListIt;
for (ipListIt = ipAddressList.begin(); ipListIt!=(ipAddressList.end()) && !found; ipListIt++) {
if (is_same_address(*ipListIt, ipTimed)) {
#ifdef CONN_DEBUG
std::cerr << "peerConnectState::updateIpAdressList() ip found in the list." << std::endl;
#endif
found = true;
//update the seen time
if (ipListIt->seenTime < ipTimed.seenTime) {
ipListIt->seenTime = ipTimed.seenTime;
#ifdef CONN_DEBUG
std::cerr << "peerConnectState::updateIpAdressList() Update seen time to : " << ipTimed.seenTime << std::endl;
#endif
}
}
}
if (!found) {
//add the current addresses to the ip list
#ifdef CONN_DEBUG
std::cerr << "peerConnectState::updateIpAdressList() adding to the ip list the current remote addr : " << id << " address : " << inet_ntoa(ipTimed.ipAddr.sin_addr);
std::cerr << ":" << ntohs(ipTimed.ipAddr.sin_port);
std::cerr << std::endl;
#endif
ipAddressList.push_back(ipTimed);
}
}
void peerConnectState::printIpAddressList() {
std::cerr << "peerConnectState::printIpAdressList() current ip list for the peer : " << id << ", size : " << ipAddressList.size() << ", adresses : " << std::endl;
for (std::list<IpAddressTimed>::iterator ipListIt = ipAddressList.begin(); ipListIt!=(ipAddressList.end()); ipListIt++) {
std::cerr << inet_ntoa(ipListIt->ipAddr.sin_addr) << ":" << ntohs(ipListIt->ipAddr.sin_port) << " seenTime : " << ipListIt->seenTime << std::endl;
}
}
bool peerConnectState::extractExtAddress(std::list<IpAddressTimed> IpAddressTimedList, IpAddressTimed &resultAddress) {//extract first address that is not the same as local address
sortIpAddressListBySeenTime(IpAddressTimedList);
//check if the ip list contains the current remote address of the connected peer
std::list<IpAddressTimed>::iterator ipListIt;
for (ipListIt = IpAddressTimedList.begin(); ipListIt!=(IpAddressTimedList.end()); ++ipListIt) {
//assume address is valid if not private, is not 0 and is not loopback
//if ((ipListIt->ipAddr.sin_addr.s_addr != 0)
if (ipListIt->ipAddr.sin_addr.s_addr != 0 && ipListIt->ipAddr.sin_port != 0 &&
ipListIt->ipAddr.sin_addr.s_addr != 1 && ipListIt->ipAddr.sin_port != 1 &&
std::string(inet_ntoa(ipListIt->ipAddr.sin_addr)) != "1.1.1.1" &&
(!isLoopbackNet(&ipListIt->ipAddr.sin_addr)) &&
(!isPrivateNet(&ipListIt->ipAddr.sin_addr))
) {
resultAddress = *ipListIt;
return true;
}
}
return false;
}
void peerConnectState::printIpAddressList(std::list<IpAddressTimed> ipTimedList) {
#ifdef CONN_DEBUG
std::cerr << "peerConnectState::printIpAdressList()" << std::endl;
#endif
for (std::list<IpAddressTimed>::iterator ipListIt = ipTimedList.begin(); ipListIt!=(ipTimedList.end()); ipListIt++) {
#ifdef CONN_DEBUG
std::cerr << inet_ntoa(ipListIt->ipAddr.sin_addr) << ":" << ntohs(ipListIt->ipAddr.sin_port) << " seenTime : " << ipListIt->seenTime << std::endl;
#endif
}
}
p3tunnel* p3ConnectMgr::getP3tunnel() {
return mP3tunnel;
}
void p3ConnectMgr::setP3tunnel(p3tunnel *p3tun) {
mP3tunnel = p3tun;
}