Quellcode durchsuchen

Refactor API into an IceUdpMuxListener object

Paul-Louis Ageneau vor 6 Monaten
Ursprung
Commit
fcfcc4f685

+ 4 - 0
CMakeLists.txt

@@ -66,6 +66,7 @@ set(LIBDATACHANNEL_SOURCES
 	${CMAKE_CURRENT_SOURCE_DIR}/src/configuration.cpp
 	${CMAKE_CURRENT_SOURCE_DIR}/src/datachannel.cpp
 	${CMAKE_CURRENT_SOURCE_DIR}/src/description.cpp
+	${CMAKE_CURRENT_SOURCE_DIR}/src/iceudpmuxlistener.cpp
 	${CMAKE_CURRENT_SOURCE_DIR}/src/mediahandler.cpp
 	${CMAKE_CURRENT_SOURCE_DIR}/src/global.cpp
 	${CMAKE_CURRENT_SOURCE_DIR}/src/message.cpp
@@ -99,6 +100,7 @@ set(LIBDATACHANNEL_HEADERS
 	${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/configuration.hpp
 	${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/datachannel.hpp
 	${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/description.hpp
+	${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/iceudpmuxlistener.hpp
 	${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/mediahandler.hpp
 	${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/rtcpreceivingsession.hpp
 	${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/common.hpp
@@ -139,6 +141,7 @@ set(LIBDATACHANNEL_IMPL_SOURCES
 	${CMAKE_CURRENT_SOURCE_DIR}/src/impl/dtlssrtptransport.cpp
 	${CMAKE_CURRENT_SOURCE_DIR}/src/impl/dtlstransport.cpp
 	${CMAKE_CURRENT_SOURCE_DIR}/src/impl/icetransport.cpp
+	${CMAKE_CURRENT_SOURCE_DIR}/src/impl/iceudpmuxlistener.cpp
 	${CMAKE_CURRENT_SOURCE_DIR}/src/impl/init.cpp
 	${CMAKE_CURRENT_SOURCE_DIR}/src/impl/peerconnection.cpp
 	${CMAKE_CURRENT_SOURCE_DIR}/src/impl/logcounter.cpp
@@ -171,6 +174,7 @@ set(LIBDATACHANNEL_IMPL_HEADERS
 	${CMAKE_CURRENT_SOURCE_DIR}/src/impl/dtlssrtptransport.hpp
 	${CMAKE_CURRENT_SOURCE_DIR}/src/impl/dtlstransport.hpp
 	${CMAKE_CURRENT_SOURCE_DIR}/src/impl/icetransport.hpp
+	${CMAKE_CURRENT_SOURCE_DIR}/src/impl/iceudpmuxlistener.hpp
 	${CMAKE_CURRENT_SOURCE_DIR}/src/impl/init.hpp
 	${CMAKE_CURRENT_SOURCE_DIR}/src/impl/internals.hpp
 	${CMAKE_CURRENT_SOURCE_DIR}/src/impl/peerconnection.hpp

+ 0 - 11
include/rtc/global.hpp

@@ -34,17 +34,6 @@ RTC_CPP_EXPORT void InitLogger(LogLevel level, LogCallback callback = nullptr);
 RTC_CPP_EXPORT void Preload();
 RTC_CPP_EXPORT std::shared_future<void> Cleanup();
 
-struct IceUdpMuxRequest {
-	std::string localUfrag;
-	std::string remoteUfrag;
-	std::string remoteHost;
-	uint16_t remotePort;
-};
-
-RTC_CPP_EXPORT typedef std::function<void(IceUdpMuxRequest request)> IceUdpMuxCallback;
-
-RTC_CPP_EXPORT void ListenIceUdpMux (int port, IceUdpMuxCallback *callback, std::optional<std::string> bindAddress = nullptr);
-
 struct SctpSettings {
 	// For the following settings, not set means optimized default
 	optional<size_t> recvBufferSize;                // in bytes

+ 47 - 0
include/rtc/iceudpmuxlistener.hpp

@@ -0,0 +1,47 @@
+/**
+ * Copyright (c) 2025 Alex Potsides
+ * Copyright (c) 2025 Paul-Louis Ageneau
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef RTC_ICE_UDP_MUX_LISTENER_H
+#define RTC_ICE_UDP_MUX_LISTENER_H
+
+#include "common.hpp"
+
+namespace rtc {
+
+namespace impl {
+
+struct IceUdpMuxListener;
+
+} // namespace impl
+
+struct IceUdpMuxRequest { // TODO change name
+	string localUfrag;
+	string remoteUfrag;
+	string remoteAddress;
+	uint16_t remotePort;
+};
+
+class RTC_CPP_EXPORT IceUdpMuxListener final : private CheshireCat<impl::IceUdpMuxListener> {
+public:
+	IceUdpMuxListener(uint16_t port, optional<string> bindAddress = nullopt);
+	~IceUdpMuxListener();
+
+	void stop();
+
+	uint16_t port() const;
+
+	void OnUnhandledStunRequest(std::function<void(IceUdpMuxRequest)> callback);
+
+private:
+	using CheshireCat<impl::IceUdpMuxListener>::impl;
+};
+
+} // namespace rtc
+
+#endif

+ 1 - 0
include/rtc/rtc.hpp

@@ -16,6 +16,7 @@
 #include "datachannel.hpp"
 #include "peerconnection.hpp"
 #include "track.hpp"
+#include "iceudpmuxlistener.hpp"
 
 #if RTC_ENABLE_WEBSOCKET
 

+ 1 - 53
src/global.cpp

@@ -19,11 +19,6 @@
 #include "impl/init.hpp"
 
 #include <mutex>
-#include <map>
-
-#if !USE_NICE
-#include <juice/juice.h>
-#endif
 
 namespace {
 
@@ -93,54 +88,7 @@ std::shared_future<void> Cleanup() { return impl::Init::Instance().cleanup(); }
 
 void SetSctpSettings(SctpSettings s) { impl::Init::Instance().setSctpSettings(std::move(s)); }
 
-#if !USE_NICE
-
-void InvokeIceUdpMuxCallback (const juice_mux_binding_request *info, void *user_ptr) {
-	PLOG_DEBUG << "Invoking ICE UDP mux callback";
-
-	IceUdpMuxCallback *callback = (IceUdpMuxCallback*)user_ptr;
-
-	if (callback) {
-		(*callback)({
-			std::string(info->local_ufrag),
-			std::string(info->remote_ufrag),
-			std::string(info->address),
-			info->port
-		});
-	} else {
-		PLOG_DEBUG << "No ICE UDP mux callback configured for port " << info->port;
-	}
-}
-
-#endif
-
-void ListenIceUdpMux ([[maybe_unused]] int port, [[maybe_unused]] IceUdpMuxCallback *callback, [[maybe_unused]] std::optional<std::string> bindAddress) {
-	#if USE_NICE
-		PLOG_WARNING << "ListenIceUdpMux is not supported with libnice, please use libjuice";
-	#else
-	// NULL host binds to all available addresses
-	const char *host = bindAddress.has_value() ? bindAddress.value().c_str() : NULL;
-
-	if (callback == NULL) {
-		PLOG_DEBUG << "Removing ICE UDP mux callback for port " << port;
-
-		// call with NULL callback to remove the listener for the host/port
-		if (juice_mux_listen(host, port, NULL, NULL) < 0) {
-			throw std::runtime_error("Could not remove ICE UDP mux callback");
-		}
-
-		return;
-	}
-
-	PLOG_DEBUG << "Adding ICE UDP mux callback for port " << port;
-
-	if (juice_mux_listen(host, port, &InvokeIceUdpMuxCallback, callback) < 0) {
-		throw std::invalid_argument("Could not add ICE UDP mux callback");
-	}
-	#endif
-}
-
-RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, LogLevel level) {
+std::ostream &operator<<(std::ostream &out, LogLevel level) {
 	switch (level) {
 	case LogLevel::Fatal:
 		out << "fatal";

+ 29 - 0
src/iceudpmuxlistener.cpp

@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) 2025 Alex Potsides
+ * Copyright (c) 2025 Paul-Louis Ageneau
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+#include "iceudpmuxlistener.hpp"
+
+#include "impl/iceudpmuxlistener.hpp"
+
+namespace rtc {
+
+IceUdpMuxListener::IceUdpMuxListener(uint16_t port, optional<string> bindAddress)
+    : CheshireCat<impl::IceUdpMuxListener>(port, std::move(bindAddress)) {}
+
+IceUdpMuxListener::~IceUdpMuxListener() {}
+
+void IceUdpMuxListener::stop() { impl()->stop(); }
+
+uint16_t IceUdpMuxListener::port() const { return impl()->port; }
+
+void IceUdpMuxListener::OnUnhandledStunRequest(std::function<void(IceUdpMuxRequest)> callback) {
+	impl()->unhandledStunRequestCallback = callback;
+}
+
+} // namespace rtc

+ 62 - 0
src/impl/iceudpmuxlistener.cpp

@@ -0,0 +1,62 @@
+/**
+ * Copyright (c) 2025 Alex Potsides
+ * Copyright (c) 2025 Paul-Louis Ageneau
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+#include "iceudpmuxlistener.hpp"
+#include "internals.hpp"
+
+namespace rtc::impl {
+
+#if !USE_NICE
+void IceUdpMuxListener::UnhandledStunRequestCallback(const juice_mux_binding_request *info,
+                                                     void *user_ptr) {
+	auto listener = static_cast<IceUdpMuxListener *>(user_ptr);
+	if (!listener)
+		return;
+
+	IceUdpMuxRequest request;
+	request.localUfrag = info->local_ufrag;
+	request.remoteUfrag = info->remote_ufrag;
+	request.remoteAddress = info->address;
+	request.remotePort = info->port;
+	listener->unhandledStunRequestCallback(std::move(request));
+}
+#endif
+
+IceUdpMuxListener::IceUdpMuxListener(uint16_t port, optional<string> bindAddress) : port(port) {
+	PLOG_VERBOSE << "Creating IceUdpMuxListener";
+
+#if !USE_NICE
+	PLOG_DEBUG << "Registering ICE UDP mux listener for port " << port;
+	if (juice_mux_listen(bindAddress ? bindAddress->c_str() : NULL, port,
+	                     IceUdpMuxListener::UnhandledStunRequestCallback, this) < 0) {
+		throw std::runtime_error("Failed to register ICE UDP mux listener");
+	}
+#else
+	PLOG_WARNING << "ICE UDP mux is not available with libnice";
+#endif
+}
+
+IceUdpMuxListener::~IceUdpMuxListener() {
+	PLOG_VERBOSE << "Destroying IceUdpMuxListener";
+	stop();
+}
+
+void IceUdpMuxListener::stop() {
+	if (mStopped.exchange(true))
+		return;
+
+#if !USE_NICE
+	PLOG_DEBUG << "Unregistering ICE UDP mux listener for port " << port;
+	if (juice_mux_listen(NULL, port, NULL, NULL) < 0) {
+		PLOG_ERROR << "Failed to unregister ICE UDP mux listener";
+	}
+#endif
+}
+
+} // namespace rtc::impl

+ 45 - 0
src/impl/iceudpmuxlistener.hpp

@@ -0,0 +1,45 @@
+/**
+ * Copyright (c) 2025 Alex Potsides
+ * Copyright (c) 2025 Paul-Louis Ageneau
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef RTC_IMPL_ICE_UDP_MUX_LISTENER_H
+#define RTC_IMPL_ICE_UDP_MUX_LISTENER_H
+
+#include "common.hpp"
+
+#include "rtc/iceudpmuxlistener.hpp"
+
+#if !USE_NICE
+#include <juice/juice.h>
+#endif
+
+#include <atomic>
+
+namespace rtc::impl {
+
+struct IceUdpMuxListener final {
+	IceUdpMuxListener(uint16_t port, optional<string> bindAddress = nullopt);
+    ~IceUdpMuxListener();
+
+	void stop();
+
+	const uint16_t port;
+	synchronized_callback<IceUdpMuxRequest> unhandledStunRequestCallback;
+
+private:
+#if !USE_NICE
+	static void UnhandledStunRequestCallback(const juice_mux_binding_request *info, void *user_ptr);
+#endif
+
+	std::atomic<bool> mStopped;
+};
+
+}
+
+#endif
+