mirror of
https://github.com/outbackdingo/UltraGrid.git
synced 2026-03-20 06:40:03 +00:00
nat-helper utility
This commit is contained in:
38
nat-helper/CMakeLists.txt
Normal file
38
nat-helper/CMakeLists.txt
Normal file
@@ -0,0 +1,38 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
|
||||
project(nat-helper
|
||||
LANGUAGES CXX
|
||||
VERSION 0.0.1
|
||||
)
|
||||
|
||||
set(SOURCES
|
||||
main.cpp
|
||||
nat-helper.cpp
|
||||
client.cpp
|
||||
message.cpp
|
||||
room.cpp
|
||||
)
|
||||
|
||||
add_executable(nat-helper main.cpp ${SOURCES})
|
||||
|
||||
set_property(TARGET nat-helper PROPERTY CXX_STANDARD 17)
|
||||
|
||||
if (NOT CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "")
|
||||
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "" FORCE)
|
||||
endif()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
|
||||
include(CheckPIESupported)
|
||||
check_pie_supported()
|
||||
set_target_properties(nat-helper PROPERTIES POSITION_INDEPENDENT_CODE TRUE)
|
||||
target_compile_definitions(nat-helper PRIVATE FORTIFY_SOURCE=2)
|
||||
target_compile_options(nat-helper PRIVATE -fstack-protector-strong)
|
||||
target_compile_options(nat-helper PRIVATE -Wall -Wextra -pedantic)
|
||||
target_link_options(nat-helper PRIVATE "SHELL:-z relro")
|
||||
target_link_options(nat-helper PRIVATE "SHELL:-z now")
|
||||
endif()
|
||||
|
||||
target_link_libraries(nat-helper PRIVATE
|
||||
pthread
|
||||
)
|
||||
|
||||
42
nat-helper/README.md
Normal file
42
nat-helper/README.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# Hole punching coordinator for UltraGrid
|
||||
|
||||
This utility serves as a meeting point for UltraGrid clients, that need to
|
||||
connect to each other, but don't have publicly routable IP addresses.
|
||||
|
||||
Building
|
||||
---------
|
||||
mkdir build && cd build
|
||||
cmake ..
|
||||
make
|
||||
|
||||
Usage
|
||||
---------
|
||||
./nat-helper [-h/--help] [-p/--port <port>]
|
||||
|
||||
If no port is specified, 12558 is used.
|
||||
|
||||
Protocol description
|
||||
---------
|
||||
|
||||
Clients connect to the nat-helper server, identify themselves with a name, and
|
||||
join a room. Once two clients enter the same room, nat-helper forwards name,
|
||||
sdp description string, and all candidate address pairs between the two
|
||||
clients.
|
||||
|
||||
All communication is done via messages that have the following structure:
|
||||
|
||||
<HEADER><MSG_BODY>
|
||||
|
||||
`HEADER`: 5B string containing length of MSG_BODY, null-termination optional
|
||||
`MSG_BODY`: content of message, length determined by header, max 2048B
|
||||
|
||||
After establishing connection to the nat-helper server, following messages are
|
||||
sent and received in that order:
|
||||
1. Client sends its name
|
||||
2. Client sends room name to join
|
||||
3. Client sends its sdp description
|
||||
4. Client receives the name of the other client in the room
|
||||
5. Client receives the sdp description of the other client
|
||||
|
||||
After that the client sends and receives sdp candidate pairs as they are
|
||||
discovered.
|
||||
140
nat-helper/client.cpp
Normal file
140
nat-helper/client.cpp
Normal file
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* @file client.cpp
|
||||
* @author Martin Piatka <piatka@cesnet.cz>
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2021 CESNET, z. s. p. o.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, is permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of CESNET nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "client.hpp"
|
||||
|
||||
Client::Client(asio::ip::tcp::socket&& socket) : socket(std::move(socket)) { }
|
||||
|
||||
void Client::readDescription(std::function<void(Client&, bool)> onComplete){
|
||||
using namespace std::placeholders;
|
||||
inMsg.async_readMsg(socket,
|
||||
std::bind(&Client::readNameComplete,
|
||||
shared_from_this(), std::ref(socket), onComplete, _1));
|
||||
}
|
||||
|
||||
void Client::readNameComplete(asio::ip::tcp::socket& socket,
|
||||
std::function<void(Client&, bool)> onComplete,
|
||||
bool success)
|
||||
{
|
||||
if(!success){
|
||||
onComplete(*this, false);
|
||||
return;
|
||||
}
|
||||
|
||||
clientName = std::string(inMsg.getStr());
|
||||
using namespace std::placeholders;
|
||||
inMsg.async_readMsg(socket,
|
||||
std::bind(&Client::readRoomComplete,
|
||||
shared_from_this(), std::ref(socket), onComplete, _1));
|
||||
}
|
||||
|
||||
void Client::readRoomComplete(asio::ip::tcp::socket& socket,
|
||||
std::function<void(Client&, bool)> onComplete,
|
||||
bool success)
|
||||
{
|
||||
if(!success){
|
||||
onComplete(*this, false);
|
||||
return;
|
||||
}
|
||||
|
||||
roomName = std::string(inMsg.getStr());
|
||||
using namespace std::placeholders;
|
||||
inMsg.async_readMsg(socket,
|
||||
std::bind(&Client::readDescComplete, shared_from_this(), onComplete, _1));
|
||||
}
|
||||
|
||||
void Client::readDescComplete(
|
||||
std::function<void(Client&, bool)> onComplete,
|
||||
bool success)
|
||||
{
|
||||
if(!success){
|
||||
onComplete(*this, false);
|
||||
return;
|
||||
}
|
||||
|
||||
sdpDesc = std::string(inMsg.getStr());
|
||||
onComplete(*this, true);
|
||||
}
|
||||
|
||||
void Client::readCandidate(std::function<void(Client&, bool)> onComplete){
|
||||
using namespace std::placeholders;
|
||||
inMsg.async_readMsg(socket,
|
||||
std::bind(&Client::readCandidateComplete,
|
||||
shared_from_this(), onComplete, _1));
|
||||
}
|
||||
|
||||
void Client::readCandidateComplete(
|
||||
std::function<void(Client&, bool)> onComplete,
|
||||
bool success)
|
||||
{
|
||||
if(!success){
|
||||
onComplete(*this, false);
|
||||
return;
|
||||
}
|
||||
|
||||
candidates.emplace_back(inMsg.getStr());
|
||||
onComplete(*this, true);
|
||||
}
|
||||
|
||||
bool Client::isSendCallbackPending() const{
|
||||
return !sendQueue.empty() || outMsg.isSendingNow();
|
||||
}
|
||||
|
||||
|
||||
void Client::sendMsg(std::string_view msg){
|
||||
if(isSendCallbackPending()){
|
||||
sendQueue.emplace(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
outMsg.setStr(msg);
|
||||
using namespace std::placeholders;
|
||||
outMsg.async_sendMsg(socket, std::bind(&Client::onMsgSent, shared_from_this(), _1));
|
||||
}
|
||||
|
||||
void Client::onMsgSent(bool success){
|
||||
if(!success){
|
||||
//TODO
|
||||
}
|
||||
|
||||
if(sendQueue.empty())
|
||||
return;
|
||||
|
||||
using namespace std::placeholders;
|
||||
outMsg.setStr(sendQueue.front());
|
||||
sendQueue.pop();
|
||||
outMsg.async_sendMsg(socket, std::bind(&Client::onMsgSent, shared_from_this(), _1));
|
||||
}
|
||||
97
nat-helper/client.hpp
Normal file
97
nat-helper/client.hpp
Normal file
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* @file client.hpp
|
||||
* @author Martin Piatka <piatka@cesnet.cz>
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2021 CESNET, z. s. p. o.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, is permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of CESNET nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef UG_HOLE_PUNCH_CLIENT_HPP
|
||||
#define UG_HOLE_PUNCH_CLIENT_HPP
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <asio.hpp>
|
||||
#include "message.hpp"
|
||||
|
||||
class Client : public std::enable_shared_from_this<Client>{
|
||||
public:
|
||||
Client(asio::ip::tcp::socket&& socket);
|
||||
Client(const Client&) = delete;
|
||||
Client(Client&&) = delete;
|
||||
|
||||
Client& operator=(const Client&) = delete;
|
||||
Client& operator=(Client&&) = delete;
|
||||
|
||||
void readDescription(std::function<void(Client&, bool)> onComplete);
|
||||
std::string getClientName() { return clientName; }
|
||||
std::string getRoomName() { return roomName; }
|
||||
std::string getSdpDesc() { return sdpDesc; }
|
||||
|
||||
void sendMsg(std::string_view msg);
|
||||
|
||||
void readCandidate(std::function<void(Client&, bool)> onComplete);
|
||||
const std::vector<std::string>& getCandidates() { return candidates; }
|
||||
|
||||
bool isSendCallbackPending() const;
|
||||
|
||||
private:
|
||||
void readNameComplete(asio::ip::tcp::socket& socket,
|
||||
std::function<void(Client&, bool)> onComplete, bool success);
|
||||
|
||||
void readRoomComplete(asio::ip::tcp::socket& socket,
|
||||
std::function<void(Client&, bool)> onComplete, bool success);
|
||||
|
||||
void readDescComplete(
|
||||
std::function<void(Client&, bool)> onComplete, bool success);
|
||||
|
||||
void readCandidateComplete(
|
||||
std::function<void(Client&, bool)> onComplete, bool success);
|
||||
|
||||
void onMsgSent(bool success);
|
||||
|
||||
std::string clientName;
|
||||
std::string roomName;
|
||||
std::string sdpDesc;
|
||||
std::vector<std::string> candidates;
|
||||
|
||||
std::queue<std::string> sendQueue;
|
||||
|
||||
Message inMsg;
|
||||
Message outMsg;
|
||||
asio::ip::tcp::socket socket;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
90
nat-helper/main.cpp
Normal file
90
nat-helper/main.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* @file main.cpp
|
||||
* @author Martin Piatka <piatka@cesnet.cz>
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2021 CESNET, z. s. p. o.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, is permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of CESNET nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <iostream>
|
||||
#include <charconv>
|
||||
#include "nat-helper.hpp"
|
||||
|
||||
namespace {
|
||||
void printUsage(std::string_view name){
|
||||
std::cout << "Usage: "
|
||||
<< name << " [-h/--help] [-p/--port <port>]\n";
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv){
|
||||
int port = 12558;
|
||||
|
||||
for(int i = 1; i < argc; i++){
|
||||
std::string_view arg(argv[i]);
|
||||
if(arg == "-h" || arg == "--help"){
|
||||
printUsage(argv[0]);
|
||||
return 0;
|
||||
} else if(arg == "-p" || arg == "--port"){
|
||||
if(i + 1 >= argc){
|
||||
std::cerr << "Expected port number\n";
|
||||
printUsage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
std::string_view portStr(argv[++i]);
|
||||
auto res = std::from_chars(portStr.data(), portStr.data() + portStr.size(), port);
|
||||
if(res.ec != std::errc() || res.ptr == portStr.data()){
|
||||
std::cerr << "Failed to parse port number\n";
|
||||
printUsage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
std::cerr << "Unknown argument " << arg << std::endl;
|
||||
printUsage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NatHelper server(port);
|
||||
|
||||
server.run();
|
||||
|
||||
for(std::string in; std::getline(std::cin, in);){
|
||||
if(in == "exit"){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
server.stop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
120
nat-helper/message.cpp
Normal file
120
nat-helper/message.cpp
Normal file
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* @file message.cpp
|
||||
* @author Martin Piatka <piatka@cesnet.cz>
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2021 CESNET, z. s. p. o.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, is permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of CESNET nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <charconv>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include "message.hpp"
|
||||
|
||||
std::string_view Message::getStr() const{
|
||||
return std::string_view(data + headerSize, size);
|
||||
}
|
||||
|
||||
void Message::async_readMsg(asio::ip::tcp::socket& socket,
|
||||
std::function<void(bool)> onComplete)
|
||||
{
|
||||
using namespace std::placeholders;
|
||||
asio::async_read(socket,
|
||||
asio::buffer(data, headerSize),
|
||||
std::bind(&Message::async_readBody,
|
||||
this, std::ref(socket), onComplete, _1, _2));
|
||||
}
|
||||
|
||||
void Message::setStr(std::string_view msg){
|
||||
assert(!sendingNow);
|
||||
size = std::min(bodySize, msg.size());
|
||||
|
||||
memset(data, ' ', headerSize);
|
||||
std::to_chars(data, data + headerSize, size);
|
||||
|
||||
memcpy(data + headerSize, msg.data(), size);
|
||||
}
|
||||
|
||||
void Message::async_sendMsg(asio::ip::tcp::socket& socket,
|
||||
std::function<void(bool)> onComplete)
|
||||
{
|
||||
using namespace std::placeholders;
|
||||
sendingNow = true;
|
||||
asio::async_write(socket,
|
||||
asio::buffer(data, headerSize + size),
|
||||
std::bind(&Message::async_sendComplete,
|
||||
this, onComplete, _1, _2));
|
||||
}
|
||||
|
||||
void Message::async_readBody(asio::ip::tcp::socket& socket,
|
||||
std::function<void(bool)> onComplete,
|
||||
const std::error_code& ec, [[maybe_unused]] size_t readLen)
|
||||
{
|
||||
if(ec){
|
||||
onComplete(false);
|
||||
return;
|
||||
}
|
||||
|
||||
assert(readLen == headerSize);
|
||||
size_t expectedSize = 0;
|
||||
|
||||
auto res = std::from_chars(data, data + headerSize, expectedSize);
|
||||
if(res.ec != std::errc()){
|
||||
onComplete(false);
|
||||
}
|
||||
|
||||
using namespace std::placeholders;
|
||||
asio::async_read(socket,
|
||||
asio::buffer(data + headerSize, expectedSize),
|
||||
std::bind(&Message::async_readBodyComplete,
|
||||
this, onComplete, _1, _2));
|
||||
|
||||
}
|
||||
|
||||
void Message::async_readBodyComplete(std::function<void(bool)> onComplete,
|
||||
const std::error_code& ec, size_t readLen)
|
||||
{
|
||||
if(ec){
|
||||
onComplete(false);
|
||||
return;
|
||||
}
|
||||
|
||||
size = readLen;
|
||||
|
||||
onComplete(true);
|
||||
}
|
||||
|
||||
void Message::async_sendComplete(std::function<void(bool)> onComplete,
|
||||
const std::error_code& ec, [[maybe_unused]] size_t sentLen)
|
||||
{
|
||||
sendingNow = false;
|
||||
onComplete(!ec);
|
||||
}
|
||||
82
nat-helper/message.hpp
Normal file
82
nat-helper/message.hpp
Normal file
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* @file message.hpp
|
||||
* @author Martin Piatka <piatka@cesnet.cz>
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2021 CESNET, z. s. p. o.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, is permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of CESNET nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef UG_HOLE_PUNCH_MESSAGE_HPP
|
||||
#define UG_HOLE_PUNCH_MESSAGE_HPP
|
||||
|
||||
#include <string_view>
|
||||
#include <functional>
|
||||
#include <asio.hpp>
|
||||
|
||||
class Message{
|
||||
public:
|
||||
Message() = default;
|
||||
|
||||
void async_readMsg(asio::ip::tcp::socket& socket,
|
||||
std::function<void(bool)> onComplete);
|
||||
|
||||
std::string_view getStr() const;
|
||||
|
||||
void setStr(std::string_view msg);
|
||||
void async_sendMsg(asio::ip::tcp::socket& socket,
|
||||
std::function<void(bool)> onComplete);
|
||||
|
||||
size_t getSize() const { return size; }
|
||||
bool empty() const { return size == 0; }
|
||||
bool isSendingNow() const { return sendingNow; }
|
||||
void clear();
|
||||
|
||||
private:
|
||||
void async_readBody(asio::ip::tcp::socket& socket,
|
||||
std::function<void(bool)> onComplete,
|
||||
const std::error_code& ec, size_t readLen);
|
||||
|
||||
void async_readBodyComplete(std::function<void(bool)> onComplete,
|
||||
const std::error_code& ec, size_t readLen);
|
||||
|
||||
void async_sendComplete(std::function<void(bool)> onComplete,
|
||||
const std::error_code& ec, size_t sentLen);
|
||||
|
||||
size_t size = 0;
|
||||
|
||||
bool sendingNow = false;
|
||||
|
||||
static constexpr size_t headerSize = 5;
|
||||
static constexpr size_t bodySize = 2048;
|
||||
char data[headerSize + bodySize];
|
||||
};
|
||||
|
||||
#endif
|
||||
138
nat-helper/nat-helper.cpp
Normal file
138
nat-helper/nat-helper.cpp
Normal file
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* @file nat-helper.cpp
|
||||
* @author Martin Piatka <piatka@cesnet.cz>
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2021 CESNET, z. s. p. o.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, is permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of CESNET nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <iostream>
|
||||
#include <functional>
|
||||
#include "nat-helper.hpp"
|
||||
|
||||
NatHelper::NatHelper(int port) : port(port),
|
||||
io_service(),
|
||||
//work_guard(io_service.get_executor()),
|
||||
acceptor(io_service),
|
||||
pendingSocket(io_service)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
NatHelper::NatHelper() : NatHelper(12558)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void NatHelper::worker(){
|
||||
std::cout << "Running" << std::endl;
|
||||
io_service.run();
|
||||
std::cout << "End" << std::endl;
|
||||
}
|
||||
|
||||
void NatHelper::run(){
|
||||
using namespace std::placeholders;
|
||||
|
||||
asio::ip::tcp::endpoint endpoint(asio::ip::tcp::v4(), port);
|
||||
acceptor.open(endpoint.protocol());
|
||||
acceptor.bind(endpoint);
|
||||
acceptor.listen(asio::socket_base::max_connections);
|
||||
acceptor.set_option(asio::ip::tcp::acceptor::reuse_address(false));
|
||||
acceptor.async_accept(pendingSocket,
|
||||
std::bind(&NatHelper::onConnectionAccepted, this, _1));
|
||||
|
||||
std::cout << "Starting thread" << std::endl;
|
||||
worker_thread = std::thread(&NatHelper::worker, this);
|
||||
}
|
||||
|
||||
void NatHelper::stop(){
|
||||
std::cout << "Stopping..." << std::endl;
|
||||
io_service.stop();
|
||||
worker_thread.join();
|
||||
}
|
||||
|
||||
void NatHelper::onConnectionAccepted(const std::error_code& ec){
|
||||
if(ec){
|
||||
std::cerr << "Error accepting client connection: " << ec.message() << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
using namespace std::placeholders;
|
||||
|
||||
auto client = std::make_shared<Client>(std::move(pendingSocket));
|
||||
client->readDescription(
|
||||
std::bind(&NatHelper::onClientDesc, this, _1, _2));
|
||||
incomingClients.insert({client.get(), std::move(client)});
|
||||
|
||||
acceptor.async_accept(pendingSocket,
|
||||
std::bind(&NatHelper::onConnectionAccepted, this, _1));
|
||||
}
|
||||
|
||||
void NatHelper::cleanEmptyRooms(){
|
||||
for(auto it = rooms.begin(); it != rooms.end(); ){
|
||||
if(it->second->isEmpty()){
|
||||
std::cout << "Removing empty room " << it->first << "\n";
|
||||
it = rooms.erase(it);
|
||||
} else {
|
||||
it++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NatHelper::onClientDesc(Client& client, bool success){
|
||||
if(!success){
|
||||
std::cerr << "Error reading client description" << std::endl;
|
||||
incomingClients.erase(&client);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& roomName = client.getRoomName();
|
||||
std::cout << "Moving client " << client.getClientName()
|
||||
<< " to room " << roomName
|
||||
<< std::endl;
|
||||
|
||||
auto roomIt = rooms.find(roomName);
|
||||
if(roomIt == rooms.end()){
|
||||
cleanEmptyRooms();
|
||||
std::cout << "Creating room " << roomName << std::endl;
|
||||
roomIt = rooms.insert({roomName, std::make_shared<Room>(roomName)}).first;
|
||||
}
|
||||
|
||||
auto clientIt = incomingClients.find(&client);
|
||||
auto& room = roomIt->second;
|
||||
if(room->isFull()){
|
||||
std::cerr << "Room " << roomName << " is full, dropping client" << std::endl;
|
||||
} else {
|
||||
roomIt->second->addClient(std::move(clientIt->second));
|
||||
}
|
||||
incomingClients.erase(clientIt);
|
||||
}
|
||||
77
nat-helper/nat-helper.hpp
Normal file
77
nat-helper/nat-helper.hpp
Normal file
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* @file nat-helper.hpp
|
||||
* @author Martin Piatka <piatka@cesnet.cz>
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2021 CESNET, z. s. p. o.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, is permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of CESNET nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef UG_NAT_HELPER
|
||||
#define UG_NAT_HELPER
|
||||
|
||||
#include <asio.hpp>
|
||||
#include <thread>
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include "client.hpp"
|
||||
#include "room.hpp"
|
||||
|
||||
class NatHelper {
|
||||
public:
|
||||
NatHelper();
|
||||
NatHelper(int port);
|
||||
~NatHelper() = default;
|
||||
|
||||
void run();
|
||||
void stop();
|
||||
|
||||
private:
|
||||
void worker();
|
||||
|
||||
void onConnectionAccepted(const std::error_code& ec);
|
||||
void onClientDesc(Client& client, bool success);
|
||||
|
||||
void cleanEmptyRooms();
|
||||
|
||||
int port;
|
||||
|
||||
asio::io_service io_service;
|
||||
//asio::executor_work_guard<asio::io_service::executor_type> work_guard;
|
||||
std::thread worker_thread;
|
||||
|
||||
asio::ip::tcp::acceptor acceptor;
|
||||
asio::ip::tcp::socket pendingSocket;
|
||||
|
||||
std::map<Client *, std::shared_ptr<Client>> incomingClients;
|
||||
std::map<std::string, std::shared_ptr<Room>> rooms;
|
||||
};
|
||||
|
||||
#endif //UG_NAT_HELPER
|
||||
88
nat-helper/room.cpp
Normal file
88
nat-helper/room.cpp
Normal file
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* @file room.cpp
|
||||
* @author Martin Piatka <piatka@cesnet.cz>
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2021 CESNET, z. s. p. o.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, is permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of CESNET nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include "room.hpp"
|
||||
|
||||
Room::Room(std::string name) : name(std::move(name)) { }
|
||||
|
||||
void Room::addClient(std::shared_ptr<Client>&& client){
|
||||
assert(!isFull());
|
||||
|
||||
Client *clientPtr = client.get();
|
||||
|
||||
for(auto& [c, _] : clients){
|
||||
c->sendMsg(clientPtr->getClientName());
|
||||
c->sendMsg(clientPtr->getSdpDesc());
|
||||
|
||||
clientPtr->sendMsg(c->getClientName());
|
||||
clientPtr->sendMsg(c->getSdpDesc());
|
||||
for(const auto& candidate : c->getCandidates()){
|
||||
clientPtr->sendMsg(candidate);
|
||||
}
|
||||
}
|
||||
|
||||
clients.insert({clientPtr, std::move(client)});
|
||||
|
||||
using namespace std::placeholders;
|
||||
clientPtr->readCandidate(
|
||||
std::bind(&Room::onClientCandidate, shared_from_this(), _1, _2));
|
||||
|
||||
}
|
||||
|
||||
void Room::onClientCandidate(Client& client, bool success){
|
||||
if(!success){
|
||||
std::cerr << "Error reading candidate, removing client "
|
||||
<< client.getClientName() << std::endl;
|
||||
|
||||
clients.erase(&client);
|
||||
return;
|
||||
}
|
||||
|
||||
std::cout << "Client candidate recieved" << std::endl;
|
||||
|
||||
for(auto& [c, cu] : clients){
|
||||
if(&client == c)
|
||||
continue;
|
||||
|
||||
c->sendMsg(client.getCandidates().back());
|
||||
}
|
||||
|
||||
using namespace std::placeholders;
|
||||
client.readCandidate(
|
||||
std::bind(&Room::onClientCandidate, shared_from_this(), _1, _2));
|
||||
}
|
||||
60
nat-helper/room.hpp
Normal file
60
nat-helper/room.hpp
Normal file
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* @file room.hpp
|
||||
* @author Martin Piatka <piatka@cesnet.cz>
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2021 CESNET, z. s. p. o.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, is permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of CESNET nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef UG_HOLE_PUNCH_ROOM_HPP
|
||||
#define UG_HOLE_PUNCH_ROOM_HPP
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include "client.hpp"
|
||||
|
||||
class Room : public std::enable_shared_from_this<Room>{
|
||||
public:
|
||||
Room(std::string name);
|
||||
|
||||
void addClient(std::shared_ptr<Client>&& client);
|
||||
|
||||
bool isFull() const { return clients.size() >= 2; }
|
||||
bool isEmpty() const { return clients.empty(); }
|
||||
|
||||
private:
|
||||
void onClientCandidate(Client& client, bool success);
|
||||
|
||||
std::string name;
|
||||
std::map<Client *, std::shared_ptr<Client>> clients;
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user