示例#1
0
void UpnpPortMapping::mapPort(const std::string& gateway, const std::string& client, uint16_t port, PortType type, bool enable)
{
	{
		std::lock_guard<std::mutex> guard(state->stateMutex);

		for (auto it = state->pendingRequests.begin(); it != state->pendingRequests.end(); it++)
		{
			if ((*it)->getHostname() == gateway)
			{
				UpnpMappingState::TodoMapping todo;
				todo.mapping = { gateway, port, type };
				todo.client = client;
				todo.enable = enable;
				todo.blockingStream = (*it).get();
				state->waitingMapping.push_back(todo);
				return;
			}
		}	
	}

	std::string portStr = std::to_string(port);
	std::string portType = type == PortType::Tcp ? "TCP" : "UDP";

	auto request = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
		"<s:Envelope xmlns:s =\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n"
		"<s:Body>\n"
		"<u:AddPortMapping xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">\n"
		"<NewRemoteHost></NewRemoteHost>\n"
		"<NewExternalPort>" + portStr + "</NewExternalPort>\n"
		"<NewProtocol>" + portType + "</NewProtocol>\n"
		"<NewInternalPort>" + portStr + "</NewInternalPort>\n"
		"<NewInternalClient>" + client + "</NewInternalClient>\n"
		"<NewEnabled>" + std::string(enable ? "1" : "0") + "</NewEnabled>\n"
		"<NewPortMappingDescription>mtTorrent UPnP " + portStr + " " + portType + "</NewPortMappingDescription>\n"
		"<NewLeaseDuration>0</NewLeaseDuration>\n"
		"</u:AddPortMapping>\n"
		"</s:Body>\n"
		"</s:Envelope>\r\n";

	auto httpHeader = createUpnpHttpHeader(gateway + ":1900", request.length(), "urn:schemas-upnp-org:service:WANIPConnection:1#AddPortMapping");

	auto stream = std::make_shared<TcpAsyncStream>(io);
	state->pendingRequests.push_back(stream);
	auto streamPtr = stream.get();
	auto upnpState = state;

	stream->onConnectCallback = [streamPtr, httpHeader, request]()
	{
		DataBuffer buffer;	
		buffer.assign(httpHeader.begin(), httpHeader.end());
		buffer.insert(buffer.end(), request.begin(), request.end());

		streamPtr->write(buffer);
	};

	stream->onReceiveCallback = [streamPtr, upnpState, gateway, port, type]()
	{
		auto data = streamPtr->getReceivedData();
		auto header = HttpHeaderInfo::readFromBuffer(data);

		if (header.valid && data.size() >= (header.dataStart + header.dataSize))
		{
			streamPtr->consumeData(header.dataStart + header.dataSize);

			std::lock_guard<std::mutex> guard(upnpState->stateMutex);

			if (header.success)
			{
				upnpState->mappedPorts.push_back({ gateway, port, type });
			}
		}
	};

	stream->onCloseCallback = [streamPtr, upnpState, this](int code)
	{
		{
			std::lock_guard<std::mutex> guard(upnpState->stateMutex);

			for (auto it = upnpState->pendingRequests.begin(); it != upnpState->pendingRequests.end(); it++)
			{
				if ((*it).get() == streamPtr)
				{
					upnpState->pendingRequests.erase(it);
					break;
				}
			}
		}

		if (upnpState->active)
		{
			checkPendingMapping(streamPtr);
		}
	};

	stream->connect(gateway, 1900);
}
示例#2
0
void UpnpPortMapping::unmapPort(const std::string& gateway, uint16_t port, PortType type)
{
	std::string portStr = std::to_string(port);
	std::string portType = type == PortType::Tcp ? "TCP" : "UDP";

	auto request = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
		"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n"
		"<s:Body>\n"
		"<u:DeletePortMapping xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">\n"
		"<NewRemoteHost></NewRemoteHost>\n"
		"<NewProtocol>" + portType + "</NewProtocol>\n"
		"<NewExternalPort>" + portStr + "</NewExternalPort>\n"
		"</u:DeletePortMapping>\n"
		"</s:Body>\n"
		"</s:Envelope>\r\n";

	auto httpHeader = createUpnpHttpHeader(gateway + ":1900", request.length(), "urn:schemas-upnp-org:service:WANIPConnection:1#DeletePortMapping");

	auto stream = std::make_shared<TcpAsyncStream>(io);
	auto streamPtr = stream.get();
	state->pendingRequests.push_back(stream);
	auto upnpState = state;

	stream->onConnectCallback = [streamPtr, upnpState, httpHeader, request]()
	{
		DataBuffer buffer;
		buffer.assign(httpHeader.begin(), httpHeader.end());
		buffer.insert(buffer.end(), request.begin(), request.end());

		std::lock_guard<std::mutex> guard(upnpState->stateMutex);
		streamPtr->write(buffer);
	};

	stream->onReceiveCallback = [streamPtr, upnpState, gateway, port, type]()
	{
		auto data = streamPtr->getReceivedData();
		auto header = HttpHeaderInfo::readFromBuffer(data);

		if (header.valid && data.size() >= (header.dataStart + header.dataSize))
		{
			streamPtr->consumeData(header.dataStart + header.dataSize);

			std::lock_guard<std::mutex> guard(upnpState->stateMutex);

			if (header.success)
			{
				for (auto it = upnpState->mappedPorts.begin(); it != upnpState->mappedPorts.end(); it++)
				{
					if (it->gateway == gateway && it->port == port && it->type == type)
					{
						upnpState->mappedPorts.erase(it);
						break;
					}
				}
			}
		}
	};

	stream->onCloseCallback = [streamPtr, upnpState](int code)
	{
		std::lock_guard<std::mutex> guard(upnpState->stateMutex);

		for (auto it = upnpState->pendingRequests.begin(); it != upnpState->pendingRequests.end(); it++)
		{
			if ((*it).get() == streamPtr)
			{
				upnpState->pendingRequests.erase(it);
				break;
			}
		}
	};

	stream->connect(gateway, 1900);
}