/* * Copyright (c) 2011 Tobias Markmann * Licensed under the simplified BSD license. * See Documentation/Licenses/BSD-simplified.txt for more information. */ #include "PlatformNATTraversalWorker.h" #include #include #include #include #include #include #include #include namespace Swift { class PlatformNATTraversalRequest : public boost::enable_shared_from_this { public: typedef boost::shared_ptr ref; public: PlatformNATTraversalRequest(PlatformNATTraversalWorker* worker) : worker(worker) { } virtual ~PlatformNATTraversalRequest() { } virtual void doRun() { worker->addRequestToQueue(shared_from_this()); } NATTraversalInterface* getNATTraversalInterface() const { return worker->getNATTraversalInterface(); } virtual void runBlocking() = 0; private: PlatformNATTraversalWorker* worker; }; class PlatformNATTraversalGetPublicIPRequest : public NATTraversalGetPublicIPRequest, public PlatformNATTraversalRequest { public: PlatformNATTraversalGetPublicIPRequest(PlatformNATTraversalWorker* worker) : PlatformNATTraversalRequest(worker) { } virtual void run() { doRun(); } virtual void runBlocking() { onResult(getNATTraversalInterface()->getPublicIP()); } }; class PlatformNATTraversalForwardPortRequest : public NATTraversalForwardPortRequest, public PlatformNATTraversalRequest { public: PlatformNATTraversalForwardPortRequest(PlatformNATTraversalWorker* worker, unsigned int localIP, unsigned int publicIP) : PlatformNATTraversalRequest(worker), localIP(localIP), publicIP(publicIP) { } virtual void run() { doRun(); } virtual void runBlocking() { onResult(getNATTraversalInterface()->addPortForward(localIP, publicIP)); } private: unsigned int localIP; unsigned int publicIP; }; class PlatformNATTraversalRemovePortForwardingRequest : public NATTraversalRemovePortForwardingRequest, public PlatformNATTraversalRequest { public: PlatformNATTraversalRemovePortForwardingRequest(PlatformNATTraversalWorker* worker, const NATPortMapping& mapping) : PlatformNATTraversalRequest(worker), mapping(mapping) { } virtual void run() { doRun(); } virtual void runBlocking() { onResult(getNATTraversalInterface()->removePortForward(mapping)); } private: NATPortMapping mapping; }; PlatformNATTraversalWorker::PlatformNATTraversalWorker(EventLoop* eventLoop) : eventLoop(eventLoop), stopRequested(false), natPMPSupported(boost::logic::indeterminate), natPMPInterface(NULL), miniUPnPSupported(boost::logic::indeterminate), miniUPnPInterface(NULL) { nullNATTraversalInterface = new NullNATTraversalInterface(); thread = new boost::thread(boost::bind(&PlatformNATTraversalWorker::run, this)); } PlatformNATTraversalWorker::~PlatformNATTraversalWorker() { stopRequested = true; addRequestToQueue(boost::shared_ptr()); thread->join(); delete thread; delete natPMPInterface; delete miniUPnPInterface; delete nullNATTraversalInterface; } NATTraversalInterface* PlatformNATTraversalWorker::getNATTraversalInterface() const { if (boost::logic::indeterminate(miniUPnPSupported)) { miniUPnPInterface = new MiniUPnPInterface(); miniUPnPSupported = miniUPnPInterface->isAvailable(); } if (miniUPnPSupported) { return miniUPnPInterface; } if (boost::logic::indeterminate(natPMPSupported)) { natPMPInterface = new NATPMPInterface(); natPMPSupported = natPMPInterface->isAvailable(); } if (natPMPSupported) { return natPMPInterface; } return nullNATTraversalInterface; } boost::shared_ptr PlatformNATTraversalWorker::createGetPublicIPRequest() { return boost::make_shared(this); } boost::shared_ptr PlatformNATTraversalWorker::createForwardPortRequest(int localPort, int publicPort) { return boost::make_shared(this, localPort, publicPort); } boost::shared_ptr PlatformNATTraversalWorker::createRemovePortForwardingRequest(int localPort, int publicPort) { NATPortMapping mapping(localPort, publicPort, NATPortMapping::TCP); // FIXME return boost::make_shared(this, mapping); } void PlatformNATTraversalWorker::run() { while (!stopRequested) { PlatformNATTraversalRequest::ref request; { boost::unique_lock lock(queueMutex); while (queue.empty()) { queueNonEmpty.wait(lock); } request = queue.front(); queue.pop_front(); } // Check whether we don't have a non-null request (used to stop the // worker) if (request) { request->runBlocking(); } } } void PlatformNATTraversalWorker::addRequestToQueue(PlatformNATTraversalRequest::ref request) { { boost::lock_guard lock(queueMutex); queue.push_back(request); } queueNonEmpty.notify_one(); } }