should work on hardcoded port (not tested)

This commit is contained in:
Green Sky 2024-03-10 16:03:15 +01:00
commit e8d8e10980
No known key found for this signature in database
8 changed files with 341 additions and 0 deletions

22
.gitignore vendored Normal file
View File

@ -0,0 +1,22 @@
.vs/
*.o
*.swp
~*
*~
.idea/
cmake-build-debug/
cmake-build-debugandtest/
cmake-build-release/
*.stackdump
*.coredump
compile_commands.json
/build*
.clangd
.cache
.DS_Store
.AppleDouble
.LSOverride
CMakeLists.txt.user*
CMakeCache.txt

72
CMakeLists.txt Normal file
View File

@ -0,0 +1,72 @@
cmake_minimum_required(VERSION 3.24 FATAL_ERROR)
# cmake setup begin
project(solanaceae_tox_upnp)
if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
set(SOLANACEAE_TOX_UPNP_STANDALONE ON)
else()
set(SOLANACEAE_TOX_UPNP_STANDALONE OFF)
endif()
message("II SOLANACEAE_TOX_UPNP_STANDALONE " ${SOLANACEAE_TOX_UPNP_STANDALONE})
option(SOLANACEAE_TOX_UPNP_BUILD_PLUGINS "Build the solanaceae_tox_upnp plugins" ${SOLANACEAE_TOX_UPNP_STANDALONE})
if (SOLANACEAE_TOX_UPNP_STANDALONE)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
# defaulting to debug mode, if not specified
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Debug")
endif()
# setup my vim ycm :D
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# more paths
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
endif()
# external libs
add_subdirectory(./external EXCLUDE_FROM_ALL) # before increasing warn levels, sad :(
if (SOLANACEAE_TOX_UPNP_STANDALONE)
set(CMAKE_CXX_EXTENSIONS OFF)
# bump up warning levels appropriately for clang, gcc & msvc
if (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU" OR ${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
add_compile_options(
-Wall -Wextra # Reasonable and standard
-Wpedantic # Warn if non-standard C++ is used
-Wunused # Warn on anything being unused
#-Wconversion # Warn on type conversions that may lose data
#-Wsign-conversion # Warn on sign conversions
-Wshadow # Warn if a variable declaration shadows one from a parent context
)
if (NOT WIN32)
#link_libraries(-fsanitize=address)
#link_libraries(-fsanitize=address,undefined)
#link_libraries(-fsanitize-address-use-after-scope)
#link_libraries(-fsanitize=undefined)
endif()
elseif (${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
if (CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
endif()
endif()
endif()
# cmake setup end
add_subdirectory(./src)
if (SOLANACEAE_TOX_UPNP_BUILD_PLUGINS)
add_subdirectory(./plugins)
endif()

26
external/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,26 @@
cmake_minimum_required(VERSION 3.24 FATAL_ERROR)
include(FetchContent)
if (NOT TARGET solanaceae_plugin)
FetchContent_Declare(solanaceae_plugin
GIT_REPOSITORY https://github.com/Green-Sky/solanaceae_plugin.git
GIT_TAG master
)
FetchContent_MakeAvailable(solanaceae_plugin)
endif()
if (NOT TARGET miniupnpc::miniupnpc)
set(UPNPC_BUILD_STATIC ON CACHE BOOL "" FORCE)
set(UPNPC_BUILD_SHARED OFF CACHE BOOL "" FORCE)
set(UPNPC_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(UPNPC_BUILD_SAMPLE ON CACHE BOOL "" FORCE)
set(UPNPC_NO_INSTALL ON CACHE BOOL "" FORCE)
FetchContent_Declare(miniupnpc
GIT_REPOSITORY https://github.com/miniupnp/miniupnp.git
GIT_TAG master # meh
SOURCE_SUBDIR miniupnpc
)
FetchContent_MakeAvailable(miniupnpc)
endif()

13
plugins/CMakeLists.txt Normal file
View File

@ -0,0 +1,13 @@
cmake_minimum_required(VERSION 3.9...3.24 FATAL_ERROR)
########################################
add_library(plugin_tox_upnp SHARED
./plugin_tox_upnp.cpp
)
target_compile_features(plugin_tox_upnp PUBLIC cxx_std_17)
target_link_libraries(plugin_tox_upnp PUBLIC
solanaceae_tox_upnp
solanaceae_plugin
)

View File

@ -0,0 +1,58 @@
#include <solanaceae/plugin/solana_plugin_v1.h>
#include <solanaceae/tox_upnp.hpp>
#include <memory>
#include <limits>
#include <iostream>
static std::unique_ptr<ToxUPnP> g_tox_upnp = nullptr;
constexpr const char* plugin_name = "ToxUPnP";
extern "C" {
SOLANA_PLUGIN_EXPORT const char* solana_plugin_get_name(void) {
return plugin_name;
}
SOLANA_PLUGIN_EXPORT uint32_t solana_plugin_get_version(void) {
return SOLANA_PLUGIN_VERSION;
}
SOLANA_PLUGIN_EXPORT uint32_t solana_plugin_start(struct SolanaAPI* solana_api) {
std::cout << "PLUGIN " << plugin_name << " START()\n";
if (solana_api == nullptr) {
return 1;
}
try {
// TODO: toxI
// static store, could be anywhere tho
// construct with fetched dependencies
g_tox_upnp = std::make_unique<ToxUPnP>();
// register types
PLUG_PROVIDE_INSTANCE(ToxUPnP, plugin_name, g_tox_upnp.get());
} catch (const ResolveException& e) {
std::cerr << "PLUGIN " << plugin_name << " " << e.what << "\n";
return 2;
}
return 0;
}
SOLANA_PLUGIN_EXPORT void solana_plugin_stop(void) {
std::cout << "PLUGIN " << plugin_name << " STOP()\n";
g_tox_upnp.reset();
}
SOLANA_PLUGIN_EXPORT float solana_plugin_tick(float) {
return std::numeric_limits<float>::max();
}
} // extern C

17
src/CMakeLists.txt Normal file
View File

@ -0,0 +1,17 @@
cmake_minimum_required(VERSION 3.9...3.24 FATAL_ERROR)
project(solanaceae)
#########################################
add_library(solanaceae_tox_upnp
./solanaceae/tox_upnp.hpp
./solanaceae/tox_upnp.cpp
)
target_include_directories(solanaceae_tox_upnp PUBLIC .)
target_compile_features(solanaceae_tox_upnp PUBLIC cxx_std_17)
target_link_libraries(solanaceae_tox_upnp PUBLIC
miniupnpc::miniupnpc
)

114
src/solanaceae/tox_upnp.cpp Normal file
View File

@ -0,0 +1,114 @@
#include "./tox_upnp.hpp"
#include <miniupnpc.h>
#include <upnpcommands.h>
#include <upnperrors.h>
#include <chrono>
#include <iostream>
ToxUPnP::ToxUPnP(void) {
// get tox port
// start upnp thread
_thread = std::thread([this](void) {
int seconds_since_last {60*10};
bool last_mapping_succ {false};
while (!_quit) {
if (seconds_since_last < 60*10) {
std::this_thread::sleep_for(std::chrono::seconds(1));
seconds_since_last++;
continue;
}
seconds_since_last = 0;
last_mapping_succ = false;
// first get available devices
int error {0};
std::cerr << "TUPNP: starting search\n";
auto* devices = upnpDiscover(2000, nullptr, nullptr, UPNP_LOCAL_PORT_ANY, 0, 2, &error);
if (error != 0 || devices == nullptr) {
std::cerr << "TUPNP error: no device found\n";
continue;
}
std::cerr << "TUPNP: discovered devices:\n";
for (auto* d = devices; d != nullptr; d = d->pNext) {
std::cerr << " " << d->descURL << " " << d->st << " " << d->usn << "\n";
}
UPNPUrls urls;
IGDdatas data;
char lanaddr[64] = "unset";
auto res = UPNP_GetValidIGD(devices, &urls, &data, lanaddr, sizeof(lanaddr));
if (res != 1) {
std::cerr << "TUPNP error: no valid connected IGD has been found\n";
continue;
}
std::cerr << "TUPNP: valid IGD found, local ip: " << lanaddr << "\n";
const auto port_string = std::to_string(_local_port);
auto map_ret = UPNP_AddPortMapping(
urls.controlURL,
data.first.servicetype,
port_string.c_str(),
port_string.c_str(),
lanaddr,
"Tomato UPnP Tox UDP port forwarding",
"UDP",
nullptr,
"900" // lease duration in seconds
);
if (map_ret != UPNPCOMMAND_SUCCESS) {
std::cerr << "TUPNP error: adding port mapping failed " << strupnperror(map_ret) << "\n";
continue;
}
char intClient[40] {};
char intPort[6] {};
char duration[16] {};
auto getmap_ret = UPNP_GetSpecificPortMappingEntry(
urls.controlURL,
data.first.servicetype,
port_string.c_str(),
"UDP",
nullptr,
intClient,
intPort,
nullptr,
nullptr,
duration
);
if (getmap_ret != UPNPCOMMAND_SUCCESS) {
std::cerr << "TUPNP error: getting port mapping failed " << strupnperror(getmap_ret) << "\n";
// potentially succ ???
last_mapping_succ = true;
continue;
}
std::cerr << "TUPNP: mapping active external :" << port_string << " is redirected to internal " << intClient << ":" << intPort << " (for " << duration << "s)\n";
// potentially succ
last_mapping_succ = true;
FreeUPNPUrls(&urls);
freeUPNPDevlist(devices);
}
// remove mapping here?
});
}
ToxUPnP::~ToxUPnP(void) {
_quit = true;
if (_thread.joinable()) {
_thread.join();
}
}

View File

@ -0,0 +1,19 @@
#pragma once
#include <cstdint>
#include <atomic>
#include <thread>
class ToxUPnP {
// TODO: ToxI& _t;
uint16_t _local_port {33445};
std::atomic_bool _quit {false};
std::thread _thread;
public:
ToxUPnP(void);
~ToxUPnP(void);
};