Merged Changes /branches/v0.5-peernet/libretroshare/:r4237-4358

Major changes are:
 * Improvements to tcponudp library to allow multiple UdpStacks / ports, with alternative recievers.
 * Resurrected the UdpStunner code, and improved it.
 * Added UdpRelay code.
 * Modified startup code and ssludp code to use the new tcponudp and add a stunner.
 * fixed buggy rs_inet_ntoa
 * fixed a bunch of apple gcc warnings. mainly for(;;); => for(;;) ;

These changes shouldn't affect libretroshare stability... those changes will follow!




git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@4359 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
drbob 2011-06-29 18:02:44 +00:00
parent d58f838269
commit b683e663d6
19 changed files with 1679 additions and 151 deletions

View File

@ -688,7 +688,7 @@ bool ftTransferModule::checkCRC()
int n = rand()%(mFileSources.size()) ;
int p=0 ;
std::map<std::string,peerInfo>::const_iterator mit ;
for(mit = mFileSources.begin();mit != mFileSources.end() && p<n;++mit,++p);
for(mit = mFileSources.begin();mit != mFileSources.end() && p<n;++mit,++p) ;
#ifdef FT_DEBUG
std::cerr << "ftTransferModule::checkCRC(): sending CRC map request to source " << mit->first << std::endl ;

View File

@ -73,12 +73,16 @@ HEADERS += tcponudp/udppeer.h \
tcponudp/tcppacket.h \
tcponudp/tcpstream.h \
tcponudp/tou.h \
tcponudp/udpstunner.h \
tcponudp/udprelay.h \
SOURCES += tcponudp/udppeer.cc \
tcponudp/tcppacket.cc \
tcponudp/tcpstream.cc \
tcponudp/tou.cc \
tcponudp/bss_tou.c \
tcponudp/udpstunner.cc \
tcponudp/udprelay.cc \
# These two aren't actually used (and don't compile) ....
# but could be useful later

View File

@ -1637,7 +1637,7 @@ bool p3DhtMgr::dhtResultNotify(std::string idhash)
time_t now = time(NULL);
/* if notify - we must match on the second hash */
for(it = peers.begin(); (it != peers.end()) && ((it->second).hash2 != idhash); it++);
for(it = peers.begin(); (it != peers.end()) && ((it->second).hash2 != idhash); it++) ;
/* update data */
std::string peerid;
@ -1697,7 +1697,7 @@ bool p3DhtMgr::dhtResultSearch(std::string idhash,
dhtPeerEntry ent;
/* if search - we must match on the second hash */
for(it = peers.begin(); (it != peers.end()) && ((it->second).hash1 != idhash); it++);
for(it = peers.begin(); (it != peers.end()) && ((it->second).hash1 != idhash); it++) ;
/* update data */
/* ignore OFF peers */

View File

@ -99,7 +99,9 @@ int pqissludp::reset()
int pqissludp::attach()
{
sockfd = tou_socket(0,0,0);
// IN THE IMPROVED TOU LIBRARY, we need to be careful with the tou_socket PARAMETERS.
// For now, this should do!
sockfd = tou_socket(0,TOU_RECEIVER_TYPE_UDPPEER,0);
if (0 > sockfd)
{
rslog(RSL_WARNING, pqissludpzone,

View File

@ -585,7 +585,9 @@ X509 *loadX509FromDER(const uint8_t *ptr, uint32_t len)
X509 *tmp = NULL;
#ifdef __APPLE__
// This depends on which version you are compiling for... OSX10.5 doesn't have consts (old OpenSSL!)
unsigned char **certptr = (unsigned char **) &ptr;
//const unsigned char **certptr = (const unsigned char **) &ptr;
#else
const unsigned char **certptr = (const unsigned char **) &ptr;
#endif

View File

@ -57,6 +57,8 @@
#include "pqi/sslfns.h"
#include "pqi/authgpg.h"
#include "tcponudp/udpstunner.h"
class accountId
{
public:
@ -1739,6 +1741,8 @@ RsTurtle *rsTurtle = NULL ;
#ifdef RS_USE_BITDHT
#include "dht/p3bitdht.h"
#include "udp/udpstack.h"
#include "tcponudp/udppeer.h"
#include "tcponudp/udprelay.h"
#endif
/****
@ -1882,11 +1886,58 @@ int RsServer::StartupRetroShare()
}
}
p3BitDht *mBitDht = new p3BitDht(ownId, mConnMgr,
mUdpStack, bootstrapfile);
/* construct the rest of the stack, important to build them in the correct order! */
/* MOST OF THIS IS COMMENTED OUT UNTIL THE REST OF libretroshare IS READY FOR IT! */
UdpSubReceiver *udpReceivers[3];
int udpTypes[3];
// FIRST DHT STUNNER.
UdpStunner *mDhtStunner = new UdpStunner(mUdpStack);
mDhtStunner->setTargetStunPeriod(0); /* passive */
//mDhtStunner->setTargetStunPeriod(300); /* slow (5mins) */
mUdpStack->addReceiver(mDhtStunner);
// NEXT BITDHT.
p3BitDht *mBitDht = new p3BitDht(ownId, mConnMgr, mUdpStack, bootstrapfile);
// NEXT THE RELAY (NEED to keep a reference for installing RELAYS)
//UdpRelayReceiver *mRelayRecver = new UdpRelayReceiver(mUdpStack);
//udpReceivers[2] = mRelayRecver; /* RELAY Connections (DHT Port) */
//udpTypes[2] = TOU_RECEIVER_TYPE_UDPRELAY;
//mUdpStack->addReceiver(udpReceivers[2]);
// LAST ON THIS STACK IS STANDARD DIRECT TOU
udpReceivers[0] = new UdpPeerReceiver(mUdpStack); /* standard DIRECT Connections (DHT Port) */
udpTypes[0] = TOU_RECEIVER_TYPE_UDPPEER;
mUdpStack->addReceiver(udpReceivers[0]);
// NOW WE BUILD THE SECOND STACK.
// Create the Second UdpStack... Port should be random (but openable!).
//struct sockaddr_in sndladdr;
//sockaddr_clear(&sndladdr);
//sndladdr.sin_port = htons(RsInitConfig::port + 1111);
//rsUdpStack *mUdpProxyStack = new rsUdpStack(sndladdr);
// FIRSTLY THE PROXY STUNNER.
//UdpStunner *mProxyStunner = new UdpStunner(mUdpProxyStack);
// USE DEFAULT PERIOD... mDhtStunner->setTargetStunPeriod(300); /* slow (5mins) */
//mUdpStack->addReceiver(mDhtStunner);
// FINALLY THE PROXY UDP CONNECTIONS
//udpReceivers[1] = new UdpPeerReceiver(mUdpProxyStack); /* PROXY Connections (Alt UDP Port) */
//udpTypes[1] = TOU_RECEIVER_TYPE_UDPPEER;
//mUdpProxyStack->addReceiver(udpReceivers[1]);
// NOW WE CAN PASS THE RECEIVERS TO TOU.
// temp initialisation of only the DIRECT TOU.
tou_init((void **) udpReceivers, udpTypes, 1);
// REAL INITIALISATION - WITH THREE MODES - FOR LATER.
//tou_init((void **) udpReceivers, udpTypes, 3);
/* construct the rest of the stack */
tou_init(mUdpStack);
#endif

View File

@ -611,7 +611,7 @@ bool p3GameLauncher::confirmPeer(std::string gameId, std::string peerId,
int32_t i = 0;
for(it = git->second.peerIds.begin(); (i < pos) &&
(it != git->second.peerIds.end()); it++, i++);
(it != git->second.peerIds.end()); it++, i++) ;
if ((pos < 0) || (it == git->second.peerIds.end()))
{

View File

@ -829,7 +829,7 @@ bool p3Ranking::getRankings(uint32_t first, uint32_t count, std::list<std::st
uint32_t i = 0;
std::multimap<float, std::string>::reverse_iterator rit;
for(rit = mRankings.rbegin(); (i < first) && (rit != mRankings.rend()); rit++, i++);
for(rit = mRankings.rbegin(); (i < first) && (rit != mRankings.rend()); rit++, i++) ;
i = 0;
for(; (i < count) && (rit != mRankings.rend()); rit++, i++)

View File

@ -71,7 +71,7 @@ static const double RTT_ALPHA = 0.875;
// platform independent fractional timestamp.
static double getCurrentTS();
TcpStream::TcpStream(UdpPeerReceiver *lyr)
TcpStream::TcpStream(UdpSubReceiver *lyr)
:inSize(0), outSizeRead(0), outSizeNet(0),
state(TCP_CLOSED),
inStreamActive(false),

View File

@ -73,7 +73,7 @@ class TcpStream: public UdpPeer
public:
/* Top-Level exposed */
TcpStream(UdpPeerReceiver *udp);
TcpStream(UdpSubReceiver *udp);
virtual ~TcpStream() { return; }
/* user interface */
@ -230,8 +230,8 @@ uint32 int_rbytes();
struct sockaddr_in peeraddr;
bool peerKnown;
/* UdpPeerReceiver (has own Mutex!) */
UdpPeerReceiver *udp;
/* UdpSubReceiver (has own Mutex!) */
UdpSubReceiver *udp;
};

View File

@ -47,6 +47,8 @@ struct TcpOnUdp_t
int tou_fd;
int lasterrno;
TcpStream *tcp;
UdpSubReceiver *udpsr;
int udptype;
bool idle;
};
@ -57,42 +59,82 @@ static std::vector<TcpOnUdp *> tou_streams;
static int tou_inited = 0;
#include "udp/udpstack.h"
#include "tcponudp/udppeer.h"
#include "tcponudp/udprelay.h"
static UdpStack *udpstack = NULL;
static UdpPeerReceiver *udps = NULL;
static UdpSubReceiver *udpSR[MAX_TOU_RECEIVERS] = {NULL};
static uint32_t udpType[MAX_TOU_RECEIVERS] = {NULL};
static uint32_t noUdpSR = 0;
static int tou_tick_all();
/* tou_init
*
* Modified to accept a number of UdpSubRecievers!
* these can be linked to arbitary UdpStacks.
* (removed all UdpStack references here!)
*
* Unfortunately, the UdpSubReceivers have different initialisation for starting a connection.
* So the TOU interface has to accomodate this.
*
*/
/* tou_init - opens the udp port (universal bind) */
int tou_init(void *in_udpstack)
int tou_init(void **in_udpsubrecvs, int *type, int number)
{
UdpStack *stack = (UdpStack *) in_udpstack;
UdpSubReceiver **usrArray = (UdpSubReceiver **) in_udpsubrecvs;
if (number > MAX_TOU_RECEIVERS)
{
std::cerr << "tou_init() Invalid number of receivers";
std::cerr << std::endl;
return 0;
}
if (tou_inited)
{
return 1;
}
tou_streams.resize(kInitStreamTable);
noUdpSR = number;
int i;
for(i = 0; i < noUdpSR; i++)
{
udpSR[i] = usrArray[i];
udpType[i] = type[i];
}
udpstack = stack;
udps = new UdpPeerReceiver(stack);
stack->addReceiver(udps);
tou_streams.resize(kInitStreamTable);
tou_inited = 1;
return 1;
}
/* open - which does nothing */
int tou_socket(int /*domain*/, int /*type*/, int /*protocol*/)
/* open - allocates a sockfd, and checks that the type is okay */
int tou_socket(int recvIdx, int type, int /*protocol*/)
{
if (!tou_inited)
{
return -1;
}
if (recvIdx >= noUdpSR)
{
std::cerr << "tou_socket() ERROR recvIdx greater than #receivers";
std::cerr << std::endl;
return -1;
}
/* check that the index matches the type */
UdpSubReceiver *recver = udpSR[recvIdx];
uint32_t recverType = udpType[recvIdx];
if (recverType != type)
{
std::cerr << "tou_socket() ERROR type doesn't match expected type";
std::cerr << std::endl;
return -1;
}
for(unsigned int i = 1; i < tou_streams.size(); i++)
{
if (tou_streams[i] == NULL)
@ -100,6 +142,8 @@ int tou_socket(int /*domain*/, int /*type*/, int /*protocol*/)
tou_streams[i] = new TcpOnUdp();
tou_streams[i] -> tou_fd = i;
tou_streams[i] -> tcp = NULL;
tou_streams[i] -> udpsr = recver;
tou_streams[i] -> udptype = recverType;
return i;
}
}
@ -112,6 +156,8 @@ int tou_socket(int /*domain*/, int /*type*/, int /*protocol*/)
{
tou -> tou_fd = tou_streams.size() -1;
tou -> tcp = NULL;
tou -> udpsr = recver;
tou -> udptype = recverType;
return tou->tou_fd;
}
@ -158,11 +204,35 @@ int tou_connect(int sockfd, const struct sockaddr *serv_addr,
return -1;
}
/* enforce that the udptype is correct */
if (tous -> udptype != TOU_RECEIVER_TYPE_UDPPEER)
{
std::cerr << "tou_connect() ERROR connect method invalid for udptype";
std::cerr << std::endl;
tous -> lasterrno = EINVAL;
return -1;
}
#ifdef TOU_DYNAMIC_CAST_CHECK
/* extra checking -> for testing purposes (dynamic cast) */
UdpPeerReceiver *upr = dynamic_cast<UdpPeerReceiver *>(tous->udpsr);
if (!upr)
{
std::cerr << "tou_connect() ERROR cannot convert type to UdpPeerReceiver";
std::cerr << std::endl;
tous -> lasterrno = EINVAL;
return -1;
}
#else
UdpPeerReceiver *upr = (UdpPeerReceiver *) (tous->udpsr);
#endif
/* create a TCP stream to connect with. */
if (!tous->tcp)
{
tous->tcp = new TcpStream(udps);
udps->addUdpPeer(tous->tcp,
tous->tcp = new TcpStream(tous->udpsr);
upr->addUdpPeer(tous->tcp,
*((const struct sockaddr_in *) serv_addr));
}
@ -178,6 +248,7 @@ int tou_connect(int sockfd, const struct sockaddr *serv_addr,
return -1;
}
/* is this ever used? should it be depreciated? */
int tou_listenfor(int sockfd, const struct sockaddr *serv_addr,
socklen_t addrlen)
{
@ -193,11 +264,34 @@ int tou_listenfor(int sockfd, const struct sockaddr *serv_addr,
return -1;
}
/* enforce that the udptype is correct */
if (tous -> udptype != TOU_RECEIVER_TYPE_UDPPEER)
{
std::cerr << "tou_connect() ERROR connect method invalid for udptype";
std::cerr << std::endl;
tous -> lasterrno = EINVAL;
return -1;
}
#ifdef TOU_DYNAMIC_CAST_CHECK
/* extra checking -> for testing purposes (dynamic cast) */
UdpPeerReceiver *upr = dynamic_cast<UdpPeerReceiver *>(tous->udpsr);
if (!upr)
{
std::cerr << "tou_connect() ERROR cannot convert type to UdpPeerReceiver";
std::cerr << std::endl;
tous -> lasterrno = EINVAL;
return -1;
}
#else
UdpPeerReceiver *upr = (UdpPeerReceiver *) (tous->udpsr);
#endif
/* create a TCP stream to connect with. */
if (!tous->tcp)
{
tous->tcp = new TcpStream(udps);
udps->addUdpPeer(tous->tcp,
tous->tcp = new TcpStream(tous->udpsr);
upr->addUdpPeer(tous->tcp,
*((const struct sockaddr_in *) serv_addr));
}
@ -214,6 +308,84 @@ int tou_listen(int /* sockfd */ , int /* backlog */ )
return 1;
}
/*
* This is the alternative RELAY connection.
*
* User needs to provide 3 ip addresses.
* These addresses should have been provided by the RELAY negogiation
* a) own ip:port
* b) proxy ip:port
* c) dest ip:port
*
* The reset of the startup is similar to other TOU connections.
* As this is likely to be run over an established UDP connection,
* there is little need for a big connection period.
*
* - like a tcp/ip connection, the connect
* will return -1 EAGAIN, until connection complete.
* - always non blocking.
*/
#define DEFAULT_RELAY_CONN_PERIOD 1
int tou_connect_via_relay(int sockfd,
const struct sockaddr_in *own_addr,
const struct sockaddr_in *proxy_addr,
const struct sockaddr_in *dest_addr)
{
if (tou_streams[sockfd] == NULL)
{
return -1;
}
TcpOnUdp *tous = tou_streams[sockfd];
/* enforce that the udptype is correct */
if (tous -> udptype != TOU_RECEIVER_TYPE_UDPRELAY)
{
std::cerr << "tou_connect() ERROR connect method invalid for udptype";
std::cerr << std::endl;
tous -> lasterrno = EINVAL;
return -1;
}
#ifdef TOU_DYNAMIC_CAST_CHECK
/* extra checking -> for testing purposes (dynamic cast) */
UdpRelayReceiver *urr = dynamic_cast<UdpRelayReceiver *>(tous->udpsr);
if (!urr)
{
std::cerr << "tou_connect() ERROR cannot convert type to UdpRelayReceiver";
std::cerr << std::endl;
tous -> lasterrno = EINVAL;
return -1;
}
#else
UdpRelayReceiver *urr = (UdpRelayReceiver *) (tous->udpsr);
#endif
/* create a TCP stream to connect with. */
if (!tous->tcp)
{
tous->tcp = new TcpStream(tous->udpsr);
UdpRelayAddrSet addrSet(own_addr, dest_addr);
urr->addUdpPeer(tous->tcp, &addrSet, proxy_addr);
}
/* We Point it at the Destination Address.
* The UdpRelayReceiver wraps and re-directs the packets to the proxy
*/
tous->tcp->connect(*dest_addr, DEFAULT_RELAY_CONN_PERIOD);
tous->tcp->tick();
tou_tick_all();
if (tous->tcp->isConnected())
{
return 0;
}
tous -> lasterrno = EINPROGRESS;
return -1;
}
/* slightly different - returns sockfd on connection */
int tou_accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
@ -362,8 +534,50 @@ int tou_close(int sockfd)
/* shut it down */
tous->tcp->close();
udps->removeUdpPeer(tous->tcp);
/* now we need to work out which type of receiver we have */
#ifdef TOU_DYNAMIC_CAST_CHECK
/* extra checking -> for testing purposes (dynamic cast) */
UdpRelayReceiver *urr = dynamic_cast<UdpRelayReceiver *>(tous->udpsr);
UdpPeerReceiver *upr = dynamic_cast<UdpPeerReceiver *>(tous->udpsr);
if (urr)
{
urr->removeUdpPeer(tous->tcp);
}
else if (upr)
{
upr->removeUdpPeer(tous->tcp);
}
else
{
/* error */
std::cerr << "tou_close() ERROR unknown udptype";
std::cerr << std::endl;
tous -> lasterrno = EINVAL;
}
#else
if (tous -> udptype == TOU_RECEIVER_TYPE_UDPRELAY)
{
UdpRelayReceiver *urr = (UdpRelayReceiver *) (tous->udpsr);
urr->removeUdpPeer(tous->tcp);
}
else if (tous -> udptype == TOU_RECEIVER_TYPE_UDPPEER)
{
UdpPeerReceiver *upr = (UdpPeerReceiver *) (tous->udpsr);
upr->removeUdpPeer(tous->tcp);
}
else
{
/* error */
std::cerr << "tou_close() ERROR unknown udptype";
std::cerr << std::endl;
tous -> lasterrno = EINVAL;
}
#endif
delete tous->tcp;
}
delete tous;
@ -374,10 +588,6 @@ int tou_close(int sockfd)
/* get an error number */
int tou_errno(int sockfd)
{
if (!udps)
{
return ENOTSOCK;
}
if (tou_streams[sockfd] == NULL)
{
return ENOTSOCK;

View File

@ -50,22 +50,34 @@
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* standard C interface (as Unix-like as possible)
* for the tou (Tcp On Udp) library
*/
/*
* Init:
* (1) need UdpStack item, which has our address already.
* The TOU library no longer references any UdpStack items.
* instead, two arrays should be passed to the init function.
* int tou_init( (void **) UdpSubReceiver **udpRecvers, int *udpType, int nUdps);
*
* The UdpSubReceivers should be derived classes, with corresponding types:
* UdpPeerReceiver TOU_RECEIVER_TYPE_UDPPEER
* UdpRelayReceiver TOU_RECEIVER_TYPE_UDPRELAY
*
*/
#define MAX_TOU_RECEIVERS 16
#define TOU_RECEIVER_TYPE_NONE 0x0000
#define TOU_RECEIVER_TYPE_UDPPEER 0x0001
#define TOU_RECEIVER_TYPE_UDPRELAY 0x0002
// hack to avoid classes in C code. (MacOSX complaining)
// will pass as UdpStack * as void *
int tou_init(void *udpStack);
int tou_init(void **udpSubRecvs, int *udpTypes, int nUdps);
#ifdef __cplusplus
extern "C" {
#endif
/* Connections are as similar to UNIX as possible
* (1) create a socket: tou_socket() this reserves a socket id.
* (2) connect: active: tou_connect() or passive: tou_listenfor().
@ -77,6 +89,18 @@ extern "C" {
* tou_bind() is not valid. tou_init performs this role.
* tou_listen() is not valid. (must listen for a specific address) use tou_listenfor() instead.
* tou_accept() can still be used.
*
****** THE ABOVE IS BECOMING LESS TRUE ********
*
* I have now added Multiple type of TOU Connections (Proxy, Relay),
* and multiple UDP Receivers (meaning you can use different ports too).
*
* The UDP receivers must be specified at startup (new tou_init())
* and the Receiver, and Type of connection must be specified when you
* open the socket.
*
* The parameters to tou_socket, therefore mean something!
* some extra checking has been put in to try and catch bad usage.
*/
/* creation/connections */
@ -87,6 +111,12 @@ int tou_connect(int sockfd, const struct sockaddr *serv_addr,
socklen_t addrlen, uint32_t conn_period);
int tou_accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
/* for relay connections */
int tou_connect_via_relay(int sockfd,
const struct sockaddr_in *own_addr,
const struct sockaddr_in *proxy_addr,
const struct sockaddr_in *dest_addr);
/* non-standard bonuses */
int tou_connected(int sockfd);
int tou_listenfor(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen);

View File

@ -70,4 +70,5 @@ int status(std::ostream &out);
};
#endif

View File

@ -0,0 +1,868 @@
/*
* tcponudp/udprelay.cc
*
* libretroshare.
*
* Copyright 2010 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 3 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 "udprelay.h"
#include <iostream>
/*
* #define DEBUG_UDP_RELAY 1
*/
//#define DEBUG_UDP_RELAY 1
#ifdef DEBUG_UDP_RELAY
// DEBUG FUNCTION
#include <sstream>
#include <iomanip>
int displayUdpRelayPacketHeader(const void *data, const int size);
#endif
/****************** UDP RELAY STUFF **********/
#define MAX_RELAY_UDP_PACKET_SIZE 1024
UdpRelayReceiver::UdpRelayReceiver(UdpPublisher *pub)
:UdpSubReceiver(pub)
{
mClassLimit.resize(UDP_RELAY_NUM_CLASS);
mClassCount.resize(UDP_RELAY_NUM_CLASS);
setRelayTotal(UDP_RELAY_DEFAULT_COUNT_ALL);
for(int i = 0; i < UDP_RELAY_NUM_CLASS; i++)
{
mClassCount[i] = 0;
}
/* only allocate this space once */
mTmpSendPkt = malloc(MAX_RELAY_UDP_PACKET_SIZE);
mTmpSendSize = MAX_RELAY_UDP_PACKET_SIZE;
return;
}
UdpRelayReceiver::~UdpRelayReceiver()
{
free(mTmpSendPkt);
}
int UdpRelayReceiver::addUdpPeer(UdpPeer *peer, UdpRelayAddrSet *endPoints, const struct sockaddr_in *proxyaddr)
{
struct sockaddr_in realPeerAddr = endPoints->mDestAddr;
{
RsStackMutex stack(relayMtx); /********** LOCK MUTEX *********/
/* check for duplicate */
std::map<struct sockaddr_in, UdpRelayEnd>::iterator it;
it = mStreams.find(realPeerAddr);
bool ok = (it == mStreams.end());
if (!ok)
{
#ifdef DEBUG_UDP_RELAY
std::cerr << "UdpPeerReceiver::addUdpPeer() ERROR Peer already exists!" << std::endl;
#endif
return 0;
}
/* setup a peer */
UdpRelayEnd ure(endPoints, proxyaddr);
mStreams[realPeerAddr] = ure;
}
{
RsStackMutex stack(udppeerMtx); /********** LOCK MUTEX *********/
#ifdef DEBUG_UDP_RELAY
std::cerr << "UdpPeerReceiver::addUdpPeer() Just installing UdpPeer!" << std::endl;
#endif
/* just overwrite */
mPeers[realPeerAddr] = peer;
}
return 1;
}
int UdpRelayReceiver::removeUdpPeer(UdpPeer *peer)
{
bool found = false;
struct sockaddr_in realPeerAddr;
/* cleanup UdpPeer, and get reference for data */
{
RsStackMutex stack(udppeerMtx); /********** LOCK MUTEX *********/
std::map<struct sockaddr_in, UdpPeer *>::iterator it;
for(it = mPeers.begin(); it != mPeers.end(); it++)
{
if (it->second == peer)
{
mPeers.erase(it);
found = true;
realPeerAddr = it->first;
break;
}
}
}
if (!found)
{
return 0;
}
/* now we cleanup the associated data */
{
RsStackMutex stack(relayMtx); /********** LOCK MUTEX *********/
std::map<struct sockaddr_in, UdpRelayEnd>::iterator it;
it = mStreams.find(realPeerAddr);
if (it != mStreams.end())
{
mStreams.erase(it);
}
else
{
/* ERROR */
}
}
return 1;
}
int UdpRelayReceiver::getRelayEnds(std::list<UdpRelayEnd> &relayEnds)
{
RsStackMutex stack(relayMtx); /********** LOCK MUTEX *********/
std::map<struct sockaddr_in, UdpRelayEnd>::iterator rit;
for(rit = mStreams.begin(); rit != mStreams.end(); rit++)
{
relayEnds.push_back(rit->second);
}
return 1;
}
int UdpRelayReceiver::getRelayProxies(std::list<UdpRelayProxy> &relayProxies)
{
RsStackMutex stack(relayMtx); /********** LOCK MUTEX *********/
std::map<UdpRelayAddrSet, UdpRelayProxy>::iterator rit;
for(rit = mRelays.begin(); rit != mRelays.end(); rit++)
{
relayProxies.push_back(rit->second);
}
return 1;
}
#define RELAY_MAX_BANDWIDTH 1000
#define RELAY_TIMEOUT 30
int UdpRelayReceiver::checkRelays()
{
RsStackMutex stack(relayMtx); /********** LOCK MUTEX *********/
/* iterate through the Relays */
std::cerr << "UdpRelayReceiver::checkRelays()";
std::cerr << std::endl;
std::list<UdpRelayAddrSet> eraseList;
std::map<UdpRelayAddrSet, UdpRelayProxy>::iterator rit;
time_t now = time(NULL);
for(rit = mRelays.begin(); rit != mRelays.end(); rit++)
{
/* calc bandwidth */
rit->second.mBandwidth = rit->second.mDataSize / (float) (now - rit->second.mLastBandwidthTS);
rit->second.mDataSize = 0;
rit->second.mLastBandwidthTS = now;
std::cerr << "UdpRelayReceiver::checkRelays()";
std::cerr << "Relay: " << rit->first;
std::cerr << " using bandwidth: " << rit->second.mBandwidth;
std::cerr << std::endl;
if (rit->second.mBandwidth > RELAY_MAX_BANDWIDTH)
{
std::cerr << "UdpRelayReceiver::checkRelays()";
std::cerr << "Dropping Relay due to excessive Bandwidth: " << rit->first;
std::cerr << std::endl;
/* if exceeding bandwidth -> drop */
eraseList.push_back(rit->first);
}
else if (now - rit->second.mLastTS > RELAY_TIMEOUT)
{
/* if haven't transmitted for ages -> drop */
std::cerr << "UdpRelayReceiver::checkRelays()";
std::cerr << "Dropping Relay due to Timeout: " << rit->first;
std::cerr << std::endl;
eraseList.push_back(rit->first);
}
}
std::list<UdpRelayAddrSet>::iterator it;
for(it = eraseList.begin(); it != eraseList.end(); it++)
{
removeUdpRelay_relayLocked(&(*it));
}
return 1;
}
int UdpRelayReceiver::removeUdpRelay(UdpRelayAddrSet *addrSet)
{
RsStackMutex stack(relayMtx); /********** LOCK MUTEX *********/
return removeUdpRelay_relayLocked(addrSet);
}
int UdpRelayReceiver::addUdpRelay(UdpRelayAddrSet *addrSet, int relayClass)
{
RsStackMutex stack(relayMtx); /********** LOCK MUTEX *********/
/* check for duplicate */
std::map<UdpRelayAddrSet, UdpRelayProxy>::iterator rit = mRelays.find(*addrSet);
int ok = (rit == mRelays.end());
if (!ok)
{
//#ifdef DEBUG_UDP_RELAY
std::cerr << "UdpRelayReceiver::addUdpRelay() ERROR Peer already exists!" << std::endl;
//#endif
return 0;
}
/* will install if there is space! */
if (installRelayClass_relayLocked(relayClass))
{
//#ifdef DEBUG_UDP_RELAY
std::cerr << "UdpRelayReceiver::addUdpRelay() adding Relay" << std::endl;
//#endif
/* create UdpRelay */
UdpRelayProxy udpRelay(addrSet, relayClass);
UdpRelayAddrSet alt = addrSet->flippedSet();
UdpRelayProxy altUdpRelay(&alt, relayClass);
/* must install two (A, B) & (B, A) */
mRelays[*addrSet] = udpRelay;
mRelays[alt] = altUdpRelay;
return 1;
}
//#ifdef DEBUG_UDP_RELAY
std::cerr << "UdpRelayReceiver::addUdpRelay() WARNING Too many Relays!" << std::endl;
//#endif
return 0;
}
int UdpRelayReceiver::removeUdpRelay_relayLocked(UdpRelayAddrSet *addrSet)
{
/* find in Relay list */
std::map<UdpRelayAddrSet, UdpRelayProxy>::iterator rit = mRelays.find(*addrSet);
if (rit == mRelays.end())
{
/* ERROR */
std::cerr << "UdpRelayReceiver::removeUdpRelay()";
std::cerr << "ERROR Finding Relay: " << *addrSet;
std::cerr << std::endl;
}
else
{
/* lets drop the count here too */
removeRelayClass_relayLocked(rit->second.mRelayClass);
mRelays.erase(rit);
}
/* rotate around and delete matching set */
UdpRelayAddrSet alt = addrSet->flippedSet();
rit = mRelays.find(alt);
if (rit == mRelays.end())
{
std::cerr << "UdpRelayReceiver::removeUdpRelay()";
std::cerr << "ERROR Finding Alt Relay: " << alt;
std::cerr << std::endl;
/* ERROR */
}
else
{
mRelays.erase(rit);
}
return 1;
}
/* Need some stats, to work out how many relays we are supporting */
int UdpRelayReceiver::installRelayClass_relayLocked(int classIdx)
{
/* check for total number of Relays */
if (mClassCount[UDP_RELAY_CLASS_ALL] >= mClassLimit[UDP_RELAY_CLASS_ALL])
{
std::cerr << "UdpRelayReceiver::installRelayClass() WARNING Too many Relays already";
std::cerr << std::endl;
return 0;
}
/* check the idx too */
if ((classIdx < 0) || (classIdx >= UDP_RELAY_NUM_CLASS))
{
std::cerr << "UdpRelayReceiver::installRelayClass() ERROR class Idx invalid";
std::cerr << std::endl;
return 0;
}
/* now check the specifics of the class */
if (mClassCount[classIdx] >= mClassLimit[classIdx])
{
std::cerr << "UdpRelayReceiver::installRelayClass() WARNING Relay Class Limit Exceeded";
std::cerr << std::endl;
return 0;
}
std::cerr << "UdpRelayReceiver::installRelayClass() Relay Class Ok, Count incremented";
std::cerr << std::endl;
/* if we get here we can add one */
mClassCount[UDP_RELAY_CLASS_ALL]++;
mClassCount[classIdx]++;
return 1;
}
int UdpRelayReceiver::removeRelayClass_relayLocked(int classIdx)
{
/* check for total number of Relays */
if (mClassCount[UDP_RELAY_CLASS_ALL] < 1)
{
std::cerr << "UdpRelayReceiver::removeRelayClass() ERROR no relays installed";
std::cerr << std::endl;
return 0;
}
/* check the idx too */
if ((classIdx < 0) || (classIdx >= UDP_RELAY_NUM_CLASS))
{
std::cerr << "UdpRelayReceiver::removeRelayClass() ERROR class Idx invalid";
std::cerr << std::endl;
return 0;
}
/* now check the specifics of the class */
if (mClassCount[classIdx] < 1)
{
std::cerr << "UdpRelayReceiver::removeRelayClass() ERROR no relay of class installed";
std::cerr << std::endl;
return 0;
}
std::cerr << "UdpRelayReceiver::removeRelayClass() Ok, Count decremented";
std::cerr << std::endl;
/* if we get here we can add one */
mClassCount[UDP_RELAY_CLASS_ALL]--;
mClassCount[classIdx]--;
return 1;
}
int UdpRelayReceiver::setRelayTotal(int count)
{
RsStackMutex stack(relayMtx); /********** LOCK MUTEX *********/
mClassLimit[UDP_RELAY_CLASS_ALL] = count;
mClassLimit[UDP_RELAY_CLASS_GENERAL] = (int) (UDP_RELAY_FRAC_GENERAL * count);
mClassLimit[UDP_RELAY_CLASS_FOF] = (int) (UDP_RELAY_FRAC_FOF * count);
mClassLimit[UDP_RELAY_CLASS_FRIENDS] = (int) (UDP_RELAY_FRAC_FRIENDS * count);
return count;
}
int UdpRelayReceiver::setRelayClassMax(int classIdx, int count)
{
RsStackMutex stack(relayMtx); /********** LOCK MUTEX *********/
/* check the idx */
if ((classIdx < 0) || (classIdx >= UDP_RELAY_NUM_CLASS))
{
std::cerr << "UdpRelayReceiver::setRelayMaximum() ERROR class Idx invalid";
std::cerr << std::endl;
return 0;
}
mClassLimit[classIdx] = count;
return 1;
}
int UdpRelayReceiver::getRelayClassMax(int classIdx)
{
RsStackMutex stack(relayMtx); /********** LOCK MUTEX *********/
/* check the idx */
if ((classIdx < 0) || (classIdx >= UDP_RELAY_NUM_CLASS))
{
std::cerr << "UdpRelayReceiver::getRelayMaximum() ERROR class Idx invalid";
std::cerr << std::endl;
return 0;
}
return mClassLimit[classIdx];
}
int UdpRelayReceiver::getRelayCount(int classIdx)
{
RsStackMutex stack(relayMtx); /********** LOCK MUTEX *********/
/* check the idx */
if ((classIdx < 0) || (classIdx >= UDP_RELAY_NUM_CLASS))
{
std::cerr << "UdpRelayReceiver::getRelayCount() ERROR class Idx invalid";
std::cerr << std::endl;
return 0;
}
return mClassCount[classIdx];
}
int UdpRelayReceiver::RelayStatus(std::ostream &out)
{
RsStackMutex stack(relayMtx); /********** LOCK MUTEX *********/
/* iterate through the Relays */
out << "UdpRelayReceiver::RelayStatus()";
out << std::endl;
std::map<UdpRelayAddrSet, UdpRelayProxy>::iterator rit;
for(rit = mRelays.begin(); rit != mRelays.end(); rit++)
{
out << "Relay for: " << rit->first;
out << std::endl;
out << "\tClass: " << rit->second.mRelayClass;
out << "\tBandwidth: " << rit->second.mBandwidth;
out << "\tDataSize: " << rit->second.mDataSize;
out << "\tLastBandwidthTS: " << rit->second.mLastBandwidthTS;
}
return 1;
}
int UdpRelayReceiver::status(std::ostream &out)
{
out << "UdpRelayReceiver::status()" << std::endl;
out << "UdpRelayReceiver::Relayed Connections:" << std::endl;
RelayStatus(out);
RsStackMutex stack(relayMtx); /********** LOCK MUTEX *********/
out << "UdpRelayReceiver::Connections:" << std::endl;
std::map<struct sockaddr_in, UdpRelayEnd>::iterator pit;
for(pit = mStreams.begin(); pit != mStreams.end(); pit++)
{
out << "\t" << pit->first << " : " << pit->second;
out << std::endl;
}
return 1;
}
#define UDP_RELAY_HEADER_SIZE 16
/* higher level interface */
int UdpRelayReceiver::recvPkt(void *data, int size, struct sockaddr_in &from)
{
/* print packet information */
#ifdef DEBUG_UDP_RELAY
std::cerr << "UdpRelayReceiver::recvPkt(" << size << ") from: " << from;
std::cerr << std::endl;
displayUdpRelayPacketHeader(data, size);
#endif
if (!isUdpRelayPacket(data, size))
{
#ifdef DEBUG_UDP_RELAY
std::cerr << "UdpRelayReceiver::recvPkt() is Not RELAY Pkt";
std::cerr << std::endl;
#endif
return 0;
}
/* decide if we are the relay, or the endpoint */
UdpRelayAddrSet addrSet;
if (!extractUdpRelayAddrSet(data, size, addrSet))
{
/* fails most basic test, drop */
return 0;
}
{
RsStackMutex stack(relayMtx); /********** LOCK MUTEX *********/
/* lookup relay first (double entries) */
std::map<UdpRelayAddrSet, UdpRelayProxy>::iterator rit = mRelays.find(addrSet);
if (rit != mRelays.end())
{
/* we are the relay */
#ifdef DEBUG_UDP_RELAY
std::cerr << "UdpRelayReceiver::recvPkt() We are the Relay. Passing onto: ";
std::cerr << rit->first.mDestAddr;
std::cerr << std::endl;
#endif
/* do accounting */
rit->second.mLastTS = time(NULL);
rit->second.mDataSize += size;
mPublisher->sendPkt(data, size, rit->first.mDestAddr, STD_RELAY_TTL);
return 1;
}
}
/* otherwise we are likely to be the endpoint,
* use the peers Address from the header
*/
{
RsStackMutex stack(udppeerMtx); /********** LOCK MUTEX *********/
std::map<struct sockaddr_in, UdpPeer *>::iterator pit = mPeers.find(addrSet.mSrcAddr);
if (pit != mPeers.end())
{
/* we are the end-point */
#ifdef DEBUG_UDP_RELAY
std::cerr << "UdpRelayReceiver::recvPkt() Sending to UdpPeer: ";
std::cerr << pit->first;
std::cerr << std::endl;
#endif
/* remove the header */
void *pktdata = (void *) (((uint8_t *) data) + UDP_RELAY_HEADER_SIZE);
int pktsize = size - UDP_RELAY_HEADER_SIZE;
if (pktsize > 0)
{
(pit->second)->recvPkt(pktdata, pktsize);
}
else
{
/* packet undersized */
#ifdef DEBUG_UDP_RELAY
std::cerr << "UdpRelayReceiver::recvPkt() ERROR Packet Undersized";
std::cerr << std::endl;
#endif
}
return 1;
}
/* done */
}
/* unknown */
#ifdef DEBUG_UDP_RELAY
std::cerr << "UdpRelayReceiver::recvPkt() Peer Unknown!";
std::cerr << std::endl;
#endif
return 0;
}
/* the address here must be the end point!,
* it cannot be proxy, as we could be using the same proxy for multiple connections.
*/
int UdpRelayReceiver::sendPkt(const void *data, int size, const struct sockaddr_in &to, int ttl)
{
RsStackMutex stack(relayMtx); /********** LOCK MUTEX *********/
/* work out who the proxy is */
std::map<struct sockaddr_in, UdpRelayEnd>::iterator it;
it = mStreams.find(to);
if (it == mStreams.end())
{
//#ifdef DEBUG_UDP_RELAY
std::cerr << "UdpRelayReceiver::sendPkt() Peer Unknown!";
std::cerr << std::endl;
//#endif
return 0;
}
/* add a header to packet */
int finalPktSize = createRelayUdpPacket(data, size, mTmpSendPkt, MAX_RELAY_UDP_PACKET_SIZE, &(it->second));
/* send the packet on */
return mPublisher->sendPkt(mTmpSendPkt, finalPktSize, it->second.mProxyAddr, STD_RELAY_TTL);
}
/***** RELAY PACKET FORMAT ****************************
*
*
* [ 0 | 1 | 2 | 3 ]
*
* [ 'R' 'L' 'Y' Version ]
* [ IP Address 1 ]
* [ Port 1 ][ IP Address 2 ....
* ... IP Address 2][ Port 2 ]
* [.... TUNNELLED DATA ....
*
*
* ... ]
*
* 16 Bytes: 4 ID, 6 IP:Port 1, 6 IP:Port 2
*/
#define UDP_IDENTITY_STRING_V1 "RLY1"
#define UDP_IDENTITY_SIZE_V1 4
int isUdpRelayPacket(const void *data, const int size)
{
if (size < UDP_RELAY_HEADER_SIZE)
return 0;
return (0 == strncmp((char *) data, UDP_IDENTITY_STRING_V1, UDP_IDENTITY_SIZE_V1));
}
#ifdef DEBUG_UDP_RELAY
int displayUdpRelayPacketHeader(const void *data, const int size)
{
int dsize = UDP_RELAY_HEADER_SIZE + 16;
if (size < dsize)
{
dsize = size;
}
std::ostringstream out;
for(int i = 0; i < dsize; i++)
{
if ((i > 0) && (i % 16 == 0))
{
out << std::endl;
}
out << std::setw(2) << std::setfill('0') << std::hex << (uint32_t) ((uint8_t*) data)[i];
}
std::cerr << "displayUdpRelayPacketHeader()" << std::endl;
std::cerr << out.str();
std::cerr << std::endl;
}
#endif
int extractUdpRelayAddrSet(const void *data, const int size, UdpRelayAddrSet &addrSet)
{
if (size < UDP_RELAY_HEADER_SIZE)
{
std::cerr << "createRelayUdpPacket() ERROR invalid size";
std::cerr << std::endl;
return 0;
}
uint8_t *header = (uint8_t *) data;
sockaddr_clear(&(addrSet.mSrcAddr));
sockaddr_clear(&(addrSet.mDestAddr));
/* as IP:Port are already in network byte order, we can just write them to the dataspace */
uint32_t ipaddr;
uint16_t port;
memcpy(&ipaddr, &(header[4]), 4);
memcpy(&port, &(header[8]), 2);
addrSet.mSrcAddr.sin_addr.s_addr = ipaddr;
addrSet.mSrcAddr.sin_port = port;
memcpy(&ipaddr, &(header[10]), 4);
memcpy(&port, &(header[14]), 2);
addrSet.mDestAddr.sin_addr.s_addr = ipaddr;
addrSet.mDestAddr.sin_port = port;
return 1;
}
int createRelayUdpPacket(const void *data, const int size, void *newpkt, int newsize, UdpRelayEnd *ure)
{
int pktsize = size + UDP_RELAY_HEADER_SIZE;
if (newsize < pktsize)
{
std::cerr << "createRelayUdpPacket() ERROR invalid size";
std::cerr << std::endl;
return 0;
}
uint8_t *header = (uint8_t *) newpkt;
memcpy(header, UDP_IDENTITY_STRING_V1, UDP_IDENTITY_SIZE_V1);
/* as IP:Port are already in network byte order, we can just write them to the dataspace */
uint32_t ipaddr = ure->mLocalAddr.sin_addr.s_addr;
uint16_t port = ure->mLocalAddr.sin_port;
memcpy(&(header[4]), &ipaddr, 4);
memcpy(&(header[8]), &port, 2);
ipaddr = ure->mRemoteAddr.sin_addr.s_addr;
port = ure->mRemoteAddr.sin_port;
memcpy(&(header[10]), &ipaddr, 4);
memcpy(&(header[14]), &port, 2);
memcpy(&(header[16]), data, size);
return pktsize;
}
/******* Small Container Class Helper Functions ****/
UdpRelayAddrSet::UdpRelayAddrSet()
{
sockaddr_clear(&mSrcAddr);
sockaddr_clear(&mDestAddr);
}
UdpRelayAddrSet::UdpRelayAddrSet(const sockaddr_in *ownAddr, const sockaddr_in *destAddr)
{
mSrcAddr = *ownAddr;
mDestAddr = *destAddr;
}
UdpRelayAddrSet UdpRelayAddrSet::flippedSet()
{
UdpRelayAddrSet flipped(&mDestAddr, &mSrcAddr);
return flipped;
}
int operator<(const UdpRelayAddrSet &a, const UdpRelayAddrSet &b)
{
if (a.mSrcAddr < b.mSrcAddr)
{
return 1;
}
if (a.mSrcAddr == b.mSrcAddr)
{
if (a.mDestAddr < b.mDestAddr)
{
return 1;
}
}
return 0;
}
UdpRelayProxy::UdpRelayProxy()
{
mBandwidth = 0;
mDataSize = 0;
mLastBandwidthTS = 0;
mLastTS = time(NULL); // Must be set here, otherwise Proxy Timesout before anything can happen!
mRelayClass = 0;
}
UdpRelayProxy::UdpRelayProxy(UdpRelayAddrSet *addrSet, int relayClass)
{
mAddrs = *addrSet;
mRelayClass = relayClass;
mBandwidth = 0;
mDataSize = 0;
mLastBandwidthTS = 0;
mLastTS = time(NULL);
}
UdpRelayEnd::UdpRelayEnd()
{
sockaddr_clear(&mLocalAddr);
sockaddr_clear(&mProxyAddr);
sockaddr_clear(&mRemoteAddr);
}
UdpRelayEnd::UdpRelayEnd(UdpRelayAddrSet *endPoints, const struct sockaddr_in *proxyaddr)
{
mLocalAddr = endPoints->mSrcAddr;
mRemoteAddr = endPoints->mDestAddr;
mProxyAddr = *proxyaddr;
}
std::ostream &operator<<(std::ostream &out, const UdpRelayAddrSet &uras)
{
out << "<" << uras.mSrcAddr << "," << uras.mDestAddr << ">";
return out;
}
std::ostream &operator<<(std::ostream &out, const UdpRelayProxy &urp)
{
time_t now = time(NULL);
out << "UdpRelayProxy for " << urp.mAddrs;
out << std::endl;
out << "\tRelayClass: " << urp.mRelayClass;
out << std::endl;
out << "\tBandwidth: " << urp.mBandwidth;
out << std::endl;
out << "\tDataSize: " << urp.mDataSize;
out << std::endl;
out << "\tLastBandwidthTS: " << now - urp.mLastBandwidthTS << " secs ago";
out << std::endl;
out << "\tLastTS: " << now - urp.mLastTS << " secs ago";
out << std::endl;
return out;
}
std::ostream &operator<<(std::ostream &out, const UdpRelayEnd &ure)
{
out << "UdpRelayEnd: <" << ure.mLocalAddr << " => " << ure.mProxyAddr << " <= ";
out << ure.mRemoteAddr << ">";
return out;
}

View File

@ -0,0 +1,186 @@
#ifndef RS_UDP_RELAY_H
#define RS_UDP_RELAY_H
/*
* tcponudp/udprelay.h
*
* libretroshare.
*
* Copyright 2010 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 3 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 "tcponudp/udppeer.h"
#include <vector>
class UdpRelayAddrSet;
class UdpRelayAddrSet
{
public:
UdpRelayAddrSet();
UdpRelayAddrSet(const sockaddr_in *ownAddr, const sockaddr_in *destAddr);
UdpRelayAddrSet flippedSet();
struct sockaddr_in mSrcAddr; /* msg source */
struct sockaddr_in mDestAddr; /* final destination */
};
int operator<(const UdpRelayAddrSet &a, const UdpRelayAddrSet &b);
class UdpRelayProxy
{
public:
UdpRelayProxy();
UdpRelayProxy(UdpRelayAddrSet *addrSet, int relayClass);
UdpRelayAddrSet mAddrs;
double mBandwidth;
uint32_t mDataSize;
time_t mLastBandwidthTS;
time_t mLastTS;
int mRelayClass;
};
class UdpRelayEnd
{
public:
UdpRelayEnd();
UdpRelayEnd(UdpRelayAddrSet *endPoints, const struct sockaddr_in *proxyaddr);
struct sockaddr_in mLocalAddr;
struct sockaddr_in mProxyAddr;
struct sockaddr_in mRemoteAddr;
};
std::ostream &operator<<(std::ostream &out, const UdpRelayAddrSet &uras);
std::ostream &operator<<(std::ostream &out, const UdpRelayProxy &urp);
std::ostream &operator<<(std::ostream &out, const UdpRelayEnd &ure);
/* we define a couple of classes (determining which class is done elsewhere)
* There will be various maximums for each type.
* Ideally you want to allow your friends to use your proxy in preference
* to randoms.
*
* At N x 2 x maxBandwidth.
*
* 10 x 2 x 1Kb/s => 20Kb/s In and Out. (quite a bit!)
* 20 x 2 x 1Kb/s => 40Kb/s Huge.
*/
#define UDP_RELAY_DEFAULT_COUNT_ALL 10
#define UDP_RELAY_FRAC_GENERAL (0.2)
#define UDP_RELAY_FRAC_FOF (0.5)
#define UDP_RELAY_FRAC_FRIENDS (0.8)
#define UDP_RELAY_NUM_CLASS 4
#define UDP_RELAY_CLASS_ALL 0
#define UDP_RELAY_CLASS_GENERAL 1
#define UDP_RELAY_CLASS_FOF 2
#define UDP_RELAY_CLASS_FRIENDS 3
#define STD_RELAY_TTL 64
class UdpRelayReceiver: public UdpSubReceiver
{
public:
UdpRelayReceiver(UdpPublisher *pub);
virtual ~UdpRelayReceiver();
/* add a TCPonUDP stream (ENDs) */
int addUdpPeer(UdpPeer *peer, UdpRelayAddrSet *endPoints, const struct sockaddr_in *proxyaddr);
int removeUdpPeer(UdpPeer *peer);
/* add a Relay Point (for the Relay).
* These don't have to be explicitly removed.
* They will be timed out when
* the end-points drop the connections
*/
int addUdpRelay(UdpRelayAddrSet *addrs, int classIdx);
int removeUdpRelay(UdpRelayAddrSet *addrs);
/* Need some stats, to work out how many relays we are supporting */
int checkRelays();
int setRelayTotal(int count); /* sets all the Relay Counts (frac based on total) */
int setRelayClassMax(int classIdx, int count); /* set a specific class maximum */
int getRelayClassMax(int classIdx);
int getRelayCount(int classIdx); /* how many relays (of this type) do we have */
int RelayStatus(std::ostream &out);
/* Extract Relay Data */
int getRelayEnds(std::list<UdpRelayEnd> &relayEnds);
int getRelayProxies(std::list<UdpRelayProxy> &relayProxies);
/* callback for recved data (overloaded from UdpReceiver) */
virtual int recvPkt(void *data, int size, struct sockaddr_in &from);
/* wrapper function for relay (overloaded from UdpSubReceiver) */
virtual int sendPkt(const void *data, int size, const struct sockaddr_in &to, int ttl);
int status(std::ostream &out);
private:
int removeUdpRelay_relayLocked(UdpRelayAddrSet *addrs);
int installRelayClass_relayLocked(int classIdx);
int removeRelayClass_relayLocked(int classIdx);
/* Unfortunately, Due the reentrant nature of this classes activities...
* the SendPkt() must be callable from inside RecvPkt().
* This means we need two seperate mutexes.
* - one for UdpPeer's, and one for Relay Data.
*
* care must be taken to lock these mutex's in a consistent manner to avoid deadlock.
* - You are not allowed to hold both at the same time!
*/
RsMutex udppeerMtx; /* for all class data (below) */
std::map<struct sockaddr_in, UdpPeer *> mPeers; /* indexed by <dest> */
RsMutex relayMtx; /* for all class data (below) */
std::vector<int> mClassLimit, mClassCount;
std::map<struct sockaddr_in, UdpRelayEnd> mStreams; /* indexed by <dest> */
std::map<UdpRelayAddrSet, UdpRelayProxy> mRelays; /* indexed by <src,dest> */
void *mTmpSendPkt;
uint32_t mTmpSendSize;
};
/* utility functions for creating / extracting UdpRelayPackets */
int isUdpRelayPacket(const void *data, const int size);
int getPacketFromUdpRelayPacket(const void *data, const int size, void **realdata, int *realsize);
int createRelayUdpPacket(const void *data, const int size, void *newpkt, int newsize, UdpRelayEnd *ure);
int extractUdpRelayAddrSet(const void *data, const int size, UdpRelayAddrSet &addrSet);
#endif

View File

@ -27,27 +27,73 @@
#include <iostream>
#include <sstream>
#include "util/rsprint.h"
static const int STUN_TTL = 64;
#define TOU_STUN_MIN_PEERS 5
/*
* #define DEBUG_UDP_STUN 1
* #define DEBUG_UDP_STUNNER 1
*/
//#define DEBUG_UDP_STUNNER 1
const int32_t TOU_STUN_MAX_FAIL_COUNT = 3; /* 3 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 */
const int32_t TOU_STUN_ADDR_MAX_AGE = 120; /* 2 minutes */
// TIMEOUT is now tied to STUN RATE ... const int32_t TOU_STUN_ADDR_MAX_AGE = 120; /* 2 minutes */
const int32_t TOU_STUN_DEFAULT_TARGET_RATE = 15; /* 20 secs is minimum to keep a NAT UDP port open */
const double TOU_SUCCESS_LPF_FACTOR = 0.90;
UdpStunner::UdpStunner(UdpPublisher *pub)
:UdpSubReceiver(pub), eaddrKnown(false), eaddrStable(false),
mStunKeepAlive(false), mStunLastRecv(0), mStunLastSend(0)
mStunLastRecvResp(0), mStunLastRecvAny(0),
mStunLastSendStun(0), mStunLastSendAny(0)
{
#ifdef UDPSTUN_ALLOW_LOCALNET
mAcceptLocalNet = false;
#endif
/* these parameters determine the rate we attempt stuns */
mPassiveStunMode = false;
mSuccessRate = 0.0;
mTargetStunPeriod = TOU_STUN_DEFAULT_TARGET_RATE;
return;
}
#ifdef UDPSTUN_ALLOW_LOCALNET
// For Local Testing Only (Releases should have the #define disabled)
void UdpStunner::SetAcceptLocalNet()
{
RsStackMutex stack(stunMtx); /********** LOCK MUTEX *********/
mAcceptLocalNet = true;
}
#endif
void UdpStunner::setTargetStunPeriod(uint32_t sec_per_stun)
{
RsStackMutex stack(stunMtx); /********** LOCK MUTEX *********/
if (sec_per_stun == 0)
{
mPassiveStunMode = true;
}
else
{
mPassiveStunMode = false;
}
mTargetStunPeriod = sec_per_stun;
}
/* higher level interface */
int UdpStunner::recvPkt(void *data, int size, struct sockaddr_in &from)
{
@ -62,7 +108,7 @@ int UdpStunner::recvPkt(void *data, int size, struct sockaddr_in &from)
/* check for STUN packet */
if (UdpStun_isStunPacket(data, size))
{
mStunLastRecv = time(NULL);
mStunLastRecvAny = time(NULL);
#ifdef DEBUG_UDP_STUNNER
std::cerr << "UdpStunner::recvPkt() is Stun Packet";
std::cerr << std::endl;
@ -76,10 +122,15 @@ int UdpStunner::recvPkt(void *data, int size, struct sockaddr_in &from)
return 0;
}
int UdpStunner::status(std::ostream &out)
{
RsStackMutex stack(stunMtx); /********** LOCK MUTEX *********/
out << "UdpStunner::status() TargetStunPeriod: " << mTargetStunPeriod;
out << " SuccessRate: " << mSuccessRate;
out << std::endl;
out << "UdpStunner::status()" << std::endl;
out << "UdpStunner::potentialpeers:" << std::endl;
std::list<TouStunPeer>::iterator it;
@ -94,10 +145,15 @@ int UdpStunner::status(std::ostream &out)
int UdpStunner::tick()
{
#ifdef DEBUG_UDP_STUNNER
std::cerr << "UdpStunner::tick()" << std::endl;
#endif
checkStunKeepAlive();
if (checkStunDesired())
{
attemptStun();
}
return 1;
}
@ -120,6 +176,8 @@ bool UdpStunner::locked_handleStunPkt(void *data, int size, struct sockaddr_in &
if (!pkt)
return false;
time_t now = time(NULL);
mStunLastSendAny = now;
int sentlen = sendPkt(pkt, len, from, STUN_TTL);
free(pkt);
@ -144,7 +202,7 @@ bool UdpStunner::locked_handleStunPkt(void *data, int size, struct sockaddr_in &
#ifdef DEBUG_UDP_STUNNER
std::cerr << "UdpStunner::handleStunPkt() got Ext Addr: ";
std::cerr << inet_ntoa(eAddr.sin_addr) << ":" << ntohs(eAddr.sin_port);
out << " from: " << from;
std::cerr << " from: " << from;
std::cerr << std::endl;
#endif
locked_recvdStun(from, eAddr);
@ -168,7 +226,7 @@ bool UdpStunner::externalAddr(struct sockaddr_in &external, uint8_t &stable)
if (eaddrKnown)
{
/* address timeout */
if (time(NULL) - eaddrTime > TOU_STUN_ADDR_MAX_AGE)
if (time(NULL) - eaddrTime > (mTargetStunPeriod * 2))
{
std::cerr << "UdpStunner::externalAddr() eaddr expired";
std::cerr << std::endl;
@ -228,13 +286,14 @@ int UdpStunner::doStun(struct sockaddr_in stun_addr)
{
RsStackMutex stack(stunMtx); /********** LOCK MUTEX *********/
mStunLastSend = time(NULL);
time_t now = time(NULL);
mStunLastSendStun = now;
mStunLastSendAny = now;
}
#ifdef DEBUG_UDP_STUNNER
std::ostringstream out;
out << "UdpStunner::doStun() Sent Stun Packet(" << sentlen << ") from:";
out << inet_ntoa(laddr.sin_addr) << ":" << ntohs(laddr.sin_port);
out << "UdpStunner::doStun() Sent Stun Packet(" << sentlen << ") ";
out << " to:";
out << inet_ntoa(stun_addr.sin_addr) << ":" << ntohs(stun_addr.sin_port);
@ -380,24 +439,11 @@ bool UdpStun_isStunPacket(void *data, int size)
/******************************* STUN Handling ********************************
* The KeepAlive part - slightly more complicated
* KeepAlive has been replaced by a targetStunRate. Set this to zero to disable.
*/
/******************************* STUN Handling ********************************/
bool UdpStunner::setStunKeepAlive(uint32_t required)
{
RsStackMutex stack(stunMtx); /********** LOCK MUTEX *********/
mStunKeepAlive = (required != 0);
#ifdef DEBUG_UDP_STUNNER
std::cerr << "UdpStunner::setStunKeepAlive() to: " << mStunKeepAlive;
std::cerr << std::endl;
#endif
return 1;
}
bool UdpStunner::addStunPeer(const struct sockaddr_in &remote, const char *peerid)
{
@ -407,20 +453,18 @@ bool UdpStunner::addStunPeer(const struct sockaddr_in &remote, const char *pe
std::cerr << std::endl;
#endif
bool needStun;
bool toStore = true;
{
RsStackMutex stack(stunMtx); /********** LOCK MUTEX *********/
needStun = (!eaddrKnown);
}
storeStunPeer(remote, peerid, needStun);
if (needStun)
{
doStun(remote);
/* only store if we're active */
toStore = !mPassiveStunMode;
}
if (toStore)
{
storeStunPeer(remote, peerid, 0);
}
return true;
}
@ -472,88 +516,154 @@ bool UdpStunner::storeStunPeer(const struct sockaddr_in &remote, const char *
}
bool UdpStunner::checkStunKeepAlive()
bool UdpStunner::checkStunDesired()
{
#ifdef DEBUG_UDP_STUNNER
std::cerr << "UdpStunner::checkStunKeepAlive()";
std::cerr << "UdpStunner::checkStunDesired()";
std::cerr << std::endl;
#endif
TouStunPeer peer;
time_t now;
{
RsStackMutex stack(stunMtx); /********** LOCK MUTEX *********/
if (!mStunKeepAlive)
if (mPassiveStunMode)
{
#ifdef DEBUG_UDP_STUNNER
std::cerr << "UdpStunner::checkStunKeepAlive() FALSE";
std::cerr << "UdpStunner::checkStunDesired() In Passive Mode";
std::cerr << std::endl;
#endif
return false; /* all good */
}
if (!eaddrKnown)
{
#ifdef DEBUG_UDP_STUNNER
std::cerr << "UdpStunner::checkStunDesired() YES, we don't have extAddr Yet";
std::cerr << std::endl;
#endif
return true; /* want our external address */
}
/* 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_STUNNER
std::cerr << "UdpStunner::checkStunKeepAlive() To Fast ... delaying";
std::cerr << std::endl;
#endif
/* too fast */
return false;
}
if (mStunList.size() < 1)
{
#ifdef DEBUG_UDP_STUNNER
std::cerr << "UdpStunner::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(stunMtx); /********** LOCK MUTEX *********/
if (peer.failCount < TOU_STUN_MAX_FAIL_COUNT)
{
peer.failCount++;
peer.lastsend = now;
mStunList.push_back(peer);
/* based on SuccessRate & TargetStunRate, we work out if we should send one
*
* if we have 100% success rate, then we can delay until exactly TARGET RATE.
* if we have 0% success rate, then try at double TARGET RATE.
*
*/
double stunPeriod = (mTargetStunPeriod / 2.0) * (1.0 + mSuccessRate);
time_t nextStun = mStunLastRecvResp + (int) stunPeriod;
#ifdef DEBUG_UDP_STUNNER
std::cerr << "UdpStunner::checkStunKeepAlive() pushing Stun peer to back of list";
std::cerr << std::endl;
std::cerr << "UdpStunner::checkStunDesired() TargetStunPeriod: " << mTargetStunPeriod;
std::cerr << " SuccessRate: " << mSuccessRate;
std::cerr << " DesiredStunPeriod: " << stunPeriod;
std::cerr << " NextStun: " << nextStun - now << " secs";
std::cerr << std::endl;
#endif
if (now >= nextStun)
{
#ifdef DEBUG_UDP_STUNNER
std::cerr << "UdpStunner::checkStunDesired() Stun is Desired";
std::cerr << std::endl;
#endif
return true;
}
else
{
#ifdef DEBUG_UDP_STUNNER
std::cerr << "UdpStunner::checkStunKeepAlive() Discarding bad stun peer";
std::cerr << "UdpStunner::checkStunDesired() Stun is Not Needed";
std::cerr << std::endl;
#endif
return false;
}
}
}
bool UdpStunner::attemptStun()
{
bool found = false;
TouStunPeer peer;
time_t now = time(NULL);
#ifdef DEBUG_UDP_STUNNER
std::cerr << "UdpStunner::attemptStun()";
std::cerr << std::endl;
#endif
{
RsStackMutex stack(stunMtx); /********** LOCK MUTEX *********/
int i;
for(i = 0; ((i < mStunList.size()) && (mStunList.size() > 0) && (!found)); i++)
{
/* extract entry */
peer = mStunList.front();
mStunList.pop_front();
/* check if expired */
if (peer.failCount > TOU_STUN_MAX_FAIL_COUNT)
{
#ifdef DEBUG_UDP_STUNNER
std::cerr << "UdpStunner::attemptStun() Peer has expired, dropping";
std::cerr << std::endl;
#endif
}
else
{
// Peer Okay, check last send time.
if (now - peer.lastsend < TOU_STUN_MAX_SEND_RATE)
{
#ifdef DEBUG_UDP_STUNNER
std::cerr << "UdpStunner::attemptStun() Peer was sent to Too Recently, pushing back";
std::cerr << std::endl;
#endif
mStunList.push_back(peer);
}
else
{
/* we have found a peer! */
#ifdef DEBUG_UDP_STUNNER
std::cerr << "UdpStunner::attemptStun() Found Peer to Stun.";
std::cerr << std::endl;
#endif
peer.failCount++;
peer.lastsend = now;
mStunList.push_back(peer);
mSuccessRate *= TOU_SUCCESS_LPF_FACTOR;
found = true;
}
}
} // END OF WHILE LOOP.
if (mStunList.size() < 1)
{
#ifdef DEBUG_UDP_STUNNER
std::cerr << "UdpStunner::attemptStun() No Peers in List. FAILED";
std::cerr << std::endl;
#endif
return false;
}
#ifdef DEBUG_UDP_STUNNER
locked_printStunList();
#endif
} // END OF MUTEX LOCKING.
if (found)
{
doStun(peer.remote);
return true;
}
return true;
return false;
}
@ -585,6 +695,29 @@ bool UdpStunner::locked_recvdStun(const struct sockaddr_in &remote, const str
}
}
/* if not found.. should we add it back in? */
/* How do we calculate the success rate?
* Don't want to count all the stuns?
* Low Pass filter won't work either...
* at send...
* mSuccessRate = 0.95 * mSuccessRate.
* at recv...
* mSuccessRate = 0.95 * mSuccessRate + 0.05;
*
* But if we split into a two stage eqn. it'll work!
* a
* mSuccessRate = 0.95 * mSuccessRate.
* at recv...
* mSuccessRate += 0.05;
*/
mSuccessRate += (1.0-TOU_SUCCESS_LPF_FACTOR);
time_t now = time(NULL);
mStunLastRecvResp = now;
mStunLastRecvAny = now;
#ifdef DEBUG_UDP_STUNNER
locked_printStunList();
#endif
@ -619,8 +752,13 @@ bool UdpStunner::locked_checkExternalAddress()
*/
time_t age = (now - it->lastsend);
if (it->response && isExternalNet(&(it->eaddr.sin_addr)) &&
(it->failCount == 0) && (age < TOU_STUN_ADDR_MAX_AGE))
if (it->response &&
#ifdef UDPSTUN_ALLOW_LOCALNET
( mAcceptLocalNet || isExternalNet(&(it->eaddr.sin_addr))) &&
#else
(isExternalNet(&(it->eaddr.sin_addr))) &&
#endif
(it->failCount == 0) && (age < (mTargetStunPeriod * 2)))
{
if (!found1)
{
@ -675,8 +813,10 @@ bool UdpStunner::locked_printStunList()
time_t now = time(NULL);
out << "locked_printStunList()" << std::endl;
out << "\tLastSend: " << now - mStunLastSend << std::endl;
out << "\tLastRecv: " << now - mStunLastRecv << std::endl;
out << "\tLastSendStun: " << now - mStunLastSendStun << std::endl;
out << "\tLastSendAny: " << now - mStunLastSendAny << std::endl;
out << "\tLastRecvResp: " << now - mStunLastRecvResp << std::endl;
out << "\tLastRecvAny: " << now - mStunLastRecvAny << std::endl;
std::list<TouStunPeer>::iterator it;
for(it = mStunList.begin(); it != mStunList.end(); it++)
@ -705,7 +845,7 @@ bool UdpStunner::getStunPeer(int idx, std::string &id,
std::list<TouStunPeer>::iterator it;
int i;
for(i=0, it=mStunList.begin(); (i<idx) && (it!=mStunList.end()); it++, i++);
for(i=0, it=mStunList.begin(); (i<idx) && (it!=mStunList.end()); it++, i++) ;
if (it != mStunList.end())
{

View File

@ -25,7 +25,13 @@
*
*/
#ifdef WINDOWS_SYS
#include "util/rswin.h"
#endif
#ifndef WINDOWS_SYS
#include <netinet/in.h>
#endif
#include "tcponudp/rsudpstack.h"
#include "util/rsthreads.h"
@ -60,7 +66,10 @@ class TouStunPeer
time_t lastsend;
uint32_t failCount;
};
/*
* #define UDPSTUN_ALLOW_LOCALNET 1
*/
class UdpStunner: public UdpSubReceiver
{
@ -69,13 +78,17 @@ class UdpStunner: public UdpSubReceiver
UdpStunner(UdpPublisher *pub);
virtual ~UdpStunner() { return; }
bool setStunKeepAlive(uint32_t required);
#ifdef UDPSTUN_ALLOW_LOCALNET
// For Local Testing Mode.
void SetAcceptLocalNet();
#endif
void setTargetStunPeriod(uint32_t sec_per_stun);
bool addStunPeer(const struct sockaddr_in &remote, const char *peerid);
bool getStunPeer(int idx, std::string &id,
struct sockaddr_in &remote, struct sockaddr_in &eaddr,
uint32_t &failCount, time_t &lastSend);
bool checkStunKeepAlive();
bool needStunPeers();
bool externalAddr(struct sockaddr_in &remote, uint8_t &stable);
@ -89,17 +102,20 @@ virtual int status(std::ostream &out);
private:
bool checkStunDesired();
bool attemptStun();
int doStun(struct sockaddr_in stun_addr);
bool storeStunPeer(const struct sockaddr_in &remote, const char *peerid, bool sent);
/* STUN handling */
bool locked_handleStunPkt(void *data, int size, struct sockaddr_in &from);
int doStun(struct sockaddr_in stun_addr);
/* stun keepAlive */
bool locked_printStunList();
bool locked_recvdStun(const struct sockaddr_in &remote, const struct sockaddr_in &extaddr);
bool locked_checkExternalAddress();
bool storeStunPeer(const struct sockaddr_in &remote, const char *peerid, bool sent);
RsMutex stunMtx; /* for all class data (below) */
@ -109,12 +125,22 @@ bool storeStunPeer(const struct sockaddr_in &remote, const char *peerid, bool
bool eaddrStable; /* if true then usable. if false -> Symmettric NAT */
time_t eaddrTime;
bool mStunKeepAlive;
time_t mStunLastRecv;
time_t mStunLastSend;
time_t mStunLastRecvResp;
time_t mStunLastRecvAny;
time_t mStunLastSendStun;
time_t mStunLastSendAny;
std::list<TouStunPeer> mStunList; /* potentials */
#ifdef UDPSTUN_ALLOW_LOCALNET
// For Local Testing Mode.
bool mAcceptLocalNet;
#endif
bool mPassiveStunMode;
uint32_t mTargetStunPeriod;
double mSuccessRate;
};
/* generic stun functions */

View File

@ -64,8 +64,8 @@ std::string RsDirUtil::getTopDir(const std::string& dir)
*/
int i,j;
int len = dir.length();
for(j = len - 1; (j > 0) && (dir[j] == '/'); j--);
for(i = j; (i > 0) && (dir[i] != '/'); i--);
for(j = len - 1; (j > 0) && (dir[j] == '/'); j--) ;
for(i = j; (i > 0) && (dir[i] != '/'); i--) ;
if (dir[i] == '/')
i++;
@ -165,11 +165,11 @@ std::string RsDirUtil::removeTopDir(const std::string& dir)
*/
int i,j;
int len = dir.length();
for(j = len - 1; (j > 0) && (dir[j] == '/'); j--);
for(i = j; (i >= 0) && (dir[i] != '/'); i--);
for(j = len - 1; (j > 0) && (dir[j] == '/'); j--) ;
for(i = j; (i >= 0) && (dir[i] != '/'); i--) ;
/* remove any more slashes */
for(; (i >= 0) && (dir[i] == '/'); i--);
for(; (i >= 0) && (dir[i] == '/'); i--) ;
for(j = 0; j <= i; j++)
{
@ -187,8 +187,8 @@ std::string RsDirUtil::getRootDir(const std::string& dir)
*/
int i,j;
int len = dir.length();
for(i = 0; (i < len) && (dir[i] == '/'); i++);
for(j = i; (j < len) && (dir[j] != '/'); j++);
for(i = 0; (i < len) && (dir[i] == '/'); i++) ;
for(j = i; (j < len) && (dir[j] != '/'); j++) ;
if (i == j)
return root; /* empty */
for(; i < j; i++)
@ -205,12 +205,12 @@ std::string RsDirUtil::removeRootDir(const std::string& path)
std::string output;
/* chew leading '/'s */
for(i = 0; (i < len) && (path[i] == '/'); i++);
for(i = 0; (i < len) && (path[i] == '/'); i++) ;
if (i == len)
return output; /* empty string */
for(j = i; (j < len) && (path[j] != '/'); j++); /* run to next '/' */
for(; (j < len) && (path[j] == '/'); j++); /* chew leading '/'s */
for(j = i; (j < len) && (path[j] != '/'); j++) ; /* run to next '/' */
for(; (j < len) && (path[j] == '/'); j++) ; /* chew leading '/'s */
for(; j < len; j++)
{
@ -236,7 +236,7 @@ std::string RsDirUtil::removeRootDirs(const std::string& path, const std::string
i++;
}
for(; (i < path.length()) && (j < root.length()) && (path[i] == root[j]); i++, j++);
for(; (i < path.length()) && (j < root.length()) && (path[i] == root[j]); i++, j++) ;
/* should have consumed root. */
if (j == root.length())

View File

@ -26,6 +26,7 @@
#include "util/rsnet.h"
#include "util/rsthreads.h"
#include <string.h>
#include <sstream>
#ifdef WINDOWS_SYS
#else
@ -137,14 +138,21 @@ std::ostream &operator<<(std::ostream &out, const struct sockaddr_in &addr)
}
/* thread-safe version of inet_ntoa */
static RsMutex inetMtx;
/*** XXX, PROBLEM this function is not Thread-Safe.
* because it can be called in lots of other parts of the program.
* which could still collide with this one!
*
* Must rewrite to make truely thread-safe.
*/
std::string rs_inet_ntoa(struct in_addr in)
{
RsStackMutex stack(inetMtx);
std::string addr(inet_ntoa(in));
return addr;
std::ostringstream str;
uint8_t *bytes = (uint8_t *) &(in.s_addr);
str << (int) bytes[0] << ".";
str << (int) bytes[1] << ".";
str << (int) bytes[2] << ".";
str << (int) bytes[3];
return str.str();
}