Major Step Forward: Integrated the UDP Relay into TcpOnUdp Library.

In theory we should have all the code to make DIRECT, PROXY and RELAY connections. 
Now comes the testing / debugging phase.

 * Switched tcpstream to use UdpSubReceiver instead of UdpPeerReceiver.
 * Modified tou_init to accept an array of UdpSubReceivers (either UdpPeerReciever or UdpRelayReceiver).
 * modified TOU to make it UdpStack agnostic (this allows multiple UDP Ports to be used).
 * tweaked tou.cc internals to handle either type of Receiver.
 * added new connect() function for initiating Relay Connections.
 * Added missing Container Helper Functions to udprelay.cc
 * Added back udpstunner.cc to libretroshare.pro
 * modified libretroshare to work with the new interfaces.
 * added (commented out) example of how the full udp stack will be initialised.




git-svn-id: http://svn.code.sf.net/p/retroshare/code/branches/v0.5-peernet@4266 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
drbob 2011-06-15 01:54:51 +00:00
parent 02b6dab081
commit 48c185192d
9 changed files with 445 additions and 40 deletions

View File

@ -82,6 +82,7 @@ SOURCES += tcponudp/udppeer.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) ....

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

@ -1740,6 +1740,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
/****
@ -1883,11 +1885,53 @@ 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];
// BITDHT FIRST.
p3BitDht *mBitDht = new p3BitDht(ownId, mConnMgr,
mUdpStack, bootstrapfile);
// THEN STUNNER.
//UdpStunner *mDhtStunner = new UdpStunner(mUdpStack);
// 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);
// 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

@ -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.
*
* UdpSubReceive
/* 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

@ -62,7 +62,7 @@ UdpRelayReceiver::~UdpRelayReceiver()
}
int UdpRelayReceiver::addUdpPeer(UdpPeer *peer, UdpRelayAddrSet *endPoints, const struct sockaddr_in &proxyaddr)
int UdpRelayReceiver::addUdpPeer(UdpPeer *peer, UdpRelayAddrSet *endPoints, const struct sockaddr_in *proxyaddr)
{
RsStackMutex stack(peerMtx); /********** LOCK MUTEX *********/
@ -81,7 +81,7 @@ int UdpRelayReceiver::addUdpPeer(UdpPeer *peer, UdpRelayAddrSet *endPoints,
}
/* setup a peer */
UdpRelayEnd ure(peer, endPoints, &proxyaddr);
UdpRelayEnd ure(peer, endPoints, proxyaddr);
mStreams[realPeerAddr] = ure;
@ -628,3 +628,120 @@ int createRelayUdpPacket(const void *data, const int size, void *newpkt, int new
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 = 0;
mRelayClass = 0;
}
UdpRelayProxy::UdpRelayProxy(UdpRelayAddrSet *addrSet, int relayClass)
{
mAddrs = *addrSet;
mRelayClass = relayClass;
mBandwidth = 0;
mDataSize = 0;
mLastBandwidthTS = 0;
mLastTS = 0;
}
UdpRelayEnd::UdpRelayEnd()
{
sockaddr_clear(&mLocalAddr);
sockaddr_clear(&mProxyAddr);
sockaddr_clear(&mRemoteAddr);
mPeer = NULL;
}
UdpRelayEnd::UdpRelayEnd(UdpPeer *peer, UdpRelayAddrSet *endPoints, const struct sockaddr_in *proxyaddr)
{
mPeer = peer;
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

@ -35,6 +35,7 @@ class UdpRelayAddrSet
{
public:
UdpRelayAddrSet();
UdpRelayAddrSet(const sockaddr_in *ownAddr, const sockaddr_in *destAddr);
UdpRelayAddrSet flippedSet();
@ -64,7 +65,7 @@ class UdpRelayEnd
{
public:
UdpRelayEnd() { return; }
UdpRelayEnd();
UdpRelayEnd(UdpPeer *peer, UdpRelayAddrSet *endPoints, const struct sockaddr_in *proxyaddr);
struct sockaddr_in mLocalAddr;
@ -111,7 +112,7 @@ class UdpRelayReceiver: public UdpSubReceiver
virtual ~UdpRelayReceiver();
/* add a TCPonUDP stream (ENDs) */
int addUdpPeer(UdpPeer *peer, UdpRelayAddrSet *endPoints, const struct sockaddr_in &proxyaddr);
int addUdpPeer(UdpPeer *peer, UdpRelayAddrSet *endPoints, const struct sockaddr_in *proxyaddr);
int removeUdpPeer(UdpPeer *peer);
/* add a Relay Point (for the Relay).