Split the upnp files into libupnp and miniupnp implementations.

modified libretroshare.pro to allow either to be used.



git-svn-id: http://svn.code.sf.net/p/retroshare/code/branches/v0.5-gxs-b1@5733 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
drbob 2012-10-28 16:51:00 +00:00
parent 1a1e453c7e
commit d208b59d33
6 changed files with 547 additions and 555 deletions

View File

@ -154,15 +154,11 @@ HEADERS += retroshare/rsgame.h \
OBJECTS_DIR = temp/obj OBJECTS_DIR = temp/obj
MOC_DIR = temp/moc MOC_DIR = temp/moc
DESTDIR = lib DESTDIR = lib
# miniupnp implementation files # linux/bsd can use either - libupnp is more complete and packaged.
#HEADERS += upnp/upnputil.h #CONFIG += upnp_miniupnpc
#SOURCES += upnp/upnputil.c CONFIG += upnp_libupnp
# libupnp implementation files
HEADERS += upnp/UPnPBase.h
SOURCES += upnp/UPnPBase.cpp
# zeroconf disabled at the end of libretroshare.pro (but need the code) # zeroconf disabled at the end of libretroshare.pro (but need the code)
#CONFIG += zeroconf #CONFIG += zeroconf
#CONFIG += zcnatassist #CONFIG += zcnatassist
@ -192,9 +188,8 @@ HEADERS += retroshare/rsgame.h \
DEFINES *= STATICLIB \ DEFINES *= STATICLIB \
WIN32 WIN32
# miniupnp implementation files CONFIG += upnp_miniupnpc
HEADERS += upnp/upnputil.h
SOURCES += upnp/upnputil.c
SSL_DIR = ../../../../openssl SSL_DIR = ../../../../openssl
UPNPC_DIR = ../../../../miniupnpc-1.3 UPNPC_DIR = ../../../../miniupnpc-1.3
GPG_ERROR_DIR = ../../../../libgpg-error-1.7 GPG_ERROR_DIR = ../../../../libgpg-error-1.7
@ -230,9 +225,8 @@ HEADERS += retroshare/rsgame.h \
# QMAKE_CFLAGS_DEBUG += -O2 # QMAKE_CFLAGS_DEBUG += -O2
DEFINES += USE_CMD_ARGS DEFINES += USE_CMD_ARGS
# miniupnp implementation files CONFIG += upnp_libupnp
HEADERS += upnp/upnputil.h
SOURCES += upnp/upnputil.c
UPNPC_DIR = ../../../lib/miniupnpc-1.3 UPNPC_DIR = ../../../lib/miniupnpc-1.3
PTHREADS_DIR = ../../../lib/pthreads-w32-2-8-0-release PTHREADS_DIR = ../../../lib/pthreads-w32-2-8-0-release
ZLIB_DIR = ../../../lib/zlib-1.2.3 ZLIB_DIR = ../../../lib/zlib-1.2.3
@ -261,10 +255,8 @@ HEADERS += retroshare/rsgame.h \
# DEFINES *= MINIUPNPC_VERSION=13 # DEFINES *= MINIUPNPC_VERSION=13
DESTDIR = lib DESTDIR = lib
# miniupnp implementation files CONFIG += upnp_miniupnpc
HEADERS += upnp/upnputil.h
SOURCES += upnp/upnputil.c
# zeroconf disabled at the end of libretroshare.pro (but need the code) # zeroconf disabled at the end of libretroshare.pro (but need the code)
CONFIG += zeroconf CONFIG += zeroconf
CONFIG += zcnatassist CONFIG += zcnatassist
@ -296,9 +288,13 @@ HEADERS += retroshare/rsgame.h \
-Dstatvfs64=statvfs \ -Dstatvfs64=statvfs \
-Dfopen64=fopen -Dfopen64=fopen
# linux/bsd can use either - libupnp is more complete and packaged.
#CONFIG += upnp_miniupnpc
CONFIG += upnp_libupnp
# libupnp implementation files # libupnp implementation files
HEADERS += upnp/UPnPBase.h HEADERS += upnp/UPnPBase.h upnp/upnphandler_linux.h
SOURCES += upnp/UPnPBase.cpp SOURCES += upnp/UPnPBase.cpp upnp/upnphandler_linux.cc
DESTDIR = lib DESTDIR = lib
} }
@ -417,7 +413,7 @@ HEADERS += retroshare/rsgame.h \
HEADERS += turtle/p3turtle.h \ HEADERS += turtle/p3turtle.h \
turtle/rsturtleitem.h \ turtle/rsturtleitem.h \
turtle/turtletypes.h turtle/turtletypes.h
HEADERS += upnp/upnphandler.h
HEADERS += util/folderiterator.h \ HEADERS += util/folderiterator.h \
util/rsdebug.h \ util/rsdebug.h \
util/smallobject.h \ util/smallobject.h \
@ -434,6 +430,7 @@ HEADERS += retroshare/rsgame.h \
util/rsrandom.h \ util/rsrandom.h \
util/radix64.h \ util/radix64.h \
util/pugiconfig.h util/pugiconfig.h
SOURCES += dbase/cachestrapper.cc \ SOURCES += dbase/cachestrapper.cc \
dbase/fimonitor.cc \ dbase/fimonitor.cc \
dbase/findex.cc \ dbase/findex.cc \
@ -549,7 +546,7 @@ HEADERS += retroshare/rsgame.h \
# turtle/turtlerouting.cc \ # turtle/turtlerouting.cc \
# turtle/turtlesearch.cc \ # turtle/turtlesearch.cc \
# turtle/turtletunnels.cc # turtle/turtletunnels.cc
SOURCES += upnp/upnphandler.cc
SOURCES += util/folderiterator.cc \ SOURCES += util/folderiterator.cc \
util/rsdebug.cc \ util/rsdebug.cc \
util/smallobject.cc \ util/smallobject.cc \
@ -564,6 +561,18 @@ HEADERS += retroshare/rsgame.h \
util/rsversion.cc \ util/rsversion.cc \
util/rswin.cc \ util/rswin.cc \
util/rsrandom.cc util/rsrandom.cc
upnp_miniupnpc {
HEADERS += upnp/upnputil.h upnp/upnphandler_miniupnp.h
SOURCES += upnp/upnputil.c upnp/upnphandler_miniupnp.cc
}
upnp_libupnp {
HEADERS += upnp/UPnPBase.h upnp/upnphandler_linux.h
SOURCES += upnp/UPnPBase.cpp upnp/upnphandler_linux.cc
DEFINES *= RS_USE_LIBUPNP
}
zeroconf { zeroconf {
HEADERS += zeroconf/p3zeroconf.h HEADERS += zeroconf/p3zeroconf.h
SOURCES += zeroconf/p3zeroconf.cc SOURCES += zeroconf/p3zeroconf.cc
@ -600,7 +609,6 @@ HEADERS += retroshare/rsgame.h \
util/contentvalue.h \ util/contentvalue.h \
gxs/gxscoreserver.h \ gxs/gxscoreserver.h \
gxs/gxssecurity.h \ gxs/gxssecurity.h \
gxs/gxssecurity.h \
gxs/rsgxsifaceimpl.h \ gxs/rsgxsifaceimpl.h \
services/p3posted.h \ services/p3posted.h \
retroshare/rsposted.h \ retroshare/rsposted.h \
@ -620,7 +628,6 @@ HEADERS += retroshare/rsgame.h \
util/contentvalue.cc \ util/contentvalue.cc \
gxs/gxscoreserver.cc \ gxs/gxscoreserver.cc \
gxs/gxssecurity.cc \ gxs/gxssecurity.cc \
gxs/gxssecurity.cc \
gxs/rsgxsifaceimpl.cc \ gxs/rsgxsifaceimpl.cc \
services/p3posted.cc \ services/p3posted.cc \
serialiser/rsposteditems.cc serialiser/rsposteditems.cc
@ -631,7 +638,7 @@ HEADERS += retroshare/rsgame.h \
services/p3idservice.h \ services/p3idservice.h \
serialiser/rsgxsiditems.h serialiser/rsgxsiditems.h
SOURCES += services/p3idservice.cc #SOURCES += services/p3idservice.cc
# serialiser/rsgxsiditems.cc \ # serialiser/rsgxsiditems.cc \
# Wiki Service # Wiki Service

View File

@ -1795,7 +1795,11 @@ RsTurtle *rsTurtle = NULL ;
#ifdef RS_ENABLE_ZCNATASSIST #ifdef RS_ENABLE_ZCNATASSIST
#include "zeroconf/p3zcnatassist.h" #include "zeroconf/p3zcnatassist.h"
#else #else
#include "upnp/upnphandler.h" #ifdef RS_USE_LIBUPNP
#include "upnp/upnphandler_linux.h"
#else
#include "upnp/upnphandler_miniupnp.h"
#endif
#endif #endif
#include "services/p3disc.h" #include "services/p3disc.h"

View File

@ -0,0 +1,431 @@
//Linux only
/* This stuff is actually C */
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
} /* extern C */
#endif
/* This stuff is actually C */
#include "upnp/upnphandler_linux.h"
#include "util/rsnet.h"
bool upnphandler::initUPnPState()
{
#ifdef UPNP_DEBUG
std::cerr << "upnphandler::initUPnPState" << std::endl;
#endif
cUPnPControlPoint = new CUPnPControlPoint(2000);
bool IGWDetected = cUPnPControlPoint->GetIGWDeviceDetected();
if (IGWDetected) {
/* MODIFY STATE */
dataMtx.lock(); /* LOCK MUTEX */
upnpState = RS_UPNP_S_READY;
#ifdef UPNP_DEBUG
std::cerr << "upnphandler::initUPnPState cUPnPControlPoint internal ip adress : ";
std::cerr << cUPnPControlPoint->getInternalIpAddress() << std::endl;
#endif
//const char ipaddr = cUPnPControlPoint->getInternalIpAddress().c_str();
inet_aton(cUPnPControlPoint->getInternalIpAddress(), &(upnp_iaddr.sin_addr));
upnp_iaddr.sin_port = htons(iport);
#ifdef UPNP_DEBUG
std::cerr << "upnphandler::initUPnPState READY" << std::endl;
#endif
dataMtx.unlock(); /* UNLOCK MUTEX */
} else {
upnpState = RS_UPNP_S_UNAVAILABLE;
#ifdef UPNP_DEBUG
std::cerr << "upnphandler::initUPnPState UNAVAILABLE" << std::endl;
#endif
}
return 0;
}
class upnpThreadData
{
public:
upnphandler *handler;
bool start;
bool stop;
};
/* Thread routines */
extern "C" void* doSetupUPnP(void* p)
{
#ifdef UPNP_DEBUG
std::cerr << "doSetupUPnP Creating upnp thread." << std::endl;
#endif
upnpThreadData *data = (upnpThreadData *) p;
if ((!data) || (!data->handler))
{
pthread_exit(NULL);
}
/* publish it! */
if (data -> stop)
{
data->handler->shutdown_upnp();
}
if (data -> start)
{
data->handler->initUPnPState();
data->handler->start_upnp();
}
delete data;
pthread_exit(NULL);
return NULL;
}
bool upnphandler::background_setup_upnp(bool start, bool stop)
{
pthread_t tid;
/* launch thread */
#ifdef UPNP_DEBUG
std::cerr << "background_setup_upnp Creating upnp thread." << std::endl;
#endif
upnpThreadData *data = new upnpThreadData();
data->handler = this;
data->start = start;
data->stop = stop;
pthread_create(&tid, 0, &doSetupUPnP, (void *) data);
pthread_detach(tid); /* so memory is reclaimed in linux */
return true;
}
bool upnphandler::start_upnp()
{
if (!(upnpState >= RS_UPNP_S_READY))
{
#ifdef UPNP_DEBUG
std::cerr << "upnphandler::start_upnp() Not Ready" << std::endl;
#endif
return false;
}
struct sockaddr_in localAddr;
{
RsStackMutex stack(dataMtx); /* LOCK STACK MUTEX */
/* if we're to load -> load */
/* select external ports */
eport_curr = eport;
if (!eport_curr)
{
/* use local port if eport is zero */
eport_curr = iport;
#ifdef UPNP_DEBUG
std::cerr << "upnphandler::start_upnp() Using LocalPort for extPort." << std::endl;
#endif
}
if (!eport_curr)
{
#ifdef UPNP_DEBUG
std::cerr << "upnphandler::start_upnp() Invalid eport ... " << std::endl;
#endif
return false;
}
/* our port */
char in_addr[256];
char in_port1[256];
upnp_iaddr.sin_port = htons(iport);
localAddr = upnp_iaddr;
uint32_t linaddr = ntohl(localAddr.sin_addr.s_addr);
snprintf(in_port1, 256, "%d", ntohs(localAddr.sin_port));
snprintf(in_addr, 256, "%d.%d.%d.%d",
((linaddr >> 24) & 0xff),
((linaddr >> 16) & 0xff),
((linaddr >> 8) & 0xff),
((linaddr >> 0) & 0xff));
#ifdef UPNP_DEBUG
std::cerr << "Attempting Redirection: InAddr: " << in_addr;
std::cerr << " InPort: " << in_port1;
std::cerr << " ePort: " << eport_curr;
std::cerr << " eProt: " << "TCP and UDP";
std::cerr << std::endl;
#endif
}
//first of all, build the mappings
std::vector<CUPnPPortMapping> upnpPortMapping1;
CUPnPPortMapping cUPnPPortMapping1 = CUPnPPortMapping(eport_curr, ntohs(localAddr.sin_port), "TCP", true, "tcp retroshare redirection");
upnpPortMapping1.push_back(cUPnPPortMapping1);
std::vector<CUPnPPortMapping> upnpPortMapping2;
CUPnPPortMapping cUPnPPortMapping2 = CUPnPPortMapping(eport_curr, ntohs(localAddr.sin_port), "UDP", true, "udp retroshare redirection");
upnpPortMapping2.push_back(cUPnPPortMapping2);
//attempt to remove formal port redirection rules
cUPnPControlPoint->DeletePortMappings(upnpPortMapping1);
cUPnPControlPoint->DeletePortMappings(upnpPortMapping2);
//add new rules
bool res = cUPnPControlPoint->AddPortMappings(upnpPortMapping1);
bool res2 = cUPnPControlPoint->AddPortMappings(upnpPortMapping2);
struct sockaddr_in extAddr;
bool extAddrResult = getExternalAddress(extAddr);
{
RsStackMutex stack(dataMtx); /* LOCK STACK MUTEX */
if (extAddrResult && (res || res2)) {
upnpState = RS_UPNP_S_ACTIVE;
} else {
upnpState = RS_UPNP_S_TCP_AND_FAILED;
}
toStart = false;
}
return (upnpState == RS_UPNP_S_ACTIVE);
}
bool upnphandler::shutdown_upnp()
{
RsStackMutex stack(dataMtx); /* LOCK STACK MUTEX */
/* always attempt this (unless no port number) */
if (eport_curr > 0 && eport > 0 && (upnpState >= RS_UPNP_S_ACTIVE))
{
#ifdef UPNP_DEBUG
std::cerr << "upnphandler::shutdown_upnp() : Attempting To Remove Redirection: port: " << eport_curr;
std::cerr << " Prot: TCP";
std::cerr << std::endl;
#endif
std::vector<CUPnPPortMapping> upnpPortMapping1;
CUPnPPortMapping cUPnPPortMapping1 = CUPnPPortMapping(eport_curr, 0, "TCP", true, "tcp redirection");
upnpPortMapping1.push_back(cUPnPPortMapping1);
cUPnPControlPoint->DeletePortMappings(upnpPortMapping1);
#ifdef UPNP_DEBUG
std::cerr << "upnphandler::shutdown_upnp() : Attempting To Remove Redirection: port: " << eport_curr;
std::cerr << " Prot: UDP";
std::cerr << std::endl;
#endif
std::vector<CUPnPPortMapping> upnpPortMapping2;
CUPnPPortMapping cUPnPPortMapping2 = CUPnPPortMapping(eport_curr, 0, "UDP", true, "udp redirection");
upnpPortMapping2.push_back(cUPnPPortMapping2);
cUPnPControlPoint->DeletePortMappings(upnpPortMapping2);
//destroy the upnp object
cUPnPControlPoint->~CUPnPControlPoint();
} else {
#ifdef UPNP_DEBUG
std::cerr << "upnphandler::shutdown_upnp() : avoid upnp connection for shutdonws because probably a net flag went down." << std::endl;
#endif
}
//stopping os ok, set starting to true for next net reset
toStop = false;
toStart = true;
upnpState = RS_UPNP_S_UNINITIALISED;
return true;
}
/************************ External Interface *****************************
*
*
*
*/
upnphandler::upnphandler()
:
upnpState(RS_UPNP_S_UNINITIALISED), dataMtx("upupState"),
cUPnPControlPoint(NULL),
toEnable(false), toStart(false), toStop(false),
iport(0),eport(0), eport_curr(0)
{
}
upnphandler::~upnphandler()
{
return;
}
/* RsIface */
void upnphandler::enable(bool active)
{
#ifdef UPNP_DEBUG
std::cerr << "upnphandler::enable called with argument active : " << active << std::endl;
std::cerr << "toEnable : " << toEnable << std::endl;
std::cerr << "toStart : " << toStart << std::endl;
#endif
dataMtx.lock(); /*** LOCK MUTEX ***/
if (active != toEnable)
{
if (active)
{
toStart = true;
}
else
{
toStop = true;
}
}
toEnable = active;
bool start = toStart;
dataMtx.unlock(); /*** UNLOCK MUTEX ***/
if (start)
{
/* make background thread to startup UPnP */
background_setup_upnp(true, false);
}
}
void upnphandler::shutdown()
{
/* blocking call to shutdown upnp */
#ifdef UPNP_DEBUG
std::cerr << "upnphandler::shutdown() called." << std::endl;
#endif
shutdown_upnp();
}
void upnphandler::restart()
{
/* non-blocking call to shutdown upnp, and startup again. */
#ifdef UPNP_DEBUG
std::cerr << "upnphandler::restart() called." << std::endl;
#endif
background_setup_upnp(true, true);
}
bool upnphandler::getEnabled()
{
dataMtx.lock(); /*** LOCK MUTEX ***/
bool on = toEnable;
dataMtx.unlock(); /*** UNLOCK MUTEX ***/
return on;
}
bool upnphandler::getActive()
{
dataMtx.lock(); /*** LOCK MUTEX ***/
#ifdef UPNP_DEBUG
std::cerr <<"upnphandler::getActive() result : " << (upnpState == RS_UPNP_S_ACTIVE) << std::endl;
#endif
bool on = (upnpState == RS_UPNP_S_ACTIVE);
dataMtx.unlock(); /*** UNLOCK MUTEX ***/
return on;
}
/* the address that the listening port is on */
void upnphandler::setInternalPort(unsigned short iport_in)
{
dataMtx.lock(); /*** LOCK MUTEX ***/
if (iport != iport_in)
{
iport = iport_in;
if ((toEnable) &&
(upnpState == RS_UPNP_S_ACTIVE))
{
toStop = true;
toStart = true;
}
}
dataMtx.unlock(); /*** UNLOCK MUTEX ***/
}
void upnphandler::setExternalPort(unsigned short eport_in)
{
dataMtx.lock(); /*** LOCK MUTEX ***/
/* flag both shutdown/start -> for restart */
if (eport != eport_in)
{
eport = eport_in;
if ((toEnable) &&
(upnpState == RS_UPNP_S_ACTIVE))
{
toStop = true;
toStart = true;
}
}
dataMtx.unlock(); /*** UNLOCK MUTEX ***/
}
/* as determined by uPnP */
bool upnphandler::getInternalAddress(struct sockaddr_in &addr)
{
dataMtx.lock(); /*** LOCK MUTEX ***/
addr = upnp_iaddr;
bool valid = (upnpState >= RS_UPNP_S_ACTIVE);
dataMtx.unlock(); /*** UNLOCK MUTEX ***/
return valid;
}
bool upnphandler::getExternalAddress(struct sockaddr_in &addr)
{
std::string externalAdress = cUPnPControlPoint->getExternalAddress();
if(!externalAdress.empty() && externalAdress != "")
{
const char* externalIPAddress = externalAdress.c_str();
#ifdef UPNP_DEBUG
std::cerr << " upnphandler::getExternalAddress() : " << externalIPAddress;
std::cerr << ":" << eport_curr;
std::cerr << std::endl;
#endif
dataMtx.lock(); /*** LOCK MUTEX ***/
sockaddr_clear(&upnp_eaddr);
inet_aton(externalIPAddress, &(upnp_eaddr.sin_addr));
upnp_eaddr.sin_family = AF_INET;
upnp_eaddr.sin_port = htons(eport_curr);
dataMtx.unlock(); /*** UNLOCK MUTEX ***/
addr = upnp_eaddr;
return true;
}
else
{
return false;
}
}

View File

@ -0,0 +1,78 @@
#ifndef _RS_UPNP_IFACE_H
#define _RS_UPNP_IFACE_H
#include <string.h>
/* platform independent networking... */
#include "pqi/pqinetwork.h"
#include "pqi/pqiassist.h"
#include "util/rsthreads.h"
#include <upnp/upnp.h>
#include "upnp/UPnPBase.h"
#define RS_UPNP_S_UNINITIALISED 0
#define RS_UPNP_S_UNAVAILABLE 1
#define RS_UPNP_S_READY 2
#define RS_UPNP_S_TCP_AND_FAILED 3
//#define RS_UPNP_S_UDP_FAILED 4
#define RS_UPNP_S_ACTIVE 5
class upnphandler: public pqiNetAssistFirewall
{
public:
upnphandler();
virtual ~upnphandler();
/* External Interface (pqiNetAssistFirewall) */
virtual void enable(bool active);
virtual void shutdown();
virtual void restart();
virtual bool getEnabled();
virtual bool getActive();
virtual void setInternalPort(unsigned short iport_in);
virtual void setExternalPort(unsigned short eport_in);
virtual bool getInternalAddress(struct sockaddr_in &addr);
virtual bool getExternalAddress(struct sockaddr_in &addr);
/* Public functions - for background thread operation,
* but effectively private from rest of RS, as in derived class
*/
unsigned int upnpState;
bool start_upnp();
bool shutdown_upnp();
bool initUPnPState();
/* Mutex for data below */
RsMutex dataMtx;
private:
CUPnPControlPoint *cUPnPControlPoint;
bool background_setup_upnp(bool, bool);
bool toEnable; /* overall on/off switch */
bool toStart; /* if set start forwarding */
bool toStop; /* if set stop forwarding */
unsigned short iport;
unsigned short eport; /* config */
unsigned short eport_curr; /* current forwarded */
/* info from upnp */
struct sockaddr_in upnp_iaddr;
struct sockaddr_in upnp_eaddr;
};
/* info from upnp */
int CtrlPointCallbackEventHandler(Upnp_EventType ,void* , void*);
#endif /* _RS_UPNP_IFACE_H */

View File

@ -1,440 +1,4 @@
//Linux only
#if !defined(WINDOWS_SYS) && !defined(__APPLE__)
/* This stuff is actually C */
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
} /* extern C */
#endif
/* This stuff is actually C */
#include "upnp/upnphandler.h"
#include "util/rsnet.h"
bool upnphandler::initUPnPState()
{
#ifdef UPNP_DEBUG
std::cerr << "upnphandler::initUPnPState" << std::endl;
#endif
cUPnPControlPoint = new CUPnPControlPoint(2000);
bool IGWDetected = cUPnPControlPoint->GetIGWDeviceDetected();
if (IGWDetected) {
/* MODIFY STATE */
dataMtx.lock(); /* LOCK MUTEX */
upnpState = RS_UPNP_S_READY;
#ifdef UPNP_DEBUG
std::cerr << "upnphandler::initUPnPState cUPnPControlPoint internal ip adress : ";
std::cerr << cUPnPControlPoint->getInternalIpAddress() << std::endl;
#endif
//const char ipaddr = cUPnPControlPoint->getInternalIpAddress().c_str();
inet_aton(cUPnPControlPoint->getInternalIpAddress(), &(upnp_iaddr.sin_addr));
upnp_iaddr.sin_port = htons(iport);
#ifdef UPNP_DEBUG
std::cerr << "upnphandler::initUPnPState READY" << std::endl;
#endif
dataMtx.unlock(); /* UNLOCK MUTEX */
} else {
upnpState = RS_UPNP_S_UNAVAILABLE;
#ifdef UPNP_DEBUG
std::cerr << "upnphandler::initUPnPState UNAVAILABLE" << std::endl;
#endif
}
return 0;
}
class upnpThreadData
{
public:
upnphandler *handler;
bool start;
bool stop;
};
/* Thread routines */
extern "C" void* doSetupUPnP(void* p)
{
#ifdef UPNP_DEBUG
std::cerr << "doSetupUPnP Creating upnp thread." << std::endl;
#endif
upnpThreadData *data = (upnpThreadData *) p;
if ((!data) || (!data->handler))
{
pthread_exit(NULL);
}
/* publish it! */
if (data -> stop)
{
data->handler->shutdown_upnp();
}
if (data -> start)
{
data->handler->initUPnPState();
data->handler->start_upnp();
}
delete data;
pthread_exit(NULL);
return NULL;
}
bool upnphandler::background_setup_upnp(bool start, bool stop)
{
pthread_t tid;
/* launch thread */
#ifdef UPNP_DEBUG
std::cerr << "background_setup_upnp Creating upnp thread." << std::endl;
#endif
upnpThreadData *data = new upnpThreadData();
data->handler = this;
data->start = start;
data->stop = stop;
pthread_create(&tid, 0, &doSetupUPnP, (void *) data);
pthread_detach(tid); /* so memory is reclaimed in linux */
return true;
}
bool upnphandler::start_upnp()
{
if (!(upnpState >= RS_UPNP_S_READY))
{
#ifdef UPNP_DEBUG
std::cerr << "upnphandler::start_upnp() Not Ready" << std::endl;
#endif
return false;
}
struct sockaddr_in localAddr;
{
RsStackMutex stack(dataMtx); /* LOCK STACK MUTEX */
/* if we're to load -> load */
/* select external ports */
eport_curr = eport;
if (!eport_curr)
{
/* use local port if eport is zero */
eport_curr = iport;
#ifdef UPNP_DEBUG
std::cerr << "upnphandler::start_upnp() Using LocalPort for extPort." << std::endl;
#endif
}
if (!eport_curr)
{
#ifdef UPNP_DEBUG
std::cerr << "upnphandler::start_upnp() Invalid eport ... " << std::endl;
#endif
return false;
}
/* our port */
char in_addr[256];
char in_port1[256];
upnp_iaddr.sin_port = htons(iport);
localAddr = upnp_iaddr;
uint32_t linaddr = ntohl(localAddr.sin_addr.s_addr);
snprintf(in_port1, 256, "%d", ntohs(localAddr.sin_port));
snprintf(in_addr, 256, "%d.%d.%d.%d",
((linaddr >> 24) & 0xff),
((linaddr >> 16) & 0xff),
((linaddr >> 8) & 0xff),
((linaddr >> 0) & 0xff));
#ifdef UPNP_DEBUG
std::cerr << "Attempting Redirection: InAddr: " << in_addr;
std::cerr << " InPort: " << in_port1;
std::cerr << " ePort: " << eport_curr;
std::cerr << " eProt: " << "TCP and UDP";
std::cerr << std::endl;
#endif
}
//first of all, build the mappings
std::vector<CUPnPPortMapping> upnpPortMapping1;
CUPnPPortMapping cUPnPPortMapping1 = CUPnPPortMapping(eport_curr, ntohs(localAddr.sin_port), "TCP", true, "tcp retroshare redirection");
upnpPortMapping1.push_back(cUPnPPortMapping1);
std::vector<CUPnPPortMapping> upnpPortMapping2;
CUPnPPortMapping cUPnPPortMapping2 = CUPnPPortMapping(eport_curr, ntohs(localAddr.sin_port), "UDP", true, "udp retroshare redirection");
upnpPortMapping2.push_back(cUPnPPortMapping2);
//attempt to remove formal port redirection rules
cUPnPControlPoint->DeletePortMappings(upnpPortMapping1);
cUPnPControlPoint->DeletePortMappings(upnpPortMapping2);
//add new rules
bool res = cUPnPControlPoint->AddPortMappings(upnpPortMapping1);
bool res2 = cUPnPControlPoint->AddPortMappings(upnpPortMapping2);
struct sockaddr_in extAddr;
bool extAddrResult = getExternalAddress(extAddr);
{
RsStackMutex stack(dataMtx); /* LOCK STACK MUTEX */
if (extAddrResult && (res || res2)) {
upnpState = RS_UPNP_S_ACTIVE;
} else {
upnpState = RS_UPNP_S_TCP_AND_FAILED;
}
toStart = false;
}
return (upnpState == RS_UPNP_S_ACTIVE);
}
bool upnphandler::shutdown_upnp()
{
RsStackMutex stack(dataMtx); /* LOCK STACK MUTEX */
/* always attempt this (unless no port number) */
if (eport_curr > 0 && eport > 0 && (upnpState >= RS_UPNP_S_ACTIVE))
{
#ifdef UPNP_DEBUG
std::cerr << "upnphandler::shutdown_upnp() : Attempting To Remove Redirection: port: " << eport_curr;
std::cerr << " Prot: TCP";
std::cerr << std::endl;
#endif
std::vector<CUPnPPortMapping> upnpPortMapping1;
CUPnPPortMapping cUPnPPortMapping1 = CUPnPPortMapping(eport_curr, 0, "TCP", true, "tcp redirection");
upnpPortMapping1.push_back(cUPnPPortMapping1);
cUPnPControlPoint->DeletePortMappings(upnpPortMapping1);
#ifdef UPNP_DEBUG
std::cerr << "upnphandler::shutdown_upnp() : Attempting To Remove Redirection: port: " << eport_curr;
std::cerr << " Prot: UDP";
std::cerr << std::endl;
#endif
std::vector<CUPnPPortMapping> upnpPortMapping2;
CUPnPPortMapping cUPnPPortMapping2 = CUPnPPortMapping(eport_curr, 0, "UDP", true, "udp redirection");
upnpPortMapping2.push_back(cUPnPPortMapping2);
cUPnPControlPoint->DeletePortMappings(upnpPortMapping2);
//destroy the upnp object
cUPnPControlPoint->~CUPnPControlPoint();
} else {
#ifdef UPNP_DEBUG
std::cerr << "upnphandler::shutdown_upnp() : avoid upnp connection for shutdonws because probably a net flag went down." << std::endl;
#endif
}
//stopping os ok, set starting to true for next net reset
toStop = false;
toStart = true;
upnpState = RS_UPNP_S_UNINITIALISED;
return true;
}
/************************ External Interface *****************************
*
*
*
*/
upnphandler::upnphandler()
:
upnpState(RS_UPNP_S_UNINITIALISED), dataMtx("upupState"),
cUPnPControlPoint(NULL),
toEnable(false), toStart(false), toStop(false),
iport(0),eport(0), eport_curr(0)
{
}
upnphandler::~upnphandler()
{
return;
}
/* RsIface */
void upnphandler::enable(bool active)
{
#ifdef UPNP_DEBUG
std::cerr << "upnphandler::enable called with argument active : " << active << std::endl;
std::cerr << "toEnable : " << toEnable << std::endl;
std::cerr << "toStart : " << toStart << std::endl;
#endif
dataMtx.lock(); /*** LOCK MUTEX ***/
if (active != toEnable)
{
if (active)
{
toStart = true;
}
else
{
toStop = true;
}
}
toEnable = active;
bool start = toStart;
dataMtx.unlock(); /*** UNLOCK MUTEX ***/
if (start)
{
/* make background thread to startup UPnP */
background_setup_upnp(true, false);
}
}
void upnphandler::shutdown()
{
/* blocking call to shutdown upnp */
#ifdef UPNP_DEBUG
std::cerr << "upnphandler::shutdown() called." << std::endl;
#endif
shutdown_upnp();
}
void upnphandler::restart()
{
/* non-blocking call to shutdown upnp, and startup again. */
#ifdef UPNP_DEBUG
std::cerr << "upnphandler::restart() called." << std::endl;
#endif
background_setup_upnp(true, true);
}
bool upnphandler::getEnabled()
{
dataMtx.lock(); /*** LOCK MUTEX ***/
bool on = toEnable;
dataMtx.unlock(); /*** UNLOCK MUTEX ***/
return on;
}
bool upnphandler::getActive()
{
dataMtx.lock(); /*** LOCK MUTEX ***/
#ifdef UPNP_DEBUG
std::cerr <<"upnphandler::getActive() result : " << (upnpState == RS_UPNP_S_ACTIVE) << std::endl;
#endif
bool on = (upnpState == RS_UPNP_S_ACTIVE);
dataMtx.unlock(); /*** UNLOCK MUTEX ***/
return on;
}
/* the address that the listening port is on */
void upnphandler::setInternalPort(unsigned short iport_in)
{
dataMtx.lock(); /*** LOCK MUTEX ***/
if (iport != iport_in)
{
iport = iport_in;
if ((toEnable) &&
(upnpState == RS_UPNP_S_ACTIVE))
{
toStop = true;
toStart = true;
}
}
dataMtx.unlock(); /*** UNLOCK MUTEX ***/
}
void upnphandler::setExternalPort(unsigned short eport_in)
{
dataMtx.lock(); /*** LOCK MUTEX ***/
/* flag both shutdown/start -> for restart */
if (eport != eport_in)
{
eport = eport_in;
if ((toEnable) &&
(upnpState == RS_UPNP_S_ACTIVE))
{
toStop = true;
toStart = true;
}
}
dataMtx.unlock(); /*** UNLOCK MUTEX ***/
}
/* as determined by uPnP */
bool upnphandler::getInternalAddress(struct sockaddr_in &addr)
{
dataMtx.lock(); /*** LOCK MUTEX ***/
addr = upnp_iaddr;
bool valid = (upnpState >= RS_UPNP_S_ACTIVE);
dataMtx.unlock(); /*** UNLOCK MUTEX ***/
return valid;
}
bool upnphandler::getExternalAddress(struct sockaddr_in &addr)
{
std::string externalAdress = cUPnPControlPoint->getExternalAddress();
if(!externalAdress.empty() && externalAdress != "")
{
const char* externalIPAddress = externalAdress.c_str();
#ifdef UPNP_DEBUG
std::cerr << " upnphandler::getExternalAddress() : " << externalIPAddress;
std::cerr << ":" << eport_curr;
std::cerr << std::endl;
#endif
dataMtx.lock(); /*** LOCK MUTEX ***/
sockaddr_clear(&upnp_eaddr);
inet_aton(externalIPAddress, &(upnp_eaddr.sin_addr));
upnp_eaddr.sin_family = AF_INET;
upnp_eaddr.sin_port = htons(eport_curr);
dataMtx.unlock(); /*** UNLOCK MUTEX ***/
addr = upnp_eaddr;
return true;
}
else
{
return false;
}
}
#endif
// Windows / Mac version. // Windows / Mac version.
#if defined(WINDOWS_SYS) || defined(__APPLE__)
/* This stuff is actually C */ /* This stuff is actually C */
#ifdef __cplusplus #ifdef __cplusplus
@ -1001,4 +565,3 @@ bool upnphandler::getExternalAddress(struct sockaddr_in &addr)
return valid; return valid;
} }
#endif

View File

@ -1,94 +1,4 @@
//Linux only... //windows/osx (miniupnpc) implementation
#if !defined(WINDOWS_SYS) && !defined(__APPLE__)
#ifndef _RS_UPNP_IFACE_H
#define _RS_UPNP_IFACE_H
#include <string.h>
/* platform independent networking... */
#include "pqi/pqinetwork.h"
#include "pqi/pqiassist.h"
#include "util/rsthreads.h"
#include <upnp/upnp.h>
#include "upnp/UPnPBase.h"
#define RS_UPNP_S_UNINITIALISED 0
#define RS_UPNP_S_UNAVAILABLE 1
#define RS_UPNP_S_READY 2
#define RS_UPNP_S_TCP_AND_FAILED 3
//#define RS_UPNP_S_UDP_FAILED 4
#define RS_UPNP_S_ACTIVE 5
class upnphandler: public pqiNetAssistFirewall
{
public:
upnphandler();
virtual ~upnphandler();
/* External Interface (pqiNetAssistFirewall) */
virtual void enable(bool active);
virtual void shutdown();
virtual void restart();
virtual bool getEnabled();
virtual bool getActive();
virtual void setInternalPort(unsigned short iport_in);
virtual void setExternalPort(unsigned short eport_in);
virtual bool getInternalAddress(struct sockaddr_in &addr);
virtual bool getExternalAddress(struct sockaddr_in &addr);
/* Public functions - for background thread operation,
* but effectively private from rest of RS, as in derived class
*/
unsigned int upnpState;
bool start_upnp();
bool shutdown_upnp();
bool initUPnPState();
/* Mutex for data below */
RsMutex dataMtx;
private:
CUPnPControlPoint *cUPnPControlPoint;
bool background_setup_upnp(bool, bool);
bool toEnable; /* overall on/off switch */
bool toStart; /* if set start forwarding */
bool toStop; /* if set stop forwarding */
unsigned short iport;
unsigned short eport; /* config */
unsigned short eport_curr; /* current forwarded */
/* info from upnp */
struct sockaddr_in upnp_iaddr;
struct sockaddr_in upnp_eaddr;
};
/* info from upnp */
int CtrlPointCallbackEventHandler(Upnp_EventType ,void* , void*);
#endif /* _RS_UPNP_IFACE_H */
#endif
#if defined(WINDOWS_SYS) || defined(__APPLE__)
//windows implementation
#ifndef _RS_UPNP_IFACE_H #ifndef _RS_UPNP_IFACE_H
#define _RS_UPNP_IFACE_H #define _RS_UPNP_IFACE_H
@ -194,4 +104,3 @@ bool checkUPnPActive();
}; };
#endif /* _RS_UPNP_IFACE_H */ #endif /* _RS_UPNP_IFACE_H */
#endif