From 79998dd70c6855c48a8f952c3c2d5dd3dbc52109 Mon Sep 17 00:00:00 2001 From: drbob Date: Sat, 14 Jan 2012 16:41:00 +0000 Subject: [PATCH] Added Native (Bonjour API) Nat Port Forwarding to OSX. * new classe p3zcNatAssist * moved some common ZeroConf functions / definitions around. * moved virtual tick() to parent class: pqiNetAssist * added zcNetAssist section to makefiles. (active for OSX build) * setup switch between p3zcNatAssist & upnphandler in rsinit.cc NOTE: Still to test network restart, etc, and correct exchange of external Ip Address. git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@4800 b45a01b8-16f6-495d-af2f-9b41ad6348cc --- libretroshare/src/libretroshare.pro | 16 + libretroshare/src/pqi/p3netmgr.cc | 10 +- libretroshare/src/pqi/p3netmgr.h | 4 +- libretroshare/src/pqi/pqiassist.h | 4 +- libretroshare/src/rsserver/rsinit.cc | 12 +- libretroshare/src/zeroconf/p3zcnatassist.cc | 434 ++++++++++++++++++++ libretroshare/src/zeroconf/p3zcnatassist.h | 110 +++++ libretroshare/src/zeroconf/p3zeroconf.cc | 8 +- libretroshare/src/zeroconf/p3zeroconf.h | 7 +- 9 files changed, 589 insertions(+), 16 deletions(-) create mode 100644 libretroshare/src/zeroconf/p3zcnatassist.cc create mode 100644 libretroshare/src/zeroconf/p3zcnatassist.h diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index d18120245..277eb9419 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -314,6 +314,7 @@ mac { SOURCES += upnp/upnputil.c CONFIG += zeroconf + CONFIG += zcnatassist # Beautiful Hack to fix 64bit file access. QMAKE_CXXFLAGS *= -Dfseeko64=fseeko -Dftello64=ftello -Dfopen64=fopen -Dvstatfs64=vstatfs @@ -647,6 +648,7 @@ minimal { services/p3photoservice.cc } + zeroconf { HEADERS += zeroconf/p3zeroconf.h \ @@ -657,3 +659,17 @@ SOURCES += zeroconf/p3zeroconf.cc \ } +# This is seperated from the above for windows/linux platforms. +# It is acceptable to build in zeroconf and have it not work, +# but unacceptable to rely on Apple's libraries for Upnp when we have alternatives. + +zcnatassist { + +HEADERS += zeroconf/p3zcnatassist.h \ + +SOURCES += zeroconf/p3zcnatassist.cc \ + + DEFINES *= RS_ENABLE_ZCNATASSIST + +} + diff --git a/libretroshare/src/pqi/p3netmgr.cc b/libretroshare/src/pqi/p3netmgr.cc index 727ad9f35..357261d79 100644 --- a/libretroshare/src/pqi/p3netmgr.cc +++ b/libretroshare/src/pqi/p3netmgr.cc @@ -429,7 +429,7 @@ void p3NetMgrIMPL::tick() void p3NetMgrIMPL::slowTick() { netTick(); - netAssistConnectTick(); + netAssistTick(); updateNetStateBox_temporal(); if (mDhtStunner) @@ -1489,13 +1489,19 @@ bool p3NetMgrIMPL::netAssistSetAddress( struct sockaddr_in &/*laddr*/, return true; } -void p3NetMgrIMPL::netAssistConnectTick() +void p3NetMgrIMPL::netAssistTick() { std::map::iterator it; for(it = mDhts.begin(); it != mDhts.end(); it++) { (it->second)->tick(); } + + std::map::iterator fit; + for(fit = mFwAgents.begin(); fit != mFwAgents.end(); fit++) + { + (fit->second)->tick(); + } return; } diff --git a/libretroshare/src/pqi/p3netmgr.h b/libretroshare/src/pqi/p3netmgr.h index 0c403d69a..0eee04f29 100644 --- a/libretroshare/src/pqi/p3netmgr.h +++ b/libretroshare/src/pqi/p3netmgr.h @@ -258,7 +258,9 @@ bool netAssistConnectEnabled(); bool netAssistConnectActive(); bool netAssistConnectShutdown(); bool netAssistConnectStats(uint32_t &netsize, uint32_t &localnetsize); -void netAssistConnectTick(); + +void netAssistTick(); + /* Assist Firewall */ bool netAssistExtAddress(struct sockaddr_in &extAddr); bool netAssistFirewallPorts(uint16_t iport, uint16_t eport); diff --git a/libretroshare/src/pqi/pqiassist.h b/libretroshare/src/pqi/pqiassist.h index aaa9d6770..06cb5d434 100644 --- a/libretroshare/src/pqi/pqiassist.h +++ b/libretroshare/src/pqi/pqiassist.h @@ -60,6 +60,8 @@ virtual void restart() = 0; virtual bool getEnabled() = 0; virtual bool getActive() = 0; +virtual int tick() { return 0; } /* for internal accounting */ + }; class pqiNetAssistFirewall: public pqiNetAssist @@ -135,8 +137,6 @@ class pqiNetAssistConnect: public pqiNetAssist * for the DHT, and must be non-blocking and return quickly */ -virtual int tick() = 0; /* for internal accounting */ - /* add / remove peers */ virtual bool findPeer(std::string id) = 0; diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index 587e7de3b..f1a839f11 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -1747,7 +1747,10 @@ RsTurtle *rsTurtle = NULL ; #ifdef RS_ENABLE_ZEROCONF #include "zeroconf/p3zeroconf.h" - //#include "zeroconf/p3zcnatassist.h" +#endif + +#ifdef RS_ENABLE_ZCNATASSIST + #include "zeroconf/p3zcnatassist.h" #else #include "upnp/upnphandler.h" #endif @@ -2264,12 +2267,13 @@ int RsServer::StartupRetroShare() mLinkMgr, mNetMgr, mPeerMgr); mNetMgr->addNetAssistConnect(2, mZeroConf); mNetMgr->addNetListener(mZeroConf); +#endif +#ifdef RS_ENABLE_ZCNATASSIST // Apple's UPnP & NAT-PMP assistance. - //p3zcNatAssist *mZcNatAssist = new p3zcNatAssist(); - //mNetMgr->addNetAssistFirewall(2, mZcNatAssist); + p3zcNatAssist *mZcNatAssist = new p3zcNatAssist(); + mNetMgr->addNetAssistFirewall(1, mZcNatAssist); #else - // Original UPnP Interface. pqiNetAssistFirewall *mUpnpMgr = new upnphandler(); mNetMgr->addNetAssistFirewall(1, mUpnpMgr); diff --git a/libretroshare/src/zeroconf/p3zcnatassist.cc b/libretroshare/src/zeroconf/p3zcnatassist.cc new file mode 100644 index 000000000..953897a59 --- /dev/null +++ b/libretroshare/src/zeroconf/p3zcnatassist.cc @@ -0,0 +1,434 @@ +/* + * libretroshare/src/zeroconf: p3zeroconf.cc + * + * ZeroConf interface for RetroShare. + * + * Copyright 2011-2011 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 2 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 "zeroconf/p3zeroconf.h" +#include "zeroconf/p3zcnatassist.h" + +#include +#include +#include + +#define DEBUG_ZCNATASSIST 1 + + +p3zcNatAssist::p3zcNatAssist() + :mZcMtx("p3zcNatAssist") +{ + +#ifdef DEBUG_ZCNATASSIST + std::cerr << "p3zcNatAssist::p3zcNatAssist()" << std::endl; + std::cerr << std::endl; +#endif + + mMappingStatus = ZC_SERVICE_STOPPED; + mMappingStatusTS = time(NULL); + + mLocalPort = 0; + mLocalPortSet = false; + + mExternalPort = 0; + mExternalPortSet = false; + + mMapped = false; + +} + +p3zcNatAssist::~p3zcNatAssist() +{ + shutdown(); +} + + /* pqiNetAssist - external interface functions */ +void p3zcNatAssist::enable(bool on) +{ +#ifdef DEBUG_ZCNATASSIST + std::cerr << "p3zcNatAssist::enable(" << on << ")"; + std::cerr << std::endl; +#endif + + RsStackMutex stack(mZcMtx); /****** STACK LOCK MUTEX *******/ + + mEnabled = on; + + if ((!mEnabled) && (mMappingStatus == ZC_SERVICE_ACTIVE)) + { + locked_stopMapping(); + } + +} + +void p3zcNatAssist::shutdown() /* blocking call */ +{ + +#ifdef DEBUG_ZCNATASSIST + std::cerr << "p3zcNatAssist::shutdown()"; + std::cerr << std::endl; +#endif + + enable(false); +} + +void p3zcNatAssist::restart() +{ +#ifdef DEBUG_ZCNATASSIST + std::cerr << "p3zcNatAssist::restart()"; + std::cerr << std::endl; +#endif + + RsStackMutex stack(mZcMtx); /****** STACK LOCK MUTEX *******/ + + if (mMappingStatus == ZC_SERVICE_ACTIVE) + { + locked_stopMapping(); + } +} + +bool p3zcNatAssist::getEnabled() +{ + RsStackMutex stack(mZcMtx); /****** STACK LOCK MUTEX *******/ + +#ifdef DEBUG_ZCNATASSIST + std::cerr << "p3zcNatAssist::getEnabled() : " << mEnabled; + std::cerr << std::endl; +#endif + + return mEnabled; +} + +bool p3zcNatAssist::getActive() +{ + RsStackMutex stack(mZcMtx); /****** STACK LOCK MUTEX *******/ + +#ifdef DEBUG_ZCNATASSIST + std::cerr << "p3zcNatAssist::getActive() : " << (mEnabled && mMapped); + std::cerr << std::endl; +#endif + + return (mEnabled && mMapped); +} + +void p3zcNatAssist::setInternalPort(unsigned short iport_in) +{ + +#ifdef DEBUG_ZCNATASSIST + std::cerr << "p3zcNatAssist::setInternalPort() : " << iport_in; + std::cerr << std::endl; +#endif + + bool changed = false; + { + RsStackMutex stack(mZcMtx); /****** STACK LOCK MUTEX *******/ + + changed = (mEnabled) && (mLocalPort != iport_in); + mLocalPort = iport_in; + mLocalPortSet = true; + + } + + if (changed) + { + restart(); + } +} + +void p3zcNatAssist::setExternalPort(unsigned short eport_in) +{ + +#ifdef DEBUG_ZCNATASSIST + std::cerr << "p3zcNatAssist::setExternalPort() : " << eport_in; + std::cerr << std::endl; +#endif + + bool changed = false; + { + RsStackMutex stack(mZcMtx); /****** STACK LOCK MUTEX *******/ + + changed = (mEnabled) && (mExternalPort != eport_in); + mExternalPort = eport_in; + mExternalPortSet = true; + + } + + if (changed) + { + restart(); + } +} + +bool p3zcNatAssist::getInternalAddress(struct sockaddr_in &addr) +{ + +#ifdef DEBUG_ZCNATASSIST + std::cerr << "p3zcNatAssist::getInternalAddress() always returns false"; + std::cerr << std::endl; +#endif + + return false; +} + + +bool p3zcNatAssist::getExternalAddress(struct sockaddr_in &addr) +{ + RsStackMutex stack(mZcMtx); /****** STACK LOCK MUTEX *******/ + + if (mMapped) + { +#ifdef DEBUG_ZCNATASSIST + std::cerr << "p3zcNatAssist::getExternalAddress() mMapped => true"; + std::cerr << std::endl; +#endif + addr = mExternalAddress; + return true; + } + + +#ifdef DEBUG_ZCNATASSIST + std::cerr << "p3zcNatAssist::getExternalAddress() !mMapped => false"; + std::cerr << std::endl; +#endif + + return false; +} + + +/***********************************************************************************/ + +int p3zcNatAssist::tick() +{ + { + RsStackMutex stack(mZcMtx); /****** STACK LOCK MUTEX *******/ + + locked_startMapping(); + } + + + checkServiceFDs(); // will cause callbacks - if data is ready. + + return 0; +} + +void p3zcNatAssist::checkServiceFDs() +{ + RsStackMutex stack(mZcMtx); /****** STACK LOCK MUTEX *******/ + + if (mMappingStatus == ZC_SERVICE_ACTIVE) + { + locked_checkFD(mMappingRef); + } +} + + +void p3zcNatAssist::locked_checkFD(DNSServiceRef ref) +{ + //std::cerr << "p3zcNatAssist::locked_checkFD() Start"; + //std::cerr << std::endl; + + int sockfd = DNSServiceRefSockFD(ref); + + fd_set ReadFDs, WriteFDs, ExceptFDs; + FD_ZERO(&ReadFDs); + FD_ZERO(&WriteFDs); + FD_ZERO(&ExceptFDs); + + FD_SET(sockfd, &ReadFDs); + + struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 0; + + if (select(sockfd + 1, &ReadFDs, &WriteFDs, &ExceptFDs, &timeout) < 0) + { + std::cerr << "p3zeroconf::checkFD() Select ERROR"; + std::cerr << std::endl; + return; + } + + if (FD_ISSET(sockfd, &ReadFDs)) + { + DNSServiceErrorType err = DNSServiceProcessResult(ref); + switch(err) + { + case 0: + /* ok */ + break; + default: + std::cerr << "DNSServiceProcessResult() ERROR: "; + std::cerr << displayDNSServiceError(err); + std::cerr << std::endl; + break; + } + } + + //std::cerr << "p3zcNatAssist::locked_checkFD() End"; + //std::cerr << std::endl; + return; + +} + + +void p3zcNatAssist_CallbackMapping( DNSServiceRef sdRef, DNSServiceFlags flags, + uint32_t interfaceIndex, DNSServiceErrorType errorCode, + uint32_t externalAddress, DNSServiceProtocol protocol, + uint16_t internalPort, uint16_t externalPort, + uint32_t ttl, void *context ) +{ + p3zcNatAssist *zc = (p3zcNatAssist *) context; + zc->callbackMapping(sdRef, flags, interfaceIndex, errorCode, externalAddress, protocol, internalPort, externalPort, ttl); +} + + +int p3zcNatAssist::locked_startMapping() +{ + if (!mEnabled) + { + std::cerr << "p3zcNatAssist::locked_startMapping()"; + std::cerr << "NatAssist not Enabled"; + std::cerr << std::endl; + return 0; + } + + if (!mLocalPortSet) + { + std::cerr << "p3zcNatAssist::locked_startMapping()"; + std::cerr << "Port Not Set"; + std::cerr << std::endl; + return 0; + } + + if (mMappingStatus == ZC_SERVICE_ACTIVE) + { + return 0; + } + + + std::cerr << "p3zcNatAssist::locked_startMapping() Mapping!"; + std::cerr << std::endl; + std::cerr << "p3zcNatAssist::locked_startMapping() Local Port: " << mLocalPort; + std::cerr << std::endl; + + DNSServiceRef *sdRef = &mMappingRef; + DNSServiceFlags flags = 0; /* no flags, currently reserved */ + uint32_t interfaceIndex = 0; /* primary interface */ + + DNSServiceProtocol protocol = (kDNSServiceProtocol_UDP | kDNSServiceProtocol_TCP); + uint16_t internalPort = htons(mLocalPort); + uint16_t externalPort = htons(mLocalPort); + if (mExternalPortSet) + { + externalPort = htons(mExternalPort); + } + + std::cerr << "p3zcNatAssist::locked_startMapping() External Port: " << ntohs(externalPort); + std::cerr << std::endl; + + uint32_t ttl = 0; /* default ttl */ + + DNSServiceNATPortMappingReply callBack = p3zcNatAssist_CallbackMapping; + void *context = this; + + DNSServiceErrorType errcode = DNSServiceNATPortMappingCreate(sdRef, flags, interfaceIndex, protocol, + internalPort, externalPort, ttl, callBack, context); + + if (errcode != kDNSServiceErr_NoError) + { + std::cerr << "p3zcNatAssist::locked_startMapping() ERROR: "; + std::cerr << displayDNSServiceError(errcode); + std::cerr << std::endl; + } + else + { + mMappingStatus = ZC_SERVICE_ACTIVE; + mMappingStatusTS = time(NULL); + } + + return 1; +} + + + +void p3zcNatAssist::callbackMapping(DNSServiceRef sdRef, DNSServiceFlags flags, + uint32_t interfaceIndex, DNSServiceErrorType errorCode, + uint32_t externalAddress, DNSServiceProtocol protocol, + uint16_t internalPort, uint16_t externalPort, uint32_t ttl) +{ + std::cerr << "p3zcNatAssist::callbackMapping()"; + std::cerr << std::endl; + + /* handle queryIp */ + if (errorCode != kDNSServiceErr_NoError) + { + std::cerr << "p3zcNatAssist::callbackMapping() FAILED ERROR: "; + std::cerr << displayDNSServiceError(errorCode); + std::cerr << std::endl; + return; + } + + mMapped = true; + mExternalAddress.sin_addr.s_addr = externalAddress; + mExternalAddress.sin_port = externalPort; + mTTL = ttl; + + + std::cerr << "p3zcNatAssist::callbackMapping() Success"; + std::cerr << std::endl; + + std::cerr << "interfaceIndex: " << interfaceIndex; + std::cerr << std::endl; + + std::cerr << "internalPort: " << ntohs(internalPort); + std::cerr << std::endl; + + std::cerr << "externalAddress: " << rs_inet_ntoa(mExternalAddress.sin_addr); + std::cerr << ":" << ntohs(mExternalAddress.sin_port); + std::cerr << std::endl; + + std::cerr << "protocol: " << protocol; + std::cerr << std::endl; + + std::cerr << "ttl: " << ttl; + std::cerr << std::endl; + +} + + +void p3zcNatAssist::locked_stopMapping() +{ + std::cerr << "p3zcNatAssist::locked_stopMapping()"; + std::cerr << std::endl; + + if (mMappingStatus != ZC_SERVICE_ACTIVE) + { + return; + } + + DNSServiceRefDeallocate(mMappingRef); + + mMappingStatus = ZC_SERVICE_STOPPED; + mMappingStatusTS = time(NULL); + mMapped = false; +} + + diff --git a/libretroshare/src/zeroconf/p3zcnatassist.h b/libretroshare/src/zeroconf/p3zcnatassist.h new file mode 100644 index 000000000..5171107ee --- /dev/null +++ b/libretroshare/src/zeroconf/p3zcnatassist.h @@ -0,0 +1,110 @@ +/* + * libretroshare/src/zeroconf: p3zcnatassist.h + * + * ZeroConf interface for RetroShare. + * + * Copyright 2011-2012 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 2 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". + * + */ + + +#ifndef MRK_P3_ZC_NAT_ASSIST_H +#define MRK_P3_ZC_NAT_ASSIST_H + +#include "util/rswin.h" + +#include "pqi/pqiassist.h" +#include "retroshare/rsdht.h" + +#include +#include +#include "pqi/pqinetwork.h" +#include "pqi/pqimonitor.h" +#include "pqi/p3peermgr.h" +#include "util/rsthreads.h" + +#include + + +class p3NetMgr; + +class p3zcNatAssist: public pqiNetAssistFirewall +{ + public: + p3zcNatAssist(); +virtual ~p3zcNatAssist(); + + /* pqiNetAssist - external interface functions */ +virtual int tick(); +virtual void enable(bool on); +virtual void shutdown(); /* blocking call */ +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); + + + /* pqiNetAssistConnect - external interface functions */ + + + public: + + // Callbacks must be public -> so they can be accessed. + void callbackMapping(DNSServiceRef sdRef, DNSServiceFlags flags, + uint32_t interfaceIndex, DNSServiceErrorType errorCode, + uint32_t externalAddress, DNSServiceProtocol protocol, + uint16_t internalPort, uint16_t externalPort, uint32_t ttl); + + private: + + /* monitoring fns */ + void checkServiceFDs(); + void locked_checkFD(DNSServiceRef ref); + + int locked_startMapping(); + void locked_stopMapping(); + + /**************** DATA ****************/ + + RsMutex mZcMtx; + + bool mEnabled; + bool mMapped; + + uint16_t mLocalPort; + bool mLocalPortSet; + + uint16_t mExternalPort; + bool mExternalPortSet; + + struct sockaddr_in mExternalAddress; + int mTTL; + + DNSServiceRef mMappingRef; + uint32_t mMappingStatus; + time_t mMappingStatusTS; +}; + +#endif /* MRK_P3_ZC_NAT_ASSIST_H */ + diff --git a/libretroshare/src/zeroconf/p3zeroconf.cc b/libretroshare/src/zeroconf/p3zeroconf.cc index 552643e36..3fad20ad4 100644 --- a/libretroshare/src/zeroconf/p3zeroconf.cc +++ b/libretroshare/src/zeroconf/p3zeroconf.cc @@ -43,10 +43,6 @@ #define DEBUG_ZEROCONF 1 - -#define ZC_SERVICE_STOPPED 0 -#define ZC_SERVICE_ACTIVE 1 - #define ZC_MAX_QUERY_TIME 30 #define ZC_MAX_RESOLVE_TIME 30 @@ -695,7 +691,7 @@ void p3ZeroConf::locked_stopRegister() std::cerr << "p3ZeroConf::locked_stopRegister()"; std::cerr << std::endl; - if (mBrowseStatus != ZC_SERVICE_ACTIVE) + if (mRegisterStatus != ZC_SERVICE_ACTIVE) { return; } @@ -1250,7 +1246,7 @@ int p3ZeroConf::locked_stopQueryIp() -std::string p3ZeroConf::displayDNSServiceError(DNSServiceErrorType errcode) +std::string displayDNSServiceError(DNSServiceErrorType errcode) { std::ostringstream str; switch(errcode) diff --git a/libretroshare/src/zeroconf/p3zeroconf.h b/libretroshare/src/zeroconf/p3zeroconf.h index e52a76e1c..d1130cf94 100644 --- a/libretroshare/src/zeroconf/p3zeroconf.h +++ b/libretroshare/src/zeroconf/p3zeroconf.h @@ -135,6 +135,12 @@ class zcPeerDetails }; +#define ZC_SERVICE_STOPPED 0 +#define ZC_SERVICE_ACTIVE 1 + +// This is used by p3zcNatAssist too. +std::string displayDNSServiceError(DNSServiceErrorType errcode); + class p3NetMgr; class p3ZeroConf: public pqiNetAssistConnect, public pqiNetListener @@ -233,7 +239,6 @@ virtual bool setAttachMode(bool on); int locked_completeQueryResult(zcQueryResult &qr); int locked_stopQueryIp(); - std::string displayDNSServiceError(DNSServiceErrorType errcode); /**************** DATA ****************/