#include "dht/p3bitdht.h" #include #include #include "bitdht/bdiface.h" #include "bitdht/bdstddht.h" #include "bitdht/bdmanager.h" //#include "udp/udplayer.h" #include "util/rsnet.h" #include "tcponudp/tou.h" #include "tcponudp/udpstunner.h" #include "tcponudp/udprelay.h" #include "pqi/p3netmgr.h" #include "pqi/pqimonitor.h" #define PEERNET_CONNECT_TIMEOUT 180 // Should be BIGGER than Higher level (but okay if not!) #define MIN_DETERMINISTIC_SWITCH_PERIOD 60 /*** * * #define DEBUG_BITDHT_COMMON 1 // These are the things that are called regularly (annoying for debugging specifics) * #define DEBUG_PEERNET 1 * **/ /****************************************************************************************** ************************************* Dht Callback *************************************** ******************************************************************************************/ /**** dht NodeCallback **** * * * In the old version, we used this to callback mConnCb->peerStatus() * We might want to drop this, and concentrate on the connection stuff. * * -> if an new dht peer, then pass to Stunners. * -> do we care if we know them? not really! */ int p3BitDht::InfoCallback(const bdId *id, uint32_t /*type*/, uint32_t /*flags*/, std::string /*info*/) { /* translate info */ std::string rsid; struct sockaddr_in addr = id->addr; int outtype = PNASS_TYPE_BADPEER; int outreason = PNASS_REASON_UNKNOWN; int outage = 0; #ifdef DEBUG_BITDHT_COMMON std::cerr << "p3BitDht::InfoCallback() likely BAD_PEER: "; bdStdPrintId(std::cerr, id); std::cerr << std::endl; #endif { RsStackMutex stack(dhtMtx); /********** LOCKED MUTEX ***************/ DhtPeerDetails *dpd = findInternalDhtPeer_locked(&(id->id), RSDHT_PEERTYPE_ANY); if (dpd) { rsid = dpd->mRsId; } } if (mPeerSharer) { mPeerSharer->updatePeer(rsid, addr, outtype, outreason, outage); } /* call to the Stunners to drop the address as well */ /* IDEALLY these addresses should all be filtered at UdpLayer level instead! */ if (mDhtStunner) { mDhtStunner->dropStunPeer(addr); } if (mProxyStunner) { mProxyStunner->dropStunPeer(addr); } return 1; } /**** dht NodeCallback **** * * * In the old version, we used this to callback mConnCb->peerStatus() * We might want to drop this, and concentrate on the connection stuff. * * -> if an new dht peer, then pass to Stunners. * -> do we care if we know them? not really! */ int p3BitDht::NodeCallback(const bdId *id, uint32_t peerflags) { // No need for Mutex, and Stunners are self protected. // These are the flags that will be returned by p3BitDht & RS peers with the new DHT. // if (peerflags & BITDHT_PEER_STATUS_DHT_ENGINE_VERSION) // Change to this later... if ((peerflags & BITDHT_PEER_STATUS_DHT_ENGINE) && (peerflags & BITDHT_PEER_STATUS_DHT_APPL)) { /* pass off to the Stunners * but only if they need them. * ideally don't pass to both peers... (XXX do later) */ { RsStackMutex stack(dhtMtx); /********** LOCKED MUTEX ***************/ if (id->id == mOwnDhtId) { #ifdef DEBUG_BITDHT_COMMON std::cerr << "p3BitDht::NodeCallback() Skipping own id"; bdStdPrintId(std::cerr, id); std::cerr << std::endl; #endif return 1; } } if ((mProxyStunner) && (mProxyStunner->needStunPeers())) { #ifdef DEBUG_BITDHT_COMMON std::cerr << "p3BitDht::NodeCallback() Passing BitDHT Peer to DhtStunner: "; bdStdPrintId(std::cerr, id); std::cerr << std::endl; #endif mProxyStunner->addStunPeer(id->addr, ""); } /* else */ // removed else until we have lots of peers. if ((mDhtStunner) && (mDhtStunner->needStunPeers())) { #ifdef DEBUG_BITDHT_COMMON std::cerr << "p3BitDht::NodeCallback() Passing BitDHT Peer to DhtStunner: "; bdStdPrintId(std::cerr, id); std::cerr << std::endl; #endif mDhtStunner->addStunPeer(id->addr, ""); } } return 1; } /**** dht PeerCallback **** * * * In the old version, we used this to callback mConnCb->peerConnectRequest() * we need to continue doing this, to maintain compatibility. * * -> update Dht Status, and trigger connect if ONLINE or UNREACHABLE */ int p3BitDht::PeerCallback(const bdId *id, uint32_t status) { //std::string str; //bdStdPrintNodeId(str, &(id->id)); //std::cerr << "p3BitDht::dhtPeerCallback()"; //std::cerr << std::endl; RsStackMutex stack(dhtMtx); /********** LOCKED MUTEX ***************/ DhtPeerDetails *dpd = findInternalDhtPeer_locked(&(id->id), RSDHT_PEERTYPE_FRIEND); if (!dpd) { /* ERROR */ std::cerr << "p3BitDht::PeerCallback() ERROR Unknown Peer: "; bdStdPrintId(std::cerr, id); std::cerr << " status: " << status; std::cerr << std::endl; return 0; } sockaddr_clear(&(dpd->mDhtId.addr)); switch(status) { default: dpd->mDhtState = RSDHT_PEERDHT_NOT_ACTIVE; break; case BITDHT_MGR_QUERY_FAILURE: dpd->mDhtState = RSDHT_PEERDHT_FAILURE; break; case BITDHT_MGR_QUERY_PEER_OFFLINE: dpd->mDhtState = RSDHT_PEERDHT_OFFLINE; break; case BITDHT_MGR_QUERY_PEER_UNREACHABLE: dpd->mDhtState = RSDHT_PEERDHT_UNREACHABLE; dpd->mDhtId = *id; // set the IP:Port of the unreachable peer. UnreachablePeerCallback_locked(id, status, dpd); break; case BITDHT_MGR_QUERY_PEER_ONLINE: dpd->mDhtState = RSDHT_PEERDHT_ONLINE; dpd->mDhtId = *id; // set the IP:Port of the Online peer. OnlinePeerCallback_locked(id, status, dpd); break; } time_t now = time(NULL); dpd->mDhtUpdateTS = now; return 1; } int p3BitDht::OnlinePeerCallback_locked(const bdId *id, uint32_t /*status*/, DhtPeerDetails *dpd) { /* remove unused parameter warnings */ (void) id; if ((dpd->mPeerConnectState != RSDHT_PEERCONN_DISCONNECTED) || (dpd->mPeerReqState == RSDHT_PEERREQ_RUNNING)) { #ifdef DEBUG_PEERNET std::cerr << "p3BitDht::OnlinePeerCallback_locked() WARNING Ignoring Callback: connection already underway: "; bdStdPrintId(std::cerr, id); std::cerr << std::endl; #endif return 1; } bool connectOk = true; bool doTCPCallback = false; /* work out network state */ uint32_t connectFlags = dpd->mConnectLogic.connectCb(CSB_CONNECT_DIRECT, mNetMgr->getNetworkMode(), mNetMgr->getNatHoleMode(), mNetMgr->getNatTypeMode()); // bool useProxyPort = (connectFlags & CSB_ACTION_PROXY_PORT); switch(connectFlags & CSB_ACTION_MASK_MODE) { default: case CSB_ACTION_WAIT: { connectOk = false; } break; case CSB_ACTION_TCP_CONN: { connectOk = false; doTCPCallback = true; } break; case CSB_ACTION_DIRECT_CONN: { connectOk = true; } break; case CSB_ACTION_PROXY_CONN: { /* ERROR */ std::cerr << "dhtPeerCallback: ERROR ConnectLogic returned PROXY"; std::cerr << std::endl; connectOk = false; } break; case CSB_ACTION_RELAY_CONN: { /* ERROR */ std::cerr << "dhtPeerCallback: ERROR ConnectLogic returned RELAY"; std::cerr << std::endl; connectOk = false; } break; } if (connectOk) { #ifdef DEBUG_PEERNET std::cerr << "dhtPeerCallback. Peer Online, triggering Direct Connection for: "; bdStdPrintId(std::cerr, id); std::cerr << std::endl; #endif /* Push Back PeerAction */ PeerAction ca; ca.mType = PEERNET_ACTION_TYPE_CONNECT; ca.mMode = BITDHT_CONNECT_MODE_DIRECT; ca.mDestId = *id; ca.mAnswer = BITDHT_CONNECT_ERROR_NONE; mActions.push_back(ca); } /* might need to make this an ACTION - leave for now */ if (doTCPCallback) { #ifdef DEBUG_PEERNET std::cerr << "dhtPeerCallback. Peer Online, triggering TCP Connection for: "; bdStdPrintId(std::cerr, id); std::cerr << std::endl; #endif /* Push Back PeerAction */ PeerAction ca; ca.mType = PEERNET_ACTION_TYPE_TCPATTEMPT; ca.mMode = BITDHT_CONNECT_MODE_DIRECT; ca.mDestId = *id; ca.mAnswer = BITDHT_CONNECT_ERROR_NONE; mActions.push_back(ca); //ConnectCalloutTCPAttempt(dpd->mRsId, id->addr); } return 1; } int p3BitDht::UnreachablePeerCallback_locked(const bdId *id, uint32_t /*status*/, DhtPeerDetails *dpd) { if ((dpd->mPeerConnectState != RSDHT_PEERCONN_DISCONNECTED) || (dpd->mPeerReqState == RSDHT_PEERREQ_RUNNING)) { #ifdef DEBUG_PEERNET std::cerr << "p3BitDht::UnreachablePeerCallback_locked() WARNING Ignoring Callback: connection already underway: "; bdStdPrintId(std::cerr, id); std::cerr << std::endl; #endif return 1; } #ifdef DEBUG_PEERNET std::cerr << "dhtPeerCallback. Peer Unreachable, triggering Proxy | Relay Connection for: "; bdStdPrintId(std::cerr, id); std::cerr << std::endl; #endif bool proxyOk = false; bool connectOk = true; /* work out network state */ uint32_t connectFlags = dpd->mConnectLogic.connectCb(CSB_CONNECT_UNREACHABLE, mNetMgr->getNetworkMode(), mNetMgr->getNatHoleMode(), mNetMgr->getNatTypeMode()); bool useProxyPort = (connectFlags & CSB_ACTION_PROXY_PORT); switch(connectFlags & CSB_ACTION_MASK_MODE) { default: case CSB_ACTION_WAIT: { #ifdef DEBUG_PEERNET std::cerr << "dhtPeerCallback. Request to Wait ... so no Connection Attempt for "; bdStdPrintId(std::cerr, id); std::cerr << std::endl; #endif connectOk = false; } break; case CSB_ACTION_DIRECT_CONN: { /* ERROR */ std::cerr << "dhtPeerCallback: ERROR ConnectLogic returned DIRECT"; std::cerr << std::endl; connectOk = false; } break; case CSB_ACTION_PROXY_CONN: { proxyOk = true; connectOk = true; } break; case CSB_ACTION_RELAY_CONN: { proxyOk = false; connectOk = true; } break; } if (connectOk) { /* Push Back PeerAction */ PeerAction ca; ca.mType = PEERNET_ACTION_TYPE_CONNECT; ca.mDestId = *id; dpd->mConnectLogic.storeProxyPortChoice(connectFlags, useProxyPort); if (proxyOk) { ca.mMode = BITDHT_CONNECT_MODE_PROXY; #ifdef DEBUG_PEERNET std::cerr << "dhtPeerCallback. Trying Proxy Connection."; std::cerr << std::endl; #endif } else { #ifdef DEBUG_PEERNET std::cerr << "dhtPeerCallback. Trying Relay Connection."; std::cerr << std::endl; #endif ca.mMode = BITDHT_CONNECT_MODE_RELAY; } ca.mAnswer = BITDHT_CONNECT_ERROR_NONE; mActions.push_back(ca); } else { #ifdef DEBUG_PEERNET std::cerr << "dhtPeerCallback. Cancelled Connection Attempt for "; bdStdPrintId(std::cerr, id); std::cerr << std::endl; #endif } return 1; } int p3BitDht::ValueCallback(const bdNodeId */*id*/, std::string /*key*/, uint32_t /*status*/) { std::cerr << "p3BitDht::ValueCallback() ERROR Does nothing!"; std::cerr << std::endl; return 1; } int p3BitDht::ConnectCallback(const bdId *srcId, const bdId *proxyId, const bdId *destId, uint32_t mode, uint32_t point, uint32_t param, uint32_t cbtype, uint32_t errcode) { #ifdef DEBUG_PEERNET #endif std::cerr << "p3BitDht::ConnectCallback()"; std::cerr << std::endl; std::cerr << "srcId: "; bdStdPrintId(std::cerr, srcId); std::cerr << std::endl; std::cerr << "proxyId: "; bdStdPrintId(std::cerr, proxyId); std::cerr << std::endl; std::cerr << "destId: "; bdStdPrintId(std::cerr, destId); std::cerr << std::endl; std::cerr << " mode: " << mode; std::cerr << " param: " << param; std::cerr << " point: " << point; std::cerr << " cbtype: " << cbtype; std::cerr << std::endl; /* we handle MID and START/END points differently... this is biggest difference. * so handle first. */ bdId peerId; time_t now = time(NULL); switch(point) { default: case BD_PROXY_CONNECTION_UNKNOWN_POINT: { std::cerr << "p3BitDht::dhtConnectCallback() ERROR UNKNOWN point, ignoring Callback"; std::cerr << std::endl; return 0; } case BD_PROXY_CONNECTION_START_POINT: peerId = *destId; break; case BD_PROXY_CONNECTION_END_POINT: peerId = *srcId; break; case BD_PROXY_CONNECTION_MID_POINT: { /* AS a mid point, we can receive.... AUTH,PENDING,PROXY,FAILED */ switch(cbtype) { case BITDHT_CONNECT_CB_AUTH: { #ifdef DEBUG_PEERNET std::cerr << "dhtConnectionCallback() Proxy Connection Requested Between:"; std::cerr << std::endl; bdStdPrintId(std::cerr, srcId); std::cerr << " and "; bdStdPrintId(std::cerr, destId); std::cerr << std::endl; #endif /* if there is an error code - then it is just to inform us of a failed attempt */ if (errcode) { RelayHandler_LogFailedProxyAttempt(srcId, destId, mode, errcode); /* END MID FAILED ATTEMPT */ return 1; } uint32_t bandwidth = 0; int connectionAllowed = BITDHT_CONNECT_ERROR_GENERIC; if (checkProxyAllowed(srcId, destId, mode, bandwidth)) { connectionAllowed = BITDHT_CONNECT_ANSWER_OKAY; #ifdef DEBUG_PEERNET std::cerr << "dhtConnectionCallback() Connection Allowed"; std::cerr << std::endl; #endif } else { connectionAllowed = BITDHT_CONNECT_ERROR_AUTH_DENIED; #ifdef DEBUG_PEERNET std::cerr << "dhtConnectionCallback() Connection Denied"; std::cerr << std::endl; #endif } RsStackMutex stack(dhtMtx); /********** LOCKED MUTEX ***************/ /* Push Back PeerAction */ PeerAction ca; ca.mType = PEERNET_ACTION_TYPE_AUTHORISE; ca.mMode = mode; ca.mProxyId = *proxyId; ca.mSrcId = *srcId; ca.mDestId = *destId; ca.mPoint = point; ca.mAnswer = connectionAllowed; ca.mDelayOrBandwidth = bandwidth; mActions.push_back(ca); } break; case BITDHT_CONNECT_CB_PENDING: { #ifdef DEBUG_PEERNET std::cerr << "dhtConnectionCallback() Proxy Connection Pending:"; std::cerr << std::endl; bdStdPrintId(std::cerr, srcId); std::cerr << " and "; bdStdPrintId(std::cerr, destId); std::cerr << std::endl; #endif } break; case BITDHT_CONNECT_CB_PROXY: { #ifdef DEBUG_PEERNET std::cerr << "dhtConnectionCallback() Proxy Connection Starting:"; std::cerr << std::endl; bdStdPrintId(std::cerr, srcId); std::cerr << " and "; bdStdPrintId(std::cerr, destId); std::cerr << std::endl; #endif } break; case BITDHT_CONNECT_CB_FAILED: { #ifdef DEBUG_PEERNET std::cerr << "dhtConnectionCallback() Proxy Connection Failed:"; std::cerr << std::endl; bdStdPrintId(std::cerr, srcId); std::cerr << " and "; bdStdPrintId(std::cerr, destId); std::cerr << " ErrorCode: " << errcode; int errsrc = errcode & BITDHT_CONNECT_ERROR_MASK_SOURCE; int errtype = errcode & BITDHT_CONNECT_ERROR_MASK_TYPE; std::cerr << " ErrorSrc: " << errsrc; std::cerr << " ErrorType: " << errtype; std::cerr << std::endl; #endif if (mode == BITDHT_CONNECT_MODE_RELAY) { removeRelayConnection(srcId, destId); } } break; default: case BITDHT_CONNECT_CB_START: { std::cerr << "dhtConnectionCallback() ERROR unexpected Proxy ConnectionCallback:"; std::cerr << std::endl; bdStdPrintId(std::cerr, srcId); std::cerr << " and "; bdStdPrintId(std::cerr, destId); std::cerr << std::endl; } break; } /* End the MID Point stuff */ return 1; } } /* if we get here, we are an endpoint (peer specified in peerId) */ /* translate id into string for exclusive mode */ std::string pid; bdStdPrintNodeId(pid, &(peerId.id), false); switch(cbtype) { case BITDHT_CONNECT_CB_AUTH: { #ifdef DEBUG_PEERNET std::cerr << "dhtConnectionCallback() Connection Requested By: "; bdStdPrintId(std::cerr, &(peerId)); std::cerr << std::endl; #endif int connectionAllowed = BITDHT_CONNECT_ERROR_GENERIC; if (checkConnectionAllowed(&(peerId), mode)) { connectionAllowed = BITDHT_CONNECT_ANSWER_OKAY; #ifdef DEBUG_PEERNET std::cerr << "dhtConnectionCallback() Connection Allowed"; std::cerr << std::endl; #endif } else { connectionAllowed = BITDHT_CONNECT_ERROR_AUTH_DENIED; #ifdef DEBUG_PEERNET std::cerr << "dhtConnectionCallback() Connection Denied"; std::cerr << std::endl; #endif } RsStackMutex stack(dhtMtx); /********** LOCKED MUTEX ***************/ /* Push Back PeerAction */ PeerAction ca; ca.mType = PEERNET_ACTION_TYPE_AUTHORISE; ca.mProxyId = *proxyId; ca.mSrcId = *srcId; ca.mDestId = *destId; ca.mDelayOrBandwidth = 0; /* Check Proxy ExtAddress Status (but only if connection is Allowed) */ if ((connectionAllowed == BITDHT_CONNECT_ANSWER_OKAY) && (mode == BITDHT_CONNECT_MODE_PROXY)) { #ifdef DEBUG_PEERNET std::cerr << "dhtConnectionCallback() Checking Address for Proxy"; std::cerr << std::endl; #endif struct sockaddr_in extaddr; uint8_t extStable = 0; sockaddr_clear(&extaddr); bool connectOk = false; bool proxyPort = false; bool exclusivePort = false; #ifdef DEBUG_PEERNET std::cerr << "dhtConnectionCallback(): Proxy... deciding which port to use."; std::cerr << std::endl; #endif DhtPeerDetails *dpd = findInternalDhtPeer_locked(&(peerId.id), RSDHT_PEERTYPE_FRIEND); if (dpd) { proxyPort = dpd->mConnectLogic.shouldUseProxyPort( mNetMgr->getNetworkMode(), mNetMgr->getNatHoleMode(), mNetMgr->getNatTypeMode()); dpd->mConnectLogic.storeProxyPortChoice(0, proxyPort); #ifdef DEBUG_PEERNET std::cerr << "dhtConnectionCallback: Setting ProxyPort: "; std::cerr << " UseProxyPort? " << proxyPort; std::cerr << std::endl; std::cerr << "dhtConnectionCallback: Checking ConnectLogic.NetState: "; std::cerr << dpd->mConnectLogic.calcNetState(mNetMgr->getNetworkMode(), mNetMgr->getNatHoleMode(), mNetMgr->getNatTypeMode()); std::cerr << std::endl; #endif if (proxyPort) { exclusivePort = (CSB_NETSTATE_EXCLUSIVENAT == dpd->mConnectLogic.calcNetState( mNetMgr->getNetworkMode(), mNetMgr->getNatHoleMode(), mNetMgr->getNatTypeMode())); } if (exclusivePort) { #ifdef DEBUG_PEERNET std::cerr << "dhtConnectionCallback: we Require Exclusive Proxy Port for connection"; std::cerr << std::endl; #endif } else { #ifdef DEBUG_PEERNET std::cerr << "dhtConnectionCallback: Dont need Exclusive Proxy Port for connection"; std::cerr << std::endl; #endif } connectOk = true; } else { std::cerr << "PeerAction: Connect Proxy: ERROR Cannot find PeerStatus"; std::cerr << std::endl; } UdpStunner *stunner = mProxyStunner; if (!proxyPort) { stunner = mDhtStunner; } if ((connectOk) && (stunner) && (stunner->externalAddr(extaddr, extStable))) { if (extStable) { #ifdef DEBUG_PEERNET std::cerr << "dhtConnectionCallback() Proxy Connection Attempt to: "; bdStdPrintId(std::cerr, &(peerId)); std::cerr << " is Ok as we have Stable Own External Proxy Address"; std::cerr << std::endl; #endif if (point == BD_PROXY_CONNECTION_END_POINT) { ca.mDestId.addr = extaddr; } else { ca.mSrcId.addr = extaddr; std::cerr << "dhtConnectionCallback() ERROR Proxy Auth as SrcId"; std::cerr << std::endl; } /* check if we require exclusive use of the proxy port */ if (exclusivePort) { #ifdef DEBUG_PEERNET std::cerr << "dhtConnectionCallback: Attempting to Grab ExclusiveLock of UdpStunner"; std::cerr << std::endl; #endif int stun_age = mProxyStunner->grabExclusiveMode(pid); if (stun_age > 0) { int delay = 0; if (stun_age < MIN_DETERMINISTIC_SWITCH_PERIOD) { delay = MIN_DETERMINISTIC_SWITCH_PERIOD - stun_age; } /* great we got it! */ ca.mDelayOrBandwidth = delay; #ifdef DEBUG_PEERNET std::cerr << "dhtConnectionCallback: GotExclusiveLock With Delay: " << delay; std::cerr << " for stable port"; std::cerr << std::endl; #endif DhtPeerDetails *dpd = findInternalDhtPeer_locked(&(peerId.id), RSDHT_PEERTYPE_FRIEND); if (dpd) { dpd->mExclusiveProxyLock = true; #ifdef DEBUG_PEERNET std::cerr << "dhtConnectionCallback: Success at grabbing ExclusiveLock of UdpStunner"; std::cerr << std::endl; #endif } else { std::cerr << "PeerAction: Connect Proxy: ERROR Cannot find PeerStatus"; std::cerr << std::endl; connectionAllowed = BITDHT_CONNECT_ERROR_TEMPUNAVAIL; mProxyStunner->releaseExclusiveMode(pid,false); } } else { /* failed to get exclusive mode - must wait */ connectionAllowed = BITDHT_CONNECT_ERROR_TEMPUNAVAIL; #ifdef DEBUG_PEERNET std::cerr << "dhtConnectionCallback: Failed to Grab ExclusiveLock, Returning TEMPUNAVAIL"; std::cerr << std::endl; #endif } } } else { if (exclusivePort) { connectionAllowed = BITDHT_CONNECT_ERROR_TEMPUNAVAIL; #ifdef DEBUG_PEERNET std::cerr << "dhtConnectionCallback() Proxy Connection"; std::cerr << " is Discarded, as External Proxy Address is Not Stable! (EXCLUSIVE MODE)"; std::cerr << std::endl; #endif } else { connectionAllowed = BITDHT_CONNECT_ERROR_UNREACHABLE; #ifdef DEBUG_PEERNET std::cerr << "dhtConnectionCallback() Proxy Connection"; std::cerr << " is Discarded, as Own External Proxy Address is Not Stable!"; std::cerr << std::endl; #endif } } } else { connectionAllowed = BITDHT_CONNECT_ERROR_TEMPUNAVAIL; #ifdef DEBUG_PEERNET std::cerr << "dhtConnectionCallback() ERROR Proxy Connection "; std::cerr << " is Discarded, as Failed to get Own External Proxy Address."; std::cerr << std::endl; #endif } } ca.mMode = mode; ca.mPoint = point; ca.mAnswer = connectionAllowed; mActions.push_back(ca); } break; case BITDHT_CONNECT_CB_START: { #ifdef DEBUG_PEERNET std::cerr << "dhtConnectionCallback() Connection Starting with: "; bdStdPrintId(std::cerr, &(peerId)); std::cerr << std::endl; #endif RsStackMutex stack(dhtMtx); /********** LOCKED MUTEX ***************/ /* Push Back PeerAction */ PeerAction ca; ca.mType = PEERNET_ACTION_TYPE_START; ca.mMode = mode; ca.mProxyId = *proxyId; ca.mSrcId = *srcId; ca.mDestId = *destId; ca.mPoint = point; ca.mDelayOrBandwidth = param; ca.mAnswer = BITDHT_CONNECT_ERROR_NONE; mActions.push_back(ca); } break; case BITDHT_CONNECT_CB_FAILED: { #ifdef DEBUG_PEERNET #endif std::cerr << "dhtConnectionCallback() Connection Attempt Failed with:"; bdStdPrintId(std::cerr, &(peerId)); std::cerr << std::endl; std::cerr << "dhtConnectionCallback() Proxy:"; bdStdPrintId(std::cerr, proxyId); std::cerr << std::endl; std::cerr << "dhtConnectionCallback() "; std::cerr << " ErrorCode: " << errcode; int errsrc = errcode & BITDHT_CONNECT_ERROR_MASK_SOURCE; int errtype = errcode & BITDHT_CONNECT_ERROR_MASK_TYPE; std::cerr << " ErrorSrc: " << errsrc; std::cerr << " ErrorType: " << errtype; std::cerr << std::endl; RsStackMutex stack(dhtMtx); /********** LOCKED MUTEX ***************/ DhtPeerDetails *dpd = findInternalDhtPeer_locked(&(peerId.id), RSDHT_PEERTYPE_FRIEND); if (dpd) { dpd->mPeerCbMsg = "ERROR : "; dpd->mPeerCbMsg += decodeConnectionError(errcode); dpd->mPeerCbMode = mode; dpd->mPeerCbPoint = point; dpd->mPeerCbProxyId = *proxyId; dpd->mPeerCbDestId = peerId; dpd->mPeerCbTS = now; } else { std::cerr << "dhtConnectionCallback() "; std::cerr << "ERROR Unknown Peer"; std::cerr << std::endl; } } break; case BITDHT_CONNECT_CB_REQUEST: { #ifdef DEBUG_PEERNET std::cerr << "dhtConnectionCallback() Local Connection Request Feedback:"; bdStdPrintId(std::cerr, &(peerId)); std::cerr << std::endl; std::cerr << "dhtConnectionCallback() Proxy:"; bdStdPrintId(std::cerr, proxyId); std::cerr << std::endl; #endif if (point != BD_PROXY_CONNECTION_START_POINT) { std::cerr << "dhtConnectionCallback() ERROR not START_POINT"; std::cerr << std::endl; return 0; } RsStackMutex stack(dhtMtx); /********** LOCKED MUTEX ***************/ DhtPeerDetails *dpd = findInternalDhtPeer_locked(&(peerId.id), RSDHT_PEERTYPE_FRIEND); if (dpd) { if (errcode) { ReleaseProxyExclusiveMode_locked(dpd, false); dpd->mPeerReqStatusMsg = "STOPPED: "; dpd->mPeerReqStatusMsg += decodeConnectionError(errcode); dpd->mPeerReqState = RSDHT_PEERREQ_STOPPED; dpd->mPeerReqTS = now; int updatecode = CSB_UPDATE_FAILED_ATTEMPT; int errtype = errcode & BITDHT_CONNECT_ERROR_MASK_TYPE; switch(errtype) { /* fatal errors */ case BITDHT_CONNECT_ERROR_AUTH_DENIED: { updatecode = CSB_UPDATE_AUTH_DENIED; } break; /* move on errors */ case BITDHT_CONNECT_ERROR_UNREACHABLE: // sym NAT. case BITDHT_CONNECT_ERROR_UNSUPPORTED: // mode unavailable. { updatecode = CSB_UPDATE_MODE_UNAVAILABLE; } break; /* retry attempts */ case BITDHT_CONNECT_ERROR_TEMPUNAVAIL: case BITDHT_CONNECT_ERROR_DUPLICATE: { updatecode = CSB_UPDATE_RETRY_ATTEMPT; } break; /* standard failed attempts */ case BITDHT_CONNECT_ERROR_GENERIC: case BITDHT_CONNECT_ERROR_PROTOCOL: case BITDHT_CONNECT_ERROR_TIMEOUT: case BITDHT_CONNECT_ERROR_NOADDRESS: case BITDHT_CONNECT_ERROR_OVERLOADED: /* CB_REQUEST errors */ case BITDHT_CONNECT_ERROR_TOOMANYRETRY: case BITDHT_CONNECT_ERROR_OUTOFPROXY: { updatecode = CSB_UPDATE_FAILED_ATTEMPT; } break; /* user cancelled ... no update */ case BITDHT_CONNECT_ERROR_USER: { updatecode = CSB_UPDATE_NONE; } break; } if (updatecode) { dpd->mConnectLogic.updateCb(updatecode); } } else // a new connection attempt. { dpd->mPeerReqStatusMsg = "Connect Attempt"; dpd->mPeerReqState = RSDHT_PEERREQ_RUNNING; dpd->mPeerReqMode = mode; dpd->mPeerReqProxyId = *proxyId; dpd->mPeerReqTS = now; // This also is flagged into the instant Cb info. dpd->mPeerCbMsg = "Local Connect Attempt"; dpd->mPeerCbMode = mode; dpd->mPeerCbPoint = point; dpd->mPeerCbProxyId = *proxyId; dpd->mPeerCbDestId = peerId; dpd->mPeerCbTS = now; } } else { std::cerr << "dhtConnectionCallback() ERROR Cannot find PeerStatus"; std::cerr << std::endl; } } break; default: case BITDHT_CONNECT_CB_PENDING: case BITDHT_CONNECT_CB_PROXY: { std::cerr << "dhtConnectionCallback() ERROR unexpected ConnectionCallback:"; std::cerr << std::endl; bdStdPrintId(std::cerr, srcId); std::cerr << " and "; bdStdPrintId(std::cerr, destId); std::cerr << std::endl; } break; } return 1; } /****************************************************************************************** ******************************** Dht Actions / Monitoring ******************************** ******************************************************************************************/ /* tick stuff that isn't in its own thread */ int p3BitDht::tick() { doActions(); monitorConnections(); minuteTick(); #ifdef DEBUG_PEERNET_COMMON time_t now = time(NULL); std::cerr << "p3BitDht::tick() TIME: " << ctime(&now) << std::endl; std::cerr.flush(); #endif return 1; } #define MINUTE_IN_SECS 60 #define TEN_IN_SECS 10 int p3BitDht::minuteTick() { time_t now = time(NULL); int deltaT = 0; { RsStackMutex stack(dhtMtx); /********** LOCKED MUTEX ***************/ deltaT = now-mMinuteTS; } //if (deltaT > MINUTE_IN_SECS) if (deltaT > TEN_IN_SECS) { mRelay->checkRelays(); updateDataRates(); /* temp - testing - print dht & relay traffic */ float dhtRead, dhtWrite; float relayRead, relayWrite, relayRelayed; getRelayRates(relayRead, relayWrite, relayRelayed); getDhtRates(dhtRead, dhtWrite); double denom = deltaT; #ifdef DEBUG_PEERNET_COMMON std::cerr << "p3BitDht::minuteTick() "; std::cerr << "DhtRead: " << dhtRead / denom << " kB/s "; std::cerr << "DhtWrite: " << dhtWrite / denom << " kB/s "; std::cerr << std::endl; std::cerr << "p3BitDht::minuteTick() "; std::cerr << "RelayRead: " << relayRead / denom << " kB/s "; std::cerr << "RelayWrite: " << relayWrite / denom << " kB/s "; std::cerr << "RelayRelayed: " << relayRelayed / denom << " kB/s "; std::cerr << std::endl; #endif RsStackMutex stack(dhtMtx); /********** LOCKED MUTEX ***************/ mMinuteTS = now; } return 1; } int p3BitDht::doActions() { #ifdef DEBUG_PEERNET_COMMON std::cerr << "p3BitDht::doActions()" << std::endl; #endif time_t now = time(NULL); while(mActions.size() > 0) { PeerAction action; { RsStackMutex stack(dhtMtx); /********** LOCKED MUTEX ***************/ if (mActions.size() < 1) { break; } action = mActions.front(); mActions.pop_front(); } switch(action.mType) { case PEERNET_ACTION_TYPE_CONNECT: { /* connect attempt */ #ifdef DEBUG_PEERNET std::cerr << "PeerAction. Connection Attempt to: "; bdStdPrintId(std::cerr, &(action.mDestId)); std::cerr << " mode: " << action.mMode; std::cerr << std::endl; #endif bool doConnectionRequest = false; bool connectionReqFailed = false; bool grabbedExclusivePort = false; /* translate id into string for exclusive mode */ std::string pid; bdStdPrintNodeId(pid, &(action.mDestId.id), false); // Parameters that will be used for the Connect Request. struct sockaddr_in connAddr; // We zero this address. (DHT Layer handles most cases) sockaddr_clear(&connAddr); uint32_t connStart = 1; /* > 0 indicates GO (number indicates required startup delay) */ uint32_t connDelay = 0; uint32_t failReason = CSB_UPDATE_MODE_UNAVAILABLE; if ((action.mMode == BITDHT_CONNECT_MODE_DIRECT) || (action.mMode == BITDHT_CONNECT_MODE_RELAY)) { doConnectionRequest = true; } else if (action.mMode == BITDHT_CONNECT_MODE_PROXY) { struct sockaddr_in extaddr; uint8_t extStable = 0; sockaddr_clear(&extaddr); bool proxyPort = true; bool exclusivePort = false; bool connectOk = false; #ifdef DEBUG_PEERNET std::cerr << "PeerAction: Proxy... deciding which port to use."; std::cerr << std::endl; #endif { RsStackMutex stack(dhtMtx); /********** LOCKED MUTEX ***************/ DhtPeerDetails *dpd = findInternalDhtPeer_locked(&(action.mDestId.id), RSDHT_PEERTYPE_FRIEND); if (dpd) { connectOk = true; proxyPort = dpd->mConnectLogic.getProxyPortChoice(); if (proxyPort) { #ifdef DEBUG_PEERNET std::cerr << "PeerAction: Using ProxyPort. Checking ConnectLogic.NetState: "; std::cerr << dpd->mConnectLogic.calcNetState(mNetMgr->getNetworkMode(), mNetMgr->getNatHoleMode(), mNetMgr->getNatTypeMode()); std::cerr << std::endl; #endif exclusivePort = (CSB_NETSTATE_EXCLUSIVENAT == dpd->mConnectLogic.calcNetState( mNetMgr->getNetworkMode(), mNetMgr->getNatHoleMode(), mNetMgr->getNatTypeMode())); if (exclusivePort) { #ifdef DEBUG_PEERNET std::cerr << "PeerAction: NetState indicates Exclusive Mode"; std::cerr << std::endl; #endif } } } else { std::cerr << "PeerAction: Connect Proxy: ERROR Cannot find PeerStatus"; std::cerr << std::endl; } } UdpStunner *stunner = mProxyStunner; if (!proxyPort) { stunner = mDhtStunner; } if ((connectOk) && (stunner) && (stunner->externalAddr(extaddr, extStable))) { if (extStable) { #ifdef DEBUG_PEERNET std::cerr << "PeerAction: Proxy Connection Attempt to: "; bdStdPrintId(std::cerr, &(action.mDestId)); std::cerr << " is OkGo as we have Stable Own External Proxy Address"; std::cerr << std::endl; #endif /* check if we require exclusive use of the proxy port */ if (exclusivePort) { int stun_age = mProxyStunner->grabExclusiveMode(pid); if (stun_age > 0) { int delay = 0; if (stun_age < MIN_DETERMINISTIC_SWITCH_PERIOD) { delay = MIN_DETERMINISTIC_SWITCH_PERIOD - stun_age; } #ifdef DEBUG_PEERNET std::cerr << "PeerAction: Stunner has indicated a Delay of " << delay; std::cerr << " to ensure a stable Port!"; std::cerr << std::endl; #endif /* great we got it! */ connAddr = extaddr; connDelay = delay; doConnectionRequest = true; grabbedExclusivePort = true; } else { /* failed to get exclusive mode - must wait */ connectionReqFailed = true; failReason = CSB_UPDATE_RETRY_ATTEMPT; } } else { /* stable and non-exclusive - go for it */ connAddr = extaddr; connStart = 1; doConnectionRequest = true; } } else { #ifdef DEBUG_PEERNET std::cerr << "PeerAction: WARNING Proxy Connection Attempt to: "; bdStdPrintId(std::cerr, &(action.mDestId)); std::cerr << " is Discarded, as Own External Proxy Address is Not Stable!"; std::cerr << std::endl; #endif connectionReqFailed = true; if (exclusivePort) { failReason = CSB_UPDATE_RETRY_ATTEMPT; #ifdef DEBUG_PEERNET std::cerr << "PeerAction: As Exclusive Mode, Port Will stabilise => RETRY"; std::cerr << std::endl; #endif } else { failReason = CSB_UPDATE_MODE_UNAVAILABLE; #ifdef DEBUG_PEERNET std::cerr << "PeerAction: Not Exclusive Mode, => MODE UNAVAILABLE"; std::cerr << std::endl; #endif } } } else { #ifdef DEBUG_PEERNET std::cerr << "PeerAction: ERROR Proxy Connection Attempt to: "; bdStdPrintId(std::cerr, &(action.mDestId)); std::cerr << " is Discarded, as Failed to get Own External Proxy Address."; std::cerr << std::endl; #endif connectionReqFailed = true; failReason = CSB_UPDATE_RETRY_ATTEMPT; } } if (doConnectionRequest) { if (mUdpBitDht->ConnectionRequest(&connAddr, &(action.mDestId.id), action.mMode, connDelay, connStart)) { RsStackMutex stack(dhtMtx); /********** LOCKED MUTEX ***************/ #ifdef DEBUG_PEERNET std::cerr << "PeerAction: Connection Attempt to: "; bdStdPrintId(std::cerr, &(action.mDestId)); std::cerr << " has gone ahead"; std::cerr << std::endl; #endif DhtPeerDetails *dpd = findInternalDhtPeer_locked(&(action.mDestId.id), RSDHT_PEERTYPE_FRIEND); if (dpd) { dpd->mPeerReqStatusMsg = "Connect Request"; dpd->mPeerReqState = RSDHT_PEERREQ_RUNNING; dpd->mPeerReqMode = action.mMode; dpd->mPeerReqTS = now; if (grabbedExclusivePort) { dpd->mExclusiveProxyLock = true; } } else { std::cerr << "PeerAction: Connect ERROR Cannot find PeerStatus"; std::cerr << std::endl; } } else { connectionReqFailed = true; failReason = CSB_UPDATE_MODE_UNAVAILABLE; } } if (connectionReqFailed) { #ifdef DEBUG_PEERNET std::cerr << "PeerAction: Connection Attempt to: "; bdStdPrintId(std::cerr, &(action.mDestId)); std::cerr << " is Discarded, as Mode is Unavailable"; std::cerr << std::endl; #endif //if (grabbedExclusivePort) //{ // mProxyStunner->releaseExclusiveMode(pid,false); //} RsStackMutex stack(dhtMtx); /********** LOCKED MUTEX ***************/ DhtPeerDetails *dpd = findInternalDhtPeer_locked(&(action.mDestId.id), RSDHT_PEERTYPE_FRIEND); if (dpd) { dpd->mConnectLogic.updateCb(failReason); dpd->mPeerReqStatusMsg = "Req Mode Unavailable"; dpd->mPeerReqState = RSDHT_PEERREQ_STOPPED; dpd->mPeerReqMode = action.mMode; dpd->mPeerReqTS = now; if (grabbedExclusivePort) { ReleaseProxyExclusiveMode_locked(dpd, false); } } else { std::cerr << "PeerAction: ERROR Connection Attempt to: "; bdStdPrintId(std::cerr, &(action.mDestId)); std::cerr << " has no Internal Dht Peer!"; std::cerr << std::endl; if (grabbedExclusivePort) { std::cerr << "PeerAction: ERROR ERROR, we grabd Exclusive Port to do this, trying emergency release"; std::cerr << std::endl; mProxyStunner->releaseExclusiveMode(pid,false); } } } } break; case PEERNET_ACTION_TYPE_AUTHORISE: { /* connect attempt */ #ifdef DEBUG_PEERNET std::cerr << "PeerAction. Authorise Connection between: "; bdStdPrintId(std::cerr, &(action.mSrcId)); std::cerr << " and "; bdStdPrintId(std::cerr, &(action.mDestId)); std::cerr << " mode: " << action.mMode; std::cerr << " delay/bandwidth: " << action.mDelayOrBandwidth; std::cerr << std::endl; #endif int delay = 0; int bandwidth = 0; if (action.mMode == BITDHT_CONNECT_MODE_RELAY) { bandwidth = action.mDelayOrBandwidth; } else { delay = action.mDelayOrBandwidth; } mUdpBitDht->ConnectionAuth(&(action.mSrcId), &(action.mProxyId), &(action.mDestId), action.mMode, action.mPoint, bandwidth, delay, action.mAnswer); // Only feedback to the gui if we are at END. if (action.mPoint == BD_PROXY_CONNECTION_END_POINT) { RsStackMutex stack(dhtMtx); /********** LOCKED MUTEX ***************/ DhtPeerDetails *dpd = findInternalDhtPeer_locked(&(action.mSrcId.id), RSDHT_PEERTYPE_ANY); if (dpd) { if (action.mAnswer) { dpd->mPeerCbMsg = "WE DENIED AUTH: ERROR : "; dpd->mPeerCbMsg += decodeConnectionError(action.mAnswer); } else { dpd->mPeerCbMsg = "We AUTHED"; } dpd->mPeerCbMode = action.mMode; dpd->mPeerCbPoint = action.mPoint; dpd->mPeerCbProxyId = action.mProxyId; dpd->mPeerCbDestId = action.mSrcId; dpd->mPeerCbTS = now; } // Not an error if AUTH_DENIED - cos we don't know them! (so won't be in peerList). else if (action.mAnswer | BITDHT_CONNECT_ERROR_AUTH_DENIED) { #ifdef DEBUG_PEERNET std::cerr << "PeerAction Authorise Connection "; std::cerr << "Denied Unknown Peer"; std::cerr << std::endl; #endif } else { std::cerr << "PeerAction Authorise Connection "; std::cerr << "ERROR Unknown Peer & !DENIED ???"; std::cerr << std::endl; } } } break; case PEERNET_ACTION_TYPE_START: { /* connect attempt */ #ifdef DEBUG_PEERNET std::cerr << "PeerAction. Start Connection between: "; bdStdPrintId(std::cerr, &(action.mSrcId)); std::cerr << " and "; bdStdPrintId(std::cerr, &(action.mDestId)); std::cerr << " mode: " << action.mMode; std::cerr << " delay/bandwidth: " << action.mDelayOrBandwidth; std::cerr << std::endl; #endif initiateConnection(&(action.mSrcId), &(action.mProxyId), &(action.mDestId), action.mMode, action.mPoint, action.mDelayOrBandwidth); } break; case PEERNET_ACTION_TYPE_RESTARTREQ: { /* connect attempt */ #ifdef DEBUG_PEERNET std::cerr << "PeerAction. Restart Connection Attempt to: "; bdStdPrintId(std::cerr, &(action.mDestId)); std::cerr << " mode: " << action.mMode; std::cerr << std::endl; #endif struct sockaddr_in laddr; sockaddr_clear(&laddr); uint32_t start = 1; uint32_t delay = 0; mUdpBitDht->ConnectionRequest(&laddr, &(action.mDestId.id), action.mMode, delay, start); } break; case PEERNET_ACTION_TYPE_KILLREQ: { /* connect attempt */ #ifdef DEBUG_PEERNET std::cerr << "PeerAction. Kill Connection Attempt to: "; bdStdPrintId(std::cerr, &(action.mDestId)); std::cerr << " mode: " << action.mMode; std::cerr << std::endl; #endif struct sockaddr_in laddr; sockaddr_clear(&laddr); uint32_t start = 0; uint32_t delay = 0; mUdpBitDht->ConnectionRequest(&laddr, &(action.mDestId.id), action.mMode, delay, start); } break; case PEERNET_ACTION_TYPE_TCPATTEMPT: { /* connect attempt */ #ifdef DEBUG_PEERNET std::cerr << "PeerAction. TCP Connection Attempt to: "; bdStdPrintId(std::cerr, &(action.mDestId)); std::cerr << " mode: " << action.mMode; std::cerr << std::endl; #endif std::string peerRsId; bool foundPeerId = false; { RsStackMutex stack(dhtMtx); /********** LOCKED MUTEX ***************/ DhtPeerDetails *dpd = findInternalDhtPeer_locked(&(action.mDestId.id), RSDHT_PEERTYPE_ANY); if (dpd) { peerRsId = dpd->mRsId; foundPeerId = true; #ifdef DEBUG_PEERNET std::cerr << "PeerAction. TCP Connection Attempt. DoingCallback for RsID: "; std::cerr << peerRsId; std::cerr << std::endl; #endif } else { std::cerr << "PeerAction. TCP Connection Attempt. ERROR unknown peer"; std::cerr << std::endl; } } if (foundPeerId) { ConnectCalloutTCPAttempt(peerRsId, action.mDestId.addr); } } break; } } return 1; } /****************************** Connection Logic ***************************/ /* Proxies!. * * We can allow all PROXY connections, as it is just a couple of messages, * however, we should be smart about how many RELAY connections are allowed. * * e.g. Allow 20 Relay connections. * 15 for friends, 5 for randoms. * * Can also validate addresses with own secure connections. */ int p3BitDht::checkProxyAllowed(const bdId *srcId, const bdId *destId, int mode, uint32_t &bandwidth) { #ifdef DEBUG_PEERNET std::cerr << "p3BitDht::checkProxyAllowed()"; std::cerr << std::endl; #endif // Dont think that a mutex is required here! But might be so just lock to ensure that it is possible. { RsStackMutex stack(dhtMtx); /********** LOCKED MUTEX ***************/ } if (mode == BITDHT_CONNECT_MODE_PROXY) { #ifdef DEBUG_PEERNET std::cerr << "p3BitDht::checkProxyAllowed() Allowing all PROXY connections, OKAY"; std::cerr << std::endl; #endif bandwidth = 0; // unlimited as p2p. return 1; //return CONNECTION_OKAY; } if (mode != BITDHT_CONNECT_MODE_RELAY) { #ifdef DEBUG_PEERNET std::cerr << "p3BitDht::checkProxyAllowed() unknown Connect Mode DENIED"; std::cerr << std::endl; #endif return 0; } /* will install the Relay Here... so that we reserve the Relay Space for later. * decide on relay bandwidth limitation as well */ if (RelayHandler_InstallRelayConnection(srcId, destId, mode, bandwidth)) { #ifdef DEBUG_PEERNET std::cerr << "p3BitDht::checkProxyAllowed() Successfully added Relay, Connection OKAY"; std::cerr << std::endl; #endif return 1; // CONNECT_OKAY. } else { #ifdef DEBUG_PEERNET std::cerr << "p3BitDht::checkProxyAllowed() Failed to install Relay, Connection DENIED"; std::cerr << std::endl; #endif return 0; //return CONNECT_MODE_OVERLOADED; } return 0; //return CONNECT_MODE_NOTAVAILABLE; //return CONNECT_MODE_OVERLOADED; } int p3BitDht::checkConnectionAllowed(const bdId *peerId, int mode) { (void) mode; #ifdef DEBUG_PEERNET std::cerr << "p3BitDht::checkConnectionAllowed() to: "; bdStdPrintId(std::cerr,peerId); std::cerr << " mode: " << mode; std::cerr << std::endl; #endif RsStackMutex stack(dhtMtx); /********** LOCKED MUTEX ***************/ time_t now = time(NULL); /* check if they are in our friend list */ DhtPeerDetails *dpd = findInternalDhtPeer_locked(&(peerId->id), RSDHT_PEERTYPE_FRIEND); if (!dpd) { #ifdef DEBUG_PEERNET std::cerr << "p3BitDht::checkConnectionAllowed() Peer Not Friend, DENIED"; std::cerr << std::endl; #endif /* store as failed connection attempt */ std::map::iterator it; it = mFailedPeers.find(peerId->id); if (it == mFailedPeers.end()) { mFailedPeers[peerId->id] = DhtPeerDetails(); it = mFailedPeers.find(peerId->id); } /* flag as failed */ it->second.mDhtId = *peerId; it->second.mDhtState = RSDHT_PEERDHT_NOT_ACTIVE; it->second.mDhtUpdateTS = now; it->second.mPeerType = RSDHT_PEERTYPE_OTHER; it->second.mPeerCbMsg = "Denied Non-Friend"; it->second.mPeerReqStatusMsg = "Denied Non-Friend"; it->second.mPeerReqState = RSDHT_PEERREQ_STOPPED; it->second.mPeerReqTS = now; it->second.mPeerReqMode = 0; //it->second.mPeerProxyId; it->second.mPeerReqTS = now; it->second.mPeerCbMsg = "Denied Non-Friend"; it->second.mPeerConnectMsg = "Denied Non-Friend"; it->second.mPeerConnectState = RSDHT_PEERCONN_DISCONNECTED; return 0; //return NOT_FRIEND; } /* are a friend */ if (dpd->mPeerConnectState == RSDHT_PEERCONN_CONNECTED) { std::cerr << "p3BitDht::checkConnectionAllowed() ERROR Peer Already Connected, DENIED"; std::cerr << std::endl; // STATUS UPDATE DONE IN ACTION. //it->second.mPeerStatusMsg = "2nd Connection Attempt!"; //it->second.mPeerUpdateTS = now; return 0; //return ALREADY_CONNECTED; } return 1; //return CONNECTION_OKAY; } /* So initiateConnection has to call out to other bits of RS. * critical information is: * Peer RsId, Peer Address, Connect Mode (includes Proxy/OrNot). * * What do we need: ACTIVE / PASSIVE / UNSPEC * + Min Delay Time, */ void p3BitDht::ConnectCalloutTCPAttempt(const std::string &peerId, struct sockaddr_in raddr) { struct sockaddr_in proxyaddr; struct sockaddr_in srcaddr; sockaddr_clear(&proxyaddr); sockaddr_clear(&srcaddr); uint32_t source = RS_CB_DHT; uint32_t connectFlags = RS_CB_FLAG_ORDER_UNSPEC | RS_CB_FLAG_MODE_TCP; uint32_t delay = 0; uint32_t bandwidth = 0; mConnCb->peerConnectRequest(peerId, raddr, proxyaddr, srcaddr, source, connectFlags, delay, bandwidth); } void p3BitDht::ConnectCalloutDirectOrProxy(const std::string &peerId, struct sockaddr_in raddr, uint32_t connectFlags, uint32_t delay) { struct sockaddr_in proxyaddr; struct sockaddr_in srcaddr; sockaddr_clear(&proxyaddr); sockaddr_clear(&srcaddr); uint32_t source = RS_CB_DHT; uint32_t bandwidth = 0; mConnCb->peerConnectRequest(peerId, raddr, proxyaddr, srcaddr, source, connectFlags, delay, bandwidth); } void p3BitDht::ConnectCalloutRelay(const std::string &peerId, struct sockaddr_in srcaddr, struct sockaddr_in proxyaddr, struct sockaddr_in destaddr, uint32_t connectFlags, uint32_t bandwidth) { uint32_t source = RS_CB_DHT; uint32_t delay = 0; mConnCb->peerConnectRequest(peerId, destaddr, proxyaddr, srcaddr, source, connectFlags, delay, bandwidth); } //virtual void 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) = 0; void p3BitDht::initiateConnection(const bdId *srcId, const bdId *proxyId, const bdId *destId, uint32_t mode, uint32_t loc, uint32_t delayOrBandwidth) { #ifdef DEBUG_PEERNET #endif std::cerr << "p3BitDht::initiateConnection()"; std::cerr << std::endl; std::cerr << "\t srcId: "; bdStdPrintId(std::cerr, srcId); std::cerr << std::endl; std::cerr << "\t proxyId: "; bdStdPrintId(std::cerr, proxyId); std::cerr << std::endl; std::cerr << "\t destId: "; bdStdPrintId(std::cerr, destId); std::cerr << std::endl; std::cerr << "\t Mode: " << mode << " loc: " << loc; std::cerr << std::endl; std::cerr << "\t DelayOrBandwidth: " << delayOrBandwidth; std::cerr << std::endl; bdId peerConnectId; uint32_t connectFlags = 0; uint32_t delay = 0; uint32_t bandwidth = 0; /* determine who the actual destination is. * as we always specify the remote address, this is all we need. */ if (loc == BD_PROXY_CONNECTION_START_POINT) { peerConnectId = *destId; /* lowest is active */ if (srcId < destId) { connectFlags |= RS_CB_FLAG_ORDER_ACTIVE; } else { connectFlags |= RS_CB_FLAG_ORDER_PASSIVE; } } else if (loc == BD_PROXY_CONNECTION_END_POINT) { peerConnectId = *srcId; /* lowest is active (we are now dest - in this case) */ if (destId < srcId) { connectFlags |= RS_CB_FLAG_ORDER_ACTIVE; } else { connectFlags |= RS_CB_FLAG_ORDER_PASSIVE; } } else { std::cerr << "p3BitDht::initiateConnection() ERROR, NOT either START or END"; std::cerr << std::endl; /* ERROR */ return; } #ifdef DEBUG_PEERNET std::cerr << "p3BitDht::initiateConnection() Connecting to "; bdStdPrintId(std::cerr, &peerConnectId); std::cerr << std::endl; #endif // uint32_t touConnectMode = 0; std::string rsId; { RsStackMutex stack(dhtMtx); /********** LOCKED MUTEX ***************/ DhtPeerDetails *dpd = findInternalDhtPeer_locked(&(peerConnectId.id), RSDHT_PEERTYPE_FRIEND); /* grab a socket */ if (!dpd) { std::cerr << "p3BitDht::initiateConnection() ERROR Peer not found"; std::cerr << std::endl; return; } if (dpd->mPeerConnectState != RSDHT_PEERCONN_DISCONNECTED) { std::cerr << "p3BitDht::initiateConnection() ERROR Peer is not Disconnected"; std::cerr << std::endl; return; } rsId = dpd->mRsId; /* start the connection */ /* These Socket Modes must match the TOU Stack - or it breaks. */ switch(mode) { default: case BITDHT_CONNECT_MODE_DIRECT: // touConnectMode = RSDHT_TOU_MODE_DIRECT; connectFlags |= RS_CB_FLAG_MODE_UDP_DIRECT; delay = delayOrBandwidth; break; case BITDHT_CONNECT_MODE_PROXY: { bool useProxyPort = dpd->mConnectLogic.getProxyPortChoice(); #ifdef DEBUG_PEERNET std::cerr << "p3BitDht::initiateConnection() Peer Mode Proxy... deciding which port to use."; std::cerr << " UseProxyPort? " << useProxyPort; std::cerr << std::endl; #endif delay = delayOrBandwidth; if (useProxyPort) { // touConnectMode = RSDHT_TOU_MODE_PROXY; connectFlags |= RS_CB_FLAG_MODE_UDP_PROXY; } else { // touConnectMode = RSDHT_TOU_MODE_DIRECT; connectFlags |= RS_CB_FLAG_MODE_UDP_DIRECT; } } break; case BITDHT_CONNECT_MODE_RELAY: // touConnectMode = RSDHT_TOU_MODE_RELAY; connectFlags |= RS_CB_FLAG_MODE_UDP_RELAY; bandwidth = delayOrBandwidth; break; } dpd->mPeerConnectProxyId = *proxyId; dpd->mPeerConnectPeerId = peerConnectId; /* store results in Status */ dpd->mPeerConnectMsg = "UDP started"; dpd->mPeerConnectState = RSDHT_PEERCONN_UDP_STARTED; dpd->mPeerConnectUdpTS = time(NULL); dpd->mPeerConnectMode = mode; dpd->mPeerConnectPoint = loc; } /* finally we call out to start the connection (Outside of Mutex) */ if ((mode == BITDHT_CONNECT_MODE_DIRECT) || (mode == BITDHT_CONNECT_MODE_PROXY)) { ConnectCalloutDirectOrProxy(rsId, peerConnectId.addr, connectFlags, delay); } else if (mode == BITDHT_CONNECT_MODE_RELAY) { if (loc == BD_PROXY_CONNECTION_START_POINT) { ConnectCalloutRelay(rsId, srcId->addr, proxyId->addr, destId->addr, connectFlags, bandwidth); } else // END_POINT { /* reverse order connection call */ ConnectCalloutRelay(rsId, destId->addr, proxyId->addr, srcId->addr, connectFlags, bandwidth); } } } int p3BitDht::installRelayConnection(const bdId *srcId, const bdId *destId, uint32_t &bandwidth) { RsStackMutex stack(dhtMtx); /********** LOCKED MUTEX ***************/ /* work out if either srcId or DestId is a friend */ int relayClass = UDP_RELAY_CLASS_GENERAL; #ifdef DEBUG_PEERNET std::string strId1; bdStdPrintNodeId(strId1, &(srcId->id), false); std::string strId2; bdStdPrintNodeId(strId2, &(destId->id), false); #endif /* grab a socket */ DhtPeerDetails *dpd_src = findInternalDhtPeer_locked(&(srcId->id), RSDHT_PEERTYPE_ANY); DhtPeerDetails *dpd_dest = findInternalDhtPeer_locked(&(destId->id), RSDHT_PEERTYPE_ANY); if ((dpd_src) && (dpd_src->mPeerType == RSDHT_PEERTYPE_FRIEND)) { relayClass = UDP_RELAY_CLASS_FRIENDS; } else if ((dpd_dest) && (dpd_dest->mPeerType == RSDHT_PEERTYPE_FRIEND)) { relayClass = UDP_RELAY_CLASS_FRIENDS; } else if ((dpd_src) && (dpd_src->mPeerType == RSDHT_PEERTYPE_FOF)) { relayClass = UDP_RELAY_CLASS_FOF; } else if ((dpd_dest) && (dpd_dest->mPeerType == RSDHT_PEERTYPE_FOF)) { relayClass = UDP_RELAY_CLASS_FOF; } else { relayClass = UDP_RELAY_CLASS_GENERAL; } /* will install the Relay Here... so that we reserve the Relay Space for later. */ UdpRelayAddrSet relayAddrs(&(srcId->addr), &(destId->addr)); if (mRelay->addUdpRelay(&relayAddrs, relayClass, bandwidth)) { #ifdef DEBUG_PEERNET std::cerr << "p3BitDht::installRelayConnection() Successfully added Relay, Connection OKAY"; std::cerr << std::endl; #endif return 1; // CONNECT_OKAY. } else { #ifdef DEBUG_PEERNET std::cerr << "p3BitDht::installRelayConnection() Failed to install Relay, Connection DENIED"; std::cerr << std::endl; #endif return 0; //return CONNECT_MODE_OVERLOADED; } return 0; } int p3BitDht::removeRelayConnection(const bdId *srcId, const bdId *destId) { //RsStackMutex stack(dhtMtx); /********** LOCKED MUTEX ***************/ UdpRelayAddrSet relayAddrs(&(srcId->addr), &(destId->addr)); if (mRelay->removeUdpRelay(&relayAddrs)) { #ifdef DEBUG_PEERNET std::cerr << "p3BitDht::removeRelayConnection() Successfully removed Relay"; std::cerr << std::endl; #endif return 1; } else { std::cerr << "p3BitDht::removeRelayConnection() ERROR Failed to remove Relay"; std::cerr << std::endl; return 0; } } /***************************************************** UDP Connections *****************************/ void p3BitDht::monitorConnections() { RsStackMutex stack(dhtMtx); /********** LOCKED MUTEX ***************/ time_t now = time(NULL); std::map::iterator it; for(it = mPeers.begin(); it != mPeers.end(); it++) { /* ignore ones which aren't friends */ if (it->second.mPeerType != RSDHT_PEERTYPE_FRIEND) { continue; } if (it->second.mPeerConnectState == RSDHT_PEERCONN_UDP_STARTED) { #ifdef DEBUG_PEERNET std::cerr << "p3BitDht::monitorConnections() Connection in progress to: "; bdStdPrintNodeId(std::cerr, &(it->second.mDhtId.id)); std::cerr << std::endl; #endif if (now - it->second.mPeerConnectUdpTS > PEERNET_CONNECT_TIMEOUT) { /* This CAN happen ;( */ #ifdef DEBUG_PEERNET std::cerr << "p3BitDht::monitorConnections() WARNING InProgress Connection Failed: "; bdStdPrintNodeId(std::cerr, &(it->second.mDhtId.id)); std::cerr << std::endl; #endif UdpConnectionFailed_locked(&(it->second)); } } } } void p3BitDht::Feedback_Connected(std::string pid) { RsStackMutex stack(dhtMtx); /********** LOCKED MUTEX ***************/ DhtPeerDetails *dpd = findInternalRsPeer_locked(pid); if (!dpd) { /* ERROR */ std::cerr << "p3BitDht::Feedback_Connected() ERROR peer not found: " << pid; std::cerr << std::endl; return; } /* sanity checking */ if (dpd->mPeerConnectState != RSDHT_PEERCONN_UDP_STARTED) { /* ERROR */ std::cerr << "p3BitDht::Feedback_Connected() ERROR not in UDP_STARTED mode for: "; bdStdPrintNodeId(std::cerr, &(dpd->mDhtId.id)); std::cerr << std::endl; return; } #ifdef DEBUG_PEERNET std::cerr << "p3BitDht::monitorConnections() InProgress Connection Now Active: "; bdStdPrintNodeId(std::cerr, &(dpd->mDhtId.id)); std::cerr << std::endl; #endif /* switch state! */ dpd->mPeerConnectState = RSDHT_PEERCONN_CONNECTED; dpd->mPeerConnectTS = time(NULL); dpd->mConnectLogic.updateCb(CSB_UPDATE_CONNECTED); rs_sprintf(dpd->mPeerConnectMsg, "Connected in %ld secs", dpd->mPeerConnectTS - dpd->mPeerConnectUdpTS); // Remove the Connection Request. if (dpd->mPeerReqState == RSDHT_PEERREQ_RUNNING) { #ifdef DEBUG_PEERNET std::cerr << "p3BitDht::monitorConnections() Request Active, Stopping Request"; std::cerr << std::endl; #endif /* Push Back PeerAction */ PeerAction ca; ca.mType = PEERNET_ACTION_TYPE_KILLREQ; ca.mMode = dpd->mPeerConnectMode; //ca.mProxyId = *proxyId; //ca.mSrcId = *srcId; ca.mDestId = dpd->mPeerConnectPeerId; //ca.mPoint = point; ca.mAnswer = BITDHT_CONNECT_ERROR_NONE; mActions.push_back(ca); // What the Action should do... //struct sockaddr_in tmpaddr; //bdsockaddr_clear(&tmpaddr); //int start = 0; //mUdpBitDht->ConnectionRequest(&tmpaddr, &(it->second.mPeerConnectPeerId.id), it->second.mPeerConnectMode, start); } // only an error if we initiated the connection. else if (dpd->mPeerConnectPoint == BD_PROXY_CONNECTION_START_POINT) { std::cerr << "p3BitDht::monitorConnections() ERROR Request not active, can't stop"; std::cerr << std::endl; } ReleaseProxyExclusiveMode_locked(dpd, true); } void p3BitDht::Feedback_ConnectionFailed(std::string pid) { RsStackMutex stack(dhtMtx); /********** LOCKED MUTEX ***************/ DhtPeerDetails *dpd = findInternalRsPeer_locked(pid); if (!dpd) { /* ERROR */ std::cerr << "p3BitDht::Feedback_Connected() ERROR peer not found: " << pid; std::cerr << std::endl; return; } #ifdef DEBUG_PEERNET std::cerr << "p3BitDht::Feedback_ConnectionFailed() UDP Connection Failed: "; bdStdPrintNodeId(std::cerr, &(dpd->mDhtId.id)); std::cerr << std::endl; #endif return UdpConnectionFailed_locked(dpd); } void p3BitDht::Feedback_ConnectionClosed(std::string pid) { RsStackMutex stack(dhtMtx); /********** LOCKED MUTEX ***************/ DhtPeerDetails *dpd = findInternalRsPeer_locked(pid); if (!dpd) { /* ERROR */ std::cerr << "p3BitDht::Feedback_Connected() ERROR peer not found: " << pid; std::cerr << std::endl; return; } #ifdef DEBUG_PEERNET std::cerr << "p3BitDht::Feedback_ConnectionClosed() Active Connection Closed: "; bdStdPrintNodeId(std::cerr, &(dpd->mDhtId.id)); std::cerr << std::endl; #endif return UdpConnectionFailed_locked(dpd); } void p3BitDht::UdpConnectionFailed_locked(DhtPeerDetails *dpd) { if (dpd->mPeerConnectState == RSDHT_PEERCONN_UDP_STARTED) { #ifdef DEBUG_PEERNET std::cerr << "p3BitDht::UdpConnectionFailed_locked() UDP Connection Failed: "; bdStdPrintNodeId(std::cerr, &(dpd->mDhtId.id)); std::cerr << std::endl; #endif /* shut it down */ /* ONLY need to update ConnectLogic - if it was our Attempt Running */ if (dpd->mPeerReqState == RSDHT_PEERREQ_RUNNING) { dpd->mConnectLogic.updateCb(CSB_UPDATE_FAILED_ATTEMPT); } dpd->mPeerConnectState = RSDHT_PEERCONN_DISCONNECTED; dpd->mPeerConnectMsg = "UDP Failed"; } else { #ifdef DEBUG_PEERNET std::cerr << "p3BitDht::UdpConnectionFailed_locked() Active Connection Closed: "; bdStdPrintNodeId(std::cerr, &(dpd->mDhtId.id)); std::cerr << std::endl; #endif dpd->mConnectLogic.updateCb(CSB_UPDATE_DISCONNECTED); dpd->mPeerConnectState = RSDHT_PEERCONN_DISCONNECTED; dpd->mPeerConnectClosedTS = time(NULL); rs_sprintf(dpd->mPeerConnectMsg, "Closed, Alive for: %ld secs", dpd->mPeerConnectClosedTS - dpd->mPeerConnectTS); } if (dpd->mPeerReqState == RSDHT_PEERREQ_RUNNING) { #ifdef DEBUG_PEERNET std::cerr << "p3BitDht::UdpConnectionFailed_locked() "; std::cerr << "Request Active (Paused)... Killing for next Attempt"; std::cerr << std::endl; #endif /* Push Back PeerAction */ PeerAction ca; ca.mType = PEERNET_ACTION_TYPE_KILLREQ; ca.mMode = dpd->mPeerConnectMode; //ca.mProxyId = *proxyId; //ca.mSrcId = *srcId; ca.mDestId = dpd->mPeerConnectPeerId; //ca.mPoint = point; ca.mAnswer = BITDHT_CONNECT_ERROR_NONE; mActions.push_back(ca); } // only an error if we initiated the connection. else if (dpd->mPeerConnectPoint == BD_PROXY_CONNECTION_START_POINT) { std::cerr << "p3BitDht::UdpConnectionFailed_locked() "; std::cerr << "ERROR Request not active, can't stop"; std::cerr << std::endl; } ReleaseProxyExclusiveMode_locked(dpd, true); } void p3BitDht::ReleaseProxyExclusiveMode_locked(DhtPeerDetails *dpd, bool addrChgLikely) { #ifdef DEBUG_BITDHT_COMMON #endif std::cerr << "p3BitDht::ReleaseProxyExclusiveMode_locked()"; bdStdPrintNodeId(std::cerr, &(dpd->mDhtId.id)); std::cerr << std::endl; /* translate id into string for exclusive mode */ std::string pid; bdStdPrintNodeId(pid, &(dpd->mDhtId.id), false); if (dpd->mExclusiveProxyLock) { if (mProxyStunner->releaseExclusiveMode(pid, addrChgLikely)) { dpd->mExclusiveProxyLock = false; #ifdef DEBUG_PEERNET #endif std::cerr << "p3BitDht::ReleaseProxyExclusiveMode_locked() Lock released by Connection to peer: "; bdStdPrintNodeId(std::cerr, &(dpd->mDhtId.id)); std::cerr << std::endl; } else { dpd->mExclusiveProxyLock = false; std::cerr << "p3BitDht::ReleaseProxyExclusiveMode_locked() ERROR ProxyStunner is not Locked"; bdStdPrintNodeId(std::cerr, &(dpd->mDhtId.id)); std::cerr << std::endl; } } else { #ifdef DEBUG_BITDHT_COMMON #endif std::cerr << "p3BitDht::ReleaseProxyExclusiveMode_locked() Don't Have a Lock"; std::cerr << std::endl; } } void p3BitDht::ConnectionFeedback(std::string pid, int mode) { #ifdef DEBUG_PEERNET std::cerr << "p3BitDht::ConnectionFeedback() peer: " << pid; std::cerr << " mode: " << mode; std::cerr << std::endl; #endif switch(mode) { case NETMGR_DHT_FEEDBACK_CONNECTED: #ifdef DEBUG_PEERNET std::cerr << "p3BitDht::ConnectionFeedback() HAVE CONNECTED (tcp?/udp) to peer: " << pid; std::cerr << std::endl; #endif Feedback_Connected(pid); break; case NETMGR_DHT_FEEDBACK_CONN_FAILED: #ifdef DEBUG_PEERNET std::cerr << "p3BitDht::ConnectionFeedback() UDP CONNECTION FAILED to peer: " << pid; std::cerr << std::endl; #endif Feedback_ConnectionFailed(pid); break; case NETMGR_DHT_FEEDBACK_CONN_CLOSED: #ifdef DEBUG_PEERNET std::cerr << "p3BitDht::ConnectionFeedback() CONNECTION (tcp?/udp) CLOSED to peer: " << pid; std::cerr << std::endl; #endif Feedback_ConnectionClosed(pid); break; } } /***** Check for a RelayHandler... and call its functions preferentially */ int p3BitDht::RelayHandler_LogFailedProxyAttempt(const bdId *srcId, const bdId *destId, uint32_t mode, uint32_t errcode) { { RsStackMutex stack(dhtMtx); /********* LOCKED *********/ if ((mRelayHandler) && (mRelayHandler->mLogFailedConnection)) { return mRelayHandler->mLogFailedConnection(srcId, destId, mode, errcode); } } /* NO standard handler */ return 0; } int p3BitDht::RelayHandler_InstallRelayConnection(const bdId *srcId, const bdId *destId, uint32_t mode, uint32_t &bandwidth) { { RsStackMutex stack(dhtMtx); /********* LOCKED *********/ if ((mRelayHandler) && (mRelayHandler->mInstallRelay)) { return mRelayHandler->mInstallRelay(srcId, destId, mode, bandwidth); } } /* standard handler */ return installRelayConnection(srcId, destId, bandwidth); }