From 4de4a6d783cf854dd86049d7300e47833acf50fb Mon Sep 17 00:00:00 2001 From: achingbrain Date: Fri, 14 Jun 2024 13:27:04 +0100 Subject: [PATCH] feat: add callback for unhandled STUN requests Calls the functions added to libjuice in https://github.com/paullouisageneau/libjuice/pull/248 Exports a `OnUnhandledStunRequest` function that can be passed a callback that will be invoked when an incoming STUN message is received that has no corresponding agent for the ICE ufrag. Closes #1166 --- include/rtc/global.hpp | 12 +++++++++++ include/rtc/rtc.h | 14 ++++++++++++ src/global.cpp | 49 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+) diff --git a/include/rtc/global.hpp b/include/rtc/global.hpp index 84317f4dd..b76bdc91f 100644 --- a/include/rtc/global.hpp +++ b/include/rtc/global.hpp @@ -34,6 +34,18 @@ RTC_CPP_EXPORT void InitLogger(LogLevel level, LogCallback callback = nullptr); RTC_CPP_EXPORT void Preload(); RTC_CPP_EXPORT std::shared_future Cleanup(); +RTC_CPP_EXPORT struct UnhandledStunRequest { + optional ufrag; + optional pwd; + uint8_t family; + std::string address; + uint16_t port; +}; + +RTC_CPP_EXPORT typedef std::function UnhandledStunRequestCallback; + +RTC_CPP_EXPORT void OnUnhandledStunRequest(std::string host, int port, UnhandledStunRequestCallback callback = nullptr); + struct SctpSettings { // For the following settings, not set means optimized default optional recvBufferSize; // in bytes diff --git a/include/rtc/rtc.h b/include/rtc/rtc.h index bc7aed65f..470922a13 100644 --- a/include/rtc/rtc.h +++ b/include/rtc/rtc.h @@ -172,6 +172,20 @@ typedef void(RTC_API *rtcAvailableCallbackFunc)(int id, void *ptr); typedef void(RTC_API *rtcPliHandlerCallbackFunc)(int tr, void *ptr); typedef void(RTC_API *rtcRembHandlerCallbackFunc)(int tr, unsigned int bitrate, void *ptr); +// Handle STUN requests with unexpected ufrags + +typedef struct { + const char * ufrag; + const char * pwd; + uint8_t family; + const char * address; + uint16_t port; +} rtcUnhandledStunRequest; + +typedef void(RTC_API *rtcUnhandledStunRequestCallbackFunc)(rtcUnhandledStunRequest request); + +RTC_C_EXPORT void rtcOnUnhandledStunRequest(const char *host, int port, rtcUnhandledStunRequestCallbackFunc callback); + // Log // NULL cb on the first call will log to stdout diff --git a/src/global.cpp b/src/global.cpp index 959053749..b6dd33aec 100644 --- a/src/global.cpp +++ b/src/global.cpp @@ -19,6 +19,11 @@ #include "impl/init.hpp" #include +#include + +#if !USE_NICE +#include +#endif namespace { @@ -88,6 +93,50 @@ std::shared_future Cleanup() { return impl::Init::Instance().cleanup(); } void SetSctpSettings(SctpSettings s) { impl::Init::Instance().setSctpSettings(std::move(s)); } +UnhandledStunRequestCallback unboundStunCallback; + +void InvokeUnhandledStunRequestCallback (const juice_stun_binding_t *info, void *user_ptr) { + PLOG_DEBUG << "Invoking Unbind STUN listener"; + auto callback = static_cast(user_ptr); + + (*callback)({ + .ufrag = std::string(info->ufrag), + .pwd = std::string(info->pwd), + .family = info->family, + .address = std::string(info->address), + .port = info->port + }); +} + +void OnUnhandledStunRequest ([[maybe_unused]] std::string host, [[maybe_unused]] int port, UnhandledStunRequestCallback callback) { + #if USE_NICE + PLOG_WARNING << "BindStunListener is not supported with libnice, please use libjuice"; + #else + if (callback == NULL) { + PLOG_DEBUG << "Removing unhandled STUN request listener"; + + if (juice_unbind_stun() < 0) { + throw std::runtime_error("Could not unbind STUN listener"); + } + unboundStunCallback = NULL; + + return; + } + + PLOG_DEBUG << "Adding listener for unhandled STUN requests"; + + if (unboundStunCallback != NULL) { + throw std::runtime_error("Unhandled STUN request handler already present"); + } + + unboundStunCallback = std::move(callback); + + if (juice_bind_stun(host.c_str(), port, &InvokeUnhandledStunRequestCallback, &unboundStunCallback) < 0) { + throw std::invalid_argument("Could add listener for unhandled STUN requests"); + } + #endif +} + RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, LogLevel level) { switch (level) { case LogLevel::Fatal: