diff --git a/libretroshare/src/pqi/p3connmgr.cc b/libretroshare/src/pqi/p3connmgr.cc index 2e1cccf92..bc2e4ed8d 100644 --- a/libretroshare/src/pqi/p3connmgr.cc +++ b/libretroshare/src/pqi/p3connmgr.cc @@ -75,7 +75,7 @@ peerConnectState::peerConnectState() name("nameless"), state(0), actions(0), source(0), - inConnAttempt(0), connAttemptTS(0) + inConnAttempt(0), lastattempt(0) { sockaddr_clear(&localaddr); sockaddr_clear(&serveraddr); @@ -215,6 +215,9 @@ void p3ConnectMgr::netStartup() /* StunInit gets a list of peers, and asks the DHT to find them... * This is needed for all systems so startup straight away */ +#ifdef CONN_DEBUG + std::cerr << "p3ConnectMgr::netStartup()" << std::endl; +#endif loadConfiguration(); netDhtInit(); @@ -228,18 +231,27 @@ void p3ConnectMgr::netStartup() mNetInitTS = time(NULL); +#ifdef CONN_DEBUG + std::cerr << "p3ConnectMgr::netStartup() tou_stunkeepalive() enabled" << std::endl; +#endif + tou_stunkeepalive(1); + ownState.netMode &= ~(RS_NET_MODE_ACTUAL); switch(ownState.netMode & RS_NET_MODE_TRYMODE) { case RS_NET_MODE_TRY_UPNP: - mNetStatus = RS_NET_UPNP_INIT; ownState.netMode |= RS_NET_MODE_UDP; + mNetStatus = RS_NET_UPNP_INIT; break; case RS_NET_MODE_TRY_EXT: /* v similar to UDP */ ownState.netMode |= RS_NET_MODE_EXT; mNetStatus = RS_NET_UDP_SETUP; +#ifdef CONN_DEBUG + std::cerr << "p3ConnectMgr::netStartup() disabling stunkeepalive() cos EXT" << std::endl; +#endif + tou_stunkeepalive(0); break; case RS_NET_MODE_TRY_UDP: @@ -322,6 +334,9 @@ void p3ConnectMgr::netTick() void p3ConnectMgr::netUdpInit() { +#ifdef CONN_DEBUG + std::cerr << "p3ConnectMgr::netUdpInit()" << std::endl; +#endif connMtx.lock(); /* LOCK MUTEX */ struct sockaddr_in iaddr = ownState.localaddr; @@ -335,6 +350,9 @@ void p3ConnectMgr::netUdpInit() void p3ConnectMgr::netDhtInit() { +#ifdef CONN_DEBUG + std::cerr << "p3ConnectMgr::netDhtInit()" << std::endl; +#endif connMtx.lock(); /* LOCK MUTEX */ uint32_t vs = ownState.visState; @@ -347,6 +365,9 @@ void p3ConnectMgr::netDhtInit() void p3ConnectMgr::netUpnpInit() { +#ifdef CONN_DEBUG + std::cerr << "p3ConnectMgr::netUpnpInit()" << std::endl; +#endif uint16_t eport, iport; connMtx.lock(); /* LOCK MUTEX */ @@ -390,6 +411,10 @@ void p3ConnectMgr::netUpnpCheck() /* UPnP Failed us! */ mUpnpAddrValid = false; mNetStatus = RS_NET_UDP_SETUP; +#ifdef CONN_DEBUG + std::cerr << "p3ConnectMgr::netUpnpCheck() ensabling stunkeepalive() cos UDP" << std::endl; +#endif + tou_stunkeepalive(1); connMtx.unlock(); /* UNLOCK MUTEX */ } @@ -404,6 +429,10 @@ void p3ConnectMgr::netUpnpCheck() mNetStatus = RS_NET_UDP_SETUP; /* Fix netMode & Clear others! */ ownState.netMode = RS_NET_MODE_TRY_UPNP | RS_NET_MODE_UPNP; +#ifdef CONN_DEBUG + std::cerr << "p3ConnectMgr::netUpnpCheck() disabling stunkeepalive() cos uPnP" << std::endl; +#endif + tou_stunkeepalive(0); connMtx.unlock(); /* UNLOCK MUTEX */ } @@ -964,6 +993,7 @@ bool p3ConnectMgr::connectAttempt(std::string id, struct sockaddr_in &addr, return false; } + it->second.lastattempt = time(NULL); /* time of last connect attempt */ it->second.inConnAttempt = true; it->second.currentConnAddr = it->second.connAddrs.front(); it->second.connAddrs.pop_front(); diff --git a/libretroshare/src/pqi/p3connmgr.h b/libretroshare/src/pqi/p3connmgr.h index 0520c9e63..e3fb821fb 100644 --- a/libretroshare/src/pqi/p3connmgr.h +++ b/libretroshare/src/pqi/p3connmgr.h @@ -138,7 +138,7 @@ class peerConnectState /* a list of connect attempts to make (in order) */ bool inConnAttempt; - time_t connAttemptTS; + time_t lastattempt; peerConnectAddress currentConnAddr; std::list connAddrs; diff --git a/libretroshare/src/pqi/p3dhtmgr.cc b/libretroshare/src/pqi/p3dhtmgr.cc index 63dc4842e..fc2d3180c 100644 --- a/libretroshare/src/pqi/p3dhtmgr.cc +++ b/libretroshare/src/pqi/p3dhtmgr.cc @@ -36,6 +36,8 @@ * #define P3DHTMGR_USE_LOCAL_UDP_CONN 1 // For Testing only ****/ +#define P3DHTMGR_USE_LOCAL_UDP_CONN 1 // For Testing only + /**** DHT State Variables **** * TODO: * (1) notify call in. diff --git a/libretroshare/src/rsserver/p3face-server.cc b/libretroshare/src/rsserver/p3face-server.cc index 2f6c1951a..c5b93f692 100644 --- a/libretroshare/src/rsserver/p3face-server.cc +++ b/libretroshare/src/rsserver/p3face-server.cc @@ -26,6 +26,7 @@ #include "rsserver/p3face.h" +#include "tcponudp/tou.h" #include #include @@ -176,6 +177,9 @@ void RsServer::run() { lastSec = (int) ts; + // Every second! (UDP keepalive). + tou_tick_stunkeepalive(); + // every five loops (> 5 secs) if (loop % 5 == 0) { diff --git a/libretroshare/src/tcponudp/tou.cc b/libretroshare/src/tcponudp/tou.cc index 475f74e64..7152eb91d 100644 --- a/libretroshare/src/tcponudp/tou.cc +++ b/libretroshare/src/tcponudp/tou.cc @@ -89,6 +89,24 @@ int tou_stunpeer(const struct sockaddr *my_addr, socklen_t addrlen, return 0; } +int tou_stunkeepalive(int required) +{ + if (!tou_inited) + return -1; + + udps->setStunKeepAlive(required); + return 1; +} + +int tou_tick_stunkeepalive() +{ + if (!tou_inited) + return -1; + + udps->tick(); + return 1; +} + int tou_extaddr(struct sockaddr *ext_addr, socklen_t *addrlen) { if (!tou_inited) diff --git a/libretroshare/src/tcponudp/tou.h b/libretroshare/src/tcponudp/tou.h index 058197e86..6bf72ff70 100644 --- a/libretroshare/src/tcponudp/tou.h +++ b/libretroshare/src/tcponudp/tou.h @@ -66,12 +66,18 @@ extern "C" { * (3) offer more stunpeers, for external address determination. * int tou_stunpeer(const struct sockaddr *ext_addr, socklen_t addrlen, const char *id); * (4) repeat (2)+(3) until a valid extaddr is returned. + * (5) if stunkeepalive is required, then periodically send out + * stun packets to maintain external firewall port. * */ int tou_init(const struct sockaddr *my_addr, socklen_t addrlen); int tou_extaddr(struct sockaddr *ext_addr, socklen_t *addrlen); int tou_stunpeer(const struct sockaddr *ext_addr, socklen_t addrlen, const char *id); +int tou_stunkeepalive(int required); +int tou_tick_stunkeepalive(); + + /* Connections are as similar to UNIX as possible * (1) create a socket: tou_socket() this reserves a socket id. diff --git a/libretroshare/src/tcponudp/udpsorter.cc b/libretroshare/src/tcponudp/udpsorter.cc index 00bbd4596..8610ee516 100644 --- a/libretroshare/src/tcponudp/udpsorter.cc +++ b/libretroshare/src/tcponudp/udpsorter.cc @@ -39,7 +39,10 @@ static const int STUN_TTL = 64; #define DEBUG_UDP_SORTER 1 UdpSorter::UdpSorter(struct sockaddr_in &local) - :udpLayer(NULL), laddr(local), eaddrKnown(false) + :udpLayer(NULL), laddr(local), eaddrKnown(false), + mStunKeepAlive(false), mStunLastRecv(0), mStunLastSend(0) + + { sockaddr_clear(&eaddr); @@ -58,6 +61,7 @@ void UdpSorter::recvPkt(void *data, int size, struct sockaddr_in &from) #endif sortMtx.lock(); /********** LOCK MUTEX *********/ + mStunLastRecv = time(NULL); /* look for a peer */ std::map::iterator it; @@ -70,7 +74,7 @@ void UdpSorter::recvPkt(void *data, int size, struct sockaddr_in &from) std::cerr << std::endl; /* respond */ - handleStunPkt(data, size, from); + locked_handleStunPkt(data, size, from); } else if (it == streams.end()) { @@ -146,6 +150,8 @@ int UdpSorter::tick() #ifdef DEBUG_UDP_SORTER std::cerr << "UdpSorter::tick()" << std::endl; #endif + checkStunKeepAlive(); + return 1; } @@ -187,7 +193,7 @@ int UdpSorter::addUdpPeer(UdpPeer *peer, const struct sockaddr_in &raddr) /******************************* STUN Handling ********************************/ /* respond */ -bool UdpSorter::handleStunPkt(void *data, int size, struct sockaddr_in &from) +bool UdpSorter::locked_handleStunPkt(void *data, int size, struct sockaddr_in &from) { if (size == 20) /* request */ { @@ -230,6 +236,9 @@ bool UdpSorter::handleStunPkt(void *data, int size, struct sockaddr_in &from) #endif eaddrKnown = true; eaddr = eAddr; + + locked_recvdStun(from); + return true; } } @@ -242,21 +251,6 @@ bool UdpSorter::handleStunPkt(void *data, int size, struct sockaddr_in &from) } -bool UdpSorter::addStunPeer(const struct sockaddr_in &remote, const char *peerid) -{ - /* add to the list */ -#ifdef DEBUG_UDP_SORTER - std::cerr << "UdpSorter::addStunPeer()"; - std::cerr << std::endl; - - std::cerr << "UdpSorter::addStunPeer() - just stun it!"; - std::cerr << std::endl; -#endif - - doStun(remote); - return false; -} - bool UdpSorter::externalAddr(struct sockaddr_in &external) { if (eaddrKnown) @@ -301,6 +295,10 @@ int UdpSorter::doStun(struct sockaddr_in stun_addr) /* send it off */ int sentlen = sendPkt(stundata, tmplen, stun_addr, STUN_TTL); + sortMtx.lock(); /********** LOCK MUTEX *********/ + mStunLastSend = time(NULL); + sortMtx.unlock(); /******** UNLOCK MUTEX *********/ + #ifdef DEBUG_UDP_SORTER std::ostringstream out; out << "UdpSorter::doStun() Sent Stun Packet(" << sentlen << ") from:"; @@ -444,3 +442,223 @@ bool UdpSorter::isStunPacket(void *data, int size) return false; } + +/******************************* STUN Handling ******************************** + * The KeepAlive part - slightly more complicated + * + * + */ + +const int32_t TOU_STUN_MAX_FAIL_COUNT = 10; /* 10 tries (could be higher?) */ +const int32_t TOU_STUN_MAX_SEND_RATE = 5; /* every 5 seconds */ +const int32_t TOU_STUN_MAX_RECV_RATE = 25; /* every 25 seconds */ + +/******************************* STUN Handling ********************************/ + +bool UdpSorter::setStunKeepAlive(uint32_t required) +{ + sortMtx.lock(); /********** LOCK MUTEX *********/ + + mStunKeepAlive = (required != 0); + +#ifdef DEBUG_UDP_SORTER + std::cerr << "UdpSorter::setStunKeepAlive() to: " << mStunKeepAlive; + std::cerr << std::endl; +#endif + sortMtx.unlock(); /******** UNLOCK MUTEX *********/ + + return 1; +} + +bool UdpSorter::addStunPeer(const struct sockaddr_in &remote, const char *peerid) +{ + /* add to the list */ +#ifdef DEBUG_UDP_SORTER + std::cerr << "UdpSorter::addStunPeer()"; + std::cerr << std::endl; +#endif + + storeStunPeer(remote, peerid); + + sortMtx.lock(); /********** LOCK MUTEX *********/ + bool needStun = (!eaddrKnown); + sortMtx.unlock(); /******** UNLOCK MUTEX *********/ + + if (needStun) + { + doStun(remote); + } + + return true; +} + +bool UdpSorter::storeStunPeer(const struct sockaddr_in &remote, const char *peerid) +{ + +#ifdef DEBUG_UDP_SORTER + std::cerr << "UdpSorter::storeStunPeer()"; + std::cerr << std::endl; +#endif + + RsStackMutex stack(sortMtx); /********** LOCK MUTEX *********/ + + std::list::iterator it; + for(it = mStunList.begin(); it != mStunList.end(); it++) + { + if ((remote.sin_addr.s_addr == it->remote.sin_addr.s_addr) && + (remote.sin_port == it->remote.sin_port)) + { +#ifdef DEBUG_UDP_SORTER + std::cerr << "UdpSorter::storeStunPeer() Peer Already There!"; + std::cerr << std::endl; +#endif + /* already there */ + return false; + } + } + + TouStunPeer peer(std::string(peerid), remote); + mStunList.push_back(peer); + +#ifdef DEBUG_UDP_SORTER + std::cerr << "UdpSorter::storeStunPeer() Added Peer"; + std::cerr << std::endl; +#endif + + return true; +} + + +bool UdpSorter::checkStunKeepAlive() +{ + +#ifdef DEBUG_UDP_SORTER + std::cerr << "UdpSorter::checkStunKeepAlive()"; + std::cerr << std::endl; +#endif + + TouStunPeer peer; + time_t now; + { + RsStackMutex stack(sortMtx); /********** LOCK MUTEX *********/ + + if (!mStunKeepAlive) + { +#ifdef DEBUG_UDP_SORTER + std::cerr << "UdpSorter::checkStunKeepAlive() FALSE"; + std::cerr << std::endl; +#endif + return false; /* all good */ + } + + /* check if we need to send one now */ + now = time(NULL); + + if ((now - mStunLastSend < TOU_STUN_MAX_SEND_RATE) || + (now - mStunLastRecv < TOU_STUN_MAX_RECV_RATE)) + { +#ifdef DEBUG_UDP_SORTER + std::cerr << "UdpSorter::checkStunKeepAlive() To Fast ... delaying"; + std::cerr << std::endl; +#endif + /* too fast */ + return false; + } + + if (mStunList.size() < 1) + { +#ifdef DEBUG_UDP_SORTER + std::cerr << "UdpSorter::checkStunKeepAlive() No Peers in List!"; + std::cerr << std::endl; +#endif + return false; + } + + /* extract entry */ + peer = mStunList.front(); + mStunList.pop_front(); + } + + doStun(peer.remote); + + { + RsStackMutex stack(sortMtx); /********** LOCK MUTEX *********/ + if (peer.failCount < TOU_STUN_MAX_FAIL_COUNT) + { + peer.failCount++; + peer.lastsend = now; + mStunList.push_back(peer); + +#ifdef DEBUG_UDP_SORTER + std::cerr << "UdpSorter::checkStunKeepAlive() pushing Stun peer to back of list"; + std::cerr << std::endl; +#endif + + } + else + { +#ifdef DEBUG_UDP_SORTER + std::cerr << "UdpSorter::checkStunKeepAlive() Discarding bad stun peer"; + std::cerr << std::endl; +#endif + } + + locked_printStunList(); + + } + + + return true; +} + + +bool UdpSorter::locked_recvdStun(const struct sockaddr_in &remote) +{ +#ifdef DEBUG_UDP_SORTER + std::cerr << "UdpSorter::recvdStun()"; + std::cerr << std::endl; +#endif + + locked_printStunList(); + + std::list::iterator it; + for(it = mStunList.begin(); it != mStunList.end(); it++) + { + if ((remote.sin_addr.s_addr == it->remote.sin_addr.s_addr) && + (remote.sin_port == it->remote.sin_port)) + { + it->failCount = 0; + return true; + } + } + + return false; +} + +bool UdpSorter::locked_printStunList() +{ + std::ostringstream out; + + time_t now = time(NULL); + out << "locked_printStunList()" << std::endl; + out << "\tLastSend: " << now - mStunLastSend << std::endl; + out << "\tLastRecv: " << now - mStunLastRecv << std::endl; + + std::list::iterator it; + for(it = mStunList.begin(); it != mStunList.end(); it++) + { + out << "id:" << it->id << " addr: " << inet_ntoa(it->remote.sin_addr); + out << ":" << htons(it->remote.sin_port); + out << " failCount: " << it->failCount; + out << " lastSend: " << now - it->lastsend; + out << std::endl; + } + + std::cerr << out.str(); + + return true; +} + + + + diff --git a/libretroshare/src/tcponudp/udpsorter.h b/libretroshare/src/tcponudp/udpsorter.h index d2c5f680c..937068426 100644 --- a/libretroshare/src/tcponudp/udpsorter.h +++ b/libretroshare/src/tcponudp/udpsorter.h @@ -43,6 +43,24 @@ class UdpPeer virtual void recvPkt(void *data, int size) = 0; }; + + +class TouStunPeer +{ + public: + TouStunPeer() + :lastsend(0), failCount(0) { return; } + + TouStunPeer(std::string id_in, const struct sockaddr_in &addr) + :id(id_in), remote(addr), lastsend(0), failCount(0) { return; } + + std::string id; + struct sockaddr_in remote; + time_t lastsend; + uint32_t failCount; +}; + + class UdpSorter: public UdpReceiver { public: @@ -52,7 +70,11 @@ virtual ~UdpSorter() { return; } /* add a TCPonUDP stream */ int addUdpPeer(UdpPeer *peer, const struct sockaddr_in &raddr); + +bool setStunKeepAlive(uint32_t required); bool addStunPeer(const struct sockaddr_in &remote, const char *peerid); +bool checkStunKeepAlive(); + bool externalAddr(struct sockaddr_in &remote); /* Packet IO */ @@ -76,7 +98,7 @@ int status(std::ostream &out); /* STUN handling */ bool isStunPacket(void *data, int size); -bool handleStunPkt(void *data, int size, struct sockaddr_in &from); +bool locked_handleStunPkt(void *data, int size, struct sockaddr_in &from); int doStun(struct sockaddr_in stun_addr); bool response(void *stun_pkt, int size, struct sockaddr_in &addr); @@ -84,7 +106,10 @@ bool response(void *stun_pkt, int size, struct sockaddr_in &addr); void *generate_stun_reply(struct sockaddr_in *stun_addr, int *len); bool generate_stun_pkt(void *stun_pkt, int *len); - + /* stun keepAlive */ +bool locked_printStunList(); +bool locked_recvdStun(const struct sockaddr_in &remote); +bool storeStunPeer(const struct sockaddr_in &remote, const char *peerid); UdpLayer *udpLayer; @@ -94,9 +119,16 @@ bool generate_stun_pkt(void *stun_pkt, int *len); struct sockaddr_in eaddr; /* external addr */ bool eaddrKnown; - std::list stunPeers; /* potentials */ + bool mStunKeepAlive; + time_t mStunLastRecv; + time_t mStunLastSend; + + std::list mStunList; /* potentials */ std::map streams; + + + }; #endif diff --git a/libretroshare/src/upnp/upnputil.c b/libretroshare/src/upnp/upnputil.c index befd19b0e..0d2437362 100644 --- a/libretroshare/src/upnp/upnputil.c +++ b/libretroshare/src/upnp/upnputil.c @@ -115,7 +115,7 @@ bool SetRedirectAndTest(struct UPNPUrls * urls, char externalIPAddress[16]; char intClient[16]; char intPort[6]; - char leaseDuration[] = "600"; + char leaseDuration[] = "600"; /* 10 mins */ int r; int ok = 1;