From 49b24c2b145377c50789d84281fdd556b8731e76 Mon Sep 17 00:00:00 2001 From: joss17 Date: Fri, 30 Oct 2009 00:46:36 +0000 Subject: [PATCH] add compilation swtich : libupnp for linux and miniupnp for windows git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@1786 b45a01b8-16f6-495d-af2f-9b41ad6348cc --- libretroshare/src/libretroshare.pro | 31 +- libretroshare/src/upnp/UPnPBase.cpp | 2 + libretroshare/src/upnp/UPnPBase.h | 2 + libretroshare/src/upnp/upnphandler.cc | 577 ++++++++++++++++++++++++++ libretroshare/src/upnp/upnphandler.h | 119 ++++++ libretroshare/src/upnp/upnptest.cc | 1 + libretroshare/src/upnp/upnputil.c | 291 +++++++++++++ libretroshare/src/upnp/upnputil.h | 56 +++ 8 files changed, 1063 insertions(+), 16 deletions(-) create mode 100644 libretroshare/src/upnp/upnputil.c create mode 100644 libretroshare/src/upnp/upnputil.h diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index 2a413f8a8..1368557c9 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -21,34 +21,32 @@ debug { QMAKE_CXXFLAGS *= -g } -linux-g++ { - OBJECTS_DIR = temp/linux-g++/obj +unix { DESTDIR = lib QMAKE_CXXFLAGS *= -Wall QMAKE_CC = g++ SSL_DIR = /usr/include/openssl UPNP_DIR = /usr/include/upnp + INCLUDEPATH += . $${SSL_DIR} $${UPNP_DIR} + + #gpg files HEADERS += /usr/include/gpg-error.h HEADERS += /usr/include/gpgme.h - INCLUDEPATH += . $${SSL_DIR} $${UPNP_DIR} + + #libupnp implementation files + HEADERS += upnp/UPnPBase.h + SOURCES += upnp/UPnPBase.cpp CONFIG += version_detail_bash_script } +linux-g++ { + OBJECTS_DIR = temp/linux-g++/obj +} + linux-g++-64 { OBJECTS_DIR = temp/linux-g++-64/obj - DESTDIR = lib - QMAKE_CXXFLAGS *= -Wall - QMAKE_CC = g++ - - SSL_DIR = /usr/include/openssl - UPNP_DIR = /usr/include/upnp - HEADERS += /usr/include/gpg-error.h - HEADERS += /usr/include/gpgme.h - INCLUDEPATH += . $${SSL_DIR} $${UPNP_DIR} - - CONFIG += version_detail_bash_script } version_detail_bash_script { @@ -83,8 +81,10 @@ win32 { OBJECTS_DIR = temp/obj MOC_DIR = temp/moc DEFINES = WINDOWS_SYS WIN32 STATICLIB MINGW + DEFINES *= MINIUPNPC_VERSION=13 DESTDIR = lib + UPNPC_DIR = ../../../../miniupnpc-1.3 GPG_ERROR_DIR = ../../../../libgpg-error-1.7 GPGME_DIR = ../../../../gpgme-1.1.8 @@ -93,7 +93,7 @@ win32 { ZLIB_DIR = ../../../../zlib-1.2.3 SSL_DIR = ../../../../OpenSSL - INCLUDEPATH += . $${SSL_DIR}/include $${UPNPC_DIR} $${PTHREADS_DIR} $${ZLIB_DIR} + INCLUDEPATH += . $${SSL_DIR}/include $${UPNPC_DIR} $${PTHREADS_DIR} $${ZLIB_DIR} $${GPGME_DIR}/src $${GPG_ERROR_DIR}/src } ################################### COMMON stuff ################################## @@ -286,7 +286,6 @@ SOURCES = \ ft/ftdwlqueue.cc \ dht/opendhtmgr.cc \ upnp/upnphandler.cc \ - upnp/UPnPBase.cpp \ dht/opendht.cc \ dht/opendhtstr.cc \ dht/b64.c \ diff --git a/libretroshare/src/upnp/UPnPBase.cpp b/libretroshare/src/upnp/UPnPBase.cpp index 09965288a..779b317fe 100644 --- a/libretroshare/src/upnp/UPnPBase.cpp +++ b/libretroshare/src/upnp/UPnPBase.cpp @@ -23,6 +23,8 @@ // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA // +//This file uses libupnp + #define UPNP_C #include "UPnPBase.h" diff --git a/libretroshare/src/upnp/UPnPBase.h b/libretroshare/src/upnp/UPnPBase.h index fa724804b..f9b605fa9 100644 --- a/libretroshare/src/upnp/UPnPBase.h +++ b/libretroshare/src/upnp/UPnPBase.h @@ -24,6 +24,8 @@ // +//this file uses libupnp + #include #include #include diff --git a/libretroshare/src/upnp/upnphandler.cc b/libretroshare/src/upnp/upnphandler.cc index 072675e62..afa551d7f 100644 --- a/libretroshare/src/upnp/upnphandler.cc +++ b/libretroshare/src/upnp/upnphandler.cc @@ -1,3 +1,5 @@ +//Linux and macos implementation +#ifndef WINDOWS_SYS /* This stuff is actually C */ @@ -410,3 +412,578 @@ bool upnphandler::getExternalAddress(struct sockaddr_in &addr) return false; } } +#endif + + + + +#ifdef WINDOWS_SYS + +/* 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 "upnp/upnputil.h" + +class uPnPConfigData +{ + public: + struct UPNPDev * devlist; + struct UPNPUrls urls; + struct IGDdatas data; + char lanaddr[16]; /* my ip address on the LAN */ +}; + +#include +#include + +#include "util/rsnet.h" + +bool upnphandler::initUPnPState() +{ + /* allocate memory */ + uPnPConfigData *upcd = new uPnPConfigData; + +#if MINIUPNPC_VERSION >= 11 + /* Starting from version 1.1, miniupnpc api has a new parameter (int sameport) */ + upcd->devlist = upnpDiscover(2000, NULL, NULL, 0); +#else + upcd->devlist = upnpDiscover(2000, NULL, NULL); +#endif + + if(upcd->devlist) + { + struct UPNPDev * device; + printf("List of UPNP devices found on the network :\n"); + for(device=upcd->devlist;device;device=device->pNext) + { + printf("\n desc: %s\n st: %s\n", + device->descURL, device->st); + } + putchar('\n'); + if(UPNP_GetValidIGD(upcd->devlist, &(upcd->urls), + &(upcd->data), upcd->lanaddr, + sizeof(upcd->lanaddr))) + { + printf("Found valid IGD : %s\n", + upcd->urls.controlURL); + printf("Local LAN ip address : %s\n", + upcd->lanaddr); + + /* MODIFY STATE */ + dataMtx.lock(); /* LOCK MUTEX */ + + /* convert to ipaddress. */ + inet_aton(upcd->lanaddr, &(upnp_iaddr.sin_addr)); + upnp_iaddr.sin_port = htons(iport); + + upnpState = RS_UPNP_S_READY; + if (upnpConfig) + { + delete upnpConfig; + } + upnpConfig = upcd; /* */ + + dataMtx.unlock(); /* UNLOCK MUTEX */ + + + /* done -> READY */ + return 1; + + } + else + { + fprintf(stderr, "No valid UPNP Internet Gateway Device found.\n"); + } + + + freeUPNPDevlist(upcd->devlist); + upcd->devlist = 0; + } + else + { + fprintf(stderr, "No IGD UPnP Device found on the network !\n"); + } + + /* MODIFY STATE */ + dataMtx.lock(); /* LOCK MUTEX */ + + upnpState = RS_UPNP_S_UNAVAILABLE; + delete upcd; + upnpConfig = NULL; + + dataMtx.unlock(); /* UNLOCK MUTEX */ + + /* done, FAILED -> NOT AVAILABLE */ + + return 0; +} + +bool upnphandler::printUPnPState() +{ + std::cerr << "upnphandler::printUPnPState() ... locking"; + std::cerr << std::endl; + + RsStackMutex stack(dataMtx); /* LOCK STACK MUTEX */ + + std::cerr << "upnphandler::printUPnPState() ... locked"; + std::cerr << std::endl; + + uPnPConfigData *config = upnpConfig; + if ((upnpState >= RS_UPNP_S_READY) && (config)) + { + DisplayInfos(&(config -> urls), &(config->data)); + GetConnectionStatus(&(config -> urls), &(config->data)); + ListRedirections(&(config -> urls), &(config->data)); + } + else + { + std::cerr << "UPNP not Ready" << std::endl; + } + + return 1; +} + + +bool upnphandler::checkUPnPActive() +{ + RsStackMutex stack(dataMtx); /* LOCK STACK MUTEX */ + + uPnPConfigData *config = upnpConfig; + if ((upnpState > RS_UPNP_S_READY) && (config)) + { + char eprot1[] = "TCP"; + char eprot2[] = "UDP"; + + char in_addr[256]; + char in_port1[256]; + char in_port2[256]; + char eport1[256]; + char eport2[256]; + + struct sockaddr_in localAddr = upnp_iaddr; + uint32_t linaddr = ntohl(localAddr.sin_addr.s_addr); + + snprintf(in_port1, 256, "%d", ntohs(localAddr.sin_port)); + snprintf(in_port2, 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)); + + snprintf(eport1, 256, "%d", eport_curr); + snprintf(eport2, 256, "%d", eport_curr); + + std::cerr << "upnphandler::checkUPnPState()"; + std::cerr << " Checking Redirection: InAddr: " << in_addr; + std::cerr << " InPort: " << in_port1; + std::cerr << " ePort: " << eport1; + std::cerr << " eProt: " << eprot1; + std::cerr << std::endl; + + + bool tcpOk = TestRedirect(&(config -> urls), &(config->data), + in_addr, in_port1, eport1, eprot1); + bool udpOk = TestRedirect(&(config -> urls), &(config->data), + in_addr, in_port2, eport2, eprot2); + + if ((!tcpOk) || (!udpOk)) + { + std::cerr << "upnphandler::checkUPnPState() ... Redirect Expired, restarting"; + std::cerr << std::endl; + + toStop = true; + toStart = true; + } + } + + return true; +} + +class upnpThreadData +{ + public: + upnphandler *handler; + bool start; + bool stop; +}; + + /* Thread routines */ +extern "C" void* doSetupUPnP(void* p) +{ + 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(); + } + + data->handler->printUPnPState(); + + delete data; + pthread_exit(NULL); + + return NULL; +} + +bool upnphandler::background_setup_upnp(bool start, bool stop) +{ + pthread_t tid; + + /* launch thread */ + 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() +{ + RsStackMutex stack(dataMtx); /* LOCK STACK MUTEX */ + + uPnPConfigData *config = upnpConfig; + if (!((upnpState >= RS_UPNP_S_READY) && (config))) + { + std::cerr << "upnphandler::start_upnp() Not Ready"; + std::cerr << std::endl; + return false; + } + + char eprot1[] = "TCP"; + char eprot2[] = "UDP"; + + /* 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; + std::cerr << "Using LocalPort for extPort!"; + std::cerr << std::endl; + } + + if (!eport_curr) + { + std::cerr << "Invalid eport ... "; + std::cerr << std::endl; + return false; + } + + + /* our port */ + char in_addr[256]; + char in_port1[256]; + char in_port2[256]; + char eport1[256]; + char eport2[256]; + + upnp_iaddr.sin_port = htons(iport); + struct sockaddr_in localAddr = upnp_iaddr; + uint32_t linaddr = ntohl(localAddr.sin_addr.s_addr); + + snprintf(in_port1, 256, "%d", ntohs(localAddr.sin_port)); + snprintf(in_port2, 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)); + + snprintf(eport1, 256, "%d", eport_curr); + snprintf(eport2, 256, "%d", eport_curr); + + std::cerr << "Attempting Redirection: InAddr: " << in_addr; + std::cerr << " InPort: " << in_port1; + std::cerr << " ePort: " << eport1; + std::cerr << " eProt: " << eprot1; + std::cerr << std::endl; + + if (!SetRedirectAndTest(&(config -> urls), &(config->data), + in_addr, in_port1, eport1, eprot1)) + { + upnpState = RS_UPNP_S_TCP_FAILED; + } + else if (!SetRedirectAndTest(&(config -> urls), &(config->data), + in_addr, in_port2, eport2, eprot2)) + { + upnpState = RS_UPNP_S_UDP_FAILED; + } + else + { + upnpState = RS_UPNP_S_ACTIVE; + } + + + /* now store the external address */ + char externalIPAddress[32]; + UPNP_GetExternalIPAddress(config -> urls.controlURL, + config->data.servicetype, + externalIPAddress); + + sockaddr_clear(&upnp_eaddr); + + if(externalIPAddress[0]) + { + std::cerr << "Stored External address: " << externalIPAddress; + std::cerr << ":" << eport_curr; + std::cerr << std::endl; + + inet_aton(externalIPAddress, &(upnp_eaddr.sin_addr)); + upnp_eaddr.sin_family = AF_INET; + upnp_eaddr.sin_port = htons(eport_curr); + } + else + { + std::cerr << "FAILED To get external Address"; + std::cerr << std::endl; + } + + toStart = false; + + return true; + +} + +bool upnphandler::shutdown_upnp() +{ + RsStackMutex stack(dataMtx); /* LOCK STACK MUTEX */ + + uPnPConfigData *config = upnpConfig; + if (!((upnpState >= RS_UPNP_S_READY) && (config))) + { + return false; + } + + char eprot1[] = "TCP"; + char eprot2[] = "UDP"; + + /* always attempt this (unless no port number) */ + if (eport_curr > 0) + { + + char eport1[256]; + char eport2[256]; + + snprintf(eport1, 256, "%d", eport_curr); + snprintf(eport2, 256, "%d", eport_curr); + + std::cerr << "Attempting To Remove Redirection: port: " << eport1; + std::cerr << " Prot: " << eprot1; + std::cerr << std::endl; + + RemoveRedirect(&(config -> urls), &(config->data), + eport1, eprot1); + + + std::cerr << "Attempting To Remove Redirection: port: " << eport2; + std::cerr << " Prot: " << eprot2; + std::cerr << std::endl; + + RemoveRedirect(&(config -> urls), &(config->data), + eport2, eprot2); + + upnpState = RS_UPNP_S_READY; + toStop = false; + } + + return true; + +} + +/************************ External Interface ***************************** + * + * + * + */ + +upnphandler::upnphandler() + :toEnable(false), toStart(false), toStop(false), + eport(0), eport_curr(0), + upnpState(RS_UPNP_S_UNINITIALISED), + upnpConfig(NULL) +{ + return; +} + +upnphandler::~upnphandler() +{ + return; +} + + /* RsIface */ +void upnphandler::enable(bool active) +{ + 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 */ + + shutdown_upnp(); +} + + +void upnphandler::restart() +{ + /* non-blocking call to shutdown upnp, and startup again. */ + 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 ***/ + + 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) +{ +// std::cerr << "UPnPHandler::setInternalAddress() pre Lock!" << std::endl; + dataMtx.lock(); /*** LOCK MUTEX ***/ +// std::cerr << "UPnPHandler::setInternalAddress() postLock!" << std::endl; + + std::cerr << "UPnPHandler::setInternalPort(" << iport_in << ") current port: "; + std::cerr << iport << std::endl; + + 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) +{ +// std::cerr << "UPnPHandler::getExternalPort() pre Lock!" << std::endl; + dataMtx.lock(); /*** LOCK MUTEX ***/ +// std::cerr << "UPnPHandler::getExternalPort() postLock!" << std::endl; + + std::cerr << "UPnPHandler::setExternalPort(" << eport_in << ") current port: "; + std::cerr << eport << std::endl; + + /* 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) +{ +// std::cerr << "UPnPHandler::getInternalAddress() pre Lock!" << std::endl; + dataMtx.lock(); /*** LOCK MUTEX ***/ +// std::cerr << "UPnPHandler::getInternalAddress() postLock!" << std::endl; + + std::cerr << "UPnPHandler::getInternalAddress()" << std::endl; + + addr = upnp_iaddr; + bool valid = (upnpState >= RS_UPNP_S_ACTIVE); + + dataMtx.unlock(); /*** UNLOCK MUTEX ***/ + + return valid; +} + +bool upnphandler::getExternalAddress(struct sockaddr_in &addr) +{ +// std::cerr << "UPnPHandler::getExternalAddress() pre Lock!" << std::endl; + dataMtx.lock(); /*** LOCK MUTEX ***/ +// std::cerr << "UPnPHandler::getExternalAddress() postLock!" << std::endl; + + std::cerr << "UPnPHandler::getExternalAddress()" << std::endl; + addr = upnp_eaddr; + bool valid = (upnpState == RS_UPNP_S_ACTIVE); + + dataMtx.unlock(); /*** UNLOCK MUTEX ***/ + + return valid; +} + +#endif diff --git a/libretroshare/src/upnp/upnphandler.h b/libretroshare/src/upnp/upnphandler.h index 81926c19c..f90ac17e5 100644 --- a/libretroshare/src/upnp/upnphandler.h +++ b/libretroshare/src/upnp/upnphandler.h @@ -1,3 +1,6 @@ +//Linux and macos implementation +#ifndef WINDOWS_SYS + #ifndef _RS_UPNP_IFACE_H #define _RS_UPNP_IFACE_H @@ -76,3 +79,119 @@ class upnphandler: public pqiNetAssistFirewall int CtrlPointCallbackEventHandler(Upnp_EventType ,void* , void*); #endif /* _RS_UPNP_IFACE_H */ + +#endif + + + + + + +#ifdef WINDOWS_SYS +//windows implementation +#ifndef _RS_UPNP_IFACE_H +#define _RS_UPNP_IFACE_H + +#include + +#include +#include + +/* platform independent networking... */ +#include "pqi/pqinetwork.h" +#include "pqi/pqiassist.h" + +#include "util/rsthreads.h" + +class upnpentry +{ + public: + std::string name; + std::string id; + struct sockaddr_in addr; + unsigned int flags; + int status; + int lastTs; +}; + +class upnpforward +{ + public: + std::string name; + unsigned int flags; + struct sockaddr_in iaddr; + struct sockaddr_in eaddr; + int status; + int lastTs; +}; + + +#define RS_UPNP_S_UNINITIALISED 0 +#define RS_UPNP_S_UNAVAILABLE 1 +#define RS_UPNP_S_READY 2 +#define RS_UPNP_S_TCP_FAILED 3 +#define RS_UPNP_S_UDP_FAILED 4 +#define RS_UPNP_S_ACTIVE 5 + +class uPnPConfigData; + +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 + */ + +bool start_upnp(); +bool shutdown_upnp(); + +bool initUPnPState(); +bool printUPnPState(); + + private: + +bool background_setup_upnp(bool, bool); +bool checkUPnPActive(); + + /* Mutex for data below */ + RsMutex dataMtx; + + 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 */ + unsigned int upnpState; + uPnPConfigData *upnpConfig; + + struct sockaddr_in upnp_iaddr; + struct sockaddr_in upnp_eaddr; + + /* active port forwarding */ + std::list activeForwards; + +}; + +#endif /* _RS_UPNP_IFACE_H */ +#endif diff --git a/libretroshare/src/upnp/upnptest.cc b/libretroshare/src/upnp/upnptest.cc index 6a7edf2f9..c6f55e787 100644 --- a/libretroshare/src/upnp/upnptest.cc +++ b/libretroshare/src/upnp/upnptest.cc @@ -1,3 +1,4 @@ +//this file use miniupnp #include "upnp/upnphandler.h" diff --git a/libretroshare/src/upnp/upnputil.c b/libretroshare/src/upnp/upnputil.c new file mode 100644 index 000000000..27ce2d65c --- /dev/null +++ b/libretroshare/src/upnp/upnputil.c @@ -0,0 +1,291 @@ +//this file uses miniupnp + +#include "upnp/upnputil.h" + +/* protofix() checks if protocol is "UDP" or "TCP" + * returns NULL if not */ +const char * protofix(const char * proto) +{ + static const char proto_tcp[4] = { 'T', 'C', 'P', 0}; + static const char proto_udp[4] = { 'U', 'D', 'P', 0}; + int i, b; + for(i=0, b=1; i<4; i++) + b = b && ( (proto[i] == proto_tcp[i]) + || (proto[i] == (proto_tcp[i] | 32)) ); + if(b) + return proto_tcp; + for(i=0, b=1; i<4; i++) + b = b && ( (proto[i] == proto_udp[i]) + || (proto[i] == (proto_udp[i] | 32)) ); + if(b) + return proto_udp; + return 0; +} + +void DisplayInfos(struct UPNPUrls * urls, + struct IGDdatas * data) +{ + char externalIPAddress[16]; + char connectionType[64]; + char status[64]; + char lastconnerror[64]; + unsigned int uptime; + unsigned int brUp, brDown; + UPNP_GetConnectionTypeInfo(urls->controlURL, + data->servicetype, + connectionType); + if(connectionType[0]) + printf("Connection Type : %s\n", connectionType); + else + printf("GetConnectionTypeInfo failed.\n"); + UPNP_GetStatusInfo(urls->controlURL, data->servicetype, status, &uptime, lastconnerror); + printf("Status : %s, uptime=%u LastConnError %s\n", status, uptime, lastconnerror); + UPNP_GetLinkLayerMaxBitRates(urls->controlURL_CIF, data->servicetype_CIF, + &brDown, &brUp); + printf("MaxBitRateDown : %u bps MaxBitRateUp %u bps\n", brDown, brUp); + UPNP_GetExternalIPAddress(urls->controlURL, + data->servicetype, + externalIPAddress); + if(externalIPAddress[0]) + printf("ExternalIPAddress = %s\n", externalIPAddress); + else + printf("GetExternalIPAddress failed.\n"); +} + +void GetConnectionStatus(struct UPNPUrls * urls, + struct IGDdatas * data) +{ + unsigned int bytessent, bytesreceived, packetsreceived, packetssent; + DisplayInfos(urls, data); + bytessent = UPNP_GetTotalBytesSent(urls->controlURL_CIF, data->servicetype_CIF); + bytesreceived = UPNP_GetTotalBytesReceived(urls->controlURL_CIF, data->servicetype_CIF); + packetssent = UPNP_GetTotalPacketsSent(urls->controlURL_CIF, data->servicetype_CIF); + packetsreceived = UPNP_GetTotalPacketsReceived(urls->controlURL_CIF, data->servicetype_CIF); + printf("Bytes: Sent: %8u\tRecv: %8u\n", bytessent, bytesreceived); + printf("Packets: Sent: %8u\tRecv: %8u\n", packetssent, packetsreceived); +} + +void ListRedirections(struct UPNPUrls * urls, + struct IGDdatas * data) +{ + int r; + int i = 0; + char index[6]; + char intClient[16]; + char intPort[6]; + char extPort[6]; + char protocol[4]; + char desc[80]; + char enabled[6]; + char rHost[64]; + char duration[16]; + /*unsigned int num=0; + UPNP_GetPortMappingNumberOfEntries(urls->controlURL, data->servicetype, &num); + printf("PortMappingNumberOfEntries : %u\n", num);*/ + do { + snprintf(index, 6, "%d", i); + rHost[0] = '\0'; enabled[0] = '\0'; + duration[0] = '\0'; desc[0] = '\0'; + extPort[0] = '\0'; intPort[0] = '\0'; intClient[0] = '\0'; + r = UPNP_GetGenericPortMappingEntry(urls->controlURL, data->servicetype, + index, + extPort, intClient, intPort, + protocol, desc, enabled, + rHost, duration); + if(r==0) + printf("%02d - %s %s->%s:%s\tenabled=%s leaseDuration=%s\n" + " desc='%s' rHost='%s'\n", + i, protocol, extPort, intClient, intPort, + enabled, duration, + desc, rHost); + i++; + } while(r==0); +} + +/* Test function + * 1 - get connection type + * 2 - get extenal ip address + * 3 - Add port mapping + * 4 - get this port mapping from the IGD */ +bool SetRedirectAndTest(struct UPNPUrls * urls, + struct IGDdatas * data, + const char * iaddr, + const char * iport, + const char * eport, + const char * proto) +{ + char externalIPAddress[16]; + char intClient[16]; + char intPort[6]; + char leaseDuration[] = "3600"; /* 60 mins */ + int r; + int ok = 1; + + if(!iaddr || !iport || !eport || !proto) + { + fprintf(stderr, "Wrong arguments\n"); + return 0; + } + proto = protofix(proto); + if(!proto) + { + fprintf(stderr, "invalid protocol\n"); + return 0; + } + + UPNP_GetExternalIPAddress(urls->controlURL, + data->servicetype, + externalIPAddress); + if(externalIPAddress[0]) + printf("ExternalIPAddress = %s\n", externalIPAddress); + else + printf("GetExternalIPAddress failed.\n"); + +// Unix at the moment! +#if MINIUPNPC_VERSION >= 13 + /* Starting from miniupnpc version 1.2, lease duration parameter is gone */ + r = UPNP_AddPortMapping(urls->controlURL, data->servicetype, + eport, iport, iaddr, 0, proto, NULL); +#else + #if MINIUPNPC_VERSION >= 12 + /* Starting from miniupnpc version 1.2, lease duration parameter is gone */ + r = UPNP_AddPortMapping(urls->controlURL, data->servicetype, + eport, iport, iaddr, 0, proto); + #else + /* The lease parameter is also gone in minupnpc 1.0 */ + r = UPNP_AddPortMapping(urls->controlURL, data->servicetype, + eport, iport, iaddr,0, 0, proto); + #endif +#endif + +// r = UPNP_AddPortMapping(urls->controlURL, data->servicetype, +// eport, iport, iaddr, 0, leaseDuration, proto); + +// r = UPNP_AddPortMapping(urls->controlURL, data->servicetype, +// eport, iport, iaddr, 0, proto); + if(r==0) + { + printf("AddPortMapping(%s, %s, %s) failed\n", eport, iport, iaddr); + //this seems to trigger for unknown reasons sometimes. + //rely on Checking it afterwards... + //should check IP address then! + //ok = 0; + } + + UPNP_GetSpecificPortMappingEntry(urls->controlURL, + data->servicetype, + eport, proto, + intClient, intPort); + if(intClient[0]) + printf("InternalIP:Port = %s:%s\n", intClient, intPort); + else + { + printf("GetSpecificPortMappingEntry failed.\n"); + ok = 0; + } + + if ((strcmp(iaddr, intClient) != 0) || (strcmp(iport, intPort) != 0)) + { + printf("PortMappingEntry to wrong location! FAILED\n"); + printf("IP1:\"%s\"\n", iaddr); + printf("IP2:\"%s\"\n", intClient); + printf("PORT1:\"%s\"\n", iport); + printf("PORT2:\"%s\"\n", intPort); + ok = 0; + } + + printf("external %s:%s is redirected to internal %s:%s\n", + externalIPAddress, eport, intClient, intPort); + + if (ok) + { + printf("uPnP Forward/Mapping Succeeded\n"); + } + else + { + printf("uPnP Forward/Mapping Failed\n"); + } + + return ok; +} + +bool TestRedirect(struct UPNPUrls * urls, + struct IGDdatas * data, + const char * iaddr, + const char * iport, + const char * eport, + const char * proto) +{ + char intClient[16]; + char intPort[6]; + int ok = 1; + + if(!iaddr || !iport || !eport || !proto) + { + fprintf(stderr, "Wrong arguments\n"); + return 0; + } + proto = protofix(proto); + if(!proto) + { + fprintf(stderr, "invalid protocol\n"); + return 0; + } + + UPNP_GetSpecificPortMappingEntry(urls->controlURL, + data->servicetype, + eport, proto, + intClient, intPort); + if(intClient[0]) + printf("uPnP Check: InternalIP:Port = %s:%s\n", intClient, intPort); + else + { + printf("GetSpecificPortMappingEntry failed.\n"); + ok = 0; + } + + printf("uPnP Check: External port %s is redirected to internal %s:%s\n", + eport, intClient, intPort); + + if (ok) + { + printf("uPnP Check: uPnP Forward/Mapping still Active\n"); + } + else + { + printf("uPnP Check: Forward/Mapping has been Dropped\n"); + } + + return ok; +} + + + +bool +RemoveRedirect(struct UPNPUrls * urls, + struct IGDdatas * data, + const char * eport, + const char * proto) +{ + if(!proto || !eport) + { + fprintf(stderr, "invalid arguments\n"); + return 0; + } + proto = protofix(proto); + if(!proto) + { + fprintf(stderr, "protocol invalid\n"); + return 0; + } +#if MINIUPNPC_VERSION >= 13 + UPNP_DeletePortMapping(urls->controlURL, data->servicetype, eport, proto, NULL); +#else + UPNP_DeletePortMapping(urls->controlURL, data->servicetype, eport, proto); +#endif + + return 1; +} + + +/* EOF */ diff --git a/libretroshare/src/upnp/upnputil.h b/libretroshare/src/upnp/upnputil.h new file mode 100644 index 000000000..3a132c00c --- /dev/null +++ b/libretroshare/src/upnp/upnputil.h @@ -0,0 +1,56 @@ +//this file uses miniupnp + +#ifndef MINIUPNP_UTIL_H_ +#define MINIUPNP_UTIL_H_ + +/* $Id: upnpc.c,v 1.50 2007/04/26 19:00:10 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas Bernard + * Copyright (c) 2005 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. + * */ +#include +#include +#include +#ifdef WIN32 +#include +#define snprintf _snprintf +#endif +#include +#include +#include + +/* protofix() checks if protocol is "UDP" or "TCP" + * returns NULL if not */ +const char * protofix(const char * proto); +void DisplayInfos(struct UPNPUrls * urls, + struct IGDdatas * data); + +void GetConnectionStatus(struct UPNPUrls * urls, + struct IGDdatas * data); + +void ListRedirections(struct UPNPUrls * urls, + struct IGDdatas * data); + +bool SetRedirectAndTest(struct UPNPUrls * urls, + struct IGDdatas * data, + const char * iaddr, + const char * iport, + const char * eport, + const char * proto); + +bool TestRedirect(struct UPNPUrls * urls, + struct IGDdatas * data, + const char * iaddr, + const char * iport, + const char * eport, + const char * proto); + +bool RemoveRedirect(struct UPNPUrls * urls, + struct IGDdatas * data, + const char * eport, + const char * proto); + +/* EOF */ +#endif