/* * 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 #include namespace Swift { PlatformNATTraversalWorker::PlatformNATTraversalWorker(EventLoop* eventLoop) : backendType(NotYetDecided), eventLoop(eventLoop), stopRequested(false) { checkAvailableNATTraversalProtocols(); thread = new boost::thread(boost::bind(&PlatformNATTraversalWorker::run, this)); } PlatformNATTraversalWorker::~PlatformNATTraversalWorker() { stopRequested = true; addRequestToQueue(boost::shared_ptr()); thread->join(); delete thread; } boost::shared_ptr PlatformNATTraversalWorker::createGetPublicIPRequest() { switch(backendType) { case UPnP: return boost::make_shared(this); case NATPMP: return boost::make_shared(this); case NotYetDecided: case None: break; } return boost::shared_ptr(); } boost::shared_ptr PlatformNATTraversalWorker::createForwardPortRequest(unsigned int localPort, unsigned int publicPort) { PlatformNATTraversalForwardPortRequest::PortMapping mapping; mapping.protocol = PlatformNATTraversalForwardPortRequest::PortMapping::TCP; mapping.leaseInSeconds = 60 * 60 * 24; mapping.localPort = localPort; mapping.publicPort = publicPort; switch(backendType) { case UPnP: return boost::make_shared(mapping, this); case NATPMP: return boost::make_shared(mapping, this); case NotYetDecided: case None: break; } return boost::shared_ptr(); } boost::shared_ptr PlatformNATTraversalWorker::createRemovePortForwardingRequest(unsigned int localPort, unsigned int publicPort) { PlatformNATTraversalRemovePortForwardingRequest::PortMapping mapping; mapping.protocol = PlatformNATTraversalRemovePortForwardingRequest::PortMapping::TCP; mapping.leaseInSeconds = 60 * 60 * 24; mapping.localPort = localPort; mapping.publicPort = publicPort; switch(backendType) { case UPnP: return boost::make_shared(mapping, this); case NATPMP: return boost::make_shared(mapping, this); case NotYetDecided: case None: break; } return boost::shared_ptr(); } 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(); } void PlatformNATTraversalWorker::checkAvailableNATTraversalProtocols() { boost::shared_ptr upnpRequest = boost::make_shared(this); upnpRequest->onResult.connect(boost::bind(&PlatformNATTraversalWorker::handleUPnPGetPublicIPResult, this, _1)); boost::shared_ptr natpmpRequest = boost::make_shared(this); natpmpRequest->onResult.connect(boost::bind(&PlatformNATTraversalWorker::handleNATPMPGetPublicIPResult, this, _1)); upnpRequest->run(); natpmpRequest->run(); } void PlatformNATTraversalWorker::handleUPnPGetPublicIPResult(boost::optional address) { if (backendType == NotYetDecided || backendType == None) { if (address) { SWIFT_LOG(debug) << "Found UPnP IGD in the local network." << std::endl; backendType = UPnP; } } } void PlatformNATTraversalWorker::handleNATPMPGetPublicIPResult(boost::optional address) { if (backendType == NotYetDecided || backendType == None) { if (address) { SWIFT_LOG(debug) << "Found NAT-PMP device in the local network." << std::endl; backendType = NATPMP; } } } }