Browse Source

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
achingbrain 1 year ago
parent
commit
311fea07d5
4 changed files with 79 additions and 1 deletions
  1. 1 1
      deps/libjuice
  2. 11 0
      include/rtc/global.hpp
  3. 14 0
      include/rtc/rtc.h
  4. 53 0
      src/global.cpp

+ 1 - 1
deps/libjuice

@@ -1 +1 @@
-Subproject commit ac7d2520527e8d4e74386a0e400da927aaf865c6
+Subproject commit 2fb91a3c90b9e5bde2f3cb0ecb4f53b9af027eca

+ 11 - 0
include/rtc/global.hpp

@@ -34,6 +34,17 @@ RTC_CPP_EXPORT void InitLogger(LogLevel level, LogCallback callback = nullptr);
 RTC_CPP_EXPORT void Preload();
 RTC_CPP_EXPORT std::shared_future<void> Cleanup();
 
+struct UnhandledStunRequest {
+	optional<std::string> localUfrag;
+	optional<std::string> remoteUfrag;
+	std::string address;
+	uint16_t port;
+};
+
+RTC_CPP_EXPORT typedef std::function<void(UnhandledStunRequest request)> 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<size_t> recvBufferSize;                // in bytes

+ 14 - 0
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

+ 53 - 0
src/global.cpp

@@ -19,6 +19,11 @@
 #include "impl/init.hpp"
 
 #include <mutex>
+#include <map>
+
+#if !USE_NICE
+#include <juice/juice.h>
+#endif
 
 namespace {
 
@@ -88,6 +93,54 @@ std::shared_future<void> Cleanup() { return impl::Init::Instance().cleanup(); }
 
 void SetSctpSettings(SctpSettings s) { impl::Init::Instance().setSctpSettings(std::move(s)); }
 
+#if !USE_NICE
+
+UnhandledStunRequestCallback unboundStunCallback;
+
+void InvokeUnhandledStunRequestCallback (const juice_mux_binding_request *info, void *user_ptr) {
+	PLOG_DEBUG << "Invoking Unbind STUN listener";
+	auto callback = static_cast<UnhandledStunRequestCallback *>(user_ptr);
+
+	(*callback)({
+		std::string(info->local_ufrag),
+		std::string(info->remote_ufrag),
+		std::string(info->address),
+		info->port
+	});
+}
+
+#endif
+
+void OnUnhandledStunRequest ([[maybe_unused]] std::string host, [[maybe_unused]] int port, [[maybe_unused]] 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";
+
+		// call with NULL callback to unbind
+		if (juice_mux_listen(host.c_str(), port, NULL, NULL) < 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_mux_listen(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: