瀏覽代碼

Moved all global initialization to Init singleton

Paul-Louis Ageneau 5 年之前
父節點
當前提交
6881e85071

+ 3 - 0
CMakeLists.txt

@@ -31,6 +31,8 @@ set(LIBDATACHANNEL_SOURCES
 	${CMAKE_CURRENT_SOURCE_DIR}/src/description.cpp
 	${CMAKE_CURRENT_SOURCE_DIR}/src/dtlstransport.cpp
 	${CMAKE_CURRENT_SOURCE_DIR}/src/icetransport.cpp
+	${CMAKE_CURRENT_SOURCE_DIR}/src/init.cpp
+	${CMAKE_CURRENT_SOURCE_DIR}/src/log.cpp
 	${CMAKE_CURRENT_SOURCE_DIR}/src/peerconnection.cpp
 	${CMAKE_CURRENT_SOURCE_DIR}/src/rtc.cpp
 	${CMAKE_CURRENT_SOURCE_DIR}/src/sctptransport.cpp
@@ -44,6 +46,7 @@ set(LIBDATACHANNEL_HEADERS
 	${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/datachannel.hpp
 	${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/description.hpp
 	${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/include.hpp
+	${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/init.hpp
 	${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/log.hpp
 	${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/message.hpp
 	${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/peerconnection.hpp

+ 50 - 0
include/rtc/init.hpp

@@ -0,0 +1,50 @@
+/**
+ * Copyright (c) 2020 Paul-Louis Ageneau
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef RTC_INIT_H
+#define RTC_INIT_H
+
+#include "include.hpp"
+
+#include <mutex>
+
+namespace rtc {
+
+class Init;
+using init_token = std::shared_ptr<Init>;
+
+class Init {
+public:
+	static init_token Token();
+	static void Cleanup();
+
+	~Init();
+
+private:
+	Init();
+
+	static std::weak_ptr<Init> Weak;
+	static init_token Global;
+	static std::mutex Mutex;
+};
+
+inline void Cleanup() { Init::Cleanup(); }
+
+} // namespace rtc
+
+#endif

+ 2 - 17
include/rtc/log.hpp

@@ -19,9 +19,7 @@
 #ifndef RTC_LOG_H
 #define RTC_LOG_H
 
-#include "plog/Appenders/ColorConsoleAppender.h"
 #include "plog/Log.h"
-#include "plog/Logger.h"
 
 namespace rtc {
 
@@ -35,21 +33,8 @@ enum class LogLevel { // Don't change, it must match plog severity
 	Verbose = 6
 };
 
-inline void InitLogger(plog::Severity severity, plog::IAppender *appender = nullptr) {
-	static plog::ColorConsoleAppender<plog::TxtFormatter> consoleAppender;
-	static plog::Logger<0> *logger = nullptr;
-	if (!logger) {
-		logger = &plog::init(severity, appender ? appender : &consoleAppender);
-		PLOG_DEBUG << "Logger initialized";
-	} else {
-		logger->setMaxSeverity(severity);
-		if (appender)
-			logger->addAppender(appender);
-	}
-}
-
-inline void InitLogger(LogLevel level) { InitLogger(static_cast<plog::Severity>(level)); }
-
+void InitLogger(LogLevel level);
+void InitLogger(plog::Severity severity, plog::IAppender *appender = nullptr);
 }
 
 #endif

+ 3 - 0
include/rtc/peerconnection.hpp

@@ -24,6 +24,7 @@
 #include "datachannel.hpp"
 #include "description.hpp"
 #include "include.hpp"
+#include "init.hpp"
 #include "message.hpp"
 #include "reliability.hpp"
 #include "rtc.hpp"
@@ -88,6 +89,8 @@ public:
 	void onGatheringStateChange(std::function<void(GatheringState state)> callback);
 
 private:
+	init_token mInitToken = Init::Token();
+
 	std::shared_ptr<IceTransport> initIceTransport(Description::Role role);
 	std::shared_ptr<DtlsTransport> initDtlsTransport();
 	std::shared_ptr<SctpTransport> initSctpTransport();

+ 1 - 0
include/rtc/rtc.hpp

@@ -18,6 +18,7 @@
 
 // C++ API
 #include "include.hpp"
+#include "init.hpp" // for rtc::Cleanup()
 #include "log.hpp"
 //
 #include "datachannel.hpp"

+ 0 - 7
src/certificate.cpp

@@ -245,13 +245,6 @@ shared_ptr<Certificate> make_certificate(const string &commonName) {
 	if (auto it = cache.find(commonName); it != cache.end())
 		return it->second;
 
-	if (cache.empty()) {
-		// This is the first call to OpenSSL
-		OPENSSL_init_ssl(0, NULL);
-		SSL_load_error_strings();
-		ERR_load_crypto_strings();
-	}
-
 	shared_ptr<X509> x509(X509_new(), X509_free);
 	shared_ptr<EVP_PKEY> pkey(EVP_PKEY_new(), EVP_PKEY_free);
 

+ 13 - 2
src/dtlstransport.cpp

@@ -55,6 +55,14 @@ static bool check_gnutls(int ret, const string &message = "GnuTLS error") {
 
 namespace rtc {
 
+void DtlsTransport::Init() {
+	// Nothing to do
+}
+
+void DtlsTransport::Cleanup() {
+	// Nothing to do
+}
+
 DtlsTransport::DtlsTransport(shared_ptr<IceTransport> lower, shared_ptr<Certificate> certificate,
                              verifier_callback verifierCallback,
                              state_callback stateChangeCallback)
@@ -324,7 +332,7 @@ BIO_METHOD *DtlsTransport::BioMethods = NULL;
 int DtlsTransport::TransportExIndex = -1;
 std::mutex DtlsTransport::GlobalMutex;
 
-void DtlsTransport::GlobalInit() {
+void DtlsTransport::Init() {
 	std::lock_guard lock(GlobalMutex);
 	if (!BioMethods) {
 		BioMethods = BIO_meth_new(BIO_TYPE_BIO, "DTLS writer");
@@ -340,6 +348,10 @@ void DtlsTransport::GlobalInit() {
 	}
 }
 
+void DtlsTransport::Cleanup() {
+	// Nothing to do
+}
+
 DtlsTransport::DtlsTransport(shared_ptr<IceTransport> lower, shared_ptr<Certificate> certificate,
                              verifier_callback verifierCallback, state_callback stateChangeCallback)
     : Transport(lower), mCertificate(certificate), mState(State::Disconnected),
@@ -347,7 +359,6 @@ DtlsTransport::DtlsTransport(shared_ptr<IceTransport> lower, shared_ptr<Certific
       mStateChangeCallback(std::move(stateChangeCallback)) {
 
 	PLOG_DEBUG << "Initializing DTLS transport (OpenSSL)";
-	GlobalInit();
 
 	if (!(mCtx = SSL_CTX_new(DTLS_method())))
 		throw std::runtime_error("Unable to create SSL context");

+ 3 - 1
src/dtlstransport.hpp

@@ -43,6 +43,9 @@ class IceTransport;
 
 class DtlsTransport : public Transport {
 public:
+	static void Init();
+	static void Cleanup();
+
 	enum class State { Disconnected, Connecting, Connected, Failed };
 
 	using verifier_callback = std::function<bool(const std::string &fingerprint)>;
@@ -87,7 +90,6 @@ private:
 	static int TransportExIndex;
 	static std::mutex GlobalMutex;
 
-	static void GlobalInit();
 	static int CertificateCallback(int preverify_ok, X509_STORE_CTX *ctx);
 	static void InfoCallback(const SSL *ssl, int where, int ret);
 

+ 86 - 0
src/init.cpp

@@ -0,0 +1,86 @@
+/**
+ * Copyright (c) 2020 Paul-Louis Ageneau
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "init.hpp"
+
+#include "dtlstransport.hpp"
+#include "sctptransport.hpp"
+
+#ifdef _WIN32
+#include <winsock2.h>
+#endif
+
+#if USE_GNUTLS
+// Nothing to do
+#else
+#include <openssl/err.h>
+#include <openssl/ssl.h>
+#endif
+
+using std::shared_ptr;
+
+namespace rtc {
+
+std::weak_ptr<Init> Init::Weak;
+init_token Init::Global;
+std::mutex Init::Mutex;
+
+init_token Init::Token() {
+	std::lock_guard lock(Mutex);
+
+	if (!Global) {
+		if (auto token = Weak.lock())
+			Global = token;
+		else
+			Global = shared_ptr<Init>(new Init());
+	}
+	return Global;
+}
+
+void Init::Cleanup() { Global.reset(); }
+
+Init::Init() {
+#ifdef _WIN32
+	WSADATA wsaData;
+	if (WSAStartup(MAKEWORD(2, 2), &wsaData))
+		throw std::runtime_error("WSAStartup failed, error=" + std::to_string(WSAGetLastError()));
+#endif
+
+#if USE_GNUTLS
+		// Nothing to do
+#else
+	OPENSSL_init_ssl(0, NULL);
+	SSL_load_error_strings();
+	ERR_load_crypto_strings();
+#endif
+
+	DtlsTransport::Init();
+	SctpTransport::Init();
+}
+
+Init::~Init() {
+	DtlsTransport::Cleanup();
+	SctpTransport::Cleanup();
+
+#ifdef _WIN32
+	WSACleanup();
+#endif
+}
+
+} // namespace rtc
+

+ 42 - 0
src/log.cpp

@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) 2019-2020 Paul-Louis Ageneau
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "log.hpp"
+
+#include "plog/Appenders/ColorConsoleAppender.h"
+#include "plog/Log.h"
+#include "plog/Logger.h"
+
+namespace rtc {
+
+void InitLogger(LogLevel level) { InitLogger(static_cast<plog::Severity>(level)); }
+
+void InitLogger(plog::Severity severity, plog::IAppender *appender) {
+	static plog::ColorConsoleAppender<plog::TxtFormatter> consoleAppender;
+	static plog::Logger<0> *logger = nullptr;
+	if (!logger) {
+		logger = &plog::init(severity, appender ? appender : &consoleAppender);
+		PLOG_DEBUG << "Logger initialized";
+	} else {
+		logger->setMaxSeverity(severity);
+		if (appender)
+			logger->addAppender(appender);
+	}
+}
+}
+

+ 0 - 4
src/peerconnection.cpp

@@ -25,10 +25,6 @@
 
 #include <iostream>
 
-#ifdef _WIN32
-#include <winsock2.h>
-#endif
-
 namespace rtc {
 
 using namespace std::placeholders;

+ 12 - 26
src/sctptransport.cpp

@@ -49,31 +49,20 @@ using std::shared_ptr;
 
 namespace rtc {
 
-std::mutex SctpTransport::GlobalMutex;
-int SctpTransport::InstancesCount = 0;
-
-void SctpTransport::GlobalInit() {
-	std::lock_guard lock(GlobalMutex);
-	if (InstancesCount++ == 0) {
-		usrsctp_init(0, &SctpTransport::WriteCallback, nullptr);
-		usrsctp_sysctl_set_sctp_ecn_enable(0);
-		usrsctp_sysctl_set_sctp_init_rtx_max_default(5);
-		usrsctp_sysctl_set_sctp_path_rtx_max_default(5);
-		usrsctp_sysctl_set_sctp_assoc_rtx_max_default(5);              // single path
-		usrsctp_sysctl_set_sctp_rto_min_default(1 * 1000);             // ms
-		usrsctp_sysctl_set_sctp_rto_max_default(10 * 1000);            // ms
-		usrsctp_sysctl_set_sctp_rto_initial_default(1 * 1000);         // ms
-		usrsctp_sysctl_set_sctp_init_rto_max_default(10 * 1000);       // ms
-		usrsctp_sysctl_set_sctp_heartbeat_interval_default(10 * 1000); // ms
-	}
+void SctpTransport::Init() {
+	usrsctp_init(0, &SctpTransport::WriteCallback, nullptr);
+	usrsctp_sysctl_set_sctp_ecn_enable(0);
+	usrsctp_sysctl_set_sctp_init_rtx_max_default(5);
+	usrsctp_sysctl_set_sctp_path_rtx_max_default(5);
+	usrsctp_sysctl_set_sctp_assoc_rtx_max_default(5);              // single path
+	usrsctp_sysctl_set_sctp_rto_min_default(1 * 1000);             // ms
+	usrsctp_sysctl_set_sctp_rto_max_default(10 * 1000);            // ms
+	usrsctp_sysctl_set_sctp_rto_initial_default(1 * 1000);         // ms
+	usrsctp_sysctl_set_sctp_init_rto_max_default(10 * 1000);       // ms
+	usrsctp_sysctl_set_sctp_heartbeat_interval_default(10 * 1000); // ms
 }
 
-void SctpTransport::GlobalCleanup() {
-	std::lock_guard lock(GlobalMutex);
-	if (--InstancesCount == 0) {
-		usrsctp_finish();
-	}
-}
+void SctpTransport::Cleanup() { usrsctp_finish(); }
 
 SctpTransport::SctpTransport(std::shared_ptr<Transport> lower, uint16_t port,
                              message_callback recvCallback, amount_callback bufferedAmountCallback,
@@ -84,7 +73,6 @@ SctpTransport::SctpTransport(std::shared_ptr<Transport> lower, uint16_t port,
 	onRecv(recvCallback);
 
 	PLOG_DEBUG << "Initializing SCTP transport";
-	GlobalInit();
 
 	usrsctp_register_address(this);
 	mSock = usrsctp_socket(AF_CONN, SOCK_STREAM, IPPROTO_SCTP, &SctpTransport::RecvCallback,
@@ -175,8 +163,6 @@ SctpTransport::~SctpTransport() {
 
 	usrsctp_close(mSock);
 	usrsctp_deregister_address(this);
-
-	GlobalCleanup();
 }
 
 SctpTransport::State SctpTransport::state() const { return mState; }

+ 3 - 6
src/sctptransport.hpp

@@ -35,6 +35,9 @@ namespace rtc {
 
 class SctpTransport : public Transport {
 public:
+	static void Init();
+	static void Cleanup();
+
 	enum class State { Disconnected, Connecting, Connected, Failed };
 
 	using amount_callback = std::function<void(uint16_t streamId, size_t amount)>;
@@ -106,12 +109,6 @@ private:
 	                        struct sctp_rcvinfo recv_info, int flags, void *user_data);
 	static int SendCallback(struct socket *sock, uint32_t sb_free);
 	static int WriteCallback(void *sctp_ptr, void *data, size_t len, uint8_t tos, uint8_t set_df);
-
-	void GlobalInit();
-	void GlobalCleanup();
-
-	static std::mutex GlobalMutex;
-	static int InstancesCount;
 };
 
 } // namespace rtc