Compare commits

...

14 Commits

Author SHA1 Message Date
8a61043bd7 Bumped version to 0.11.1 2021-02-04 19:31:59 +01:00
93eaa67f5c Renamed guards for consistency 2021-02-04 19:30:07 +01:00
690653f8ef Merge pull request #326 from paullouisageneau/fix-deadlock-at-exit
Fix possible deadlock at exit
2021-02-04 19:25:33 +01:00
ab392fe0da Prevent scheduling tasks while joining thread pool 2021-02-04 19:08:44 +01:00
669800b39a Merge pull request #324 from hanseuljun/uwp-fix
Uwp fix (addressing #310 with the error dialog popping up)
2021-02-04 18:40:19 +01:00
4ba8c9e3e8 Move uwp-tests and uwp-benchmark to uwp/tests and uwp/benchmark. 2021-02-03 13:57:09 -08:00
1b74ebb0f4 Make setting OUTPUT_NAME work in UWP. 2021-02-03 02:59:56 -08:00
433d5fbe7f Support datachannel-tests and datachannel-benchmark in UWP. 2021-02-03 02:51:43 -08:00
3204a77e89 Add uwp resources that stops uwp dinging with an error dialog for datachannel-tests. 2021-02-03 02:04:55 -08:00
b5589dbd57 Merge pull request #322 from paullouisageneau/fix-stoul
Add checks on std::stoul()
2021-01-30 10:13:00 +01:00
c23fb10725 Fixed compilation with libnice 2021-01-30 09:59:43 +01:00
dbfade4eb3 Changed service to port and added checks on std::stoul() 2021-01-30 09:48:55 +01:00
289b71bc8e Merge pull request #320 from paullouisageneau/fix-double-message
Clean up useless message
2021-01-28 17:42:14 +01:00
e43c3730a6 Removed useless message 2021-01-28 16:48:16 +01:00
28 changed files with 237 additions and 67 deletions

2
.gitignore vendored
View File

@ -5,7 +5,7 @@ node_modules/
*.a *.a
*.so *.so
compile_commands.json compile_commands.json
tests /tests
.DS_Store .DS_Store
.idea .idea

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.7) cmake_minimum_required(VERSION 3.7)
project(libdatachannel project(libdatachannel
VERSION 0.11.0 VERSION 0.11.1
LANGUAGES CXX) LANGUAGES CXX)
set(PROJECT_DESCRIPTION "WebRTC Data Channels Library") set(PROJECT_DESCRIPTION "WebRTC Data Channels Library")
@ -127,6 +127,24 @@ set(TESTS_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/test/benchmark.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/benchmark.cpp
) )
set(TESTS_UWP_RESOURCES
${CMAKE_CURRENT_SOURCE_DIR}/test/uwp/tests/Logo.png
${CMAKE_CURRENT_SOURCE_DIR}/test/uwp/tests/package.appxManifest
${CMAKE_CURRENT_SOURCE_DIR}/test/uwp/tests/SmallLogo.png
${CMAKE_CURRENT_SOURCE_DIR}/test/uwp/tests/SmallLogo44x44.png
${CMAKE_CURRENT_SOURCE_DIR}/test/uwp/tests/SplashScreen.png
${CMAKE_CURRENT_SOURCE_DIR}/test/uwp/tests/StoreLogo.png
${CMAKE_CURRENT_SOURCE_DIR}/test/uwp/tests/Windows_TemporaryKey.pfx)
set(BENCHMARK_UWP_RESOURCES
${CMAKE_CURRENT_SOURCE_DIR}/test/uwp/benchmark/Logo.png
${CMAKE_CURRENT_SOURCE_DIR}/test/uwp/benchmark/package.appxManifest
${CMAKE_CURRENT_SOURCE_DIR}/test/uwp/benchmark/SmallLogo.png
${CMAKE_CURRENT_SOURCE_DIR}/test/uwp/benchmark/SmallLogo44x44.png
${CMAKE_CURRENT_SOURCE_DIR}/test/uwp/benchmark/SplashScreen.png
${CMAKE_CURRENT_SOURCE_DIR}/test/uwp/benchmark/StoreLogo.png
${CMAKE_CURRENT_SOURCE_DIR}/test/uwp/benchmark/Windows_TemporaryKey.pfx)
set(CMAKE_THREAD_PREFER_PTHREAD TRUE) set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
set(THREADS_PREFER_PTHREAD_FLAG TRUE) set(THREADS_PREFER_PTHREAD_FLAG TRUE)
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
@ -284,24 +302,30 @@ endif()
# Tests # Tests
if(NOT NO_TESTS) if(NOT NO_TESTS)
add_executable(datachannel-tests ${TESTS_SOURCES}) if(CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
# Add resource files needed for UWP apps.
add_executable(datachannel-tests ${TESTS_SOURCES} ${TESTS_UWP_RESOURCES})
else()
add_executable(datachannel-tests ${TESTS_SOURCES})
endif()
set_target_properties(datachannel-tests PROPERTIES set_target_properties(datachannel-tests PROPERTIES
VERSION ${PROJECT_VERSION} VERSION ${PROJECT_VERSION}
CXX_STANDARD 17) CXX_STANDARD 17)
if(NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsStore") # Prevent a bug in manifest generation for UWP set_target_properties(datachannel-tests PROPERTIES OUTPUT_NAME tests)
set_target_properties(datachannel-tests PROPERTIES OUTPUT_NAME tests)
endif()
target_include_directories(datachannel-tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) target_include_directories(datachannel-tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
target_link_libraries(datachannel-tests datachannel) target_link_libraries(datachannel-tests datachannel)
# Benchmark # Benchmark
add_executable(datachannel-benchmark test/benchmark.cpp) if(CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
# Add resource files needed for UWP apps.
add_executable(datachannel-benchmark test/benchmark.cpp ${BENCHMARK_UWP_RESOURCES})
else()
add_executable(datachannel-benchmark test/benchmark.cpp)
endif()
set_target_properties(datachannel-benchmark PROPERTIES set_target_properties(datachannel-benchmark PROPERTIES
VERSION ${PROJECT_VERSION} VERSION ${PROJECT_VERSION}
CXX_STANDARD 17) CXX_STANDARD 17)
if(NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsStore") # Prevent a bug in manifest generation for UWP set_target_properties(datachannel-benchmark PROPERTIES OUTPUT_NAME benchmark)
set_target_properties(datachannel-benchmark PROPERTIES OUTPUT_NAME benchmark)
endif()
target_compile_definitions(datachannel-benchmark PRIVATE BENCHMARK_MAIN=1) target_compile_definitions(datachannel-benchmark PRIVATE BENCHMARK_MAIN=1)
target_include_directories(datachannel-benchmark PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) target_include_directories(datachannel-benchmark PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
target_link_libraries(datachannel-benchmark datachannel) target_link_libraries(datachannel-benchmark datachannel)

View File

@ -44,7 +44,7 @@ struct RTC_CPP_EXPORT IceServer {
RelayType relayType_ = RelayType::TurnUdp); RelayType relayType_ = RelayType::TurnUdp);
string hostname; string hostname;
string service; uint16_t port;
Type type; Type type;
string username; string username;
string password; string password;
@ -54,11 +54,11 @@ struct RTC_CPP_EXPORT IceServer {
struct RTC_CPP_EXPORT ProxyServer { struct RTC_CPP_EXPORT ProxyServer {
enum class Type { None = 0, Socks5, Http, Last = Http }; enum class Type { None = 0, Socks5, Http, Last = Http };
ProxyServer(Type type_, string ip_, uint16_t port_, string username_ = "", ProxyServer(Type type_, string hostname_, uint16_t port_, string username_ = "",
string password_ = ""); string password_ = "");
Type type; Type type;
string ip; string hostname;
uint16_t port; uint16_t port;
string username; string username;
string password; string password;

View File

@ -16,8 +16,8 @@
* along with this program; If not, see <http://www.gnu.org/licenses/>. * along with this program; If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef H264RtpPacketizer_hpp #ifndef H264_RTP_PACKETIZER_H
#define H264RtpPacketizer_hpp #define H264_RTP_PACKETIZER_H
#if RTC_ENABLE_MEDIA #if RTC_ENABLE_MEDIA
@ -43,4 +43,4 @@ public:
#endif /* RTC_ENABLE_MEDIA */ #endif /* RTC_ENABLE_MEDIA */
#endif /* H264RtpPacketizer_hpp */ #endif /* H264_RTP_PACKETIZER_H */

View File

@ -16,8 +16,8 @@
* along with this program; If not, see <http://www.gnu.org/licenses/>. * along with this program; If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef NalUnit_hpp #ifndef NAL_UNIT_H
#define NalUnit_hpp #define NAL_UNIT_H
#if RTC_ENABLE_MEDIA #if RTC_ENABLE_MEDIA
@ -63,7 +63,7 @@ private:
struct RTC_CPP_EXPORT NalUnit : binary { struct RTC_CPP_EXPORT NalUnit : binary {
NalUnit(const NalUnit &unit) = default; NalUnit(const NalUnit &unit) = default;
NalUnit(size_t size, bool includingHeader = true) NalUnit(size_t size, bool includingHeader = true)
: binary(size + (includingHeader ? 0 : 1)) {} : binary(size + (includingHeader ? 0 : 1)) {}
template <typename Iterator> template <typename Iterator>
NalUnit(Iterator begin_, Iterator end_) : binary(begin_, end_) {} NalUnit(Iterator begin_, Iterator end_) : binary(begin_, end_) {}
@ -153,4 +153,4 @@ public:
#endif /* RTC_ENABLE_MEDIA */ #endif /* RTC_ENABLE_MEDIA */
#endif /* NalUnit_hpp */ #endif /* NAL_UNIT_H */

View File

@ -167,9 +167,12 @@ bool Candidate::resolve(ResolveMode mode) {
if (getnameinfo(p->ai_addr, socklen_t(p->ai_addrlen), nodebuffer, if (getnameinfo(p->ai_addr, socklen_t(p->ai_addrlen), nodebuffer,
MAX_NUMERICNODE_LEN, servbuffer, MAX_NUMERICSERV_LEN, MAX_NUMERICNODE_LEN, servbuffer, MAX_NUMERICSERV_LEN,
NI_NUMERICHOST | NI_NUMERICSERV) == 0) { NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
try {
mPort = uint16_t(std::stoul(servbuffer));
} catch (...) {
return false;
}
mAddress = nodebuffer; mAddress = nodebuffer;
mPort = uint16_t(std::stoul(servbuffer));
mFamily = p->ai_family == AF_INET6 ? Family::Ipv6 : Family::Ipv4; mFamily = p->ai_family == AF_INET6 ? Family::Ipv6 : Family::Ipv4;
PLOG_VERBOSE << "Resolved candidate: " << mAddress << ' ' << mPort; PLOG_VERBOSE << "Resolved candidate: " << mAddress << ' ' << mPort;
break; break;

View File

@ -60,32 +60,51 @@ IceServer::IceServer(const string &url) {
username = opt[6].value_or(""); username = opt[6].value_or("");
password = opt[8].value_or(""); password = opt[8].value_or("");
hostname = opt[10].value();
service = opt[12].value_or(relayType == RelayType::TurnTls ? "5349" : "3478");
hostname = opt[10].value();
while (!hostname.empty() && hostname.front() == '[') while (!hostname.empty() && hostname.front() == '[')
hostname.erase(hostname.begin()); hostname.erase(hostname.begin());
while (!hostname.empty() && hostname.back() == ']') while (!hostname.empty() && hostname.back() == ']')
hostname.pop_back(); hostname.pop_back();
string service = opt[12].value_or(relayType == RelayType::TurnTls ? "5349" : "3478");
try {
port = uint16_t(std::stoul(service));
} catch (...) {
throw std::invalid_argument("Invalid ICE server port in URL: " + service);
}
} }
IceServer::IceServer(string hostname_, uint16_t port_) IceServer::IceServer(string hostname_, uint16_t port_)
: IceServer(std::move(hostname_), std::to_string(port_)) {} : hostname(std::move(hostname_)), port(port_), type(Type::Stun) {}
IceServer::IceServer(string hostname_, string service_) IceServer::IceServer(string hostname_, string service_)
: hostname(std::move(hostname_)), service(std::move(service_)), type(Type::Stun) {} : hostname(std::move(hostname_)), type(Type::Stun) {
try {
port = uint16_t(std::stoul(service_));
} catch (...) {
throw std::invalid_argument("Invalid ICE server port: " + service_);
}
}
IceServer::IceServer(string hostname_, uint16_t port_, string username_, string password_, IceServer::IceServer(string hostname_, uint16_t port_, string username_, string password_,
RelayType relayType_) RelayType relayType_)
: IceServer(hostname_, std::to_string(port_), std::move(username_), std::move(password_), : hostname(std::move(hostname_)), port(port_), type(Type::Turn), username(std::move(username_)),
relayType_) {} password(std::move(password_)), relayType(relayType_) {}
IceServer::IceServer(string hostname_, string service_, string username_, string password_, IceServer::IceServer(string hostname_, string service_, string username_, string password_,
RelayType relayType_) RelayType relayType_)
: hostname(std::move(hostname_)), service(std::move(service_)), type(Type::Turn), : hostname(std::move(hostname_)), type(Type::Turn), username(std::move(username_)),
username(std::move(username_)), password(std::move(password_)), relayType(relayType_) {} password(std::move(password_)), relayType(relayType_) {
try {
port = uint16_t(std::stoul(service_));
} catch (...) {
throw std::invalid_argument("Invalid ICE server port: " + service_);
}
}
ProxyServer::ProxyServer(Type type_, string ip_, uint16_t port_, string username_, string password_) ProxyServer::ProxyServer(Type type_, string hostname_, uint16_t port_, string username_,
: type(type_), ip(ip_), port(port_), username(username_), password(password_) {} string password_)
: type(type_), hostname(hostname_), port(port_), username(username_), password(password_) {}
} // namespace rtc } // namespace rtc

View File

@ -59,7 +59,13 @@ inline std::pair<string_view, string_view> parse_pair(string_view attr) {
} }
template <typename T> T to_integer(string_view s) { template <typename T> T to_integer(string_view s) {
return std::is_signed<T>::value ? T(std::stol(string(s))) : T(std::stoul(string(s))); const string str(s);
try {
return std::is_signed<T>::value ? T(std::stol(str)) : T(std::stoul(str));
}
catch(...) {
throw std::invalid_argument("Invalid integer \"" + str + "\" in description");
}
} }
} // namespace } // namespace
@ -823,7 +829,7 @@ void Description::Media::parseSdpLine(string_view line) {
} else if (key == "rtcp-mux") { } else if (key == "rtcp-mux") {
// always added // always added
} else if (key == "ssrc") { } else if (key == "ssrc") {
mSsrcs.emplace_back(std::stoul(string(value))); mSsrcs.emplace_back(to_integer<uint32_t>(value));
} else { } else {
Entry::parseSdpLine(line); Entry::parseSdpLine(line);
} }
@ -843,7 +849,7 @@ std::vector<uint32_t> Description::Media::getSSRCs() {
for (auto &val : mAttributes) { for (auto &val : mAttributes) {
PLOG_DEBUG << val; PLOG_DEBUG << val;
if (val.find("ssrc:") == 0) { if (val.find("ssrc:") == 0) {
vec.emplace_back(std::stoul(string(val.substr(5, val.find(" "))))); vec.emplace_back(to_integer<uint32_t>(val.substr(5, val.find(" "))));
} }
} }
return vec; return vec;

View File

@ -103,11 +103,11 @@ IceTransport::IceTransport(const Configuration &config, candidate_callback candi
// Pick a STUN server // Pick a STUN server
for (auto &server : servers) { for (auto &server : servers) {
if (!server.hostname.empty() && server.type == IceServer::Type::Stun) { if (!server.hostname.empty() && server.type == IceServer::Type::Stun) {
if (server.service.empty()) if (server.port == 0)
server.service = "3478"; // STUN UDP port server.port = 3478; // STUN UDP port
PLOG_INFO << "Using STUN server \"" << server.hostname << ":" << server.service << "\""; PLOG_INFO << "Using STUN server \"" << server.hostname << ":" << server.port << "\"";
jconfig.stun_server_host = server.hostname.c_str(); jconfig.stun_server_host = server.hostname.c_str();
jconfig.stun_server_port = uint16_t(std::stoul(server.service)); jconfig.stun_server_port = server.port;
break; break;
} }
} }
@ -119,13 +119,13 @@ IceTransport::IceTransport(const Configuration &config, candidate_callback candi
int k = 0; int k = 0;
for (auto &server : servers) { for (auto &server : servers) {
if (!server.hostname.empty() && server.type == IceServer::Type::Turn) { if (!server.hostname.empty() && server.type == IceServer::Type::Turn) {
if (server.service.empty()) if (server.port == 0)
server.service = "3478"; // TURN UDP port server.port = 3478; // TURN UDP port
PLOG_INFO << "Using TURN server \"" << server.hostname << ":" << server.service << "\""; PLOG_INFO << "Using TURN server \"" << server.hostname << ":" << server.port << "\"";
turn_servers[k].host = server.hostname.c_str(); turn_servers[k].host = server.hostname.c_str();
turn_servers[k].username = server.username.c_str(); turn_servers[k].username = server.username.c_str();
turn_servers[k].password = server.password.c_str(); turn_servers[k].password = server.password.c_str();
turn_servers[k].port = uint16_t(std::stoul(server.service)); turn_servers[k].port = server.port;
if (++k >= MAX_TURN_SERVERS_COUNT) if (++k >= MAX_TURN_SERVERS_COUNT)
break; break;
} }
@ -402,7 +402,7 @@ IceTransport::IceTransport(const Configuration &config, candidate_callback candi
if (config.proxyServer.has_value()) { if (config.proxyServer.has_value()) {
ProxyServer proxyServer = config.proxyServer.value(); ProxyServer proxyServer = config.proxyServer.value();
g_object_set(G_OBJECT(mNiceAgent.get()), "proxy-type", proxyServer.type, nullptr); g_object_set(G_OBJECT(mNiceAgent.get()), "proxy-type", proxyServer.type, nullptr);
g_object_set(G_OBJECT(mNiceAgent.get()), "proxy-ip", proxyServer.ip.c_str(), nullptr); g_object_set(G_OBJECT(mNiceAgent.get()), "proxy-ip", proxyServer.hostname.c_str(), nullptr);
g_object_set(G_OBJECT(mNiceAgent.get()), "proxy-port", proxyServer.port, nullptr); g_object_set(G_OBJECT(mNiceAgent.get()), "proxy-port", proxyServer.port, nullptr);
g_object_set(G_OBJECT(mNiceAgent.get()), "proxy-username", proxyServer.username.c_str(), g_object_set(G_OBJECT(mNiceAgent.get()), "proxy-username", proxyServer.username.c_str(),
nullptr); nullptr);
@ -422,8 +422,8 @@ IceTransport::IceTransport(const Configuration &config, candidate_callback candi
continue; continue;
if (server.type != IceServer::Type::Stun) if (server.type != IceServer::Type::Stun)
continue; continue;
if (server.service.empty()) if (server.port == 0)
server.service = "3478"; // STUN UDP port server.port = 3478; // STUN UDP port
struct addrinfo hints = {}; struct addrinfo hints = {};
hints.ai_family = AF_INET; // IPv4 hints.ai_family = AF_INET; // IPv4
@ -431,9 +431,10 @@ IceTransport::IceTransport(const Configuration &config, candidate_callback candi
hints.ai_protocol = IPPROTO_UDP; hints.ai_protocol = IPPROTO_UDP;
hints.ai_flags = AI_ADDRCONFIG; hints.ai_flags = AI_ADDRCONFIG;
struct addrinfo *result = nullptr; struct addrinfo *result = nullptr;
if (getaddrinfo(server.hostname.c_str(), server.service.c_str(), &hints, &result) != 0) { if (getaddrinfo(server.hostname.c_str(), std::to_string(server.port).c_str(), &hints,
&result) != 0) {
PLOG_WARNING << "Unable to resolve STUN server address: " << server.hostname << ':' PLOG_WARNING << "Unable to resolve STUN server address: " << server.hostname << ':'
<< server.service; << server.port;
continue; continue;
} }
@ -444,7 +445,7 @@ IceTransport::IceTransport(const Configuration &config, candidate_callback candi
if (getnameinfo(p->ai_addr, p->ai_addrlen, nodebuffer, MAX_NUMERICNODE_LEN, if (getnameinfo(p->ai_addr, p->ai_addrlen, nodebuffer, MAX_NUMERICNODE_LEN,
servbuffer, MAX_NUMERICNODE_LEN, servbuffer, MAX_NUMERICNODE_LEN,
NI_NUMERICHOST | NI_NUMERICSERV) == 0) { NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
PLOG_INFO << "Using STUN server \"" << server.hostname << ":" << server.service PLOG_INFO << "Using STUN server \"" << server.hostname << ":" << server.port
<< "\""; << "\"";
g_object_set(G_OBJECT(mNiceAgent.get()), "stun-server", nodebuffer, nullptr); g_object_set(G_OBJECT(mNiceAgent.get()), "stun-server", nodebuffer, nullptr);
g_object_set(G_OBJECT(mNiceAgent.get()), "stun-server-port", g_object_set(G_OBJECT(mNiceAgent.get()), "stun-server-port",
@ -466,8 +467,8 @@ IceTransport::IceTransport(const Configuration &config, candidate_callback candi
continue; continue;
if (server.type != IceServer::Type::Turn) if (server.type != IceServer::Type::Turn)
continue; continue;
if (server.service.empty()) if (server.port == 0)
server.service = server.relayType == IceServer::RelayType::TurnTls ? "5349" : "3478"; server.port = server.relayType == IceServer::RelayType::TurnTls ? 5349 : 3478;
struct addrinfo hints = {}; struct addrinfo hints = {};
hints.ai_family = AF_UNSPEC; hints.ai_family = AF_UNSPEC;
@ -477,9 +478,10 @@ IceTransport::IceTransport(const Configuration &config, candidate_callback candi
server.relayType == IceServer::RelayType::TurnUdp ? IPPROTO_UDP : IPPROTO_TCP; server.relayType == IceServer::RelayType::TurnUdp ? IPPROTO_UDP : IPPROTO_TCP;
hints.ai_flags = AI_ADDRCONFIG; hints.ai_flags = AI_ADDRCONFIG;
struct addrinfo *result = nullptr; struct addrinfo *result = nullptr;
if (getaddrinfo(server.hostname.c_str(), server.service.c_str(), &hints, &result) != 0) { if (getaddrinfo(server.hostname.c_str(), std::to_string(server.port).c_str(), &hints,
&result) != 0) {
PLOG_WARNING << "Unable to resolve TURN server address: " << server.hostname << ':' PLOG_WARNING << "Unable to resolve TURN server address: " << server.hostname << ':'
<< server.service; << server.port;
continue; continue;
} }
@ -490,7 +492,7 @@ IceTransport::IceTransport(const Configuration &config, candidate_callback candi
if (getnameinfo(p->ai_addr, p->ai_addrlen, nodebuffer, MAX_NUMERICNODE_LEN, if (getnameinfo(p->ai_addr, p->ai_addrlen, nodebuffer, MAX_NUMERICNODE_LEN,
servbuffer, MAX_NUMERICNODE_LEN, servbuffer, MAX_NUMERICNODE_LEN,
NI_NUMERICHOST | NI_NUMERICSERV) == 0) { NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
PLOG_INFO << "Using TURN server \"" << server.hostname << ":" << server.service PLOG_INFO << "Using TURN server \"" << server.hostname << ":" << server.port
<< "\""; << "\"";
NiceRelayType niceRelayType; NiceRelayType niceRelayType;
switch (server.relayType) { switch (server.relayType) {

View File

@ -25,18 +25,39 @@ Processor::Processor(size_t limit) : mTasks(limit) {}
Processor::~Processor() { join(); } Processor::~Processor() { join(); }
void Processor::join() { void Processor::join() {
std::unique_lock lock(mMutex); // We need to detect situations where the thread pool does not execute a pending task at exit
mCondition.wait(lock, [this]() { return !mPending && mTasks.empty(); }); std::optional<unsigned int> counter;
while (true) {
std::shared_future<void> pending;
{
std::unique_lock lock(mMutex);
if (!mPending // no pending task
|| (counter && *counter == mCounter)) { // or no scheduled task after the last one
// Processing is stopped, clear everything and return
mPending.reset();
while (!mTasks.empty())
mTasks.pop();
return;
}
pending = *mPending;
counter = mCounter;
}
// Wait for the pending task
pending.wait();
}
} }
void Processor::schedule() { void Processor::schedule() {
std::unique_lock lock(mMutex); std::unique_lock lock(mMutex);
if (auto next = mTasks.tryPop()) { if (auto next = mTasks.tryPop()) {
ThreadPool::Instance().enqueue(std::move(*next)); mPending = ThreadPool::Instance().enqueue(std::move(*next)).share();
++mCounter;
} else { } else {
// No more tasks mPending.reset(); // No more tasks
mPending = false;
mCondition.notify_all();
} }
} }

View File

@ -54,10 +54,10 @@ protected:
const init_token mInitToken = Init::Token(); const init_token mInitToken = Init::Token();
Queue<std::function<void()>> mTasks; Queue<std::function<void()>> mTasks;
bool mPending = false; // true iff a task is pending in the thread pool std::optional<std::shared_future<void>> mPending; // future of the pending task
unsigned int mCounter = 0; // Number of scheduled tasks
mutable std::mutex mMutex; mutable std::mutex mMutex;
std::condition_variable mCondition;
}; };
template <class F, class... Args> void Processor::enqueue(F &&f, Args &&...args) { template <class F, class... Args> void Processor::enqueue(F &&f, Args &&...args) {
@ -65,12 +65,12 @@ template <class F, class... Args> void Processor::enqueue(F &&f, Args &&...args)
auto bound = std::bind(std::forward<F>(f), std::forward<Args>(args)...); auto bound = std::bind(std::forward<F>(f), std::forward<Args>(args)...);
auto task = [this, bound = std::move(bound)]() mutable { auto task = [this, bound = std::move(bound)]() mutable {
scope_guard guard(std::bind(&Processor::schedule, this)); // chain the next task scope_guard guard(std::bind(&Processor::schedule, this)); // chain the next task
return bound(); bound();
}; };
if (!mPending) { if (!mPending) {
ThreadPool::Instance().enqueue(std::move(task)); mPending = ThreadPool::Instance().enqueue(std::move(task)).share();
mPending = true; ++mCounter;
} else { } else {
mTasks.push(std::move(task)); mTasks.push(std::move(task));
} }

View File

@ -588,7 +588,6 @@ int SctpTransport::handleWrite(byte *data, size_t len, uint8_t /*tos*/, uint8_t
std::unique_lock lock(mWriteMutex); std::unique_lock lock(mWriteMutex);
PLOG_VERBOSE << "Handle write, len=" << len; PLOG_VERBOSE << "Handle write, len=" << len;
auto message = make_message(data, data + len);
if (!outgoing(make_message(data, data + len))) if (!outgoing(make_message(data, data + len)))
return -1; return -1;

View File

@ -96,6 +96,10 @@ std::function<void()> ThreadPool::dequeue() {
mCondition.wait(lock); mCondition.wait(lock);
} }
} }
while (!mTasks.empty())
mTasks.pop();
return nullptr; return nullptr;
} }

View File

@ -100,8 +100,16 @@ auto ThreadPool::schedule(clock::duration delay, F &&f, Args &&...args)
template <class F, class... Args> template <class F, class... Args>
auto ThreadPool::schedule(clock::time_point time, F &&f, Args &&...args) auto ThreadPool::schedule(clock::time_point time, F &&f, Args &&...args)
-> invoke_future_t<F, Args...> { -> invoke_future_t<F, Args...> {
std::unique_lock lock(mMutex);
using R = std::invoke_result_t<std::decay_t<F>, std::decay_t<Args>...>; using R = std::invoke_result_t<std::decay_t<F>, std::decay_t<Args>...>;
std::unique_lock lock(mMutex);
if (mJoining) {
std::promise<R> promise;
std::future<R> result = promise.get_future();
promise.set_exception(std::make_exception_ptr(
std::runtime_error("Scheduled a task while joining the thread pool")));
return result;
}
auto bound = std::bind(std::forward<F>(f), std::forward<Args>(args)...); auto bound = std::bind(std::forward<F>(f), std::forward<Args>(args)...);
auto task = std::make_shared<std::packaged_task<R()>>([bound = std::move(bound)]() mutable { auto task = std::make_shared<std::packaged_task<R()>>([bound = std::move(bound)]() mutable {
try { try {

BIN
test/uwp/benchmark/Logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 909 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 B

Binary file not shown.

View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4"
xmlns:iot2="http://schemas.microsoft.com/appx/manifest/iot/windows10/2"
IgnorableNamespaces="uap mp">
<Identity Name="EF284012-D73C-360F-A800-2D2910675E38" Publisher="CN=CMake" Version="1.0.0.0" />
<mp:PhoneIdentity PhoneProductId="EF284012-D73C-360F-A800-2D2910675E38" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
<Properties>
<DisplayName>datachannel-benchmark</DisplayName>
<PublisherDisplayName>CMake</PublisherDisplayName>
<Logo>StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate" />
</Resources>
<Applications>
<Application
Id="App"
Executable="benchmark.exe"
EntryPoint="datachannel-benchmark.App"
desktop4:Subsystem="console"
desktop4:SupportsMultipleInstances="true"
iot2:Subsystem="console"
iot2:SupportsMultipleInstances="true">
<uap:VisualElements
DisplayName="datachannel-benchmark"
Description="datachannel-benchmark"
BackgroundColor="#336699"
Square150x150Logo="Logo.png"
Square44x44Logo="SmallLogo44x44.png">
<uap:SplashScreen Image="SplashScreen.png" />
</uap:VisualElements>
</Application>
</Applications>
</Package>

BIN
test/uwp/tests/Logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 909 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 B

Binary file not shown.

View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4"
xmlns:iot2="http://schemas.microsoft.com/appx/manifest/iot/windows10/2"
IgnorableNamespaces="uap mp">
<Identity Name="7D85E652-0312-3746-8F5A-315F52839776" Publisher="CN=CMake" Version="1.0.0.0" />
<mp:PhoneIdentity PhoneProductId="7D85E652-0312-3746-8F5A-315F52839776" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
<Properties>
<DisplayName>datachannel-tests</DisplayName>
<PublisherDisplayName>CMake</PublisherDisplayName>
<Logo>StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate" />
</Resources>
<Applications>
<Application
Id="App"
Executable="tests.exe"
EntryPoint="datachannel-tests.App"
desktop4:Subsystem="console"
desktop4:SupportsMultipleInstances="true"
iot2:Subsystem="console"
iot2:SupportsMultipleInstances="true">
<uap:VisualElements
DisplayName="datachannel-tests"
Description="datachannel-tests"
BackgroundColor="#336699"
Square150x150Logo="Logo.png"
Square44x44Logo="SmallLogo44x44.png">
<uap:SplashScreen Image="SplashScreen.png" />
</uap:VisualElements>
</Application>
</Applications>
</Package>