Skip to content

Commit 7dc38e1

Browse files
Merge pull request #1211 from achingbrain/feat/expose-callback-for-unknown-stun-ufrag
feat: add listener for unhandled STUN requests with ICE UDP mux
2 parents 4254cb4 + ffb8231 commit 7dc38e1

8 files changed

+190
-2
lines changed

CMakeLists.txt

+4
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ set(LIBDATACHANNEL_SOURCES
6666
${CMAKE_CURRENT_SOURCE_DIR}/src/configuration.cpp
6767
${CMAKE_CURRENT_SOURCE_DIR}/src/datachannel.cpp
6868
${CMAKE_CURRENT_SOURCE_DIR}/src/description.cpp
69+
${CMAKE_CURRENT_SOURCE_DIR}/src/iceudpmuxlistener.cpp
6970
${CMAKE_CURRENT_SOURCE_DIR}/src/mediahandler.cpp
7071
${CMAKE_CURRENT_SOURCE_DIR}/src/global.cpp
7172
${CMAKE_CURRENT_SOURCE_DIR}/src/message.cpp
@@ -99,6 +100,7 @@ set(LIBDATACHANNEL_HEADERS
99100
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/configuration.hpp
100101
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/datachannel.hpp
101102
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/description.hpp
103+
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/iceudpmuxlistener.hpp
102104
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/mediahandler.hpp
103105
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/rtcpreceivingsession.hpp
104106
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/common.hpp
@@ -139,6 +141,7 @@ set(LIBDATACHANNEL_IMPL_SOURCES
139141
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/dtlssrtptransport.cpp
140142
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/dtlstransport.cpp
141143
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/icetransport.cpp
144+
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/iceudpmuxlistener.cpp
142145
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/init.cpp
143146
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/peerconnection.cpp
144147
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/logcounter.cpp
@@ -171,6 +174,7 @@ set(LIBDATACHANNEL_IMPL_HEADERS
171174
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/dtlssrtptransport.hpp
172175
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/dtlstransport.hpp
173176
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/icetransport.hpp
177+
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/iceudpmuxlistener.hpp
174178
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/init.hpp
175179
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/internals.hpp
176180
${CMAKE_CURRENT_SOURCE_DIR}/src/impl/peerconnection.hpp

include/rtc/iceudpmuxlistener.hpp

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* Copyright (c) 2025 Alex Potsides
3+
* Copyright (c) 2025 Paul-Louis Ageneau
4+
*
5+
* This Source Code Form is subject to the terms of the Mozilla Public
6+
* License, v. 2.0. If a copy of the MPL was not distributed with this
7+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
8+
*/
9+
10+
#ifndef RTC_ICE_UDP_MUX_LISTENER_H
11+
#define RTC_ICE_UDP_MUX_LISTENER_H
12+
13+
#include "common.hpp"
14+
15+
namespace rtc {
16+
17+
namespace impl {
18+
19+
struct IceUdpMuxListener;
20+
21+
} // namespace impl
22+
23+
struct IceUdpMuxRequest { // TODO change name
24+
string localUfrag;
25+
string remoteUfrag;
26+
string remoteAddress;
27+
uint16_t remotePort;
28+
};
29+
30+
class RTC_CPP_EXPORT IceUdpMuxListener final : private CheshireCat<impl::IceUdpMuxListener> {
31+
public:
32+
IceUdpMuxListener(uint16_t port, optional<string> bindAddress = nullopt);
33+
~IceUdpMuxListener();
34+
35+
void stop();
36+
37+
uint16_t port() const;
38+
39+
void OnUnhandledStunRequest(std::function<void(IceUdpMuxRequest)> callback);
40+
41+
private:
42+
using CheshireCat<impl::IceUdpMuxListener>::impl;
43+
};
44+
45+
} // namespace rtc
46+
47+
#endif

include/rtc/rtc.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "datachannel.hpp"
1717
#include "peerconnection.hpp"
1818
#include "track.hpp"
19+
#include "iceudpmuxlistener.hpp"
1920

2021
#if RTC_ENABLE_WEBSOCKET
2122

src/global.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ std::shared_future<void> Cleanup() { return impl::Init::Instance().cleanup(); }
8888

8989
void SetSctpSettings(SctpSettings s) { impl::Init::Instance().setSctpSettings(std::move(s)); }
9090

91-
RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, LogLevel level) {
91+
std::ostream &operator<<(std::ostream &out, LogLevel level) {
9292
switch (level) {
9393
case LogLevel::Fatal:
9494
out << "fatal";

src/iceudpmuxlistener.cpp

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/**
2+
* Copyright (c) 2025 Alex Potsides
3+
* Copyright (c) 2025 Paul-Louis Ageneau
4+
*
5+
* This Source Code Form is subject to the terms of the Mozilla Public
6+
* License, v. 2.0. If a copy of the MPL was not distributed with this
7+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
8+
*/
9+
10+
#include "iceudpmuxlistener.hpp"
11+
12+
#include "impl/iceudpmuxlistener.hpp"
13+
14+
namespace rtc {
15+
16+
IceUdpMuxListener::IceUdpMuxListener(uint16_t port, optional<string> bindAddress)
17+
: CheshireCat<impl::IceUdpMuxListener>(port, std::move(bindAddress)) {}
18+
19+
IceUdpMuxListener::~IceUdpMuxListener() {}
20+
21+
void IceUdpMuxListener::stop() { impl()->stop(); }
22+
23+
uint16_t IceUdpMuxListener::port() const { return impl()->port; }
24+
25+
void IceUdpMuxListener::OnUnhandledStunRequest(std::function<void(IceUdpMuxRequest)> callback) {
26+
impl()->unhandledStunRequestCallback = callback;
27+
}
28+
29+
} // namespace rtc

src/impl/iceudpmuxlistener.cpp

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/**
2+
* Copyright (c) 2025 Alex Potsides
3+
* Copyright (c) 2025 Paul-Louis Ageneau
4+
*
5+
* This Source Code Form is subject to the terms of the Mozilla Public
6+
* License, v. 2.0. If a copy of the MPL was not distributed with this
7+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
8+
*/
9+
10+
#include "iceudpmuxlistener.hpp"
11+
#include "internals.hpp"
12+
13+
namespace rtc::impl {
14+
15+
#if !USE_NICE
16+
void IceUdpMuxListener::UnhandledStunRequestCallback(const juice_mux_binding_request *info,
17+
void *user_ptr) {
18+
auto listener = static_cast<IceUdpMuxListener *>(user_ptr);
19+
if (!listener)
20+
return;
21+
22+
IceUdpMuxRequest request;
23+
request.localUfrag = info->local_ufrag;
24+
request.remoteUfrag = info->remote_ufrag;
25+
request.remoteAddress = info->address;
26+
request.remotePort = info->port;
27+
listener->unhandledStunRequestCallback(std::move(request));
28+
}
29+
#endif
30+
31+
IceUdpMuxListener::IceUdpMuxListener(uint16_t port, [[maybe_unused]] optional<string> bindAddress) : port(port) {
32+
PLOG_VERBOSE << "Creating IceUdpMuxListener";
33+
34+
#if !USE_NICE
35+
PLOG_DEBUG << "Registering ICE UDP mux listener for port " << port;
36+
if (juice_mux_listen(bindAddress ? bindAddress->c_str() : NULL, port,
37+
IceUdpMuxListener::UnhandledStunRequestCallback, this) < 0) {
38+
throw std::runtime_error("Failed to register ICE UDP mux listener");
39+
}
40+
#else
41+
PLOG_WARNING << "ICE UDP mux is not available with libnice";
42+
#endif
43+
}
44+
45+
IceUdpMuxListener::~IceUdpMuxListener() {
46+
PLOG_VERBOSE << "Destroying IceUdpMuxListener";
47+
stop();
48+
}
49+
50+
void IceUdpMuxListener::stop() {
51+
if (mStopped.exchange(true))
52+
return;
53+
54+
#if !USE_NICE
55+
PLOG_DEBUG << "Unregistering ICE UDP mux listener for port " << port;
56+
if (juice_mux_listen(NULL, port, NULL, NULL) < 0) {
57+
PLOG_ERROR << "Failed to unregister ICE UDP mux listener";
58+
}
59+
#endif
60+
}
61+
62+
} // namespace rtc::impl

src/impl/iceudpmuxlistener.hpp

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/**
2+
* Copyright (c) 2025 Alex Potsides
3+
* Copyright (c) 2025 Paul-Louis Ageneau
4+
*
5+
* This Source Code Form is subject to the terms of the Mozilla Public
6+
* License, v. 2.0. If a copy of the MPL was not distributed with this
7+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
8+
*/
9+
10+
#ifndef RTC_IMPL_ICE_UDP_MUX_LISTENER_H
11+
#define RTC_IMPL_ICE_UDP_MUX_LISTENER_H
12+
13+
#include "common.hpp"
14+
15+
#include "rtc/iceudpmuxlistener.hpp"
16+
17+
#if !USE_NICE
18+
#include <juice/juice.h>
19+
#endif
20+
21+
#include <atomic>
22+
23+
namespace rtc::impl {
24+
25+
struct IceUdpMuxListener final {
26+
IceUdpMuxListener(uint16_t port, optional<string> bindAddress = nullopt);
27+
~IceUdpMuxListener();
28+
29+
void stop();
30+
31+
const uint16_t port;
32+
synchronized_callback<IceUdpMuxRequest> unhandledStunRequestCallback;
33+
34+
private:
35+
#if !USE_NICE
36+
static void UnhandledStunRequestCallback(const juice_mux_binding_request *info, void *user_ptr);
37+
#endif
38+
39+
std::atomic<bool> mStopped;
40+
};
41+
42+
}
43+
44+
#endif
45+

0 commit comments

Comments
 (0)