/* * libretroshare/src/pqi: p3linkmgr.cc * * 3P/PQI network interface for RetroShare. * * Copyright 2007-2011 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/p3linkmgr.h" #include "pqi/p3peermgr.h" #include "pqi/p3netmgr.h" #include "pqi/authssl.h" #include "pqi/p3dhtmgr.h" // Only need it for constants. #include "tcponudp/tou.h" #include "util/extaddrfinder.h" #include "util/dnsresolver.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 "retroshare/rsiface.h" #include /* Network setup States */ /**** * #define LINKMGR_DEBUG 1 * #define LINKMGR_DEBUG_CONNFAIL 1 * #define LINKMGR_DEBUG_ACTIONS 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_TCP_DEFAULT_PERIOD = 10; const uint32_t P3CONNMGR_UDP_DEFAULT_PERIOD = 40; #define MAX_AVAIL_PERIOD 230 //times a peer stay in available state when not connected #define MIN_RETRY_PERIOD 140 #define MAX_RANDOM_ATTEMPT_OFFSET 6 // seconds. void printConnectState(std::ostream &out, peerConnectState &peer); peerConnectAddress::peerConnectAddress() :delay(0), period(0), type(0), ts(0) { sockaddr_clear(&addr); } peerAddrInfo::peerAddrInfo() :found(false), type(0), ts(0) { } peerConnectState::peerConnectState() :id("unknown"), connecttype(0), lastavailable(0), lastattempt(0), name(""), state(0), actions(0), source(0), inConnAttempt(0) { //sockaddr_clear(¤tlocaladdr); //sockaddr_clear(¤tserveraddr); return; } std::string textPeerConnectState(peerConnectState &state) { std::ostringstream out; out << "Id: " << state.id << std::endl; std::string output = out.str(); return output; } /********* * NOTES: * * p3LinkMgr doesn't store anything. All configuration is handled by p3PeerMgr. * * p3LinkMgr recvs the Discovery / Dht / Status updates.... tries the address. * at success the address is pushed to p3PeerMgr for storage. * */ p3LinkMgrIMPL::p3LinkMgrIMPL(p3PeerMgrIMPL *peerMgr, p3NetMgrIMPL *netMgr) :mPeerMgr(peerMgr), mNetMgr(netMgr), mLinkMtx("p3LinkMgr"),mStatusChanged(false) { { RsStackMutex stack(mLinkMtx); /****** STACK LOCK MUTEX *******/ mAllowTunnelConnection = false; mDNSResolver = new DNSResolver(); mRetryPeriod = MIN_RETRY_PERIOD; lastGroupId = 1; /* setup Banned Ip Address - static for now */ struct in_addr bip; memset(&bip, 0, sizeof(bip)); bip.s_addr = 1; mBannedIpList.push_back(bip); } #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgr() Startup" << std::endl; #endif return; } void p3LinkMgrIMPL::setTunnelConnection(bool b) { RsStackMutex stack(mLinkMtx); /****** STACK LOCK MUTEX *******/ mAllowTunnelConnection = b; } bool p3LinkMgrIMPL::getTunnelConnection() { RsStackMutex stack(mLinkMtx); /****** STACK LOCK MUTEX *******/ return mAllowTunnelConnection; } bool p3LinkMgrIMPL::setLocalAddress(struct sockaddr_in addr) { RsStackMutex stack(mLinkMtx); /****** STACK LOCK MUTEX *******/ mLocalAddress = addr; } struct sockaddr_in p3LinkMgrIMPL::getLocalAddress() { RsStackMutex stack(mLinkMtx); /****** STACK LOCK MUTEX *******/ return mLocalAddress; } bool p3LinkMgrIMPL::isOnline(const std::string &ssl_id) { RsStackMutex stack(mLinkMtx); /****** STACK LOCK MUTEX *******/ std::map::iterator it; it = mFriendList.find(ssl_id); if (it == mFriendList.end()) { return false; } if (it->second.state & RS_PEER_S_CONNECTED) { return true; } return false; } void p3LinkMgrIMPL::getOnlineList(std::list &ssl_peers) { RsStackMutex stack(mLinkMtx); /****** STACK LOCK MUTEX *******/ std::map::iterator it; for(it = mFriendList.begin(); it != mFriendList.end(); it++) { if (it->second.state & RS_PEER_S_CONNECTED) { ssl_peers.push_back(it->first); } } return; } void p3LinkMgrIMPL::getFriendList(std::list &ssl_peers) { RsStackMutex stack(mLinkMtx); /****** STACK LOCK MUTEX *******/ std::map::iterator it; for(it = mFriendList.begin(); it != mFriendList.end(); it++) { ssl_peers.push_back(it->first); } return; } int p3LinkMgrIMPL::getFriendCount() { RsStackMutex stack(mLinkMtx); /****** STACK LOCK MUTEX *******/ return mFriendList.size(); } int p3LinkMgrIMPL::getOnlineCount() { RsStackMutex stack(mLinkMtx); /****** STACK LOCK MUTEX *******/ int count = 0; std::map::iterator it; for(it = mFriendList.begin(); it != mFriendList.end(); it++) { if (it->second.state & RS_PEER_S_CONNECTED) { count++; } } return count; } bool p3LinkMgrIMPL::getFriendNetStatus(const std::string &id, peerConnectState &state) { RsStackMutex stack(mLinkMtx); /****** STACK LOCK MUTEX *******/ std::map::iterator it; it = mFriendList.find(id); if (it == mFriendList.end()) { return false; } state = it->second; return true; } void p3LinkMgrIMPL::setFriendVisibility(const std::string &id, bool isVisible) { /* set visibility */ { RsStackMutex stack(mLinkMtx); /****** STACK LOCK MUTEX *******/ int count = 0; std::map::iterator it; it = mFriendList.find(id); if (it == mFriendList.end()) { /* */ std::cerr << "p3LinkMgrIMPL::setFriendVisibility() ERROR peer unknown: " << id; std::cerr << std::endl; return; } if (it->second.dhtVisible == isVisible) { /* no change in state */ return; } it->second.dhtVisible = isVisible; if (it->second.state & RS_PEER_S_CONNECTED) { /* dont worry about it */ return; } } /* switch the NetAssistOn/Off */ mNetMgr->netAssistFriend(id, isVisible); } void p3LinkMgrIMPL::tick() { statusTick(); tickMonitors(); } void p3LinkMgrIMPL::statusTick() { /* iterate through peers ... * if been available for long time ... remove flag * if last attempt a while - retryConnect. * etc. */ #ifdef LINKMGR_DEBUG_TICK std::cerr << "p3LinkMgrIMPL::statusTick()" << std::endl; #endif std::list retryIds; std::list::iterator it2; //std::list dummyToRemove; { time_t now = time(NULL); time_t oldavail = now - MAX_AVAIL_PERIOD; time_t retry = now - mRetryPeriod; RsStackMutex stack(mLinkMtx); /****** LOCK MUTEX ******/ std::map::iterator it; for(it = mFriendList.begin(); it != mFriendList.end(); it++) { if (it->second.state & RS_PEER_S_CONNECTED) { continue; } if ((it->second.state & RS_PEER_S_ONLINE) && (it->second.lastavailable < oldavail)) { #ifdef LINKMGR_DEBUG_TICK std::cerr << "p3LinkMgrIMPL::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); } } } #ifndef P3CONNMGR_NO_AUTO_CONNECTION for(it2 = retryIds.begin(); it2 != retryIds.end(); it2++) { #ifdef LINKMGR_DEBUG_TICK std::cerr << "p3LinkMgrIMPL::statusTick() RETRY TIMEOUT for: "; std::cerr << *it2; std::cerr << std::endl; #endif /* retry it! */ retryConnect(*it2); } #endif } /******************************** Network Status ********************************* * Configuration Loading / Saving. */ void p3LinkMgrIMPL::addMonitor(pqiMonitor *mon) { RsStackMutex stack(mLinkMtx); /****** STACK LOCK MUTEX *******/ std::list::iterator it; it = std::find(clients.begin(), clients.end(), mon); if (it != clients.end()) { return; } mon->setLinkMgr(this); clients.push_back(mon); return; } void p3LinkMgrIMPL::removeMonitor(pqiMonitor *mon) { RsStackMutex stack(mLinkMtx); /****** STACK LOCK MUTEX *******/ std::list::iterator it; it = std::find(clients.begin(), clients.end(), mon); if (it == clients.end()) { return; } (*it)->setLinkMgr(NULL); clients.erase(it); return; } void p3LinkMgrIMPL::tickMonitors() { bool doStatusChange = false; std::list actionList; std::map::iterator it; { RsStackMutex stack(mLinkMtx); /****** STACK LOCK MUTEX *******/ if (mStatusChanged) { #ifdef LINKMGR_DEBUG_ACTIONS std::cerr << "p3LinkMgrIMPL::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 LINKMGR_DEBUG_ACTIONS 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 LINKMGR_DEBUG_ACTIONS 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 LINKMGR_DEBUG_ACTIONS std::cerr << "Sending to " << clients.size() << " monitorClients" << std::endl; #endif /* send to all monitors */ std::list::iterator mit; for(mit = clients.begin(); mit != clients.end(); mit++) { (*mit)->statusChange(actionList); } } #ifdef WINDOWS_SYS /////////////////////////////////////////////////////////// // hack for too many connections /* notify all monitors */ std::list::iterator mit; for(mit = clients.begin(); mit != clients.end(); mit++) { (*mit)->statusChanged(); } /////////////////////////////////////////////////////////// #endif { RsStackMutex stack(mLinkMtx); /****** STACK LOCK MUTEX *******/ /* Now Cleanup OthersList (served its purpose (MOVE Action)) */ mOthersList.clear(); } } const std::string p3LinkMgrIMPL::getOwnId() { return AuthSSL::getAuthSSL()->OwnId(); } bool p3LinkMgrIMPL::connectAttempt(const std::string &id, struct sockaddr_in &raddr, struct sockaddr_in &proxyaddr, struct sockaddr_in &srcaddr, uint32_t &delay, uint32_t &period, uint32_t &type, uint32_t &flags, uint32_t &bandwidth) { RsStackMutex stack(mLinkMtx); /****** STACK LOCK MUTEX *******/ /* check for existing */ std::map::iterator it; it = mFriendList.find(id); if (it == mFriendList.end()) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::connectAttempt() FAILED Not in FriendList! id: " << id << std::endl; #endif return false; } if (it->second.connAddrs.size() < 1) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::connectAttempt() FAILED No ConnectAddresses id: " << id << std::endl; #endif return false; } if (it->second.state & RS_PEER_S_CONNECTED) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::connectAttempt() Already FLAGGED as connected!!!!" << std::endl; std::cerr << "p3LinkMgrIMPL::connectAttempt() But allowing anyway!!!" << std::endl; #endif } it->second.lastattempt = time(NULL); it->second.inConnAttempt = true; it->second.currentConnAddrAttempt = it->second.connAddrs.front(); it->second.connAddrs.pop_front(); raddr = it->second.currentConnAddrAttempt.addr; delay = it->second.currentConnAddrAttempt.delay; period = it->second.currentConnAddrAttempt.period; type = it->second.currentConnAddrAttempt.type; flags = it->second.currentConnAddrAttempt.flags; proxyaddr = it->second.currentConnAddrAttempt.proxyaddr; srcaddr = it->second.currentConnAddrAttempt.srcaddr; bandwidth = it->second.currentConnAddrAttempt.bandwidth; #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::connectAttempt() found an address: id: " << id << std::endl; std::cerr << " laddr: " << rs_inet_ntoa(addr.sin_addr) << " lport: " << ntohs(addr.sin_port) << " delay: " << delay << " period: " << period; std::cerr << " type: " << type << std::endl; #endif if (raddr.sin_addr.s_addr == 0 || raddr.sin_port == 0) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::connectAttempt() WARNING: address or port is null" << std::endl; std::cerr << " type: " << type << std::endl; #endif } return true; } /**************************** * Update state, * trigger retry if necessary, * * remove from DHT? * */ bool p3LinkMgrIMPL::connectResult(const std::string &id, bool success, uint32_t flags, struct sockaddr_in remote_peer_address) { bool doDhtAssist = false ; bool updatePeerAddr = false; bool updateLastContact = false; { RsStackMutex stack(mLinkMtx); /****** STACK LOCK MUTEX *******/ rslog(RSL_WARNING, p3connectzone, "p3LinkMgrIMPL::connectResult() called Connect!: id: " + id); if (success) { rslog(RSL_WARNING, p3connectzone, "p3LinkMgrIMPL::connectResult() called with SUCCESS."); } else { rslog(RSL_WARNING, p3connectzone, "p3LinkMgrIMPL::connectResult() called with FAILED."); } if (id == getOwnId()) { #ifdef LINKMGR_DEBUG rslog(RSL_WARNING, p3connectzone, "p3LinkMgrIMPL::connectResult() Failed, connecting to own id: "); #endif return false; } /* check for existing */ std::map::iterator it; it = mFriendList.find(id); if (it == mFriendList.end()) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::connectResult() ERROR, missing Friend " << " id: " << id << std::endl; #endif return false; } if (success) { /* update address (should also come through from DISC) */ #ifdef LINKMGR_DEBUG_CONNFAIL std::cerr << "p3LinkMgrIMPL::connectResult() Connect!: id: " << id << std::endl; std::cerr << " Success: " << success << " flags: " << flags << std::endl; #endif #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::connectResult() Connect!: id: " << id << std::endl; std::cerr << " Success: " << success << " flags: " << flags << std::endl; #endif rslog(RSL_WARNING, p3connectzone, "p3LinkMgrIMPL::connectResult() Success"); /* change state */ it->second.state |= RS_PEER_S_CONNECTED; it->second.actions |= RS_PEER_CONNECTED; it->second.connecttype = flags; updateLastContact = true; /* time of connect */ /* only update the peer's address if we were in a connect attempt. * Otherwise, they connected to us, and the address will be a * random port of their outgoing TCP socket * * NB even if we received the connection, the IP address is likely to okay. */ //used to send back to the peer it's own ext address //it->second.currentserveraddr = remote_peer_address; // THIS TEST IS A Bit BAD XXX, we should update their address anyway... // This means we only update connections that we've made.. so maybe not too bad? 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)) { updatePeerAddr = true; #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::connectResult() adding current peer address in list." << std::endl; #endif } /* remove other attempts */ it->second.inConnAttempt = false; it->second.connAddrs.clear(); mStatusChanged = true; } else { #ifdef LINKMGR_DEBUG_CONNFAIL std::cerr << "p3LinkMgrIMPL::connectResult() Disconnect/Fail: flags: " << flags << " id: " << id; std::cerr << std::endl; if (it->second.inConnAttempt) { std::cerr << "p3LinkMgrIMPL::connectResult() Likely Connect Fail, as inConnAttempt Flag is set"; std::cerr << std::endl; } if (it->second.state & RS_PEER_S_CONNECTED) { std::cerr << "p3LinkMgrIMPL::connectResult() Likely DISCONNECT, as state set to Connected"; std::cerr << std::endl; } #endif it->second.inConnAttempt = false; #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::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; mStatusChanged = true; updateLastContact = true; /* time of disconnect */ } if (it->second.connAddrs.size() >= 1) { it->second.actions |= RS_PEER_CONNECT_REQ; mStatusChanged = true; } if (it->second.dhtVisible) { doDhtAssist = true; } } } if (updatePeerAddr) { pqiIpAddress raddr; raddr.mAddr = remote_peer_address; raddr.mSeenTime = time(NULL); raddr.mSrc = 0; #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::connectResult() Success and we initiated connection... Updating Address"; std::cerr << std::endl; #endif mPeerMgr->updateCurrentAddress(id, raddr); } if (updateLastContact) { mPeerMgr->updateLastContact(id); } /* inform NetAssist of result. This is slightly duplicating below, as we switch it on/off * in a second anyway. However, the FAILURE of UDP connection, must be informed. * * actually the way the DHT works at the moment, both forms of feedback are required. * this handles connection requests, the other searches. As they are independent... do both. */ if (flags == RS_NET_CONN_UDP_ALL) { #ifdef LINKMGR_DEBUG #endif std::cerr << "p3LinkMgrIMPL::connectResult() Sending Feedback for UDP connection"; std::cerr << std::endl; if (success) { #ifdef LINKMGR_DEBUG #endif std::cerr << "p3LinkMgrIMPL::connectResult() UDP Update CONNECTED to: " << id; std::cerr << std::endl; mNetMgr->netAssistStatusUpdate(id, NETMGR_DHT_FEEDBACK_CONNECTED); } else { #ifdef LINKMGR_DEBUG #endif std::cerr << "p3LinkMgrIMPL::connectResult() UDP Update FAILED to: " << id; std::cerr << std::endl; /* have no differentiation between failure and closed? */ mNetMgr->netAssistStatusUpdate(id, NETMGR_DHT_FEEDBACK_CONN_FAILED); } } if (success) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::connectResult() Success switching off DhtAssist for friend: " << id; std::cerr << std::endl; #endif /* always switch it off now */ mNetMgr->netAssistFriend(id,false) ; } else { if (doDhtAssist) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::connectResult() Fail, Enabling DhtAssist for: " << id; std::cerr << std::endl; #endif mNetMgr->netAssistFriend(id,true) ; } else { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::connectResult() Fail, No DhtAssist, as No DHT visibility for: " << id; std::cerr << std::endl; #endif } } return success; } /******************************** Feedback ...... ********************************* * From various sources */ void p3LinkMgrIMPL::peerStatus(std::string id, const pqiIpAddrSet &addrs, uint32_t type, uint32_t flags, uint32_t source) { /* HACKED UP FIX ****/ std::map::iterator it; bool isFriend = true; time_t now = time(NULL); peerAddrInfo details; details.type = type; details.found = true; details.addrs = addrs; details.ts = now; bool updateNetConfig = (source == RS_CB_PERSON); uint32_t peerVisibility = 0; uint32_t peerNetMode = 0; uint32_t ownNetMode = mNetMgr->getNetworkMode(); { RsStackMutex stack(mLinkMtx); /****** STACK LOCK MUTEX *******/ { /* Log */ std::ostringstream out; out << "p3LinkMgrIMPL::peerStatus()" << " id: " << id; out << " type: " << type << " flags: " << flags; out << " source: " << source; out << std::endl; addrs.printAddrs(out); rslog(RSL_WARNING, p3connectzone, out.str()); #ifdef LINKMGR_DEBUG std::cerr << out.str(); #endif } /* 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 LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::peerStatus() Peer Not Found - Ignore" << std::endl; #endif return; } #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::peerStatus() Peer is in mOthersList" << std::endl; #endif } #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::peerStatus() Current Peer State:" << std::endl; printConnectState(std::cerr, it->second); std::cerr << std::endl; #endif /* update the status */ /* if source is DHT */ if (source == RS_CB_DHT) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::peerStatus() Update From DHT:"; std::cerr << std::endl; #endif /* 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; } else if (source == RS_CB_DISC) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::peerStatus() Update From DISC:"; std::cerr << std::endl; #endif /* 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; 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; } } else if (source == RS_CB_PERSON) { /* PERSON can tell us about * 1) online / offline * 2) connect address * -> update all! */ #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::peerStatus() Update From PERSON:"; std::cerr << std::endl; #endif it->second.source = RS_CB_PERSON; it->second.peer = details; 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 * * One problem with these states... is that we will never find them via DHT * if these flags are switched off here... If we get a connection attempt via DHT * we should switch the DHT search back on. */ peerNetMode = 0; //it->second.netMode &= (~RS_NET_MODE_ACTUAL); /* clear actual flags */ if (flags & RS_NET_FLAGS_EXTERNAL_ADDR) { peerNetMode = RS_NET_MODE_EXT; } else if (flags & RS_NET_FLAGS_STABLE_UDP) { peerNetMode = RS_NET_MODE_UDP; } else { peerNetMode = RS_NET_MODE_UNREACHABLE; } /* always update VIS status */ if (flags & RS_NET_FLAGS_USE_DISC) { peerVisibility &= (~RS_VIS_STATE_NODISC); } else { peerVisibility |= RS_VIS_STATE_NODISC; } if (flags & RS_NET_FLAGS_USE_DHT) { peerVisibility &= (~RS_VIS_STATE_NODHT); } else { peerVisibility |= RS_VIS_STATE_NODHT; } } /* Determine Reachability (only advisory) */ if (ownNetMode & RS_NET_MODE_UDP) { if ((details.type & RS_NET_CONN_UDP_DHT_SYNC) || (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 (ownNetMode & 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 LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::peerStatus() NOT FRIEND " << " id: " << id << std::endl; #endif { rslog(RSL_WARNING, p3connectzone, "p3LinkMgrIMPL::peerStatus() NO CONNECT (not friend)"); } return; } /* if already connected -> done */ if (it->second.state & RS_PEER_S_CONNECTED) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::peerStatus() PEER ONLINE ALREADY " << " id: " << id << std::endl; #endif { /* Log */ rslog(RSL_WARNING, p3connectzone, "p3LinkMgrIMPL::peerStatus() NO CONNECT (already connected!)"); } return; } } /****** STACK UNLOCK MUTEX *******/ bool newAddrs = mPeerMgr->updateAddressList(id, addrs); if (updateNetConfig) { mPeerMgr -> setVisState(id, peerVisibility); mPeerMgr -> setNetworkMode(id, peerNetMode); } #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::peerStatus()" << " id: " << id; std::cerr << " type: " << type << " flags: " << flags; std::cerr << " source: " << source << std::endl; std::cerr << " addrs: " << std::endl; addrs.printAddrs(std::cerr); std::cerr << std::endl; #endif #ifndef P3CONNMGR_NO_AUTO_CONNECTION #ifndef P3CONNMGR_NO_TCP_CONNECTIONS if (newAddrs) { retryConnectTCP(id); } #endif // P3CONNMGR_NO_TCP_CONNECTIONS #else #endif // P3CONNMGR_NO_AUTO_CONNECTION #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::peerStatus() Resulting Peer State:" << std::endl; printConnectState(std::cerr, it->second); std::cerr << std::endl; #endif } /* This has become very unwieldy - as extra arguments are required for UDP connections */ void p3LinkMgrIMPL::peerConnectRequest(std::string id, struct sockaddr_in raddr, struct sockaddr_in proxyaddr, struct sockaddr_in srcaddr, uint32_t source, uint32_t flags, uint32_t delay, uint32_t bandwidth) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::peerConnectRequest() id: " << id; std::cerr << " raddr: " << rs_inet_ntoa(raddr.sin_addr) << ":" << ntohs(raddr.sin_port); std::cerr << " proxyaddr: " << rs_inet_ntoa(proxyaddr.sin_addr) << ":" << ntohs(proxyaddr.sin_port); std::cerr << " srcaddr: " << rs_inet_ntoa(srcaddr.sin_addr) << ":" << ntohs(srcaddr.sin_port); std::cerr << " source: " << source; std::cerr << " flags: " << flags; std::cerr << " delay: " << delay; std::cerr << " bandwidth: " << bandwidth; std::cerr << std::endl; #endif { /* Log */ std::ostringstream out; out << "p3LinkMgrIMPL::peerConnectRequest() id: " << id; out << " raddr: " << rs_inet_ntoa(raddr.sin_addr) << ":" << ntohs(raddr.sin_port); std::cerr << " proxyaddr: " << rs_inet_ntoa(proxyaddr.sin_addr) << ":" << ntohs(proxyaddr.sin_port); std::cerr << " srcaddr: " << rs_inet_ntoa(srcaddr.sin_addr) << ":" << ntohs(srcaddr.sin_port); out << " source: " << source; out << " flags: " << flags; out << " delay: " << delay; out << " bandwidth: " << bandwidth; rslog(RSL_WARNING, p3connectzone, out.str()); } /******************** TCP PART *****************************/ #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::peerConnectRequest() (From DHT Only)" << std::endl; #endif if (source == RS_CB_DHT) { if (flags & RS_CB_FLAG_MODE_TCP) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::peerConnectRequest() DHT says Online ==> so try TCP"; std::cerr << std::endl; #endif { RsStackMutex stack(mLinkMtx); /****** STACK LOCK MUTEX *******/ std::map::iterator it; if (mFriendList.end() == (it = mFriendList.find(id))) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::peerConnectRequest() ERROR Peer is not Friend" << std::endl; #endif return; } /* if already connected -> done */ if (it->second.state & RS_PEER_S_CONNECTED) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::peerConnectRequest() ERROR Peer Already Connected" << std::endl; #endif } /* setup specific attempt for DHT found address. */ locked_ConnectAttempt_SpecificAddress(&(it->second), &raddr); } retryConnect(id); } else { /* UDP Attempt! */ #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::peerConnectRequest() DHT says CONNECT ==> tryConnectUDP()"; std::cerr << std::endl; #endif tryConnectUDP(id, raddr, proxyaddr, srcaddr, flags, delay, bandwidth); } return; } else { // IS THIS USED??? std::cerr << "p3LinkMgrIMPL::peerConnectRequest() ERROR source OTHER ==> NOOP" << std::endl; std::cerr << std::endl; return; } } /*******************************************************************/ /*******************************************************************/ /*************** External Control ****************/ bool p3LinkMgrIMPL::retryConnect(const std::string &id) { /* push all available addresses onto the connect addr stack */ #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::retryConnect() id: " << id << std::endl; #endif #ifndef P3CONNMGR_NO_TCP_CONNECTIONS retryConnectTCP(id); #endif // P3CONNMGR_NO_TCP_CONNECTIONS return true; } bool p3LinkMgrIMPL::tryConnectUDP(const std::string &id, struct sockaddr_in &rUdpAddr, struct sockaddr_in &proxyaddr, struct sockaddr_in &srcaddr, uint32_t flags, uint32_t delay, uint32_t bandwidth) { RsStackMutex stack(mLinkMtx); /****** STACK LOCK MUTEX *******/ /* push all available addresses onto the connect addr stack */ #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::retryConnectTCP() id: " << id << std::endl; #endif if (id == getOwnId()) { #ifdef LINKMGR_DEBUG rslog(RSL_WARNING, p3connectzone, "p3LinkMgrIMPL::retryConnectUDP() Failed, connecting to own id: "); #endif return false; } /* look up the id */ std::map::iterator it; if (mFriendList.end() == (it = mFriendList.find(id))) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::retryConnectUDP() Peer is not Friend" << std::endl; #endif return false; } /* if already connected -> done */ if (it->second.state & RS_PEER_S_CONNECTED) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::retryConnectUDP() Peer Already Connected" << std::endl; #endif if (it->second.connecttype & RS_NET_CONN_TUNNEL) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::retryConnectUDP() Peer Connected through a tunnel connection, let's try a normal connection." << std::endl; #endif } else { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::retryConnectUDP() Peer Connected no more connection attempts" << std::endl; #endif return false; } } /* Explicit Request to start the UDP connection */ if (isValidNet(&(rUdpAddr.sin_addr))) { #ifdef LINKMGR_DEBUG std::cerr << "Adding udp connection attempt: "; std::cerr << "Addr: " << rs_inet_ntoa(rUdpAddr.sin_addr); std::cerr << ":" << ntohs(rUdpAddr.sin_port); std::cerr << std::endl; #endif peerConnectAddress pca; pca.addr = rUdpAddr; pca.type = RS_NET_CONN_UDP_PEER_SYNC; pca.delay = delay; pca.ts = time(NULL); pca.period = P3CONNMGR_UDP_DEFAULT_PERIOD; pca.flags = flags; pca.proxyaddr = proxyaddr; pca.srcaddr = srcaddr; pca.bandwidth = bandwidth; // Push address to the front... so it happens quickly (before any timings are lost). addAddressIfUnique(it->second.connAddrs, pca, true); } /* finish it off */ return locked_ConnectAttempt_Complete(&(it->second)); } bool p3LinkMgrIMPL::retryConnectTCP(const std::string &id) { /* Check if we should retry first */ { RsStackMutex stack(mLinkMtx); /****** STACK LOCK MUTEX *******/ /* push all available addresses onto the connect addr stack... * with the following exceptions: * - check local address, see if it is the same network as us - check address age. don't add old ones */ #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::retryConnectTCP() id: " << id << std::endl; #endif if (id == getOwnId()) { #ifdef LINKMGR_DEBUG rslog(RSL_WARNING, p3connectzone, "p3LinkMgrIMPL::retryConnectTCP() Failed, connecting to own id: "); #endif return false; } /* look up the id */ std::map::iterator it; if (mFriendList.end() == (it = mFriendList.find(id))) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::retryConnectTCP() Peer is not Friend" << std::endl; #endif return false; } /* if already connected -> done */ if (it->second.state & RS_PEER_S_CONNECTED) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::retryConnectTCP() Peer Already Connected" << std::endl; #endif if (it->second.connecttype & RS_NET_CONN_TUNNEL) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::retryConnectTCP() Peer Connected through a tunnel connection, let's try a normal connection." << std::endl; #endif } else { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::retryConnectTCP() Peer Connected no more connection attempts" << std::endl; #endif return false; } } } /****** END of LOCKED ******/ #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::retryConnectTCP() Getting Address from PeerMgr for : " << id; std::cerr << std::endl; #endif /* If we reach here, must retry .... extract the required info from p3PeerMgr */ struct sockaddr_in lAddr; struct sockaddr_in eAddr; pqiIpAddrSet histAddrs; std::string dyndns; if (mPeerMgr->getConnectAddresses(id, lAddr, eAddr, histAddrs, dyndns)) { RsStackMutex stack(mLinkMtx); /****** STACK LOCK MUTEX *******/ std::map::iterator it; if (mFriendList.end() != (it = mFriendList.find(id))) { locked_ConnectAttempt_CurrentAddresses(&(it->second), &lAddr, &eAddr); locked_ConnectAttempt_HistoricalAddresses(&(it->second), histAddrs); uint16_t dynPort = ntohs(eAddr.sin_port); if (!dynPort) dynPort = ntohs(lAddr.sin_port); if (dynPort) { locked_ConnectAttempt_AddDynDNS(&(it->second), dyndns, dynPort); } //locked_ConnectAttempt_AddTunnel(&(it->second)); /* finish it off */ return locked_ConnectAttempt_Complete(&(it->second)); } else { std::cerr << "p3LinkMgrIMPL::retryConnectTCP() ERROR failed to find friend data : " << id; std::cerr << std::endl; } } else { std::cerr << "p3LinkMgrIMPL::retryConnectTCP() ERROR failed to addresses from PeerMgr for: " << id; std::cerr << std::endl; } return false; } #define MAX_TCP_ADDR_AGE (3600 * 24 * 14) // two weeks in seconds. bool p3LinkMgrIMPL::locked_CheckPotentialAddr(const struct sockaddr_in *addr, time_t age) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::locked_CheckPotentialAddr("; std::cerr << rs_inet_ntoa(addr->sin_addr); std::cerr << ":" << ntohs(addr->sin_port); std::cerr << ", " << age << ")"; std::cerr << std::endl; #endif /* * if it is old - quick rejection */ if (age > MAX_TCP_ADDR_AGE) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::locked_CheckPotentialAddr() REJECTING - TOO OLD"; std::cerr << std::endl; #endif return false; } bool isValid = isValidNet(&(addr->sin_addr)); // bool isLoopback = isLoopbackNet(&(addr->sin_addr)); // bool isPrivate = isPrivateNet(&(addr->sin_addr)); bool isExternal = isExternalNet(&(addr->sin_addr)); /* if invalid - quick rejection */ if (!isValid) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::locked_CheckPotentialAddr() REJECTING - INVALID"; std::cerr << std::endl; #endif return false; } /* if it is on the ban list - ignore */ /* checks - is it the dreaded 1.0.0.0 */ std::list::const_iterator it; for(it = mBannedIpList.begin(); it != mBannedIpList.end(); it++) { if (it->s_addr == addr->sin_addr.s_addr) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::locked_CheckPotentialAddr() REJECTING - ON BANNED IPLIST"; std::cerr << std::endl; #endif return false; } } /* if it is an external address, we'll accept it. * - even it is meant to be a local address. */ if (isExternal) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::locked_CheckPotentialAddr() ACCEPTING - EXTERNAL"; std::cerr << std::endl; #endif return true; } /* get here, it is private or loopback * - can only connect to these addresses if we are on the same subnet. - check net against our local address. */ std::cerr << "p3LinkMgrIMPL::locked_CheckPotentialAddr() Checking sameNet against: "; std::cerr << rs_inet_ntoa(mLocalAddress.sin_addr); std::cerr << ")"; std::cerr << std::endl; if (sameNet(&(mLocalAddress.sin_addr), &(addr->sin_addr))) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::locked_CheckPotentialAddr() ACCEPTING - PRIVATE & sameNET"; std::cerr << std::endl; #endif return true; } #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::locked_CheckPotentialAddr() REJECTING - PRIVATE & !sameNET"; std::cerr << std::endl; #endif /* else it fails */ return false; } void p3LinkMgrIMPL::locked_ConnectAttempt_SpecificAddress(peerConnectState *peer, struct sockaddr_in *remoteAddr) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::locked_ConnectAttempt_SpecificAddresses()"; std::cerr << std::endl; #endif if ((remoteAddr) && (locked_CheckPotentialAddr(remoteAddr, 0))) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::locked_ConnectAttempt_SpecificAddresses() "; std::cerr << "Adding tcp connection attempt: "; std::cerr << "Addr: " << rs_inet_ntoa(remoteAddr->sin_addr); std::cerr << ":" << ntohs(remoteAddr->sin_port); std::cerr << std::endl; #endif peerConnectAddress pca; pca.addr = *remoteAddr; pca.type = RS_NET_CONN_TCP_EXTERNAL; pca.delay = P3CONNMGR_TCP_DEFAULT_DELAY; pca.ts = time(NULL); pca.period = P3CONNMGR_TCP_DEFAULT_PERIOD; sockaddr_clear(&(pca.proxyaddr)); sockaddr_clear(&(pca.srcaddr)); pca.bandwidth = 0; addAddressIfUnique(peer->connAddrs, pca, false); } } void p3LinkMgrIMPL::locked_ConnectAttempt_CurrentAddresses(peerConnectState *peer, struct sockaddr_in *localAddr, struct sockaddr_in *serverAddr) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::locked_ConnectAttempt_CurrentAddresses()"; std::cerr << std::endl; #endif // Just push all the addresses onto the stack. /* try "current addresses" first */ if ((localAddr) && (locked_CheckPotentialAddr(localAddr, 0))) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::locked_ConnectAttempt_CurrentAddresses() "; std::cerr << "Adding tcp connection attempt: "; std::cerr << "Current Local Addr: " << rs_inet_ntoa(localAddr->sin_addr); std::cerr << ":" << ntohs(localAddr->sin_port); std::cerr << std::endl; #endif peerConnectAddress pca; pca.addr = *localAddr; pca.type = RS_NET_CONN_TCP_LOCAL; pca.delay = P3CONNMGR_TCP_DEFAULT_DELAY; pca.ts = time(NULL); pca.period = P3CONNMGR_TCP_DEFAULT_PERIOD; sockaddr_clear(&(pca.proxyaddr)); sockaddr_clear(&(pca.srcaddr)); pca.bandwidth = 0; addAddressIfUnique(peer->connAddrs, pca, false); } if ((serverAddr) && (locked_CheckPotentialAddr(serverAddr, 0))) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::locked_ConnectAttempt_CurrentAddresses() "; std::cerr << "Adding tcp connection attempt: "; std::cerr << "Current Ext Addr: " << rs_inet_ntoa(serverAddr->sin_addr); std::cerr << ":" << ntohs(serverAddr->sin_port); std::cerr << std::endl; #endif peerConnectAddress pca; pca.addr = *serverAddr; pca.type = RS_NET_CONN_TCP_EXTERNAL; pca.delay = P3CONNMGR_TCP_DEFAULT_DELAY; pca.ts = time(NULL); pca.period = P3CONNMGR_TCP_DEFAULT_PERIOD; sockaddr_clear(&(pca.proxyaddr)); sockaddr_clear(&(pca.srcaddr)); pca.bandwidth = 0; addAddressIfUnique(peer->connAddrs, pca, false); } } void p3LinkMgrIMPL::locked_ConnectAttempt_HistoricalAddresses(peerConnectState *peer, const pqiIpAddrSet &ipAddrs) { /* now try historical addresses */ /* try local addresses first */ std::list::const_iterator ait; time_t now = time(NULL); #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::locked_ConnectAttempt_HistoricalAddresses()"; std::cerr << std::endl; #endif for(ait = ipAddrs.mLocal.mAddrs.begin(); ait != ipAddrs.mLocal.mAddrs.end(); ait++) { if (locked_CheckPotentialAddr(&(ait->mAddr), now - ait->mSeenTime)) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::locked_ConnectAttempt_HistoricalAddresses() "; std::cerr << "Adding tcp connection attempt: "; std::cerr << "Local Addr: " << rs_inet_ntoa(ait->mAddr.sin_addr); std::cerr << ":" << ntohs(ait->mAddr.sin_port); std::cerr << std::endl; #endif peerConnectAddress pca; pca.addr = ait->mAddr; pca.type = RS_NET_CONN_TCP_LOCAL; pca.delay = P3CONNMGR_TCP_DEFAULT_DELAY; pca.ts = time(NULL); pca.period = P3CONNMGR_TCP_DEFAULT_PERIOD; sockaddr_clear(&(pca.proxyaddr)); sockaddr_clear(&(pca.srcaddr)); pca.bandwidth = 0; addAddressIfUnique(peer->connAddrs, pca, false); } } for(ait = ipAddrs.mExt.mAddrs.begin(); ait != ipAddrs.mExt.mAddrs.end(); ait++) { if (locked_CheckPotentialAddr(&(ait->mAddr), now - ait->mSeenTime)) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::locked_ConnectAttempt_HistoricalAddresses() "; std::cerr << "Adding tcp connection attempt: "; std::cerr << "Ext Addr: " << rs_inet_ntoa(ait->mAddr.sin_addr); std::cerr << ":" << ntohs(ait->mAddr.sin_port); std::cerr << std::endl; #endif peerConnectAddress pca; pca.addr = ait->mAddr; pca.type = RS_NET_CONN_TCP_EXTERNAL; pca.delay = P3CONNMGR_TCP_DEFAULT_DELAY; pca.ts = time(NULL); pca.period = P3CONNMGR_TCP_DEFAULT_PERIOD; sockaddr_clear(&(pca.proxyaddr)); sockaddr_clear(&(pca.srcaddr)); pca.bandwidth = 0; addAddressIfUnique(peer->connAddrs, pca, false); } } } void p3LinkMgrIMPL::locked_ConnectAttempt_AddDynDNS(peerConnectState *peer, std::string dyndns, uint16_t port) { /* try dyndns address too */ struct in_addr addr; if (!dyndns.empty() && port) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::locked_ConnectAttempt_AddDynDNS() Looking up DynDNS address: " << dyndns << std::endl; #endif if(mDNSResolver->getIPAddressFromString(dyndns, addr)) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::locked_ConnectAttempt_AddDynDNS() "; std::cerr << "Adding tcp connection attempt: "; std::cerr << "DynDNS Addr: " << rs_inet_ntoa(addr); std::cerr << ":" << ntohs(port); std::cerr << std::endl; #endif peerConnectAddress pca; pca.addr.sin_family = AF_INET; pca.addr.sin_addr.s_addr = addr.s_addr; pca.addr.sin_port = htons(port); pca.type = RS_NET_CONN_TCP_EXTERNAL; //for the delay, we add a random time and some more time when the friend list is big pca.delay = P3CONNMGR_TCP_DEFAULT_DELAY; pca.ts = time(NULL); pca.period = P3CONNMGR_TCP_DEFAULT_PERIOD; sockaddr_clear(&(pca.proxyaddr)); sockaddr_clear(&(pca.srcaddr)); pca.bandwidth = 0; /* check address validity */ if (locked_CheckPotentialAddr(&(pca.addr), 0)) { addAddressIfUnique(peer->connAddrs, pca, false); } } else { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::locked_ConnectAttempt_AddDynDNS() DNSResolver hasn't found addr yet"; std::cerr << std::endl; #endif } } else { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::locked_ConnectAttempt_AddDynDNS() Address(" << dyndns << ") or Port(" << port << ") NULL ignoring"; std::cerr << std::endl; #endif } } void p3LinkMgrIMPL::locked_ConnectAttempt_AddTunnel(peerConnectState *peer) { if (!(peer->state & RS_PEER_S_CONNECTED) && mAllowTunnelConnection) { #ifdef LINKMGR_DEBUG std::cerr << "Adding TUNNEL Connection Attempt"; std::cerr << std::endl; #endif peerConnectAddress pca; pca.type = RS_NET_CONN_TUNNEL; pca.ts = time(NULL); pca.period = 0; sockaddr_clear(&pca.addr); sockaddr_clear(&(pca.proxyaddr)); sockaddr_clear(&(pca.srcaddr)); pca.bandwidth = 0; addAddressIfUnique(peer->connAddrs, pca, false); } } bool p3LinkMgrIMPL::addAddressIfUnique(std::list &addrList, peerConnectAddress &pca, bool pushFront) { /* iterate through the list, and make sure it isn't already * in the list */ #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::addAddressIfUnique() Checking Address: " << rs_inet_ntoa(pca.addr.sin_addr); std::cerr << std::endl; #endif std::list::iterator it; for(it = addrList.begin(); it != addrList.end(); it++) { if ((pca.addr.sin_addr.s_addr == it->addr.sin_addr.s_addr) && (pca.addr.sin_port == it->addr.sin_port) && (pca.type == it->type)) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::addAddressIfUnique() Discarding Duplicate Address"; std::cerr << std::endl; #endif /* already */ return false; } } #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::addAddressIfUnique() Adding New Address"; std::cerr << std::endl; #endif if (pushFront) { addrList.push_front(pca); } else { addrList.push_back(pca); } return true; } bool p3LinkMgrIMPL::locked_ConnectAttempt_Complete(peerConnectState *peer) { /* flag as last attempt to prevent loop */ //add a random perturbation between 0 and 2 sec. peer->lastattempt = time(NULL) + rand() % MAX_RANDOM_ATTEMPT_OFFSET; if (peer->inConnAttempt) { /* -> it'll automatically use the addresses we added */ #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::locked_ConnectAttempt_Complete() Already in CONNECT ATTEMPT"; std::cerr << std::endl; std::cerr << "p3LinkMgrIMPL::locked_ConnectAttempt_Complete() Remaining ConnAddr Count: " << peer->connAddrs.size(); std::cerr << std::endl; #endif return true; } /* start a connection attempt */ if (peer->connAddrs.size() > 0) { #ifdef LINKMGR_DEBUG std::ostringstream out; out << "p3LinkMgrIMPL::locked_ConnectAttempt_Complete() Started CONNECT ATTEMPT! " ; out << std::endl; out << "p3LinkMgrIMPL::locked_ConnectAttempt_Complete() ConnAddr Count: " << peer->connAddrs.size(); rslog(RSL_DEBUG_ALERT, p3connectzone, out.str()); std::cerr << out.str() << std::endl; #endif peer->actions |= RS_PEER_CONNECT_REQ; mStatusChanged = true; return true; } else { #ifdef LINKMGR_DEBUG std::ostringstream out; out << "p3LinkMgrIMPL::locked_ConnectAttempt_Complete() No addr in the connect attempt list. Not suitable for CONNECT ATTEMPT! "; rslog(RSL_DEBUG_ALERT, p3connectzone, out.str()); std::cerr << out.str() << std::endl; #endif return false; } return false; } /*********************************************************************************************************** ************************************* Handling of Friends ************************************************* ***********************************************************************************************************/ int p3LinkMgrIMPL::addFriend(const std::string &id, bool isVisible) { { RsStackMutex stack(mLinkMtx); /****** STACK LOCK MUTEX *******/ #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::addFriend(" << id << "," << isVisible << ")"; std::cerr << std::endl; #endif std::map::iterator it; it = mFriendList.find(id); if (it != mFriendList.end()) { std::cerr << "p3LinkMgrIMPL::addFriend() ERROR, friend already exists : " << id; std::cerr << std::endl; return 0; } peerConnectState pcs; pcs.dhtVisible = isVisible; pcs.id = id; pcs.name = "NoName"; pcs.state = RS_PEER_S_FRIEND; pcs.actions = RS_PEER_NEW; mFriendList[id] = pcs; mStatusChanged = true; } mNetMgr->netAssistFriend(id, isVisible); return 1; } int p3LinkMgrIMPL::removeFriend(const std::string &id) { { RsStackMutex stack(mLinkMtx); /****** STACK LOCK MUTEX *******/ #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::removeFriend(" << id << ")"; std::cerr << std::endl; #endif std::map::iterator it; it = mFriendList.find(id); if (it == mFriendList.end()) { std::cerr << "p3LinkMgrIMPL::removeFriend() ERROR, friend not there : " << id; std::cerr << std::endl; return 0; } /* Move to OthersList (so remove can be handled via the action) */ peerConnectState peer = it->second; 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; mFriendList.erase(it); } mNetMgr->netAssistFriend(id, false); return 1; } void p3LinkMgrIMPL::printPeerLists(std::ostream &out) { { RsStackMutex stack(mLinkMtx); /****** STACK LOCK MUTEX *******/ out << "p3LinkMgrIMPL::printPeerLists() Friend List"; out << std::endl; std::map::iterator it; for(it = mFriendList.begin(); it != mFriendList.end(); it++) { out << "\t SSL ID: " << it->second.id; out << "\t State: " << it->second.state; out << std::endl; } out << "p3LinkMgrIMPL::printPeerLists() Others List"; out << std::endl; for(it = mOthersList.begin(); it != mOthersList.end(); it++) { out << "\t SSL ID: " << it->second.id; out << "\t State: " << it->second.state; } } return; } void printConnectState(std::ostream &out, peerConnectState &peer) { out << "Friend: " << peer.name << " Id: " << peer.id << " State: " << peer.state; if (peer.state & RS_PEER_S_FRIEND) out << " S:RS_PEER_S_FRIEND"; if (peer.state & RS_PEER_S_ONLINE) out << " S:RS_PEER_S_ONLINE"; if (peer.state & RS_PEER_S_CONNECTED) out << " S:RS_PEER_S_CONNECTED"; out << " Actions: " << peer.actions; if (peer.actions & RS_PEER_NEW) out << " A:RS_PEER_NEW"; if (peer.actions & RS_PEER_MOVED) out << " A:RS_PEER_MOVED"; if (peer.actions & RS_PEER_CONNECTED) out << " A:RS_PEER_CONNECTED"; if (peer.actions & RS_PEER_DISCONNECTED) out << " A:RS_PEER_DISCONNECTED"; if (peer.actions & RS_PEER_CONNECT_REQ) out << " A:RS_PEER_CONNECT_REQ"; out << std::endl; return; }