Additions to tcponudp to add a TouKeepAlive system.

This is only used if we are in 'firewalled' mode.



git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@360 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
drbob 2008-02-28 10:43:33 +00:00
parent 31454138b7
commit 6dd3d30d8e
9 changed files with 335 additions and 25 deletions

View File

@ -75,7 +75,7 @@ peerConnectState::peerConnectState()
name("nameless"), state(0), actions(0), name("nameless"), state(0), actions(0),
source(0), source(0),
inConnAttempt(0), connAttemptTS(0) inConnAttempt(0), lastattempt(0)
{ {
sockaddr_clear(&localaddr); sockaddr_clear(&localaddr);
sockaddr_clear(&serveraddr); sockaddr_clear(&serveraddr);
@ -215,6 +215,9 @@ void p3ConnectMgr::netStartup()
/* StunInit gets a list of peers, and asks the DHT to find them... /* StunInit gets a list of peers, and asks the DHT to find them...
* This is needed for all systems so startup straight away * This is needed for all systems so startup straight away
*/ */
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::netStartup()" << std::endl;
#endif
loadConfiguration(); loadConfiguration();
netDhtInit(); netDhtInit();
@ -228,18 +231,27 @@ void p3ConnectMgr::netStartup()
mNetInitTS = time(NULL); 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); ownState.netMode &= ~(RS_NET_MODE_ACTUAL);
switch(ownState.netMode & RS_NET_MODE_TRYMODE) switch(ownState.netMode & RS_NET_MODE_TRYMODE)
{ {
case RS_NET_MODE_TRY_UPNP: case RS_NET_MODE_TRY_UPNP:
mNetStatus = RS_NET_UPNP_INIT;
ownState.netMode |= RS_NET_MODE_UDP; ownState.netMode |= RS_NET_MODE_UDP;
mNetStatus = RS_NET_UPNP_INIT;
break; break;
case RS_NET_MODE_TRY_EXT: /* v similar to UDP */ case RS_NET_MODE_TRY_EXT: /* v similar to UDP */
ownState.netMode |= RS_NET_MODE_EXT; ownState.netMode |= RS_NET_MODE_EXT;
mNetStatus = RS_NET_UDP_SETUP; mNetStatus = RS_NET_UDP_SETUP;
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::netStartup() disabling stunkeepalive() cos EXT" << std::endl;
#endif
tou_stunkeepalive(0);
break; break;
case RS_NET_MODE_TRY_UDP: case RS_NET_MODE_TRY_UDP:
@ -322,6 +334,9 @@ void p3ConnectMgr::netTick()
void p3ConnectMgr::netUdpInit() void p3ConnectMgr::netUdpInit()
{ {
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::netUdpInit()" << std::endl;
#endif
connMtx.lock(); /* LOCK MUTEX */ connMtx.lock(); /* LOCK MUTEX */
struct sockaddr_in iaddr = ownState.localaddr; struct sockaddr_in iaddr = ownState.localaddr;
@ -335,6 +350,9 @@ void p3ConnectMgr::netUdpInit()
void p3ConnectMgr::netDhtInit() void p3ConnectMgr::netDhtInit()
{ {
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::netDhtInit()" << std::endl;
#endif
connMtx.lock(); /* LOCK MUTEX */ connMtx.lock(); /* LOCK MUTEX */
uint32_t vs = ownState.visState; uint32_t vs = ownState.visState;
@ -347,6 +365,9 @@ void p3ConnectMgr::netDhtInit()
void p3ConnectMgr::netUpnpInit() void p3ConnectMgr::netUpnpInit()
{ {
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::netUpnpInit()" << std::endl;
#endif
uint16_t eport, iport; uint16_t eport, iport;
connMtx.lock(); /* LOCK MUTEX */ connMtx.lock(); /* LOCK MUTEX */
@ -390,6 +411,10 @@ void p3ConnectMgr::netUpnpCheck()
/* UPnP Failed us! */ /* UPnP Failed us! */
mUpnpAddrValid = false; mUpnpAddrValid = false;
mNetStatus = RS_NET_UDP_SETUP; 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 */ connMtx.unlock(); /* UNLOCK MUTEX */
} }
@ -404,6 +429,10 @@ void p3ConnectMgr::netUpnpCheck()
mNetStatus = RS_NET_UDP_SETUP; mNetStatus = RS_NET_UDP_SETUP;
/* Fix netMode & Clear others! */ /* Fix netMode & Clear others! */
ownState.netMode = RS_NET_MODE_TRY_UPNP | RS_NET_MODE_UPNP; 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 */ connMtx.unlock(); /* UNLOCK MUTEX */
} }
@ -964,6 +993,7 @@ bool p3ConnectMgr::connectAttempt(std::string id, struct sockaddr_in &addr,
return false; return false;
} }
it->second.lastattempt = time(NULL); /* time of last connect attempt */
it->second.inConnAttempt = true; it->second.inConnAttempt = true;
it->second.currentConnAddr = it->second.connAddrs.front(); it->second.currentConnAddr = it->second.connAddrs.front();
it->second.connAddrs.pop_front(); it->second.connAddrs.pop_front();

View File

@ -138,7 +138,7 @@ class peerConnectState
/* a list of connect attempts to make (in order) */ /* a list of connect attempts to make (in order) */
bool inConnAttempt; bool inConnAttempt;
time_t connAttemptTS; time_t lastattempt;
peerConnectAddress currentConnAddr; peerConnectAddress currentConnAddr;
std::list<peerConnectAddress> connAddrs; std::list<peerConnectAddress> connAddrs;

View File

@ -36,6 +36,8 @@
* #define P3DHTMGR_USE_LOCAL_UDP_CONN 1 // For Testing only * #define P3DHTMGR_USE_LOCAL_UDP_CONN 1 // For Testing only
****/ ****/
#define P3DHTMGR_USE_LOCAL_UDP_CONN 1 // For Testing only
/**** DHT State Variables **** /**** DHT State Variables ****
* TODO: * TODO:
* (1) notify call in. * (1) notify call in.

View File

@ -26,6 +26,7 @@
#include "rsserver/p3face.h" #include "rsserver/p3face.h"
#include "tcponudp/tou.h"
#include <sstream> #include <sstream>
#include <sys/time.h> #include <sys/time.h>
@ -176,6 +177,9 @@ void RsServer::run()
{ {
lastSec = (int) ts; lastSec = (int) ts;
// Every second! (UDP keepalive).
tou_tick_stunkeepalive();
// every five loops (> 5 secs) // every five loops (> 5 secs)
if (loop % 5 == 0) if (loop % 5 == 0)
{ {

View File

@ -89,6 +89,24 @@ int tou_stunpeer(const struct sockaddr *my_addr, socklen_t addrlen,
return 0; 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) int tou_extaddr(struct sockaddr *ext_addr, socklen_t *addrlen)
{ {
if (!tou_inited) if (!tou_inited)

View File

@ -66,12 +66,18 @@ extern "C" {
* (3) offer more stunpeers, for external address determination. * (3) offer more stunpeers, for external address determination.
* int tou_stunpeer(const struct sockaddr *ext_addr, socklen_t addrlen, const char *id); * int tou_stunpeer(const struct sockaddr *ext_addr, socklen_t addrlen, const char *id);
* (4) repeat (2)+(3) until a valid extaddr is returned. * (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_init(const struct sockaddr *my_addr, socklen_t addrlen);
int tou_extaddr(struct sockaddr *ext_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_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 /* Connections are as similar to UNIX as possible
* (1) create a socket: tou_socket() this reserves a socket id. * (1) create a socket: tou_socket() this reserves a socket id.

View File

@ -39,7 +39,10 @@ static const int STUN_TTL = 64;
#define DEBUG_UDP_SORTER 1 #define DEBUG_UDP_SORTER 1
UdpSorter::UdpSorter(struct sockaddr_in &local) 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); sockaddr_clear(&eaddr);
@ -58,6 +61,7 @@ void UdpSorter::recvPkt(void *data, int size, struct sockaddr_in &from)
#endif #endif
sortMtx.lock(); /********** LOCK MUTEX *********/ sortMtx.lock(); /********** LOCK MUTEX *********/
mStunLastRecv = time(NULL);
/* look for a peer */ /* look for a peer */
std::map<struct sockaddr_in, UdpPeer *>::iterator it; std::map<struct sockaddr_in, UdpPeer *>::iterator it;
@ -70,7 +74,7 @@ void UdpSorter::recvPkt(void *data, int size, struct sockaddr_in &from)
std::cerr << std::endl; std::cerr << std::endl;
/* respond */ /* respond */
handleStunPkt(data, size, from); locked_handleStunPkt(data, size, from);
} }
else if (it == streams.end()) else if (it == streams.end())
{ {
@ -146,6 +150,8 @@ int UdpSorter::tick()
#ifdef DEBUG_UDP_SORTER #ifdef DEBUG_UDP_SORTER
std::cerr << "UdpSorter::tick()" << std::endl; std::cerr << "UdpSorter::tick()" << std::endl;
#endif #endif
checkStunKeepAlive();
return 1; return 1;
} }
@ -187,7 +193,7 @@ int UdpSorter::addUdpPeer(UdpPeer *peer, const struct sockaddr_in &raddr)
/******************************* STUN Handling ********************************/ /******************************* STUN Handling ********************************/
/* respond */ /* 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 */ if (size == 20) /* request */
{ {
@ -230,6 +236,9 @@ bool UdpSorter::handleStunPkt(void *data, int size, struct sockaddr_in &from)
#endif #endif
eaddrKnown = true; eaddrKnown = true;
eaddr = eAddr; eaddr = eAddr;
locked_recvdStun(from);
return true; 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) bool UdpSorter::externalAddr(struct sockaddr_in &external)
{ {
if (eaddrKnown) if (eaddrKnown)
@ -301,6 +295,10 @@ int UdpSorter::doStun(struct sockaddr_in stun_addr)
/* send it off */ /* send it off */
int sentlen = sendPkt(stundata, tmplen, stun_addr, STUN_TTL); int sentlen = sendPkt(stundata, tmplen, stun_addr, STUN_TTL);
sortMtx.lock(); /********** LOCK MUTEX *********/
mStunLastSend = time(NULL);
sortMtx.unlock(); /******** UNLOCK MUTEX *********/
#ifdef DEBUG_UDP_SORTER #ifdef DEBUG_UDP_SORTER
std::ostringstream out; std::ostringstream out;
out << "UdpSorter::doStun() Sent Stun Packet(" << sentlen << ") from:"; out << "UdpSorter::doStun() Sent Stun Packet(" << sentlen << ") from:";
@ -444,3 +442,223 @@ bool UdpSorter::isStunPacket(void *data, int size)
return false; 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<TouStunPeer>::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<TouStunPeer>::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<TouStunPeer>::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;
}

View File

@ -43,6 +43,24 @@ class UdpPeer
virtual void recvPkt(void *data, int size) = 0; 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 class UdpSorter: public UdpReceiver
{ {
public: public:
@ -52,7 +70,11 @@ virtual ~UdpSorter() { return; }
/* add a TCPonUDP stream */ /* add a TCPonUDP stream */
int addUdpPeer(UdpPeer *peer, const struct sockaddr_in &raddr); 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 addStunPeer(const struct sockaddr_in &remote, const char *peerid);
bool checkStunKeepAlive();
bool externalAddr(struct sockaddr_in &remote); bool externalAddr(struct sockaddr_in &remote);
/* Packet IO */ /* Packet IO */
@ -76,7 +98,7 @@ int status(std::ostream &out);
/* STUN handling */ /* STUN handling */
bool isStunPacket(void *data, int size); 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); int doStun(struct sockaddr_in stun_addr);
bool response(void *stun_pkt, int size, struct sockaddr_in &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); void *generate_stun_reply(struct sockaddr_in *stun_addr, int *len);
bool generate_stun_pkt(void *stun_pkt, 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; UdpLayer *udpLayer;
@ -94,9 +119,16 @@ bool generate_stun_pkt(void *stun_pkt, int *len);
struct sockaddr_in eaddr; /* external addr */ struct sockaddr_in eaddr; /* external addr */
bool eaddrKnown; bool eaddrKnown;
std::list<struct sockaddr_in> stunPeers; /* potentials */ bool mStunKeepAlive;
time_t mStunLastRecv;
time_t mStunLastSend;
std::list<TouStunPeer> mStunList; /* potentials */
std::map<struct sockaddr_in, UdpPeer *> streams; std::map<struct sockaddr_in, UdpPeer *> streams;
}; };
#endif #endif

View File

@ -115,7 +115,7 @@ bool SetRedirectAndTest(struct UPNPUrls * urls,
char externalIPAddress[16]; char externalIPAddress[16];
char intClient[16]; char intClient[16];
char intPort[6]; char intPort[6];
char leaseDuration[] = "600"; char leaseDuration[] = "600"; /* 10 mins */
int r; int r;
int ok = 1; int ok = 1;