From 98924943a62ca082a90ab71d0dc3ba01300a5208 Mon Sep 17 00:00:00 2001 From: winlin Date: Wed, 24 Jun 2020 17:03:56 +0800 Subject: [PATCH 01/37] Build: Refine the options for configure --- trunk/auto/options.sh | 19 +++---------------- trunk/configure | 12 ++++++------ 2 files changed, 9 insertions(+), 22 deletions(-) diff --git a/trunk/auto/options.sh b/trunk/auto/options.sh index f0b9e56c0..39599e082 100755 --- a/trunk/auto/options.sh +++ b/trunk/auto/options.sh @@ -203,8 +203,7 @@ Experts: --use-shared-st Use link shared libraries for ST which uses MPL license. --use-shared-srt Use link shared libraries for SRT which uses MPL license. --build-tag= Set the build object directory suffix. - --with-clean Configure SRS and do make clean if possible. - --without-clean Configure SRS and never make clean even possible. + --clean=on|off Whether do 'make clean' when configure. --detect-sendmmsg=on|off Whether detect the sendmmsg API. --has-sendmmsg=on|off Whether OS supports sendmmsg API. --simulator=on|off Whether enable RTC network simulator. @@ -437,7 +436,7 @@ if [ $help = yes ]; then exit 0 fi -function apply_user_presets() { +function apply_detail_options() { # always set the log level for all presets. SRS_LOG_VERBOSE=NO SRS_LOG_INFO=NO @@ -536,19 +535,7 @@ function apply_user_presets() { if [[ $SRS_RTC == YES && $SRS_FFMPEG_FIT == RESERVED ]]; then SRS_FFMPEG_FIT=YES fi -} -apply_user_presets -##################################################################################### -# parse detail feature options -##################################################################################### -for option -do - parse_user_option_to_value_and_option - parse_user_option -done - -function apply_user_detail_options() { # if transcode/ingest specified, requires the ffmpeg stub classes. SRS_FFMPEG_STUB=NO if [ $SRS_TRANSCODE = YES ]; then SRS_FFMPEG_STUB=YES; fi @@ -611,7 +598,7 @@ function apply_user_detail_options() { SRS_SENDMMSG=NO fi } -apply_user_detail_options +apply_detail_options function regenerate_options() { # save all config options to macro to write to auto headers file diff --git a/trunk/configure b/trunk/configure index 20c6a1ed9..605fc2db8 100755 --- a/trunk/configure +++ b/trunk/configure @@ -499,13 +499,13 @@ destroy: (cd ${SRS_OBJS_DIR} && rm -rf ${SRS_PLATFORM}) clean_srs: - (cd ${SRS_OBJS_DIR} && rm -rf srs srs_utest) - (cd ${SRS_OBJS_DIR}/${SRS_PLATFORM} && rm -rf include/* lib/*) - (cd ${SRS_OBJS_DIR}/${SRS_PLATFORM} && find src -name "*.o" -delete) - (cd ${SRS_OBJS_DIR}/${SRS_PLATFORM} && find utest -name "*.o" -delete) + @(cd ${SRS_OBJS_DIR} && rm -rf srs srs_utest) + @(cd ${SRS_OBJS_DIR}/${SRS_PLATFORM} && rm -rf include/* lib/*) + @(cd ${SRS_OBJS_DIR}/${SRS_PLATFORM} && find src -name "*.o" -delete) + @(cd ${SRS_OBJS_DIR}/${SRS_PLATFORM} && find utest -name "*.o" -delete) clean_modules: - (cd ${SRS_OBJS_DIR} && rm -rf $__mdefaults) + @(cd ${SRS_OBJS_DIR} && rm -rf $__mdefaults) clean_openssl: (cd ${SRS_OBJS_DIR}/${SRS_PLATFORM} && rm -rf openssl*) @@ -783,7 +783,7 @@ done # Do cleanup when configure done. ##################################################################################### if [[ $SRS_CLEAN == YES && -f Makefile ]]; then - echo "Do full cleanup, you can disable it by: --without-clean" + echo "Do full cleanup, you can disable it by: --clean=off" make clean fi From 6807299ed2f45f50235a2f8d430f903a5ce55eab Mon Sep 17 00:00:00 2001 From: "jinxue.cgh" Date: Wed, 24 Jun 2020 17:09:26 +0800 Subject: [PATCH 02/37] rtc: refine get dtls_context according request --- trunk/src/app/srs_app_rtc_conn.cpp | 2 +- trunk/src/app/srs_app_rtc_dtls.cpp | 141 +++++++++++++++++------------ trunk/src/app/srs_app_rtc_dtls.hpp | 6 +- 3 files changed, 86 insertions(+), 63 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index e592d5341..d443e03d2 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -154,7 +154,7 @@ srs_error_t SrsRtcDtls::initialize(SrsRequest* r) } // TODO: FIXME: Support config by vhost to use RSA or ECDSA certificate. - if ((dtls = SSL_new(SrsDtls::instance()->get_dtls_ctx())) == NULL) { + if ((dtls = SSL_new(SrsDtls::instance()->get_dtls_ctx(r))) == NULL) { return srs_error_new(ERROR_OpenSslCreateSSL, "SSL_new dtls"); } diff --git a/trunk/src/app/srs_app_rtc_dtls.cpp b/trunk/src/app/srs_app_rtc_dtls.cpp index 68419af8c..255573f44 100644 --- a/trunk/src/app/srs_app_rtc_dtls.cpp +++ b/trunk/src/app/srs_app_rtc_dtls.cpp @@ -38,12 +38,24 @@ SrsDtls* SrsDtls::_instance = NULL; SrsDtls::SrsDtls() { - dtls_ctx = NULL; + dtls_cert = NULL; + dtls_pkey = NULL; + eckey = NULL; } SrsDtls::~SrsDtls() { - SSL_CTX_free(dtls_ctx); + if (eckey) { + EC_KEY_free(eckey); + } + + if (dtls_pkey) { + EVP_PKEY_free(dtls_pkey); + } + + if (dtls_cert) { + X509_free(dtls_cert); + } } // The return value of verify_callback controls the strategy of the further verification process. If verify_callback @@ -66,7 +78,7 @@ srs_error_t SrsDtls::init(SrsRequest* r) srs_error_t err = srs_success; // Initialize once. - if (dtls_ctx) { + if (dtls_cert) { return err; } @@ -78,14 +90,6 @@ srs_error_t SrsDtls::init(SrsRequest* r) OpenSSL_add_ssl_algorithms(); #endif -#if OPENSSL_VERSION_NUMBER < 0x10002000L // v1.0.2 - dtls_ctx = SSL_CTX_new(DTLSv1_method()); -#else - dtls_ctx = SSL_CTX_new(DTLS_method()); - //dtls_ctx = SSL_CTX_new(DTLSv1_method()); - //dtls_ctx = SSL_CTX_new(DTLSv1_2_method()); -#endif - // Initialize SRTP first. srs_assert(srtp_init() == 0); @@ -93,7 +97,7 @@ srs_error_t SrsDtls::init(SrsRequest* r) bool is_ecdsa = _srs_config->get_rtc_server_ecdsa(); // Create keys by RSA or ECDSA. - EVP_PKEY* dtls_pkey = EVP_PKEY_new(); + dtls_pkey = EVP_PKEY_new(); srs_assert(dtls_pkey); if (!is_ecdsa) { // By RSA RSA* rsa = RSA_new(); @@ -116,14 +120,9 @@ srs_error_t SrsDtls::init(SrsRequest* r) BN_free(exponent); } if (is_ecdsa) { // By ECDSA, https://stackoverflow.com/a/6006898 - EC_KEY* eckey = EC_KEY_new(); + eckey = EC_KEY_new(); srs_assert(eckey); -#if OPENSSL_VERSION_NUMBER >= 0x10002000L // v1.0.2 - // For ECDSA, we could set the curves list. - // @see https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set1_curves_list.html - SSL_CTX_set1_curves_list(dtls_ctx, "P-521:P-384:P-256"); -#endif // Should use the curves in ClientHello.supported_groups // For example: // Supported Group: x25519 (0x001d) @@ -145,25 +144,15 @@ srs_error_t SrsDtls::init(SrsRequest* r) srs_assert(EC_KEY_set_group(eckey, ecgroup) == 1); srs_assert(EC_KEY_generate_key(eckey) == 1); - // For openssl <1.1, we must set the ECDH manually. - // @see https://stackoverrun.com/cn/q/10791887 -#if OPENSSL_VERSION_NUMBER < 0x10100000L // v1.1.x - #if OPENSSL_VERSION_NUMBER < 0x10002000L // v1.0.2 - SSL_CTX_set_tmp_ecdh(dtls_ctx, eckey); - #else - SSL_CTX_set_ecdh_auto(dtls_ctx, 1); - #endif -#endif // @see https://www.openssl.org/docs/man1.1.0/man3/EVP_PKEY_type.html srs_assert(EVP_PKEY_set1_EC_KEY(dtls_pkey, eckey) == 1); EC_GROUP_free(ecgroup); - EC_KEY_free(eckey); } // Create certificate, from previous generated pkey. // TODO: Support ECDSA certificate. - X509* dtls_cert = X509_new(); + dtls_cert = X509_new(); srs_assert(dtls_cert); if (true) { X509_NAME* subject = X509_NAME_new(); @@ -191,36 +180,6 @@ srs_error_t SrsDtls::init(SrsRequest* r) X509_NAME_free(subject); } - // Setup DTLS context. - if (true) { - // We use "ALL", while you can use "DEFAULT" means "ALL:!EXPORT:!LOW:!aNULL:!eNULL:!SSLv2" - // @see https://www.openssl.org/docs/man1.0.2/man1/ciphers.html - srs_assert(SSL_CTX_set_cipher_list(dtls_ctx, "ALL") == 1); - - // Setup the certificate. - srs_assert(SSL_CTX_use_certificate(dtls_ctx, dtls_cert) == 1); - srs_assert(SSL_CTX_use_PrivateKey(dtls_ctx, dtls_pkey) == 1); - - // Server will send Certificate Request. - // @see https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set_verify.html - // TODO: FIXME: Config it, default to off to make the packet smaller. - SSL_CTX_set_verify(dtls_ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, verify_callback); - // The depth count is "level 0:peer certificate", "level 1: CA certificate", - // "level 2: higher level CA certificate", and so on. - // @see https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set_verify.html - SSL_CTX_set_verify_depth(dtls_ctx, 4); - - // Whether we should read as many input bytes as possible (for non-blocking reads) or not. - // @see https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set_read_ahead.html - SSL_CTX_set_read_ahead(dtls_ctx, 1); - - // TODO: Maybe we can use SRTP-GCM in future. - // @see https://bugs.chromium.org/p/chromium/issues/detail?id=713701 - // @see https://groups.google.com/forum/#!topic/discuss-webrtc/PvCbWSetVAQ - // @remark Only support SRTP_AES128_CM_SHA1_80, please read ssl/d1_srtp.c - srs_assert(SSL_CTX_set_tlsext_use_srtp(dtls_ctx, "SRTP_AES128_CM_SHA1_80") == 0); - } - // Show DTLS fingerprint if (true) { char fp[100] = {0}; @@ -257,8 +216,70 @@ SrsDtls* SrsDtls::instance() return _instance; } -SSL_CTX* SrsDtls::get_dtls_ctx() +SSL_CTX* SrsDtls::get_dtls_ctx(SrsRequest* r) { + SSL_CTX* dtls_ctx; +#if OPENSSL_VERSION_NUMBER < 0x10002000L // v1.0.2 + dtls_ctx = SSL_CTX_new(DTLSv1_method()); +#else + dtls_ctx = SSL_CTX_new(DTLS_method()); + //dtls_ctx = SSL_CTX_new(DTLSv1_method()); + //dtls_ctx = SSL_CTX_new(DTLSv1_2_method()); +#endif + + // Whether use ECDSA certificate. + bool is_ecdsa = _srs_config->get_rtc_server_ecdsa(); + if (is_ecdsa) { // By ECDSA, https://stackoverflow.com/a/6006898 + EC_KEY* eckey = EC_KEY_new(); + srs_assert(eckey); + +#if OPENSSL_VERSION_NUMBER >= 0x10002000L // v1.0.2 + // For ECDSA, we could set the curves list. + // @see https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set1_curves_list.html + SSL_CTX_set1_curves_list(dtls_ctx, "P-521:P-384:P-256"); +#endif + + // For openssl <1.1, we must set the ECDH manually. + // @see https://stackoverrun.com/cn/q/10791887 +#if OPENSSL_VERSION_NUMBER < 0x10100000L // v1.1.x + #if OPENSSL_VERSION_NUMBER < 0x10002000L // v1.0.2 + SSL_CTX_set_tmp_ecdh(dtls_ctx, eckey); + #else + SSL_CTX_set_ecdh_auto(dtls_ctx, 1); + #endif +#endif + } + + // Setup DTLS context. + if (true) { + // We use "ALL", while you can use "DEFAULT" means "ALL:!EXPORT:!LOW:!aNULL:!eNULL:!SSLv2" + // @see https://www.openssl.org/docs/man1.0.2/man1/ciphers.html + srs_assert(SSL_CTX_set_cipher_list(dtls_ctx, "ALL") == 1); + + // Setup the certificate. + srs_assert(SSL_CTX_use_certificate(dtls_ctx, dtls_cert) == 1); + srs_assert(SSL_CTX_use_PrivateKey(dtls_ctx, dtls_pkey) == 1); + + // Server will send Certificate Request. + // @see https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set_verify.html + // TODO: FIXME: Config it, default to off to make the packet smaller. + SSL_CTX_set_verify(dtls_ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, verify_callback); + // The depth count is "level 0:peer certificate", "level 1: CA certificate", + // "level 2: higher level CA certificate", and so on. + // @see https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set_verify.html + SSL_CTX_set_verify_depth(dtls_ctx, 4); + + // Whether we should read as many input bytes as possible (for non-blocking reads) or not. + // @see https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set_read_ahead.html + SSL_CTX_set_read_ahead(dtls_ctx, 1); + + // TODO: Maybe we can use SRTP-GCM in future. + // @see https://bugs.chromium.org/p/chromium/issues/detail?id=713701 + // @see https://groups.google.com/forum/#!topic/discuss-webrtc/PvCbWSetVAQ + // @remark Only support SRTP_AES128_CM_SHA1_80, please read ssl/d1_srtp.c + srs_assert(SSL_CTX_set_tlsext_use_srtp(dtls_ctx, "SRTP_AES128_CM_SHA1_80") == 0); + } + return dtls_ctx; } diff --git a/trunk/src/app/srs_app_rtc_dtls.hpp b/trunk/src/app/srs_app_rtc_dtls.hpp index 892aa945b..3f25814a0 100644 --- a/trunk/src/app/srs_app_rtc_dtls.hpp +++ b/trunk/src/app/srs_app_rtc_dtls.hpp @@ -38,7 +38,9 @@ private: static SrsDtls* _instance; private: std::string fingerprint; - SSL_CTX* dtls_ctx; + X509* dtls_cert; + EVP_PKEY* dtls_pkey; + EC_KEY* eckey; private: SrsDtls(); virtual ~SrsDtls(); @@ -46,7 +48,7 @@ public: srs_error_t init(SrsRequest* r); public: static SrsDtls* instance(); - SSL_CTX* get_dtls_ctx(); + SSL_CTX* get_dtls_ctx(SrsRequest* r); public: std::string get_fingerprint() const; }; From 0bf0a6140116440b5644b8552eafd330752e1885 Mon Sep 17 00:00:00 2001 From: winlin Date: Wed, 24 Jun 2020 18:03:09 +0800 Subject: [PATCH 03/37] RTC: Refine DTLS code. --- trunk/src/app/srs_app_rtc_conn.cpp | 4 ++-- trunk/src/app/srs_app_rtc_dtls.cpp | 3 ++- trunk/src/app/srs_app_rtc_dtls.hpp | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index d443e03d2..291392646 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -153,8 +153,8 @@ srs_error_t SrsRtcDtls::initialize(SrsRequest* r) return srs_error_wrap(err, "DTLS init"); } - // TODO: FIXME: Support config by vhost to use RSA or ECDSA certificate. - if ((dtls = SSL_new(SrsDtls::instance()->get_dtls_ctx(r))) == NULL) { + // TODO: FIXME: Leak for SSL_CTX* return by build_dtls_ctx. + if ((dtls = SSL_new(SrsDtls::instance()->build_dtls_ctx())) == NULL) { return srs_error_new(ERROR_OpenSslCreateSSL, "SSL_new dtls"); } diff --git a/trunk/src/app/srs_app_rtc_dtls.cpp b/trunk/src/app/srs_app_rtc_dtls.cpp index 255573f44..5291a6fc3 100644 --- a/trunk/src/app/srs_app_rtc_dtls.cpp +++ b/trunk/src/app/srs_app_rtc_dtls.cpp @@ -216,7 +216,7 @@ SrsDtls* SrsDtls::instance() return _instance; } -SSL_CTX* SrsDtls::get_dtls_ctx(SrsRequest* r) +SSL_CTX* SrsDtls::build_dtls_ctx() { SSL_CTX* dtls_ctx; #if OPENSSL_VERSION_NUMBER < 0x10002000L // v1.0.2 @@ -228,6 +228,7 @@ SSL_CTX* SrsDtls::get_dtls_ctx(SrsRequest* r) #endif // Whether use ECDSA certificate. + // TODO: FIXME: Support config by vhost to use RSA or ECDSA certificate. bool is_ecdsa = _srs_config->get_rtc_server_ecdsa(); if (is_ecdsa) { // By ECDSA, https://stackoverflow.com/a/6006898 EC_KEY* eckey = EC_KEY_new(); diff --git a/trunk/src/app/srs_app_rtc_dtls.hpp b/trunk/src/app/srs_app_rtc_dtls.hpp index 3f25814a0..3296b50b2 100644 --- a/trunk/src/app/srs_app_rtc_dtls.hpp +++ b/trunk/src/app/srs_app_rtc_dtls.hpp @@ -48,7 +48,7 @@ public: srs_error_t init(SrsRequest* r); public: static SrsDtls* instance(); - SSL_CTX* get_dtls_ctx(SrsRequest* r); + SSL_CTX* build_dtls_ctx(); public: std::string get_fingerprint() const; }; From f3f9636d80759196987d9bda4bb6cb29ed0b66fa Mon Sep 17 00:00:00 2001 From: "jinxue.cgh" Date: Wed, 24 Jun 2020 20:03:21 +0800 Subject: [PATCH 04/37] RTC: refine dtls certificate --- trunk/src/app/srs_app_rtc_conn.cpp | 4 -- trunk/src/app/srs_app_rtc_dtls.cpp | 98 +++++++++++++++++----------- trunk/src/app/srs_app_rtc_dtls.hpp | 38 ++++++++--- trunk/src/app/srs_app_rtc_server.cpp | 12 +++- trunk/src/app/srs_app_rtc_server.hpp | 1 + 5 files changed, 100 insertions(+), 53 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 291392646..5ce7c8b55 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -149,10 +149,6 @@ srs_error_t SrsRtcDtls::initialize(SrsRequest* r) { srs_error_t err = srs_success; - if ((err = SrsDtls::instance()->init(r)) != srs_success) { - return srs_error_wrap(err, "DTLS init"); - } - // TODO: FIXME: Leak for SSL_CTX* return by build_dtls_ctx. if ((dtls = SSL_new(SrsDtls::instance()->build_dtls_ctx())) == NULL) { return srs_error_new(ERROR_OpenSslCreateSSL, "SSL_new dtls"); diff --git a/trunk/src/app/srs_app_rtc_dtls.cpp b/trunk/src/app/srs_app_rtc_dtls.cpp index 5291a6fc3..2a3dab050 100644 --- a/trunk/src/app/srs_app_rtc_dtls.cpp +++ b/trunk/src/app/srs_app_rtc_dtls.cpp @@ -34,16 +34,14 @@ using namespace std; #include #include -SrsDtls* SrsDtls::_instance = NULL; - -SrsDtls::SrsDtls() +SrsDtlsCertificate::SrsDtlsCertificate() { dtls_cert = NULL; dtls_pkey = NULL; eckey = NULL; } -SrsDtls::~SrsDtls() +SrsDtlsCertificate::~SrsDtlsCertificate() { if (eckey) { EC_KEY_free(eckey); @@ -58,22 +56,7 @@ SrsDtls::~SrsDtls() } } -// The return value of verify_callback controls the strategy of the further verification process. If verify_callback -// returns 0, the verification process is immediately stopped with "verification failed" state. If SSL_VERIFY_PEER is -// set, a verification failure alert is sent to the peer and the TLS/SSL handshake is terminated. If verify_callback -// returns 1, the verification process is continued. If verify_callback always returns 1, the TLS/SSL handshake will -// not be terminated with respect to verification failures and the connection will be established. The calling process -// can however retrieve the error code of the last verification error using SSL_get_verify_result(3) or by maintaining -// its own error storage managed by verify_callback. -// @see https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set_verify.html -static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) -{ - // Always OK, we don't check the certificate of client, - // because we allow client self-sign certificate. - return 1; -} - -srs_error_t SrsDtls::init(SrsRequest* r) +srs_error_t SrsDtlsCertificate::initialize() { srs_error_t err = srs_success; @@ -94,12 +77,12 @@ srs_error_t SrsDtls::init(SrsRequest* r) srs_assert(srtp_init() == 0); // Whether use ECDSA certificate. - bool is_ecdsa = _srs_config->get_rtc_server_ecdsa(); + ecdsa_mode = _srs_config->get_rtc_server_ecdsa(); // Create keys by RSA or ECDSA. dtls_pkey = EVP_PKEY_new(); srs_assert(dtls_pkey); - if (!is_ecdsa) { // By RSA + if (!ecdsa_mode) { // By RSA RSA* rsa = RSA_new(); srs_assert(rsa); @@ -119,7 +102,7 @@ srs_error_t SrsDtls::init(SrsRequest* r) RSA_free(rsa); BN_free(exponent); } - if (is_ecdsa) { // By ECDSA, https://stackoverflow.com/a/6006898 + if (ecdsa_mode) { // By ECDSA, https://stackoverflow.com/a/6006898 eckey = EC_KEY_new(); srs_assert(eckey); @@ -208,6 +191,56 @@ srs_error_t SrsDtls::init(SrsRequest* r) return err; } +X509* SrsDtlsCertificate::get_cert() +{ + return dtls_cert; +} + +EVP_PKEY* SrsDtlsCertificate::get_public_key() +{ + return dtls_pkey; +} + +EC_KEY* SrsDtlsCertificate::get_ecdsa_key() +{ + return eckey; +} + +std::string SrsDtlsCertificate::get_fingerprint() +{ + return fingerprint; +} + +bool SrsDtlsCertificate::is_ecdsa() +{ + return ecdsa_mode; +} + +SrsDtls* SrsDtls::_instance = NULL; + +SrsDtls::SrsDtls() +{ +} + +SrsDtls::~SrsDtls() +{ +} + +// The return value of verify_callback controls the strategy of the further verification process. If verify_callback +// returns 0, the verification process is immediately stopped with "verification failed" state. If SSL_VERIFY_PEER is +// set, a verification failure alert is sent to the peer and the TLS/SSL handshake is terminated. If verify_callback +// returns 1, the verification process is continued. If verify_callback always returns 1, the TLS/SSL handshake will +// not be terminated with respect to verification failures and the connection will be established. The calling process +// can however retrieve the error code of the last verification error using SSL_get_verify_result(3) or by maintaining +// its own error storage managed by verify_callback. +// @see https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set_verify.html +static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) +{ + // Always OK, we don't check the certificate of client, + // because we allow client self-sign certificate. + return 1; +} + SrsDtls* SrsDtls::instance() { if (!_instance) { @@ -227,12 +260,7 @@ SSL_CTX* SrsDtls::build_dtls_ctx() //dtls_ctx = SSL_CTX_new(DTLSv1_2_method()); #endif - // Whether use ECDSA certificate. - // TODO: FIXME: Support config by vhost to use RSA or ECDSA certificate. - bool is_ecdsa = _srs_config->get_rtc_server_ecdsa(); - if (is_ecdsa) { // By ECDSA, https://stackoverflow.com/a/6006898 - EC_KEY* eckey = EC_KEY_new(); - srs_assert(eckey); + if (_rtc_dtls_certificate->is_ecdsa()) { // By ECDSA, https://stackoverflow.com/a/6006898 #if OPENSSL_VERSION_NUMBER >= 0x10002000L // v1.0.2 // For ECDSA, we could set the curves list. @@ -244,7 +272,7 @@ SSL_CTX* SrsDtls::build_dtls_ctx() // @see https://stackoverrun.com/cn/q/10791887 #if OPENSSL_VERSION_NUMBER < 0x10100000L // v1.1.x #if OPENSSL_VERSION_NUMBER < 0x10002000L // v1.0.2 - SSL_CTX_set_tmp_ecdh(dtls_ctx, eckey); + SSL_CTX_set_tmp_ecdh(dtls_ctx, _rtc_dtls_certificate->get_ecdsa_key()); #else SSL_CTX_set_ecdh_auto(dtls_ctx, 1); #endif @@ -258,8 +286,8 @@ SSL_CTX* SrsDtls::build_dtls_ctx() srs_assert(SSL_CTX_set_cipher_list(dtls_ctx, "ALL") == 1); // Setup the certificate. - srs_assert(SSL_CTX_use_certificate(dtls_ctx, dtls_cert) == 1); - srs_assert(SSL_CTX_use_PrivateKey(dtls_ctx, dtls_pkey) == 1); + srs_assert(SSL_CTX_use_certificate(dtls_ctx, _rtc_dtls_certificate->get_cert()) == 1); + srs_assert(SSL_CTX_use_PrivateKey(dtls_ctx, _rtc_dtls_certificate->get_public_key()) == 1); // Server will send Certificate Request. // @see https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set_verify.html @@ -283,9 +311,3 @@ SSL_CTX* SrsDtls::build_dtls_ctx() return dtls_ctx; } - -std::string SrsDtls::get_fingerprint() const -{ - return fingerprint; -} - diff --git a/trunk/src/app/srs_app_rtc_dtls.hpp b/trunk/src/app/srs_app_rtc_dtls.hpp index 3296b50b2..e132ff8d7 100644 --- a/trunk/src/app/srs_app_rtc_dtls.hpp +++ b/trunk/src/app/srs_app_rtc_dtls.hpp @@ -32,25 +32,45 @@ class SrsRequest; #include +class SrsDtlsCertificate +{ +private: + std::string fingerprint; + bool ecdsa_mode; + X509* dtls_cert; + EVP_PKEY* dtls_pkey; + EC_KEY* eckey; +public: + SrsDtlsCertificate(); + virtual ~SrsDtlsCertificate(); +public: + // Initialize DTLS certificate. + srs_error_t initialize(); + // dtls_cert + X509* get_cert(); + // public key + EVP_PKEY* get_public_key(); + // ECDSA key + EC_KEY* get_ecdsa_key(); + // certificate fingerprint + std::string get_fingerprint(); + // whether is ecdsa + bool is_ecdsa(); +}; + +// @global dtls certficate for rtc module. +SrsDtlsCertificate* _rtc_dtls_certificate = new SrsDtlsCertificate(); + class SrsDtls { private: static SrsDtls* _instance; -private: - std::string fingerprint; - X509* dtls_cert; - EVP_PKEY* dtls_pkey; - EC_KEY* eckey; private: SrsDtls(); virtual ~SrsDtls(); -public: - srs_error_t init(SrsRequest* r); public: static SrsDtls* instance(); SSL_CTX* build_dtls_ctx(); -public: - std::string get_fingerprint() const; }; #endif diff --git a/trunk/src/app/srs_app_rtc_server.cpp b/trunk/src/app/srs_app_rtc_server.cpp index 673165e4e..5c1ce5e51 100644 --- a/trunk/src/app/srs_app_rtc_server.cpp +++ b/trunk/src/app/srs_app_rtc_server.cpp @@ -333,7 +333,7 @@ srs_error_t SrsRtcServer::create_session( local_sdp.set_ice_ufrag(local_ufrag); local_sdp.set_ice_pwd(local_pwd); local_sdp.set_fingerprint_algo("sha-256"); - local_sdp.set_fingerprint(SrsDtls::instance()->get_fingerprint()); + local_sdp.set_fingerprint(_rtc_dtls_certificate->get_fingerprint()); // We allows to mock the eip of server. if (!mock_eip.empty()) { @@ -366,7 +366,7 @@ srs_error_t SrsRtcServer::create_session2(SrsSdp& local_sdp, SrsRtcSession** pse local_sdp.set_ice_ufrag(local_ufrag); local_sdp.set_ice_pwd(local_pwd); local_sdp.set_fingerprint_algo("sha-256"); - local_sdp.set_fingerprint(SrsDtls::instance()->get_fingerprint()); + local_sdp.set_fingerprint(_rtc_dtls_certificate->get_fingerprint()); // We allows to mock the eip of server. std::vector candidate_ips = get_candidate_ips(); @@ -521,12 +521,20 @@ RtcServerAdapter::RtcServerAdapter() RtcServerAdapter::~RtcServerAdapter() { srs_freep(rtc); + + if (_rtc_dtls_certificate) { + srs_freep(_rtc_dtls_certificate); + } } srs_error_t RtcServerAdapter::initialize() { srs_error_t err = srs_success; + if ((err = _rtc_dtls_certificate->initialize()) != srs_success) { + return srs_error_wrap(err, "rtc dtls certificate initialize"); + } + if ((err = rtc->initialize()) != srs_success) { return srs_error_wrap(err, "rtc server initialize"); } diff --git a/trunk/src/app/srs_app_rtc_server.hpp b/trunk/src/app/srs_app_rtc_server.hpp index 164971710..a39fce66b 100644 --- a/trunk/src/app/srs_app_rtc_server.hpp +++ b/trunk/src/app/srs_app_rtc_server.hpp @@ -31,6 +31,7 @@ #include #include #include +#include #include From 9addade2b4baa51068ca26545c189ae9cbdfd30d Mon Sep 17 00:00:00 2001 From: "jinxue.cgh" Date: Wed, 24 Jun 2020 20:21:36 +0800 Subject: [PATCH 05/37] RTC: delete SrsDTLS single instance --- trunk/src/app/srs_app_rtc_conn.cpp | 2 +- trunk/src/app/srs_app_rtc_dtls.cpp | 47 +++++++++++----------------- trunk/src/app/srs_app_rtc_dtls.hpp | 11 +++---- trunk/src/app/srs_app_rtc_server.cpp | 13 ++++---- trunk/src/app/srs_app_rtc_server.hpp | 1 - 5 files changed, 30 insertions(+), 44 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 5ce7c8b55..9b27f7893 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -150,7 +150,7 @@ srs_error_t SrsRtcDtls::initialize(SrsRequest* r) srs_error_t err = srs_success; // TODO: FIXME: Leak for SSL_CTX* return by build_dtls_ctx. - if ((dtls = SSL_new(SrsDtls::instance()->build_dtls_ctx())) == NULL) { + if ((dtls = SSL_new(SrsDtls::build_dtls_ctx())) == NULL) { return srs_error_new(ERROR_OpenSslCreateSSL, "SSL_new dtls"); } diff --git a/trunk/src/app/srs_app_rtc_dtls.cpp b/trunk/src/app/srs_app_rtc_dtls.cpp index 2a3dab050..3bbdc5ee9 100644 --- a/trunk/src/app/srs_app_rtc_dtls.cpp +++ b/trunk/src/app/srs_app_rtc_dtls.cpp @@ -34,6 +34,21 @@ using namespace std; #include #include +// The return value of verify_callback controls the strategy of the further verification process. If verify_callback +// returns 0, the verification process is immediately stopped with "verification failed" state. If SSL_VERIFY_PEER is +// set, a verification failure alert is sent to the peer and the TLS/SSL handshake is terminated. If verify_callback +// returns 1, the verification process is continued. If verify_callback always returns 1, the TLS/SSL handshake will +// not be terminated with respect to verification failures and the connection will be established. The calling process +// can however retrieve the error code of the last verification error using SSL_get_verify_result(3) or by maintaining +// its own error storage managed by verify_callback. +// @see https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set_verify.html +static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) +{ + // Always OK, we don't check the certificate of client, + // because we allow client self-sign certificate. + return 1; +} + SrsDtlsCertificate::SrsDtlsCertificate() { dtls_cert = NULL; @@ -216,7 +231,6 @@ bool SrsDtlsCertificate::is_ecdsa() return ecdsa_mode; } -SrsDtls* SrsDtls::_instance = NULL; SrsDtls::SrsDtls() { @@ -226,29 +240,6 @@ SrsDtls::~SrsDtls() { } -// The return value of verify_callback controls the strategy of the further verification process. If verify_callback -// returns 0, the verification process is immediately stopped with "verification failed" state. If SSL_VERIFY_PEER is -// set, a verification failure alert is sent to the peer and the TLS/SSL handshake is terminated. If verify_callback -// returns 1, the verification process is continued. If verify_callback always returns 1, the TLS/SSL handshake will -// not be terminated with respect to verification failures and the connection will be established. The calling process -// can however retrieve the error code of the last verification error using SSL_get_verify_result(3) or by maintaining -// its own error storage managed by verify_callback. -// @see https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set_verify.html -static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) -{ - // Always OK, we don't check the certificate of client, - // because we allow client self-sign certificate. - return 1; -} - -SrsDtls* SrsDtls::instance() -{ - if (!_instance) { - _instance = new SrsDtls(); - } - return _instance; -} - SSL_CTX* SrsDtls::build_dtls_ctx() { SSL_CTX* dtls_ctx; @@ -260,7 +251,7 @@ SSL_CTX* SrsDtls::build_dtls_ctx() //dtls_ctx = SSL_CTX_new(DTLSv1_2_method()); #endif - if (_rtc_dtls_certificate->is_ecdsa()) { // By ECDSA, https://stackoverflow.com/a/6006898 + if (_srs_rtc_dtls_certificate->is_ecdsa()) { // By ECDSA, https://stackoverflow.com/a/6006898 #if OPENSSL_VERSION_NUMBER >= 0x10002000L // v1.0.2 // For ECDSA, we could set the curves list. @@ -272,7 +263,7 @@ SSL_CTX* SrsDtls::build_dtls_ctx() // @see https://stackoverrun.com/cn/q/10791887 #if OPENSSL_VERSION_NUMBER < 0x10100000L // v1.1.x #if OPENSSL_VERSION_NUMBER < 0x10002000L // v1.0.2 - SSL_CTX_set_tmp_ecdh(dtls_ctx, _rtc_dtls_certificate->get_ecdsa_key()); + SSL_CTX_set_tmp_ecdh(dtls_ctx, _srs_rtc_dtls_certificate->get_ecdsa_key()); #else SSL_CTX_set_ecdh_auto(dtls_ctx, 1); #endif @@ -286,8 +277,8 @@ SSL_CTX* SrsDtls::build_dtls_ctx() srs_assert(SSL_CTX_set_cipher_list(dtls_ctx, "ALL") == 1); // Setup the certificate. - srs_assert(SSL_CTX_use_certificate(dtls_ctx, _rtc_dtls_certificate->get_cert()) == 1); - srs_assert(SSL_CTX_use_PrivateKey(dtls_ctx, _rtc_dtls_certificate->get_public_key()) == 1); + srs_assert(SSL_CTX_use_certificate(dtls_ctx, _srs_rtc_dtls_certificate->get_cert()) == 1); + srs_assert(SSL_CTX_use_PrivateKey(dtls_ctx, _srs_rtc_dtls_certificate->get_public_key()) == 1); // Server will send Certificate Request. // @see https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set_verify.html diff --git a/trunk/src/app/srs_app_rtc_dtls.hpp b/trunk/src/app/srs_app_rtc_dtls.hpp index e132ff8d7..6ed55b3ce 100644 --- a/trunk/src/app/srs_app_rtc_dtls.hpp +++ b/trunk/src/app/srs_app_rtc_dtls.hpp @@ -58,19 +58,16 @@ public: bool is_ecdsa(); }; -// @global dtls certficate for rtc module. -SrsDtlsCertificate* _rtc_dtls_certificate = new SrsDtlsCertificate(); +// @global config object. +extern SrsDtlsCertificate* _srs_rtc_dtls_certificate; class SrsDtls { -private: - static SrsDtls* _instance; -private: +public: SrsDtls(); virtual ~SrsDtls(); public: - static SrsDtls* instance(); - SSL_CTX* build_dtls_ctx(); + static SSL_CTX* build_dtls_ctx(); }; #endif diff --git a/trunk/src/app/srs_app_rtc_server.cpp b/trunk/src/app/srs_app_rtc_server.cpp index 5c1ce5e51..5ecc50d65 100644 --- a/trunk/src/app/srs_app_rtc_server.cpp +++ b/trunk/src/app/srs_app_rtc_server.cpp @@ -40,6 +40,9 @@ #include #include +// @global dtls certficate for rtc module. +SrsDtlsCertificate* _srs_rtc_dtls_certificate = new SrsDtlsCertificate(); + using namespace std; static bool is_stun(const uint8_t* data, const int size) @@ -333,7 +336,7 @@ srs_error_t SrsRtcServer::create_session( local_sdp.set_ice_ufrag(local_ufrag); local_sdp.set_ice_pwd(local_pwd); local_sdp.set_fingerprint_algo("sha-256"); - local_sdp.set_fingerprint(_rtc_dtls_certificate->get_fingerprint()); + local_sdp.set_fingerprint(_srs_rtc_dtls_certificate->get_fingerprint()); // We allows to mock the eip of server. if (!mock_eip.empty()) { @@ -366,7 +369,7 @@ srs_error_t SrsRtcServer::create_session2(SrsSdp& local_sdp, SrsRtcSession** pse local_sdp.set_ice_ufrag(local_ufrag); local_sdp.set_ice_pwd(local_pwd); local_sdp.set_fingerprint_algo("sha-256"); - local_sdp.set_fingerprint(_rtc_dtls_certificate->get_fingerprint()); + local_sdp.set_fingerprint(_srs_rtc_dtls_certificate->get_fingerprint()); // We allows to mock the eip of server. std::vector candidate_ips = get_candidate_ips(); @@ -521,17 +524,13 @@ RtcServerAdapter::RtcServerAdapter() RtcServerAdapter::~RtcServerAdapter() { srs_freep(rtc); - - if (_rtc_dtls_certificate) { - srs_freep(_rtc_dtls_certificate); - } } srs_error_t RtcServerAdapter::initialize() { srs_error_t err = srs_success; - if ((err = _rtc_dtls_certificate->initialize()) != srs_success) { + if ((err = _srs_rtc_dtls_certificate->initialize()) != srs_success) { return srs_error_wrap(err, "rtc dtls certificate initialize"); } diff --git a/trunk/src/app/srs_app_rtc_server.hpp b/trunk/src/app/srs_app_rtc_server.hpp index a39fce66b..164971710 100644 --- a/trunk/src/app/srs_app_rtc_server.hpp +++ b/trunk/src/app/srs_app_rtc_server.hpp @@ -31,7 +31,6 @@ #include #include #include -#include #include From 2948b90f43c74c9c0f2b858b5577ed5e8dff7a2b Mon Sep 17 00:00:00 2001 From: "jinxue.cgh" Date: Thu, 25 Jun 2020 12:03:21 +0800 Subject: [PATCH 06/37] RTC: refine rtc dtls --- trunk/src/app/srs_app_rtc_conn.cpp | 187 ++++++++--------------------- trunk/src/app/srs_app_rtc_conn.hpp | 27 ++--- trunk/src/app/srs_app_rtc_dtls.cpp | 139 ++++++++++++++++++++- trunk/src/app/srs_app_rtc_dtls.hpp | 35 +++++- 4 files changed, 235 insertions(+), 153 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 9b27f7893..517d42178 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -43,7 +43,6 @@ using namespace std; #include #include #include -#include #include #include #include @@ -111,29 +110,26 @@ SrsNtp SrsNtp::to_time_ms(uint64_t ntp) } -SrsRtcDtls::SrsRtcDtls(SrsRtcSession* s) +SrsSecurityTransport::SrsSecurityTransport(SrsRtcSession* s) { session_ = s; - dtls = NULL; - bio_in = NULL; - bio_out = NULL; - client_key = ""; server_key = ""; srtp_send = NULL; srtp_recv = NULL; + dtls_ = new SrsDtls((ISrsDtlsCallback*)this); + handshake_done = false; } -SrsRtcDtls::~SrsRtcDtls() +SrsSecurityTransport::~SrsSecurityTransport() { - if (dtls) { - // this function will free bio_in and bio_out - SSL_free(dtls); - dtls = NULL; + if (dtls_) { + srs_freep(dtls_); + dtls_ = NULL; } if (srtp_send) { @@ -145,118 +141,40 @@ SrsRtcDtls::~SrsRtcDtls() } } -srs_error_t SrsRtcDtls::initialize(SrsRequest* r) -{ - srs_error_t err = srs_success; - - // TODO: FIXME: Leak for SSL_CTX* return by build_dtls_ctx. - if ((dtls = SSL_new(SrsDtls::build_dtls_ctx())) == NULL) { - return srs_error_new(ERROR_OpenSslCreateSSL, "SSL_new dtls"); - } - - // Dtls setup passive, as server role. - SSL_set_accept_state(dtls); - - if ((bio_in = BIO_new(BIO_s_mem())) == NULL) { - return srs_error_new(ERROR_OpenSslBIONew, "BIO_new in"); - } - - if ((bio_out = BIO_new(BIO_s_mem())) == NULL) { - BIO_free(bio_in); - return srs_error_new(ERROR_OpenSslBIONew, "BIO_new out"); - } - - SSL_set_bio(dtls, bio_in, bio_out); - - return err; +srs_error_t SrsSecurityTransport::initialize(SrsRequest* r) +{ + return dtls_->initialize(r); } -srs_error_t SrsRtcDtls::handshake() +srs_error_t SrsSecurityTransport::do_handshake() +{ + return dtls_->do_handshake(); +} + +srs_error_t SrsSecurityTransport::write_dtls_data(void* data, int size) { srs_error_t err = srs_success; - - int ret = SSL_do_handshake(dtls); - - unsigned char *out_bio_data; - int out_bio_len = BIO_get_mem_data(bio_out, &out_bio_data); - - int ssl_err = SSL_get_error(dtls, ret); - switch(ssl_err) { - case SSL_ERROR_NONE: { - if ((err = on_dtls_handshake_done()) != srs_success) { - return srs_error_wrap(err, "dtls handshake done handle"); - } - break; - } - - case SSL_ERROR_WANT_READ: { - break; - } - - case SSL_ERROR_WANT_WRITE: { - break; - } - - default: { - break; - } - } - - if (out_bio_len) { - if ((err = session_->sendonly_skt->sendto(out_bio_data, out_bio_len, 0)) != srs_success) { + if (size) { + if ((err = session_->sendonly_skt->sendto(data, size, 0)) != srs_success) { return srs_error_wrap(err, "send dtls packet"); } } if (session_->blackhole && session_->blackhole_addr && session_->blackhole_stfd) { // Ignore any error for black-hole. - void* p = out_bio_data; int len = out_bio_len; SrsRtcSession* s = session_; + void* p = data; int len = size; SrsRtcSession* s = session_; srs_sendto(s->blackhole_stfd, p, len, (sockaddr*)s->blackhole_addr, sizeof(sockaddr_in), SRS_UTIME_NO_TIMEOUT); } return err; } -srs_error_t SrsRtcDtls::on_dtls(char* data, int nb_data) +srs_error_t SrsSecurityTransport::on_dtls(char* data, int nb_data) { - srs_error_t err = srs_success; - if (BIO_reset(bio_in) != 1) { - return srs_error_new(ERROR_OpenSslBIOReset, "BIO_reset"); - } - if (BIO_reset(bio_out) != 1) { - return srs_error_new(ERROR_OpenSslBIOReset, "BIO_reset"); - } - - if (BIO_write(bio_in, data, nb_data) <= 0) { - // TODO: 0 or -1 maybe block, use BIO_should_retry to check. - return srs_error_new(ERROR_OpenSslBIOWrite, "BIO_write"); - } - - if (session_->blackhole && session_->blackhole_addr && session_->blackhole_stfd) { - // Ignore any error for black-hole. - void* p = data; int len = nb_data; SrsRtcSession* s = session_; - srs_sendto(s->blackhole_stfd, p, len, (sockaddr*)s->blackhole_addr, sizeof(sockaddr_in), SRS_UTIME_NO_TIMEOUT); - } - - if (!handshake_done) { - err = handshake(); - } else { - while (BIO_ctrl_pending(bio_in) > 0) { - char dtls_read_buf[8092]; - int nb = SSL_read(dtls, dtls_read_buf, sizeof(dtls_read_buf)); - - if (nb > 0) { - if ((err =on_dtls_application_data(dtls_read_buf, nb)) != srs_success) { - return srs_error_wrap(err, "dtls application data process"); - } - } - } - } - - return err; + return dtls_->on_dtls(data, nb_data); } -srs_error_t SrsRtcDtls::on_dtls_handshake_done() +srs_error_t SrsSecurityTransport::on_dtls_handshake_done() { srs_error_t err = srs_success; srs_trace("rtc session=%s, DTLS handshake done.", session_->id().c_str()); @@ -269,7 +187,7 @@ srs_error_t SrsRtcDtls::on_dtls_handshake_done() return session_->on_connection_established(); } -srs_error_t SrsRtcDtls::on_dtls_application_data(const char* buf, const int nb_buf) +srs_error_t SrsSecurityTransport::on_dtls_application_data(const char* buf, const int nb_buf) { srs_error_t err = srs_success; @@ -278,14 +196,15 @@ srs_error_t SrsRtcDtls::on_dtls_application_data(const char* buf, const int nb_b return err; } -srs_error_t SrsRtcDtls::srtp_initialize() +srs_error_t SrsSecurityTransport::srtp_initialize() { srs_error_t err = srs_success; unsigned char material[SRTP_MASTER_KEY_LEN * 2] = {0}; // client(SRTP_MASTER_KEY_KEY_LEN + SRTP_MASTER_KEY_SALT_LEN) + server static const string dtls_srtp_lable = "EXTRACTOR-dtls_srtp"; - if (!SSL_export_keying_material(dtls, material, sizeof(material), dtls_srtp_lable.c_str(), dtls_srtp_lable.size(), NULL, 0, 0)) { - return srs_error_new(ERROR_RTC_SRTP_INIT, "SSL_export_keying_material failed"); + + if ((err = dtls_->export_keying_material(material, sizeof(material), dtls_srtp_lable.c_str(), dtls_srtp_lable.size(), NULL, 0, 0)) != srs_success) { + return err; } size_t offset = 0; @@ -312,7 +231,7 @@ srs_error_t SrsRtcDtls::srtp_initialize() return err; } -srs_error_t SrsRtcDtls::srtp_send_init() +srs_error_t SrsSecurityTransport::srtp_send_init() { srs_error_t err = srs_success; @@ -347,7 +266,7 @@ srs_error_t SrsRtcDtls::srtp_send_init() return err; } -srs_error_t SrsRtcDtls::srtp_recv_init() +srs_error_t SrsSecurityTransport::srtp_recv_init() { srs_error_t err = srs_success; @@ -380,7 +299,7 @@ srs_error_t SrsRtcDtls::srtp_recv_init() return err; } -srs_error_t SrsRtcDtls::protect_rtp(char* out_buf, const char* in_buf, int& nb_out_buf) +srs_error_t SrsSecurityTransport::protect_rtp(char* out_buf, const char* in_buf, int& nb_out_buf) { srs_error_t err = srs_success; @@ -398,7 +317,7 @@ srs_error_t SrsRtcDtls::protect_rtp(char* out_buf, const char* in_buf, int& nb_o } // TODO: FIXME: Merge with protect_rtp. -srs_error_t SrsRtcDtls::protect_rtp2(void* rtp_hdr, int* len_ptr) +srs_error_t SrsSecurityTransport::protect_rtp2(void* rtp_hdr, int* len_ptr) { srs_error_t err = srs_success; @@ -414,7 +333,7 @@ srs_error_t SrsRtcDtls::protect_rtp2(void* rtp_hdr, int* len_ptr) return err; } -srs_error_t SrsRtcDtls::unprotect_rtp(char* out_buf, const char* in_buf, int& nb_out_buf) +srs_error_t SrsSecurityTransport::unprotect_rtp(char* out_buf, const char* in_buf, int& nb_out_buf) { srs_error_t err = srs_success; @@ -432,7 +351,7 @@ srs_error_t SrsRtcDtls::unprotect_rtp(char* out_buf, const char* in_buf, int& nb return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "rtp unprotect failed"); } -srs_error_t SrsRtcDtls::protect_rtcp(char* out_buf, const char* in_buf, int& nb_out_buf) +srs_error_t SrsSecurityTransport::protect_rtcp(char* out_buf, const char* in_buf, int& nb_out_buf) { srs_error_t err = srs_success; @@ -449,7 +368,7 @@ srs_error_t SrsRtcDtls::protect_rtcp(char* out_buf, const char* in_buf, int& nb_ return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtcp protect failed"); } -srs_error_t SrsRtcDtls::unprotect_rtcp(char* out_buf, const char* in_buf, int& nb_out_buf) +srs_error_t SrsSecurityTransport::unprotect_rtcp(char* out_buf, const char* in_buf, int& nb_out_buf) { srs_error_t err = srs_success; @@ -701,7 +620,7 @@ srs_error_t SrsRtcPlayer::send_packets(SrsRtcSource* source, const vectordtls_) { + if (!session_->transport_) { return err; } @@ -784,7 +703,7 @@ srs_error_t SrsRtcPlayer::do_send_packets(const std::vector& pkt // Whether encrypt the RTP bytes. if (encrypt) { int nn_encrypt = (int)iov->iov_len; - if ((err = session_->dtls_->protect_rtp2(iov->iov_base, &nn_encrypt)) != srs_success) { + if ((err = session_->transport_->protect_rtp2(iov->iov_base, &nn_encrypt)) != srs_success) { return srs_error_wrap(err, "srtp protect"); } iov->iov_len = (size_t)nn_encrypt; @@ -1172,7 +1091,7 @@ srs_error_t SrsRtcPublisher::initialize(uint32_t vssrc, uint32_t assrc, uint8_t void SrsRtcPublisher::check_send_nacks(SrsRtpNackForReceiver* nack, uint32_t ssrc) { // If DTLS is not OK, drop all messages. - if (!session_->dtls_) { + if (!session_->transport_) { return; } @@ -1210,7 +1129,7 @@ void SrsRtcPublisher::check_send_nacks(SrsRtpNackForReceiver* nack, uint32_t ssr int nb_protected_buf = stream.pos(); // FIXME: Merge nack rtcp into one packets. - if (session_->dtls_->protect_rtcp(protected_buf, stream.data(), nb_protected_buf) == srs_success) { + if (session_->transport_->protect_rtcp(protected_buf, stream.data(), nb_protected_buf) == srs_success) { // TODO: FIXME: Check error. session_->sendonly_skt->sendto(protected_buf, nb_protected_buf, 0); } @@ -1224,7 +1143,7 @@ srs_error_t SrsRtcPublisher::send_rtcp_rr(uint32_t ssrc, SrsRtpRingBuffer* rtp_q srs_error_t err = srs_success; // If DTLS is not OK, drop all messages. - if (!session_->dtls_) { + if (!session_->transport_) { return err; } @@ -1268,7 +1187,7 @@ srs_error_t SrsRtcPublisher::send_rtcp_rr(uint32_t ssrc, SrsRtpRingBuffer* rtp_q char protected_buf[kRtpPacketSize]; int nb_protected_buf = stream.pos(); - if ((err = session_->dtls_->protect_rtcp(protected_buf, stream.data(), nb_protected_buf)) != srs_success) { + if ((err = session_->transport_->protect_rtcp(protected_buf, stream.data(), nb_protected_buf)) != srs_success) { return srs_error_wrap(err, "protect rtcp rr"); } @@ -1282,7 +1201,7 @@ srs_error_t SrsRtcPublisher::send_rtcp_xr_rrtr(uint32_t ssrc) srs_error_t err = srs_success; // If DTLS is not OK, drop all messages. - if (!session_->dtls_) { + if (!session_->transport_) { return err; } @@ -1328,7 +1247,7 @@ srs_error_t SrsRtcPublisher::send_rtcp_xr_rrtr(uint32_t ssrc) char protected_buf[kRtpPacketSize]; int nb_protected_buf = stream.pos(); - if ((err = session_->dtls_->protect_rtcp(protected_buf, stream.data(), nb_protected_buf)) != srs_success) { + if ((err = session_->transport_->protect_rtcp(protected_buf, stream.data(), nb_protected_buf)) != srs_success) { return srs_error_wrap(err, "protect rtcp xr"); } @@ -1343,7 +1262,7 @@ srs_error_t SrsRtcPublisher::send_rtcp_fb_pli(uint32_t ssrc) srs_error_t err = srs_success; // If DTLS is not OK, drop all messages. - if (!session_->dtls_) { + if (!session_->transport_) { return err; } @@ -1365,7 +1284,7 @@ srs_error_t SrsRtcPublisher::send_rtcp_fb_pli(uint32_t ssrc) char protected_buf[kRtpPacketSize]; int nb_protected_buf = stream.pos(); - if ((err = session_->dtls_->protect_rtcp(protected_buf, stream.data(), nb_protected_buf)) != srs_success) { + if ((err = session_->transport_->protect_rtcp(protected_buf, stream.data(), nb_protected_buf)) != srs_success) { return srs_error_wrap(err, "protect rtcp psfb pli"); } @@ -1396,7 +1315,7 @@ srs_error_t SrsRtcPublisher::on_twcc(uint16_t sn) { } int nb_protected_buf = buffer->pos(); char protected_buf[kRtpPacketSize]; - if (session_->dtls_->protect_rtcp(protected_buf, pkt, nb_protected_buf) == srs_success) { + if (session_->transport_->protect_rtcp(protected_buf, pkt, nb_protected_buf) == srs_success) { session_->sendonly_skt->sendto(protected_buf, nb_protected_buf, 0); } } @@ -1416,7 +1335,7 @@ srs_error_t SrsRtcPublisher::on_rtp(char* data, int nb_data) // Decrypt the cipher to plaintext RTP data. int nb_unprotected_buf = nb_data; char* unprotected_buf = new char[kRtpPacketSize]; - if ((err = session_->dtls_->unprotect_rtp(unprotected_buf, data, nb_unprotected_buf)) != srs_success) { + if ((err = session_->transport_->unprotect_rtp(unprotected_buf, data, nb_unprotected_buf)) != srs_success) { // We try to decode the RTP header for more detail error informations. SrsBuffer b0(data, nb_data); SrsRtpHeader h0; h0.decode(&b0); err = srs_error_wrap(err, "marker=%u, pt=%u, seq=%u, ts=%u, ssrc=%u, pad=%u, payload=%uB", h0.get_marker(), h0.get_payload_type(), @@ -1980,7 +1899,7 @@ SrsRtcSession::SrsRtcSession(SrsRtcServer* s) player_ = NULL; sendonly_skt = NULL; server_ = s; - dtls_ = new SrsRtcDtls(this); + transport_ = new SrsSecurityTransport(this); state_ = INIT; last_stun_time = 0; @@ -1996,7 +1915,7 @@ SrsRtcSession::~SrsRtcSession() { srs_freep(player_); srs_freep(publisher_); - srs_freep(dtls_); + srs_freep(transport_); srs_freep(req); srs_close_stfd(blackhole_stfd); srs_freep(blackhole_addr); @@ -2079,7 +1998,7 @@ srs_error_t SrsRtcSession::initialize(SrsRtcSource* source, SrsRequest* r, bool is_publisher_ = is_publisher; source_ = source; - if ((err = dtls_->initialize(req)) != srs_success) { + if ((err = transport_->initialize(req)) != srs_success) { return srs_error_wrap(err, "init"); } @@ -2146,20 +2065,20 @@ srs_error_t SrsRtcSession::on_stun(SrsUdpMuxSocket* skt, SrsStunPacket* r) srs_error_t SrsRtcSession::on_dtls(char* data, int nb_data) { - return dtls_->on_dtls(data, nb_data); + return transport_->on_dtls(data, nb_data); } srs_error_t SrsRtcSession::on_rtcp(char* data, int nb_data) { srs_error_t err = srs_success; - if (dtls_ == NULL) { + if (transport_ == NULL) { return srs_error_new(ERROR_RTC_RTCP, "recv unexpect rtp packet before dtls done"); } char unprotected_buf[kRtpPacketSize]; int nb_unprotected_buf = nb_data; - if ((err = dtls_->unprotect_rtcp(unprotected_buf, data, nb_unprotected_buf)) != srs_success) { + if ((err = transport_->unprotect_rtcp(unprotected_buf, data, nb_unprotected_buf)) != srs_success) { return srs_error_wrap(err, "rtcp unprotect failed"); } @@ -2186,7 +2105,7 @@ srs_error_t SrsRtcSession::on_rtp(char* data, int nb_data) return srs_error_new(ERROR_RTC_RTCP, "rtc publisher null"); } - if (dtls_ == NULL) { + if (transport_ == NULL) { return srs_error_new(ERROR_RTC_RTCP, "recv unexpect rtp packet before dtls done"); } diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 39df677c4..97cb4da5b 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -108,14 +109,11 @@ enum SrsRtcSessionStateType CLOSED = 5, }; -class SrsRtcDtls +class SrsSecurityTransport : public ISrsDtlsCallback { private: SrsRtcSession* session_; - - SSL* dtls; - BIO* bio_in; - BIO* bio_out; + SrsDtls* dtls_; std::string client_key; std::string server_key; @@ -124,24 +122,25 @@ private: srtp_t srtp_recv; bool handshake_done; - public: - SrsRtcDtls(SrsRtcSession* s); - virtual ~SrsRtcDtls(); + SrsSecurityTransport(SrsRtcSession* s); + virtual ~SrsSecurityTransport(); srs_error_t initialize(SrsRequest* r); + srs_error_t do_handshake(); srs_error_t on_dtls(char* data, int nb_data); - srs_error_t on_dtls_handshake_done(); - srs_error_t on_dtls_application_data(const char* data, const int len); public: srs_error_t protect_rtp(char* protected_buf, const char* ori_buf, int& nb_protected_buf); srs_error_t protect_rtp2(void* rtp_hdr, int* len_ptr); srs_error_t unprotect_rtp(char* unprotected_buf, const char* ori_buf, int& nb_unprotected_buf); srs_error_t protect_rtcp(char* protected_buf, const char* ori_buf, int& nb_protected_buf); srs_error_t unprotect_rtcp(char* unprotected_buf, const char* ori_buf, int& nb_unprotected_buf); -private: - srs_error_t handshake(); +// implement ISrsDtlsCallback +public: + virtual srs_error_t on_dtls_handshake_done(); + virtual srs_error_t on_dtls_application_data(const char* data, const int len); + virtual srs_error_t write_dtls_data(void* data, int size); private: srs_error_t srtp_initialize(); srs_error_t srtp_send_init(); @@ -322,7 +321,7 @@ private: class SrsRtcSession { - friend class SrsRtcDtls; + friend class SrsSecurityTransport; friend class SrsRtcPlayer; friend class SrsRtcPublisher; public: @@ -330,7 +329,7 @@ public: private: SrsRtcServer* server_; SrsRtcSessionStateType state_; - SrsRtcDtls* dtls_; + SrsSecurityTransport* transport_; SrsRtcPlayer* player_; SrsRtcPublisher* publisher_; bool is_publisher_; diff --git a/trunk/src/app/srs_app_rtc_dtls.cpp b/trunk/src/app/srs_app_rtc_dtls.cpp index 3bbdc5ee9..8e99fba05 100644 --- a/trunk/src/app/srs_app_rtc_dtls.cpp +++ b/trunk/src/app/srs_app_rtc_dtls.cpp @@ -231,13 +231,32 @@ bool SrsDtlsCertificate::is_ecdsa() return ecdsa_mode; } - -SrsDtls::SrsDtls() +ISrsDtlsCallback::ISrsDtlsCallback() { } +ISrsDtlsCallback::~ISrsDtlsCallback() +{ +} + +SrsDtls::SrsDtls(ISrsDtlsCallback* cb) +{ + callback = cb; + handshake_done = false; +} + SrsDtls::~SrsDtls() { + if (dtls_ctx) { + SSL_CTX_free(dtls_ctx); + dtls_ctx = NULL; + } + + if (dtls) { + // this function will free bio_in and bio_out + SSL_free(dtls); + dtls = NULL; + } } SSL_CTX* SrsDtls::build_dtls_ctx() @@ -302,3 +321,119 @@ SSL_CTX* SrsDtls::build_dtls_ctx() return dtls_ctx; } + +srs_error_t SrsDtls::initialize(SrsRequest* r) +{ + srs_error_t err = srs_success; + + dtls_ctx = build_dtls_ctx(); + // TODO: FIXME: Leak for SSL_CTX* return by build_dtls_ctx. + if ((dtls = SSL_new(dtls_ctx)) == NULL) { + return srs_error_new(ERROR_OpenSslCreateSSL, "SSL_new dtls"); + } + + // Dtls setup passive, as server role. + SSL_set_accept_state(dtls); + + if ((bio_in = BIO_new(BIO_s_mem())) == NULL) { + return srs_error_new(ERROR_OpenSslBIONew, "BIO_new in"); + } + + if ((bio_out = BIO_new(BIO_s_mem())) == NULL) { + BIO_free(bio_in); + return srs_error_new(ERROR_OpenSslBIONew, "BIO_new out"); + } + + SSL_set_bio(dtls, bio_in, bio_out); + + return err; +} + +srs_error_t SrsDtls::handshake() +{ + srs_error_t err = srs_success; + + int ret = SSL_do_handshake(dtls); + + unsigned char *out_bio_data; + int out_bio_len = BIO_get_mem_data(bio_out, &out_bio_data); + + int ssl_err = SSL_get_error(dtls, ret); + switch(ssl_err) { + case SSL_ERROR_NONE: { + if ((callback == NULL) || ((err = callback->on_dtls_handshake_done()) != srs_success)) { + return srs_error_wrap(err, "dtls handshake done handle"); + } + break; + } + + case SSL_ERROR_WANT_READ: { + break; + } + + case SSL_ERROR_WANT_WRITE: { + break; + } + + default: { + break; + } + } + + if (out_bio_len && callback) { + if ((err = callback->write_dtls_data(out_bio_data, out_bio_len)) != srs_success) { + return srs_error_wrap(err, "send dtls packet"); + } + } + + return err; +} + +srs_error_t SrsDtls::on_dtls(char* data, int nb_data) +{ + srs_error_t err = srs_success; + if (BIO_reset(bio_in) != 1) { + return srs_error_new(ERROR_OpenSslBIOReset, "BIO_reset"); + } + if (BIO_reset(bio_out) != 1) { + return srs_error_new(ERROR_OpenSslBIOReset, "BIO_reset"); + } + + if (BIO_write(bio_in, data, nb_data) <= 0) { + // TODO: 0 or -1 maybe block, use BIO_should_retry to check. + return srs_error_new(ERROR_OpenSslBIOWrite, "BIO_write"); + } + + if (!handshake_done) { + err = handshake(); + } else { + while (BIO_ctrl_pending(bio_in) > 0) { + char dtls_read_buf[8092]; + int nb = SSL_read(dtls, dtls_read_buf, sizeof(dtls_read_buf)); + + if (nb > 0 && callback) { + if ((err = callback->on_dtls_application_data(dtls_read_buf, nb)) != srs_success) { + return srs_error_wrap(err, "dtls application data process"); + } + } + } + } + + return err; +} + +srs_error_t SrsDtls::do_handshake() +{ + return handshake(); +} + +srs_error_t SrsDtls::export_keying_material(unsigned char *out, size_t olen, const char *label, size_t llen, const unsigned char *p, size_t plen, int use_context) +{ + srs_error_t err = srs_success; + + if (!SSL_export_keying_material(dtls, out, olen, label, llen, p, plen, use_context)) { + return srs_error_new(ERROR_RTC_SRTP_INIT, "SSL_export_keying_material failed"); + } + + return err; +} \ No newline at end of file diff --git a/trunk/src/app/srs_app_rtc_dtls.hpp b/trunk/src/app/srs_app_rtc_dtls.hpp index 6ed55b3ce..3a50646ff 100644 --- a/trunk/src/app/srs_app_rtc_dtls.hpp +++ b/trunk/src/app/srs_app_rtc_dtls.hpp @@ -61,13 +61,42 @@ public: // @global config object. extern SrsDtlsCertificate* _srs_rtc_dtls_certificate; -class SrsDtls +class ISrsDtlsCallback { public: - SrsDtls(); + ISrsDtlsCallback(); + virtual ~ISrsDtlsCallback(); +public: + // DTLS handshake done callback. + virtual srs_error_t on_dtls_handshake_done() = 0; + // DTLS receive application data callback. + virtual srs_error_t on_dtls_application_data(const char* data, const int len) = 0; + // DTLS write dtls data. + virtual srs_error_t write_dtls_data(void* data, int size) = 0; +}; + +class SrsDtls +{ +private: + SSL_CTX* dtls_ctx; + SSL* dtls; + BIO* bio_in; + BIO* bio_out; + + ISrsDtlsCallback* callback; + + bool handshake_done; +public: + SrsDtls(ISrsDtlsCallback* callback); virtual ~SrsDtls(); public: - static SSL_CTX* build_dtls_ctx(); + srs_error_t initialize(SrsRequest* r); + srs_error_t do_handshake(); + srs_error_t on_dtls(char* data, int nb_data); + srs_error_t export_keying_material(unsigned char *out, size_t olen, const char *label, size_t llen, const unsigned char *p, size_t plen, int use_context); +private: + SSL_CTX* build_dtls_ctx(); + srs_error_t handshake(); }; #endif From 81d2e10f65bf232c9985a0de0a7969d3b760d680 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 25 Jun 2020 13:14:59 +0800 Subject: [PATCH 07/37] Refactor ISrsContext and ISrsLog --- trunk/src/app/srs_app_log.cpp | 30 ++++++++-------- trunk/src/app/srs_app_log.hpp | 6 ++-- trunk/src/kernel/srs_kernel_log.cpp | 50 ++------------------------ trunk/src/kernel/srs_kernel_log.hpp | 40 ++++++++++----------- trunk/src/main/srs_main_ingest_hls.cpp | 2 +- trunk/src/main/srs_main_mp4_parser.cpp | 2 +- trunk/src/main/srs_main_server.cpp | 4 +-- trunk/src/protocol/srs_service_log.hpp | 2 +- trunk/src/utest/srs_utest.cpp | 2 +- trunk/src/utest/srs_utest.hpp | 2 +- trunk/src/utest/srs_utest_kernel.cpp | 22 ------------ 11 files changed, 47 insertions(+), 115 deletions(-) diff --git a/trunk/src/app/srs_app_log.cpp b/trunk/src/app/srs_app_log.cpp index 0671bfb9f..045812f50 100644 --- a/trunk/src/app/srs_app_log.cpp +++ b/trunk/src/app/srs_app_log.cpp @@ -44,7 +44,7 @@ // reserved for the end of log data, it must be strlen(LOG_TAIL) #define LOG_TAIL_SIZE 1 -SrsFastLog::SrsFastLog() +SrsFileLog::SrsFileLog() { level = SrsLogLevelTrace; log_data = new char[LOG_MAX_SIZE]; @@ -54,7 +54,7 @@ SrsFastLog::SrsFastLog() utc = false; } -SrsFastLog::~SrsFastLog() +SrsFileLog::~SrsFileLog() { srs_freepa(log_data); @@ -68,7 +68,7 @@ SrsFastLog::~SrsFastLog() } } -srs_error_t SrsFastLog::initialize() +srs_error_t SrsFileLog::initialize() { if (_srs_config) { _srs_config->subscribe(this); @@ -81,7 +81,7 @@ srs_error_t SrsFastLog::initialize() return srs_success; } -void SrsFastLog::reopen() +void SrsFileLog::reopen() { if (fd > 0) { ::close(fd); @@ -94,7 +94,7 @@ void SrsFastLog::reopen() open_log_file(); } -void SrsFastLog::verbose(const char* tag, const char* context_id, const char* fmt, ...) +void SrsFileLog::verbose(const char* tag, const char* context_id, const char* fmt, ...) { if (level > SrsLogLevelVerbose) { return; @@ -114,7 +114,7 @@ void SrsFastLog::verbose(const char* tag, const char* context_id, const char* fm write_log(fd, log_data, size, SrsLogLevelVerbose); } -void SrsFastLog::info(const char* tag, const char* context_id, const char* fmt, ...) +void SrsFileLog::info(const char* tag, const char* context_id, const char* fmt, ...) { if (level > SrsLogLevelInfo) { return; @@ -134,7 +134,7 @@ void SrsFastLog::info(const char* tag, const char* context_id, const char* fmt, write_log(fd, log_data, size, SrsLogLevelInfo); } -void SrsFastLog::trace(const char* tag, const char* context_id, const char* fmt, ...) +void SrsFileLog::trace(const char* tag, const char* context_id, const char* fmt, ...) { if (level > SrsLogLevelTrace) { return; @@ -154,7 +154,7 @@ void SrsFastLog::trace(const char* tag, const char* context_id, const char* fmt, write_log(fd, log_data, size, SrsLogLevelTrace); } -void SrsFastLog::warn(const char* tag, const char* context_id, const char* fmt, ...) +void SrsFileLog::warn(const char* tag, const char* context_id, const char* fmt, ...) { if (level > SrsLogLevelWarn) { return; @@ -174,7 +174,7 @@ void SrsFastLog::warn(const char* tag, const char* context_id, const char* fmt, write_log(fd, log_data, size, SrsLogLevelWarn); } -void SrsFastLog::error(const char* tag, const char* context_id, const char* fmt, ...) +void SrsFileLog::error(const char* tag, const char* context_id, const char* fmt, ...) { if (level > SrsLogLevelError) { return; @@ -200,14 +200,14 @@ void SrsFastLog::error(const char* tag, const char* context_id, const char* fmt, write_log(fd, log_data, size, SrsLogLevelError); } -srs_error_t SrsFastLog::on_reload_utc_time() +srs_error_t SrsFileLog::on_reload_utc_time() { utc = _srs_config->get_utc_time(); return srs_success; } -srs_error_t SrsFastLog::on_reload_log_tank() +srs_error_t SrsFileLog::on_reload_log_tank() { srs_error_t err = srs_success; @@ -234,7 +234,7 @@ srs_error_t SrsFastLog::on_reload_log_tank() return err; } -srs_error_t SrsFastLog::on_reload_log_level() +srs_error_t SrsFileLog::on_reload_log_level() { srs_error_t err = srs_success; @@ -247,7 +247,7 @@ srs_error_t SrsFastLog::on_reload_log_level() return err; } -srs_error_t SrsFastLog::on_reload_log_file() +srs_error_t SrsFileLog::on_reload_log_file() { srs_error_t err = srs_success; @@ -267,7 +267,7 @@ srs_error_t SrsFastLog::on_reload_log_file() return err; } -void SrsFastLog::write_log(int& fd, char *str_log, int size, int level) +void SrsFileLog::write_log(int& fd, char *str_log, int size, int level) { // ensure the tail and EOF of string // LOG_TAIL_SIZE for the TAIL char. @@ -307,7 +307,7 @@ void SrsFastLog::write_log(int& fd, char *str_log, int size, int level) } } -void SrsFastLog::open_log_file() +void SrsFileLog::open_log_file() { if (!_srs_config) { return; diff --git a/trunk/src/app/srs_app_log.hpp b/trunk/src/app/srs_app_log.hpp index 81a9e1696..d05461c06 100644 --- a/trunk/src/app/srs_app_log.hpp +++ b/trunk/src/app/srs_app_log.hpp @@ -35,7 +35,7 @@ // Use memory/disk cache and donot flush when write log. // it's ok to use it without config, which will log to console, and default trace level. // when you want to use different level, override this classs, set the protected _level. -class SrsFastLog : public ISrsLog, public ISrsReloadHandler +class SrsFileLog : public ISrsLog, public ISrsReloadHandler { private: // Defined in SrsLogLevel. @@ -49,8 +49,8 @@ private: // Whether use utc time. bool utc; public: - SrsFastLog(); - virtual ~SrsFastLog(); + SrsFileLog(); + virtual ~SrsFileLog(); // Interface ISrsLog public: virtual srs_error_t initialize(); diff --git a/trunk/src/kernel/srs_kernel_log.cpp b/trunk/src/kernel/srs_kernel_log.cpp index 2fd5ae072..6cfe61068 100644 --- a/trunk/src/kernel/srs_kernel_log.cpp +++ b/trunk/src/kernel/srs_kernel_log.cpp @@ -23,8 +23,6 @@ #include -#include - ISrsLog::ISrsLog() { } @@ -33,56 +31,12 @@ ISrsLog::~ISrsLog() { } -srs_error_t ISrsLog::initialize() -{ - return srs_success; -} - -void ISrsLog::reopen() +ISrsContext::ISrsContext() { } -void ISrsLog::verbose(const char* /*tag*/, const char* /*context_id*/, const char* /*fmt*/, ...) +ISrsContext::~ISrsContext() { } -void ISrsLog::info(const char* /*tag*/, const char* /*context_id*/, const char* /*fmt*/, ...) -{ -} - -void ISrsLog::trace(const char* /*tag*/, const char* /*context_id*/, const char* /*fmt*/, ...) -{ -} - -void ISrsLog::warn(const char* /*tag*/, const char* /*context_id*/, const char* /*fmt*/, ...) -{ -} - -void ISrsLog::error(const char* /*tag*/, const char* /*context_id*/, const char* /*fmt*/, ...) -{ -} - -ISrsThreadContext::ISrsThreadContext() -{ -} - -ISrsThreadContext::~ISrsThreadContext() -{ -} - -std::string ISrsThreadContext::generate_id() -{ - return ""; -} - -std::string ISrsThreadContext::get_id() -{ - return ""; -} - -std::string ISrsThreadContext::set_id(std::string /*v*/) -{ - return ""; -} - diff --git a/trunk/src/kernel/srs_kernel_log.hpp b/trunk/src/kernel/srs_kernel_log.hpp index 56aefce4c..9d47c3371 100644 --- a/trunk/src/kernel/srs_kernel_log.hpp +++ b/trunk/src/kernel/srs_kernel_log.hpp @@ -60,49 +60,49 @@ public: virtual ~ISrsLog(); public: // Initialize log utilities. - virtual srs_error_t initialize(); + virtual srs_error_t initialize() = 0; // Reopen the log file for log rotate. - virtual void reopen(); + virtual void reopen() = 0; public: // The log for verbose, very verbose information. - virtual void verbose(const char* tag, const char* context_id, const char* fmt, ...); + virtual void verbose(const char* tag, const char* context_id, const char* fmt, ...) = 0; // The log for debug, detail information. - virtual void info(const char* tag, const char* context_id, const char* fmt, ...); + virtual void info(const char* tag, const char* context_id, const char* fmt, ...) = 0; // The log for trace, important information. - virtual void trace(const char* tag, const char* context_id, const char* fmt, ...); + virtual void trace(const char* tag, const char* context_id, const char* fmt, ...) = 0; // The log for warn, warn is something should take attention, but not a error. - virtual void warn(const char* tag, const char* context_id, const char* fmt, ...); + virtual void warn(const char* tag, const char* context_id, const char* fmt, ...) = 0; // The log for error, something error occur, do something about the error, ie. close the connection, // but we will donot abort the program. - virtual void error(const char* tag, const char* context_id, const char* fmt, ...); + virtual void error(const char* tag, const char* context_id, const char* fmt, ...) = 0; }; -// The context id manager to identify context, for instance, the green-thread. -// Usage: -// _srs_context->generate_id(); // when thread start. -// _srs_context->get_id(); // get current generated id. -// int old_id = _srs_context->set_id(1000); // set context id if need to merge thread context. -// The context for multiple clients. -class ISrsThreadContext +// The logic context for a RTMP connection, or RTC Session. +// We can grep the context id to identify the logic unit, for debugging. +// For example: +// _srs_context->generate_id(); // Generate a new context. +// _srs_context->get_id(); // Get current context. +// int old_id = _srs_context->set_id("1000"); // Change the context. +class ISrsContext { public: - ISrsThreadContext(); - virtual ~ISrsThreadContext(); + ISrsContext(); + virtual ~ISrsContext(); public: // Generate the id for current context. - virtual std::string generate_id(); + virtual std::string generate_id() = 0; // Get the generated id of current context. - virtual std::string get_id(); + virtual std::string get_id() = 0; // Set the id of current context. // @return the previous id value; 0 if no context. - virtual std::string set_id(std::string v); + virtual std::string set_id(std::string v) = 0; }; // @global User must provides a log object extern ISrsLog* _srs_log; // @global User must implements the LogContext and define a global instance. -extern ISrsThreadContext* _srs_context; +extern ISrsContext* _srs_context; // Log style. // Use __FUNCTION__ to print c method diff --git a/trunk/src/main/srs_main_ingest_hls.cpp b/trunk/src/main/srs_main_ingest_hls.cpp index 34eb3a7da..29b928a61 100644 --- a/trunk/src/main/srs_main_ingest_hls.cpp +++ b/trunk/src/main/srs_main_ingest_hls.cpp @@ -52,7 +52,7 @@ srs_error_t proxy_hls2rtmp(std::string hls, std::string rtmp); // @global log and context. ISrsLog* _srs_log = new SrsConsoleLog(SrsLogLevelTrace, false); -ISrsThreadContext* _srs_context = new SrsThreadContext(); +ISrsContext* _srs_context = new SrsThreadContext(); /** * main entrance. diff --git a/trunk/src/main/srs_main_mp4_parser.cpp b/trunk/src/main/srs_main_mp4_parser.cpp index 66b5ea525..c3ccfec14 100644 --- a/trunk/src/main/srs_main_mp4_parser.cpp +++ b/trunk/src/main/srs_main_mp4_parser.cpp @@ -38,7 +38,7 @@ using namespace std; // @global log and context. ISrsLog* _srs_log = new SrsConsoleLog(SrsLogLevelTrace, false); -ISrsThreadContext* _srs_context = new SrsThreadContext(); +ISrsContext* _srs_context = new SrsThreadContext(); srs_error_t parse(std::string mp4_file, bool verbose) { diff --git a/trunk/src/main/srs_main_server.cpp b/trunk/src/main/srs_main_server.cpp index 3a73b7b55..e9d6e51be 100644 --- a/trunk/src/main/srs_main_server.cpp +++ b/trunk/src/main/srs_main_server.cpp @@ -69,8 +69,8 @@ srs_error_t run_hybrid_server(); void show_macro_features(); // @global log and context. -ISrsLog* _srs_log = new SrsFastLog(); -ISrsThreadContext* _srs_context = new SrsThreadContext(); +ISrsLog* _srs_log = new SrsFileLog(); +ISrsContext* _srs_context = new SrsThreadContext(); // @global config object for app module. SrsConfig* _srs_config = new SrsConfig(); diff --git a/trunk/src/protocol/srs_service_log.hpp b/trunk/src/protocol/srs_service_log.hpp index 72c93400d..a0bd141ab 100644 --- a/trunk/src/protocol/srs_service_log.hpp +++ b/trunk/src/protocol/srs_service_log.hpp @@ -34,7 +34,7 @@ // The st thread context, get_id will get the st-thread id, // which identify the client. -class SrsThreadContext : public ISrsThreadContext +class SrsThreadContext : public ISrsContext { private: std::map cache; diff --git a/trunk/src/utest/srs_utest.cpp b/trunk/src/utest/srs_utest.cpp index 06b69e118..9d8678518 100644 --- a/trunk/src/utest/srs_utest.cpp +++ b/trunk/src/utest/srs_utest.cpp @@ -41,7 +41,7 @@ srs_utime_t _srs_tmp_timeout = (100 * SRS_UTIME_MILLISECONDS); // kernel module. ISrsLog* _srs_log = new MockEmptyLog(SrsLogLevelDisabled); -ISrsThreadContext* _srs_context = new ISrsThreadContext(); +ISrsContext* _srs_context = new SrsThreadContext(); // app module. SrsConfig* _srs_config = NULL; SrsServer* _srs_server = NULL; diff --git a/trunk/src/utest/srs_utest.hpp b/trunk/src/utest/srs_utest.hpp index ffda614d9..22d0d70e2 100644 --- a/trunk/src/utest/srs_utest.hpp +++ b/trunk/src/utest/srs_utest.hpp @@ -95,7 +95,7 @@ extern srs_utime_t _srs_tmp_timeout; // print the bytes. void srs_bytes_print(char* pa, int size); -class MockEmptyLog : public SrsFastLog +class MockEmptyLog : public SrsFileLog { public: MockEmptyLog(SrsLogLevel l); diff --git a/trunk/src/utest/srs_utest_kernel.cpp b/trunk/src/utest/srs_utest_kernel.cpp index bc0109ef1..deab330cb 100644 --- a/trunk/src/utest/srs_utest_kernel.cpp +++ b/trunk/src/utest/srs_utest_kernel.cpp @@ -4090,28 +4090,6 @@ VOID TEST(KernelFLVTest, CoverSharedPtrMessage) } } -VOID TEST(KernelLogTest, CoverAll) -{ - srs_error_t err; - - if (true) { - ISrsLog l; - HELPER_EXPECT_SUCCESS(l.initialize()); - - l.reopen(); - l.verbose("TAG", "0", "log"); - l.info("TAG", "0", "log"); - l.trace("TAG", "0", "log"); - l.warn("TAG", "0", "log"); - l.error("TAG", "0", "log"); - - ISrsThreadContext ctx; - ctx.set_id("10"); - EXPECT_EQ("", ctx.get_id()); - EXPECT_EQ("", ctx.generate_id()); - } -} - VOID TEST(KernelMp3Test, CoverAll) { srs_error_t err; From b6ecb0a18f21a4eaf34fb8c9cee76636e778a628 Mon Sep 17 00:00:00 2001 From: "jinxue.cgh" Date: Thu, 25 Jun 2020 14:50:14 +0800 Subject: [PATCH 08/37] RTC: refine srtp layer --- trunk/src/app/srs_app_rtc_conn.cpp | 174 ++++------------------------- trunk/src/app/srs_app_rtc_conn.hpp | 13 +-- trunk/src/app/srs_app_rtc_dtls.cpp | 139 ++++++++++++++++++++++- trunk/src/app/srs_app_rtc_dtls.hpp | 20 +++- 4 files changed, 181 insertions(+), 165 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 517d42178..5b2a6b57f 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -71,9 +71,6 @@ string gen_random_str(int len) return ret; } -const int SRTP_MASTER_KEY_KEY_LEN = 16; -const int SRTP_MASTER_KEY_SALT_LEN = 14; - uint64_t SrsNtp::kMagicNtpFractionalUnit = 1ULL << 32; SrsNtp::SrsNtp() @@ -114,13 +111,9 @@ SrsSecurityTransport::SrsSecurityTransport(SrsRtcSession* s) { session_ = s; - client_key = ""; - server_key = ""; - - srtp_send = NULL; - srtp_recv = NULL; - dtls_ = new SrsDtls((ISrsDtlsCallback*)this); + srtp_send = new SrsSRTP(); + srtp_recv = new SrsSRTP(); handshake_done = false; } @@ -133,11 +126,11 @@ SrsSecurityTransport::~SrsSecurityTransport() } if (srtp_send) { - srtp_dealloc(srtp_send); + srs_freep(srtp_send); } if (srtp_recv) { - srtp_dealloc(srtp_recv); + srs_freep(srtp_recv); } } @@ -200,189 +193,68 @@ srs_error_t SrsSecurityTransport::srtp_initialize() { srs_error_t err = srs_success; - unsigned char material[SRTP_MASTER_KEY_LEN * 2] = {0}; // client(SRTP_MASTER_KEY_KEY_LEN + SRTP_MASTER_KEY_SALT_LEN) + server - static const string dtls_srtp_lable = "EXTRACTOR-dtls_srtp"; + std::string send_key; + std::string recv_key; - if ((err = dtls_->export_keying_material(material, sizeof(material), dtls_srtp_lable.c_str(), dtls_srtp_lable.size(), NULL, 0, 0)) != srs_success) { + if ((err = dtls_->get_srtp_key(recv_key, send_key)) != srs_success) { return err; } - size_t offset = 0; - - std::string client_master_key(reinterpret_cast(material), SRTP_MASTER_KEY_KEY_LEN); - offset += SRTP_MASTER_KEY_KEY_LEN; - std::string server_master_key(reinterpret_cast(material + offset), SRTP_MASTER_KEY_KEY_LEN); - offset += SRTP_MASTER_KEY_KEY_LEN; - std::string client_master_salt(reinterpret_cast(material + offset), SRTP_MASTER_KEY_SALT_LEN); - offset += SRTP_MASTER_KEY_SALT_LEN; - std::string server_master_salt(reinterpret_cast(material + offset), SRTP_MASTER_KEY_SALT_LEN); - - client_key = client_master_key + client_master_salt; - server_key = server_master_key + server_master_salt; - - if ((err = srtp_send_init()) != srs_success) { + if ((err = srtp_send->initialize(send_key, true)) != srs_success) { return srs_error_wrap(err, "srtp send init failed"); } - if ((err = srtp_recv_init()) != srs_success) { + if ((err = srtp_recv->initialize(recv_key, false)) != srs_success) { return srs_error_wrap(err, "srtp recv init failed"); } return err; } -srs_error_t SrsSecurityTransport::srtp_send_init() -{ - srs_error_t err = srs_success; - - srtp_policy_t policy; - bzero(&policy, sizeof(policy)); - - // TODO: Maybe we can use SRTP-GCM in future. - // @see https://bugs.chromium.org/p/chromium/issues/detail?id=713701 - // @see https://groups.google.com/forum/#!topic/discuss-webrtc/PvCbWSetVAQ - srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp); - srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp); - - policy.ssrc.type = ssrc_any_outbound; - - policy.ssrc.value = 0; - // TODO: adjust window_size - policy.window_size = 8192; - policy.allow_repeat_tx = 1; - policy.next = NULL; - - uint8_t *key = new uint8_t[server_key.size()]; - memcpy(key, server_key.data(), server_key.size()); - policy.key = key; - - if (srtp_create(&srtp_send, &policy) != srtp_err_status_ok) { - srs_freepa(key); - return srs_error_new(ERROR_RTC_SRTP_INIT, "srtp_create failed"); - } - - srs_freepa(key); - - return err; -} - -srs_error_t SrsSecurityTransport::srtp_recv_init() -{ - srs_error_t err = srs_success; - - srtp_policy_t policy; - bzero(&policy, sizeof(policy)); - - srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp); - srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp); - - policy.ssrc.type = ssrc_any_inbound; - - policy.ssrc.value = 0; - // TODO: adjust window_size - policy.window_size = 8192; - policy.allow_repeat_tx = 1; - policy.next = NULL; - - uint8_t *key = new uint8_t[client_key.size()]; - memcpy(key, client_key.data(), client_key.size()); - policy.key = key; - - // TODO: FIXME: Wrap error code. - if (srtp_create(&srtp_recv, &policy) != srtp_err_status_ok) { - srs_freepa(key); - return srs_error_new(ERROR_RTC_SRTP_INIT, "srtp_create failed"); - } - - srs_freepa(key); - - return err; -} - srs_error_t SrsSecurityTransport::protect_rtp(char* out_buf, const char* in_buf, int& nb_out_buf) { - srs_error_t err = srs_success; - - if (srtp_send) { - memcpy(out_buf, in_buf, nb_out_buf); - // TODO: FIXME: Wrap error code. - if (srtp_protect(srtp_send, out_buf, &nb_out_buf) != 0) { - return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtp protect failed"); - } - - return err; + if (!srtp_send) { + return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtp protect failed"); } - return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtp protect failed"); + return srtp_send->protect_rtp(out_buf, in_buf, nb_out_buf); } // TODO: FIXME: Merge with protect_rtp. srs_error_t SrsSecurityTransport::protect_rtp2(void* rtp_hdr, int* len_ptr) { - srs_error_t err = srs_success; - if (!srtp_send) { return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtp protect"); } - // TODO: FIXME: Wrap error code. - if (srtp_protect(srtp_send, rtp_hdr, len_ptr) != 0) { - return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtp protect"); - } - - return err; + return srtp_send->protect_rtp2(rtp_hdr, len_ptr); } srs_error_t SrsSecurityTransport::unprotect_rtp(char* out_buf, const char* in_buf, int& nb_out_buf) { - srs_error_t err = srs_success; - - if (srtp_recv) { - memcpy(out_buf, in_buf, nb_out_buf); - - srtp_err_status_t r0 = srtp_unprotect(srtp_recv, out_buf, &nb_out_buf); - if (r0 != srtp_err_status_ok) { - return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "unprotect r0=%u", r0); - } - - return err; + if (!srtp_recv) { + return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "rtp unprotect failed"); } - - return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "rtp unprotect failed"); + + return srtp_recv->unprotect_rtp(out_buf, in_buf, nb_out_buf); } srs_error_t SrsSecurityTransport::protect_rtcp(char* out_buf, const char* in_buf, int& nb_out_buf) { - srs_error_t err = srs_success; - - if (srtp_send) { - memcpy(out_buf, in_buf, nb_out_buf); - // TODO: FIXME: Wrap error code. - if (srtp_protect_rtcp(srtp_send, out_buf, &nb_out_buf) != 0) { - return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtcp protect failed"); - } - - return err; + if (!srtp_send) { + return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtcp protect failed"); } - return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtcp protect failed"); + return srtp_send->protect_rtcp(out_buf, in_buf, nb_out_buf); } srs_error_t SrsSecurityTransport::unprotect_rtcp(char* out_buf, const char* in_buf, int& nb_out_buf) { - srs_error_t err = srs_success; - - if (srtp_recv) { - memcpy(out_buf, in_buf, nb_out_buf); - // TODO: FIXME: Wrap error code. - if (srtp_unprotect_rtcp(srtp_recv, out_buf, &nb_out_buf) != srtp_err_status_ok) { - return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "rtcp unprotect failed"); - } - - return err; + if (!srtp_recv) { + return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "rtcp unprotect failed"); } - return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "rtcp unprotect failed"); + return srtp_recv->unprotect_rtcp(out_buf, in_buf, nb_out_buf); } SrsRtcOutgoingInfo::SrsRtcOutgoingInfo() diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 97cb4da5b..09e2fe35c 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -44,9 +44,6 @@ #include #include -#include -#include - class SrsUdpMuxSocket; class SrsConsumer; class SrsStunPacket; @@ -114,12 +111,8 @@ class SrsSecurityTransport : public ISrsDtlsCallback private: SrsRtcSession* session_; SrsDtls* dtls_; - - std::string client_key; - std::string server_key; - - srtp_t srtp_send; - srtp_t srtp_recv; + SrsSRTP* srtp_send; + SrsSRTP* srtp_recv; bool handshake_done; public: @@ -143,8 +136,6 @@ public: virtual srs_error_t write_dtls_data(void* data, int size); private: srs_error_t srtp_initialize(); - srs_error_t srtp_send_init(); - srs_error_t srtp_recv_init(); }; // A group of RTP packets for outgoing(send to players). diff --git a/trunk/src/app/srs_app_rtc_dtls.cpp b/trunk/src/app/srs_app_rtc_dtls.cpp index 8e99fba05..4c98b5ab6 100644 --- a/trunk/src/app/srs_app_rtc_dtls.cpp +++ b/trunk/src/app/srs_app_rtc_dtls.cpp @@ -427,13 +427,148 @@ srs_error_t SrsDtls::do_handshake() return handshake(); } -srs_error_t SrsDtls::export_keying_material(unsigned char *out, size_t olen, const char *label, size_t llen, const unsigned char *p, size_t plen, int use_context) +const int SRTP_MASTER_KEY_KEY_LEN = 16; +const int SRTP_MASTER_KEY_SALT_LEN = 14; +srs_error_t SrsDtls::get_srtp_key(std::string& client_key, std::string& server_key) { srs_error_t err = srs_success; - if (!SSL_export_keying_material(dtls, out, olen, label, llen, p, plen, use_context)) { + unsigned char material[SRTP_MASTER_KEY_LEN * 2] = {0}; // client(SRTP_MASTER_KEY_KEY_LEN + SRTP_MASTER_KEY_SALT_LEN) + server + static const string dtls_srtp_lable = "EXTRACTOR-dtls_srtp"; + if (!SSL_export_keying_material(dtls, material, sizeof(material), dtls_srtp_lable.c_str(), dtls_srtp_lable.size(), NULL, 0, 0)) { return srs_error_new(ERROR_RTC_SRTP_INIT, "SSL_export_keying_material failed"); } + size_t offset = 0; + + std::string client_master_key(reinterpret_cast(material), SRTP_MASTER_KEY_KEY_LEN); + offset += SRTP_MASTER_KEY_KEY_LEN; + std::string server_master_key(reinterpret_cast(material + offset), SRTP_MASTER_KEY_KEY_LEN); + offset += SRTP_MASTER_KEY_KEY_LEN; + std::string client_master_salt(reinterpret_cast(material + offset), SRTP_MASTER_KEY_SALT_LEN); + offset += SRTP_MASTER_KEY_SALT_LEN; + std::string server_master_salt(reinterpret_cast(material + offset), SRTP_MASTER_KEY_SALT_LEN); + + client_key = client_master_key + client_master_salt; + server_key = server_master_key + server_master_salt; + + return err; +} + +SrsSRTP::SrsSRTP() +{ + srtp_ctx = NULL; +} + +SrsSRTP::~SrsSRTP() +{ + if (srtp_ctx) { + srtp_dealloc(srtp_ctx); + } +} + +srs_error_t SrsSRTP::initialize(string srtp_key, bool send) +{ + srs_error_t err = srs_success; + + srtp_policy_t policy; + bzero(&policy, sizeof(policy)); + + // TODO: Maybe we can use SRTP-GCM in future. + // @see https://bugs.chromium.org/p/chromium/issues/detail?id=713701 + // @see https://groups.google.com/forum/#!topic/discuss-webrtc/PvCbWSetVAQ + srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp); + srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp); + + if (send) { + policy.ssrc.type = ssrc_any_outbound; + } else { + policy.ssrc.type = ssrc_any_inbound; + } + + + policy.ssrc.value = 0; + // TODO: adjust window_size + policy.window_size = 8192; + policy.allow_repeat_tx = 1; + policy.next = NULL; + + //uint8_t *key = new uint8_t[server_key.size()]; + //memcpy(key, server_key.data(), server_key.size()); + uint8_t *key = new uint8_t[srtp_key.size()]; + memcpy(key, srtp_key.data(), srtp_key.size()); + policy.key = key; + + if (srtp_create(&srtp_ctx, &policy) != srtp_err_status_ok) { + srs_freepa(key); + return srs_error_new(ERROR_RTC_SRTP_INIT, "srtp_create failed"); + } + + srs_freepa(key); + + return err; +} + +srs_error_t SrsSRTP::protect_rtp(char* out_buf, const char* in_buf, int& nb_out_buf) +{ + srs_error_t err = srs_success; + + memcpy(out_buf, in_buf, nb_out_buf); + // TODO: FIXME: Wrap error code. + if (srtp_protect(srtp_ctx, out_buf, &nb_out_buf) != 0) { + return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtp protect failed"); + } + + return err; +} + +srs_error_t SrsSRTP::protect_rtp2(void* rtp_hdr, int* len_ptr) +{ + srs_error_t err = srs_success; + + // TODO: FIXME: Wrap error code. + if (srtp_protect(srtp_ctx, rtp_hdr, len_ptr) != 0) { + return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtp protect"); + } + + return err; +} + +srs_error_t SrsSRTP::unprotect_rtp(char* out_buf, const char* in_buf, int& nb_out_buf) +{ + srs_error_t err = srs_success; + + memcpy(out_buf, in_buf, nb_out_buf); + srtp_err_status_t r0 = srtp_unprotect(srtp_ctx, out_buf, &nb_out_buf); + if (r0 != srtp_err_status_ok) { + return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "unprotect r0=%u", r0); + } + + return err; +} + +srs_error_t SrsSRTP::protect_rtcp(char* out_buf, const char* in_buf, int& nb_out_buf) +{ + srs_error_t err = srs_success; + + memcpy(out_buf, in_buf, nb_out_buf); + // TODO: FIXME: Wrap error code. + if (srtp_protect_rtcp(srtp_ctx, out_buf, &nb_out_buf) != 0) { + return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtcp protect failed"); + } + + return err; +} + +srs_error_t SrsSRTP::unprotect_rtcp(char* out_buf, const char* in_buf, int& nb_out_buf) +{ + srs_error_t err = srs_success; + + memcpy(out_buf, in_buf, nb_out_buf); + // TODO: FIXME: Wrap error code. + if (srtp_unprotect_rtcp(srtp_ctx, out_buf, &nb_out_buf) != srtp_err_status_ok) { + return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "rtcp unprotect failed"); + } + return err; } \ No newline at end of file diff --git a/trunk/src/app/srs_app_rtc_dtls.hpp b/trunk/src/app/srs_app_rtc_dtls.hpp index 3a50646ff..ecc1fb389 100644 --- a/trunk/src/app/srs_app_rtc_dtls.hpp +++ b/trunk/src/app/srs_app_rtc_dtls.hpp @@ -31,6 +31,7 @@ class SrsRequest; #include +#include class SrsDtlsCertificate { @@ -93,10 +94,27 @@ public: srs_error_t initialize(SrsRequest* r); srs_error_t do_handshake(); srs_error_t on_dtls(char* data, int nb_data); - srs_error_t export_keying_material(unsigned char *out, size_t olen, const char *label, size_t llen, const unsigned char *p, size_t plen, int use_context); + srs_error_t get_srtp_key(std::string& send_key, std::string& recv_key); private: SSL_CTX* build_dtls_ctx(); srs_error_t handshake(); }; +class SrsSRTP +{ +private: + srtp_t srtp_ctx; +public: + SrsSRTP(); + virtual ~SrsSRTP(); +public: + srs_error_t initialize(std::string srtp_key, bool send); +public: + srs_error_t protect_rtp(char* protected_buf, const char* ori_buf, int& nb_protected_buf); + srs_error_t protect_rtp2(void* rtp_hdr, int* len_ptr); + srs_error_t unprotect_rtp(char* unprotected_buf, const char* ori_buf, int& nb_unprotected_buf); + srs_error_t protect_rtcp(char* protected_buf, const char* ori_buf, int& nb_protected_buf); + srs_error_t unprotect_rtcp(char* unprotected_buf, const char* ori_buf, int& nb_unprotected_buf); +}; + #endif From acf9c9d25b2716e7049d1ae67887d1220c9de777 Mon Sep 17 00:00:00 2001 From: "jinxue.cgh" Date: Thu, 25 Jun 2020 15:01:05 +0800 Subject: [PATCH 09/37] RTC: refine get_srtp_key parameter name --- trunk/src/app/srs_app_rtc_dtls.cpp | 6 +++--- trunk/src/app/srs_app_rtc_dtls.hpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_dtls.cpp b/trunk/src/app/srs_app_rtc_dtls.cpp index 4c98b5ab6..895b1bdd8 100644 --- a/trunk/src/app/srs_app_rtc_dtls.cpp +++ b/trunk/src/app/srs_app_rtc_dtls.cpp @@ -429,7 +429,7 @@ srs_error_t SrsDtls::do_handshake() const int SRTP_MASTER_KEY_KEY_LEN = 16; const int SRTP_MASTER_KEY_SALT_LEN = 14; -srs_error_t SrsDtls::get_srtp_key(std::string& client_key, std::string& server_key) +srs_error_t SrsDtls::get_srtp_key(std::string& recv_key, std::string& send_key) { srs_error_t err = srs_success; @@ -449,8 +449,8 @@ srs_error_t SrsDtls::get_srtp_key(std::string& client_key, std::string& server_k offset += SRTP_MASTER_KEY_SALT_LEN; std::string server_master_salt(reinterpret_cast(material + offset), SRTP_MASTER_KEY_SALT_LEN); - client_key = client_master_key + client_master_salt; - server_key = server_master_key + server_master_salt; + recv_key = client_master_key + client_master_salt; + send_key = server_master_key + server_master_salt; return err; } diff --git a/trunk/src/app/srs_app_rtc_dtls.hpp b/trunk/src/app/srs_app_rtc_dtls.hpp index ecc1fb389..41eaa7bdb 100644 --- a/trunk/src/app/srs_app_rtc_dtls.hpp +++ b/trunk/src/app/srs_app_rtc_dtls.hpp @@ -94,7 +94,7 @@ public: srs_error_t initialize(SrsRequest* r); srs_error_t do_handshake(); srs_error_t on_dtls(char* data, int nb_data); - srs_error_t get_srtp_key(std::string& send_key, std::string& recv_key); + srs_error_t get_srtp_key(std::string& recv_key, std::string& send_key); private: SSL_CTX* build_dtls_ctx(); srs_error_t handshake(); From 99016af42a1b2bec80dd1eecbd5338da58ad2ac5 Mon Sep 17 00:00:00 2001 From: "jinxue.cgh" Date: Thu, 25 Jun 2020 20:47:17 +0800 Subject: [PATCH 10/37] RTC: transport use single srtp --- trunk/src/app/srs_app_rtc_conn.cpp | 74 +++++++++++------------- trunk/src/app/srs_app_rtc_conn.hpp | 20 ++++--- trunk/src/app/srs_app_rtc_dtls.cpp | 93 ++++++++++++++++-------------- trunk/src/app/srs_app_rtc_dtls.hpp | 22 +++++-- 4 files changed, 112 insertions(+), 97 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 5b2a6b57f..66bf8345b 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -112,8 +112,7 @@ SrsSecurityTransport::SrsSecurityTransport(SrsRtcSession* s) session_ = s; dtls_ = new SrsDtls((ISrsDtlsCallback*)this); - srtp_send = new SrsSRTP(); - srtp_recv = new SrsSRTP(); + srtp_ = new SrsSRTP(); handshake_done = false; } @@ -125,12 +124,9 @@ SrsSecurityTransport::~SrsSecurityTransport() dtls_ = NULL; } - if (srtp_send) { - srs_freep(srtp_send); - } - - if (srtp_recv) { - srs_freep(srtp_recv); + if (srtp_) { + srs_freep(srtp_); + srtp_ = NULL; } } @@ -199,62 +195,58 @@ srs_error_t SrsSecurityTransport::srtp_initialize() if ((err = dtls_->get_srtp_key(recv_key, send_key)) != srs_success) { return err; } - - if ((err = srtp_send->initialize(send_key, true)) != srs_success) { - return srs_error_wrap(err, "srtp send init failed"); - } - - if ((err = srtp_recv->initialize(recv_key, false)) != srs_success) { - return srs_error_wrap(err, "srtp recv init failed"); + + if ((err = srtp_->initialize(recv_key, send_key)) != srs_success) { + return srs_error_wrap(err, "srtp init failed"); } return err; } -srs_error_t SrsSecurityTransport::protect_rtp(char* out_buf, const char* in_buf, int& nb_out_buf) +srs_error_t SrsSecurityTransport::protect_rtp(const char* plaintext, char* cipher, int& nb_cipher) { - if (!srtp_send) { + if (!srtp_) { return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtp protect failed"); } - return srtp_send->protect_rtp(out_buf, in_buf, nb_out_buf); + return srtp_->protect_rtp(plaintext, cipher, nb_cipher); +} + +srs_error_t SrsSecurityTransport::protect_rtcp(const char* plaintext, char* cipher, int& nb_cipher) +{ + if (!srtp_) { + return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtcp protect failed"); + } + + return srtp_->protect_rtcp(plaintext, cipher, nb_cipher); } // TODO: FIXME: Merge with protect_rtp. srs_error_t SrsSecurityTransport::protect_rtp2(void* rtp_hdr, int* len_ptr) { - if (!srtp_send) { + if (!srtp_) { return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtp protect"); } - return srtp_send->protect_rtp2(rtp_hdr, len_ptr); + return srtp_->protect_rtp2(rtp_hdr, len_ptr); } -srs_error_t SrsSecurityTransport::unprotect_rtp(char* out_buf, const char* in_buf, int& nb_out_buf) +srs_error_t SrsSecurityTransport::unprotect_rtp(const char* cipher, char* plaintext, int& nb_plaintext) { - if (!srtp_recv) { + if (!srtp_) { return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "rtp unprotect failed"); } - return srtp_recv->unprotect_rtp(out_buf, in_buf, nb_out_buf); + return srtp_->unprotect_rtp(cipher, plaintext, nb_plaintext); } -srs_error_t SrsSecurityTransport::protect_rtcp(char* out_buf, const char* in_buf, int& nb_out_buf) +srs_error_t SrsSecurityTransport::unprotect_rtcp(const char* cipher, char* plaintext, int& nb_plaintext) { - if (!srtp_send) { - return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtcp protect failed"); - } - - return srtp_send->protect_rtcp(out_buf, in_buf, nb_out_buf); -} - -srs_error_t SrsSecurityTransport::unprotect_rtcp(char* out_buf, const char* in_buf, int& nb_out_buf) -{ - if (!srtp_recv) { + if (!srtp_) { return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "rtcp unprotect failed"); } - return srtp_recv->unprotect_rtcp(out_buf, in_buf, nb_out_buf); + return srtp_->unprotect_rtcp(cipher, plaintext, nb_plaintext); } SrsRtcOutgoingInfo::SrsRtcOutgoingInfo() @@ -1059,7 +1051,7 @@ srs_error_t SrsRtcPublisher::send_rtcp_rr(uint32_t ssrc, SrsRtpRingBuffer* rtp_q char protected_buf[kRtpPacketSize]; int nb_protected_buf = stream.pos(); - if ((err = session_->transport_->protect_rtcp(protected_buf, stream.data(), nb_protected_buf)) != srs_success) { + if ((err = session_->transport_->protect_rtcp(stream.data(), protected_buf, nb_protected_buf)) != srs_success) { return srs_error_wrap(err, "protect rtcp rr"); } @@ -1119,7 +1111,7 @@ srs_error_t SrsRtcPublisher::send_rtcp_xr_rrtr(uint32_t ssrc) char protected_buf[kRtpPacketSize]; int nb_protected_buf = stream.pos(); - if ((err = session_->transport_->protect_rtcp(protected_buf, stream.data(), nb_protected_buf)) != srs_success) { + if ((err = session_->transport_->protect_rtcp(stream.data(), protected_buf, nb_protected_buf)) != srs_success) { return srs_error_wrap(err, "protect rtcp xr"); } @@ -1156,7 +1148,7 @@ srs_error_t SrsRtcPublisher::send_rtcp_fb_pli(uint32_t ssrc) char protected_buf[kRtpPacketSize]; int nb_protected_buf = stream.pos(); - if ((err = session_->transport_->protect_rtcp(protected_buf, stream.data(), nb_protected_buf)) != srs_success) { + if ((err = session_->transport_->protect_rtcp(stream.data(), protected_buf, nb_protected_buf)) != srs_success) { return srs_error_wrap(err, "protect rtcp psfb pli"); } @@ -1187,7 +1179,7 @@ srs_error_t SrsRtcPublisher::on_twcc(uint16_t sn) { } int nb_protected_buf = buffer->pos(); char protected_buf[kRtpPacketSize]; - if (session_->transport_->protect_rtcp(protected_buf, pkt, nb_protected_buf) == srs_success) { + if (session_->transport_->protect_rtcp(pkt, protected_buf, nb_protected_buf) == srs_success) { session_->sendonly_skt->sendto(protected_buf, nb_protected_buf, 0); } } @@ -1207,7 +1199,7 @@ srs_error_t SrsRtcPublisher::on_rtp(char* data, int nb_data) // Decrypt the cipher to plaintext RTP data. int nb_unprotected_buf = nb_data; char* unprotected_buf = new char[kRtpPacketSize]; - if ((err = session_->transport_->unprotect_rtp(unprotected_buf, data, nb_unprotected_buf)) != srs_success) { + if ((err = session_->transport_->unprotect_rtp(data, unprotected_buf, nb_unprotected_buf)) != srs_success) { // We try to decode the RTP header for more detail error informations. SrsBuffer b0(data, nb_data); SrsRtpHeader h0; h0.decode(&b0); err = srs_error_wrap(err, "marker=%u, pt=%u, seq=%u, ts=%u, ssrc=%u, pad=%u, payload=%uB", h0.get_marker(), h0.get_payload_type(), @@ -1950,7 +1942,7 @@ srs_error_t SrsRtcSession::on_rtcp(char* data, int nb_data) char unprotected_buf[kRtpPacketSize]; int nb_unprotected_buf = nb_data; - if ((err = transport_->unprotect_rtcp(unprotected_buf, data, nb_unprotected_buf)) != srs_success) { + if ((err = transport_->unprotect_rtcp(data, unprotected_buf, nb_unprotected_buf)) != srs_success) { return srs_error_wrap(err, "rtcp unprotect failed"); } diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 09e2fe35c..9a5b71e61 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -111,9 +111,7 @@ class SrsSecurityTransport : public ISrsDtlsCallback private: SrsRtcSession* session_; SrsDtls* dtls_; - SrsSRTP* srtp_send; - SrsSRTP* srtp_recv; - + SrsSRTP* srtp_; bool handshake_done; public: SrsSecurityTransport(SrsRtcSession* s); @@ -124,11 +122,19 @@ public: srs_error_t do_handshake(); srs_error_t on_dtls(char* data, int nb_data); public: - srs_error_t protect_rtp(char* protected_buf, const char* ori_buf, int& nb_protected_buf); + // Encrypt the input plaintext to output cipher with nb_cipher bytes. + // @remark Note that the nb_cipher is the size of input plaintext, and + // it also is the length of output cipher when return. + srs_error_t protect_rtp(const char* plaintext, char* cipher, int& nb_cipher); + srs_error_t protect_rtcp(const char* plaintext, char* cipher, int& nb_cipher); + // Encrypt the input rtp_hdr with *len_ptr bytes. + // @remark the input plaintext and out cipher reuse rtp_hdr. srs_error_t protect_rtp2(void* rtp_hdr, int* len_ptr); - srs_error_t unprotect_rtp(char* unprotected_buf, const char* ori_buf, int& nb_unprotected_buf); - srs_error_t protect_rtcp(char* protected_buf, const char* ori_buf, int& nb_protected_buf); - srs_error_t unprotect_rtcp(char* unprotected_buf, const char* ori_buf, int& nb_unprotected_buf); + // Decrypt the input cipher to output cipher with nb_cipher bytes. + // @remark Note that the nb_plaintext is the size of input cipher, and + // it also is the length of output plaintext when return. + srs_error_t unprotect_rtp(const char* cipher, char* plaintext, int& nb_plaintext); + srs_error_t unprotect_rtcp(const char* cipher, char* plaintext, int& nb_plaintext); // implement ISrsDtlsCallback public: virtual srs_error_t on_dtls_handshake_done(); diff --git a/trunk/src/app/srs_app_rtc_dtls.cpp b/trunk/src/app/srs_app_rtc_dtls.cpp index 895b1bdd8..58953d3ae 100644 --- a/trunk/src/app/srs_app_rtc_dtls.cpp +++ b/trunk/src/app/srs_app_rtc_dtls.cpp @@ -30,6 +30,7 @@ using namespace std; #include #include #include +#include #include #include @@ -457,17 +458,22 @@ srs_error_t SrsDtls::get_srtp_key(std::string& recv_key, std::string& send_key) SrsSRTP::SrsSRTP() { - srtp_ctx = NULL; + recv_ctx_ = NULL; + send_ctx_ = NULL; } SrsSRTP::~SrsSRTP() { - if (srtp_ctx) { - srtp_dealloc(srtp_ctx); + if (recv_ctx_) { + srtp_dealloc(recv_ctx_); + } + + if (send_ctx_) { + srtp_dealloc(send_ctx_); } } -srs_error_t SrsSRTP::initialize(string srtp_key, bool send) +srs_error_t SrsSRTP::initialize(string recv_key, std::string send_key) { srs_error_t err = srs_success; @@ -480,66 +486,80 @@ srs_error_t SrsSRTP::initialize(string srtp_key, bool send) srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp); srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp); - if (send) { - policy.ssrc.type = ssrc_any_outbound; - } else { - policy.ssrc.type = ssrc_any_inbound; - } - - policy.ssrc.value = 0; // TODO: adjust window_size policy.window_size = 8192; policy.allow_repeat_tx = 1; policy.next = NULL; - //uint8_t *key = new uint8_t[server_key.size()]; - //memcpy(key, server_key.data(), server_key.size()); - uint8_t *key = new uint8_t[srtp_key.size()]; - memcpy(key, srtp_key.data(), srtp_key.size()); - policy.key = key; + // init recv context + policy.ssrc.type = ssrc_any_inbound; + uint8_t *rkey = new uint8_t[recv_key.size()]; + SrsAutoFreeA(uint8_t, rkey); + memcpy(rkey, recv_key.data(), recv_key.size()); + policy.key = rkey; - if (srtp_create(&srtp_ctx, &policy) != srtp_err_status_ok) { - srs_freepa(key); - return srs_error_new(ERROR_RTC_SRTP_INIT, "srtp_create failed"); + if (srtp_create(&recv_ctx_, &policy) != srtp_err_status_ok) { + return srs_error_new(ERROR_RTC_SRTP_INIT, "srtp_create recv failed"); } - srs_freepa(key); + policy.ssrc.type = ssrc_any_outbound; + uint8_t *skey = new uint8_t[send_key.size()]; + SrsAutoFreeA(uint8_t, skey); + memcpy(skey, send_key.data(), send_key.size()); + policy.key = skey; + + if (srtp_create(&send_ctx_, &policy) != srtp_err_status_ok) { + return srs_error_new(ERROR_RTC_SRTP_INIT, "srtp_create recv failed"); + } return err; } -srs_error_t SrsSRTP::protect_rtp(char* out_buf, const char* in_buf, int& nb_out_buf) +srs_error_t SrsSRTP::protect_rtp(const char* plaintext, char* cipher, int& nb_cipher) { srs_error_t err = srs_success; - memcpy(out_buf, in_buf, nb_out_buf); + memcpy(cipher, plaintext, nb_cipher); // TODO: FIXME: Wrap error code. - if (srtp_protect(srtp_ctx, out_buf, &nb_out_buf) != 0) { + if (srtp_protect(send_ctx_, cipher, &nb_cipher) != 0) { return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtp protect failed"); } return err; } +srs_error_t SrsSRTP::protect_rtcp(const char* plaintext, char* cipher, int& nb_cipher) +{ + srs_error_t err = srs_success; + + memcpy(cipher, plaintext, nb_cipher); + // TODO: FIXME: Wrap error code. + if (srtp_protect_rtcp(send_ctx_, cipher, &nb_cipher) != 0) { + return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtcp protect failed"); + } + + return err; +} + srs_error_t SrsSRTP::protect_rtp2(void* rtp_hdr, int* len_ptr) { srs_error_t err = srs_success; // TODO: FIXME: Wrap error code. - if (srtp_protect(srtp_ctx, rtp_hdr, len_ptr) != 0) { + if (srtp_protect(send_ctx_, rtp_hdr, len_ptr) != 0) { return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtp protect"); } return err; } -srs_error_t SrsSRTP::unprotect_rtp(char* out_buf, const char* in_buf, int& nb_out_buf) +srs_error_t SrsSRTP::unprotect_rtp(const char* cipher, char* plaintext, int& nb_plaintext) { srs_error_t err = srs_success; - memcpy(out_buf, in_buf, nb_out_buf); - srtp_err_status_t r0 = srtp_unprotect(srtp_ctx, out_buf, &nb_out_buf); + memcpy(plaintext, cipher, nb_plaintext); + srtp_err_status_t r0 = srtp_unprotect(recv_ctx_, plaintext, &nb_plaintext); if (r0 != srtp_err_status_ok) { return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "unprotect r0=%u", r0); } @@ -547,26 +567,13 @@ srs_error_t SrsSRTP::unprotect_rtp(char* out_buf, const char* in_buf, int& nb_ou return err; } -srs_error_t SrsSRTP::protect_rtcp(char* out_buf, const char* in_buf, int& nb_out_buf) +srs_error_t SrsSRTP::unprotect_rtcp(const char* cipher, char* plaintext, int& nb_plaintext) { srs_error_t err = srs_success; - memcpy(out_buf, in_buf, nb_out_buf); + memcpy(plaintext, cipher, nb_plaintext); // TODO: FIXME: Wrap error code. - if (srtp_protect_rtcp(srtp_ctx, out_buf, &nb_out_buf) != 0) { - return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtcp protect failed"); - } - - return err; -} - -srs_error_t SrsSRTP::unprotect_rtcp(char* out_buf, const char* in_buf, int& nb_out_buf) -{ - srs_error_t err = srs_success; - - memcpy(out_buf, in_buf, nb_out_buf); - // TODO: FIXME: Wrap error code. - if (srtp_unprotect_rtcp(srtp_ctx, out_buf, &nb_out_buf) != srtp_err_status_ok) { + if (srtp_unprotect_rtcp(recv_ctx_, plaintext, &nb_plaintext) != srtp_err_status_ok) { return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "rtcp unprotect failed"); } diff --git a/trunk/src/app/srs_app_rtc_dtls.hpp b/trunk/src/app/srs_app_rtc_dtls.hpp index 41eaa7bdb..759042457 100644 --- a/trunk/src/app/srs_app_rtc_dtls.hpp +++ b/trunk/src/app/srs_app_rtc_dtls.hpp @@ -103,18 +103,28 @@ private: class SrsSRTP { private: - srtp_t srtp_ctx; + srtp_t recv_ctx_; + srtp_t send_ctx_; public: SrsSRTP(); virtual ~SrsSRTP(); public: - srs_error_t initialize(std::string srtp_key, bool send); + // Intialize srtp context with recv_key and send_key. + srs_error_t initialize(std::string recv_key, std::string send_key); public: - srs_error_t protect_rtp(char* protected_buf, const char* ori_buf, int& nb_protected_buf); + // Encrypt the input plaintext to output cipher with nb_cipher bytes. + // @remark Note that the nb_cipher is the size of input plaintext, and + // it also is the length of output cipher when return. + srs_error_t protect_rtp(const char* plaintext, char* cipher, int& nb_cipher); + srs_error_t protect_rtcp(const char* plaintext, char* cipher, int& nb_cipher); + // Encrypt the input rtp_hdr with *len_ptr bytes. + // @remark the input plaintext and out cipher reuse rtp_hdr. srs_error_t protect_rtp2(void* rtp_hdr, int* len_ptr); - srs_error_t unprotect_rtp(char* unprotected_buf, const char* ori_buf, int& nb_unprotected_buf); - srs_error_t protect_rtcp(char* protected_buf, const char* ori_buf, int& nb_protected_buf); - srs_error_t unprotect_rtcp(char* unprotected_buf, const char* ori_buf, int& nb_unprotected_buf); + // Decrypt the input cipher to output cipher with nb_cipher bytes. + // @remark Note that the nb_plaintext is the size of input cipher, and + // it also is the length of output plaintext when return. + srs_error_t unprotect_rtp(const char* cipher, char* plaintext, int& nb_plaintext); + srs_error_t unprotect_rtcp(const char* cipher, char* plaintext, int& nb_plaintext); }; #endif From 94a4eaffdaf9416058252e458cc5c288bf14f6dd Mon Sep 17 00:00:00 2001 From: winlin Date: Fri, 26 Jun 2020 15:19:48 +0800 Subject: [PATCH 11/37] Ignore any dump files --- trunk/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/trunk/.gitignore b/trunk/.gitignore index a719848e8..c5ff54605 100644 --- a/trunk/.gitignore +++ b/trunk/.gitignore @@ -43,4 +43,5 @@ srs /webrtc /configure.sh /janus +*.dump From 62b70943d4fe07f1ad5fb7b852e876c7dd2711d4 Mon Sep 17 00:00:00 2001 From: winlin Date: Fri, 26 Jun 2020 15:20:24 +0800 Subject: [PATCH 12/37] RTC: Fix TWCC delta bug. --- trunk/src/kernel/srs_kernel_rtc_rtcp.cpp | 147 ++++++++++++----------- trunk/src/kernel/srs_kernel_rtc_rtcp.hpp | 3 +- 2 files changed, 78 insertions(+), 72 deletions(-) diff --git a/trunk/src/kernel/srs_kernel_rtc_rtcp.cpp b/trunk/src/kernel/srs_kernel_rtc_rtcp.cpp index 226e6e70d..a4248a694 100644 --- a/trunk/src/kernel/srs_kernel_rtc_rtcp.cpp +++ b/trunk/src/kernel/srs_kernel_rtc_rtcp.cpp @@ -773,6 +773,17 @@ srs_error_t SrsRtcpTWCC::encode(SrsBuffer *buffer) { srs_error_t err = srs_success; + err = do_encode(buffer); + + clear(); + + return err; +} + +srs_error_t SrsRtcpTWCC::do_encode(SrsBuffer *buffer) +{ + srs_error_t err = srs_success; + if(!buffer->require(nb_bytes())) { return srs_error_new(ERROR_RTC_RTCP, "requires %d bytes", nb_bytes()); } @@ -787,85 +798,79 @@ srs_error_t SrsRtcpTWCC::encode(SrsBuffer *buffer) uint16_t last_sn = base_sn_; packet_count_ = recv_packes_.size(); - do { - // encode chunk - SrsRtcpTWCC::SrsRtcpTWCCChunk chunk; - for(; it_sn != recv_sns_.end(); ++it_sn) { - uint16_t current_sn = *it_sn; - // calculate delta - it_ts = recv_packes_.find(current_sn); - srs_utime_t delta_us = calculate_delta_us(it_ts->second, last_ts); - uint16_t delta = delta_us; - if(delta != delta_us) { - return srs_error_new(ERROR_RTC_RTCP, "twcc: delta:%lld, exceeds the 16-bit base receive delta", delta_us); - } - - if(current_sn > (last_sn + 1)) { - // lost packet - for(uint16_t lost_sn = last_sn + 1; lost_sn < current_sn; ++lost_sn) { - process_pkt_chunk(chunk, 0); - packet_count_++; - } - } - - // FIXME 24-bit base receive delta not supported - int recv_delta_size = (delta >= 0 && delta <= 0xff) ? 1 : 2; - if ((err = process_pkt_chunk(chunk, recv_delta_size)) != srs_success) { - return srs_error_new(ERROR_RTC_RTCP, "delta_size %d, failed to append_recv_delta", recv_delta_size); - } - - pkt_deltas_.push_back(delta); - last_ts += delta * kTwccFbDeltaUnit; - pkt_len += recv_delta_size; - last_sn = current_sn; + // encode chunk + SrsRtcpTWCC::SrsRtcpTWCCChunk chunk; + for(; it_sn != recv_sns_.end(); ++it_sn) { + uint16_t current_sn = *it_sn; + // calculate delta + it_ts = recv_packes_.find(current_sn); + srs_utime_t delta_us = calculate_delta_us(it_ts->second, last_ts); + int16_t delta = delta_us; + if(delta != delta_us) { + return srs_error_new(ERROR_RTC_RTCP, "twcc: delta:%" PRId64 ", exceeds the 16bits", delta_us); } - if(0 < chunk.size) { - if((err = encode_remaining_chunk(chunk)) != srs_success) { - return srs_error_wrap(err, "encode chunk"); + if(current_sn > (last_sn + 1)) { + // lost packet + for(uint16_t lost_sn = last_sn + 1; lost_sn < current_sn; ++lost_sn) { + process_pkt_chunk(chunk, 0); + packet_count_++; } } - // encode rtcp twcc packet - if((pkt_len % 4) == 0) { - header_.length = pkt_len / 4; + // FIXME 24-bit base receive delta not supported + int recv_delta_size = (delta >= 0 && delta <= 0xff) ? 1 : 2; + if ((err = process_pkt_chunk(chunk, recv_delta_size)) != srs_success) { + return srs_error_new(ERROR_RTC_RTCP, "delta_size %d, failed to append_recv_delta", recv_delta_size); + } + + pkt_deltas_.push_back(delta); + last_ts += delta * kTwccFbDeltaUnit; + pkt_len += recv_delta_size; + last_sn = current_sn; + } + + if(0 < chunk.size) { + if((err = encode_remaining_chunk(chunk)) != srs_success) { + return srs_error_wrap(err, "encode chunk"); + } + } + + // encode rtcp twcc packet + if((pkt_len % 4) == 0) { + header_.length = pkt_len / 4; + } else { + header_.length = (pkt_len + 4 - (pkt_len%4)) / 4; + } + header_.length -= 1; + + if(srs_success != (err = encode_header(buffer))) { + return srs_error_wrap(err, "encode header"); + } + buffer->write_4bytes(sender_ssrc_); + buffer->write_4bytes(media_ssrc_); + buffer->write_2bytes(base_sn_); + buffer->write_2bytes(packet_count_); + buffer->write_3bytes(reference_time_); + buffer->write_1bytes(fb_pkt_count_); + + for(vector::iterator it = encoded_chucks_.begin(); it != encoded_chucks_.end(); ++it) { + buffer->write_2bytes(*it); + } + for(vector::iterator it = pkt_deltas_.begin(); it != pkt_deltas_.end(); ++it) { + if(0 <= *it && 0xFF >= *it) { + // small delta + uint8_t delta = *it; + buffer->write_1bytes(delta); } else { - header_.length = (pkt_len + 4 - (pkt_len%4)) / 4; - } - header_.length -= 1; - - if(srs_success != (err = encode_header(buffer))) { - err = srs_error_wrap(err, "encode header"); - break; - } - buffer->write_4bytes(sender_ssrc_); - buffer->write_4bytes(media_ssrc_); - buffer->write_2bytes(base_sn_); - buffer->write_2bytes(packet_count_); - buffer->write_3bytes(reference_time_); - buffer->write_1bytes(fb_pkt_count_); - - for(vector::iterator it = encoded_chucks_.begin(); it != encoded_chucks_.end(); ++it) { + // large or negative delta buffer->write_2bytes(*it); } - for(vector::iterator it = pkt_deltas_.begin(); it != pkt_deltas_.end(); ++it) { - if(0 <= *it && 0xFF >= *it) { - // small delta - uint8_t delta = *it; - buffer->write_1bytes(delta); - } else { - // large or negative delta - buffer->write_2bytes(*it); - } - } - while((pkt_len % 4) != 0) { - buffer->write_1bytes(0); - pkt_len++; - } - - } while(0); - - clear(); + } + while((pkt_len % 4) != 0) { + buffer->write_1bytes(0); + pkt_len++; + } return err; } diff --git a/trunk/src/kernel/srs_kernel_rtc_rtcp.hpp b/trunk/src/kernel/srs_kernel_rtc_rtcp.hpp index 975fbbbe2..acb04ec24 100644 --- a/trunk/src/kernel/srs_kernel_rtc_rtcp.hpp +++ b/trunk/src/kernel/srs_kernel_rtc_rtcp.hpp @@ -293,7 +293,8 @@ public: virtual srs_error_t decode(SrsBuffer *buffer); virtual int nb_bytes(); virtual srs_error_t encode(SrsBuffer *buffer); - +private: + srs_error_t do_encode(SrsBuffer *buffer); }; class SrsRtcpNack : public SrsRtcpCommon From 5cc0f70f62d5393c67d63c75580b4900df4e56ba Mon Sep 17 00:00:00 2001 From: winlin Date: Fri, 26 Jun 2020 15:24:37 +0800 Subject: [PATCH 13/37] RTC: Refine the extensions for RTP. --- trunk/src/app/srs_app_rtc_conn.cpp | 4 +- trunk/src/app/srs_app_rtc_conn.hpp | 2 +- trunk/src/kernel/srs_kernel_rtc_rtp.cpp | 343 +++++++++++++++++------- trunk/src/kernel/srs_kernel_rtc_rtp.hpp | 73 +++-- 4 files changed, 305 insertions(+), 117 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 66bf8345b..2828d0baa 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -917,7 +917,7 @@ srs_error_t SrsRtcPublisher::initialize(uint32_t vssrc, uint32_t assrc, uint8_t req = r; if (twcc_ext_id_ != 0) { - extension_map_.register_by_uri(twcc_ext_id_, kTWCCExt); + extension_types_.register_by_uri(twcc_ext_id_, kTWCCExt); } // TODO: FIXME: Support reload. nack_enabled_ = _srs_config->get_rtc_nack_enabled(session_->req->vhost); @@ -1224,7 +1224,7 @@ srs_error_t SrsRtcPublisher::on_rtp(char* data, int nb_data) if (true) { pkt->set_decode_handler(this); - pkt->set_rtp_header_extensions(&extension_map_); + pkt->set_extension_types(&extension_types_); pkt->shared_msg = new SrsSharedPtrMessage(); pkt->shared_msg->wrap(buf, nb_buf); diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 9a5b71e61..7899821c3 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -277,7 +277,7 @@ private: uint8_t twcc_ext_id_; uint8_t twcc_fb_count_; SrsRtcpTWCC rtcp_twcc_; - SrsRtpHeaderExtensionMap extension_map_; + SrsRtpExtensionTypes extension_types_; public: SrsRtcPublisher(SrsRtcSession* session); virtual ~SrsRtcPublisher(); diff --git a/trunk/src/kernel/srs_kernel_rtc_rtp.cpp b/trunk/src/kernel/srs_kernel_rtc_rtp.cpp index 9d2698ff7..840db3185 100644 --- a/trunk/src/kernel/srs_kernel_rtc_rtp.cpp +++ b/trunk/src/kernel/srs_kernel_rtc_rtp.cpp @@ -53,15 +53,15 @@ int32_t srs_seq_distance(uint16_t value, uint16_t pre_value) return srs_rtp_seq_distance(pre_value, value); } -SrsRtpHeaderExtensionMap::SrsRtpHeaderExtensionMap() +SrsRtpExtensionTypes::SrsRtpExtensionTypes() { } -SrsRtpHeaderExtensionMap::~SrsRtpHeaderExtensionMap() +SrsRtpExtensionTypes::~SrsRtpExtensionTypes() { } -bool SrsRtpHeaderExtensionMap::register_by_uri(int id, std::string uri) +bool SrsRtpExtensionTypes::register_by_uri(int id, std::string uri) { for (int i = 0; i < (int)sizeof(kExtensions); ++i) { if (kExtensions[i].uri == uri) { @@ -71,7 +71,7 @@ bool SrsRtpHeaderExtensionMap::register_by_uri(int id, std::string uri) return false; } -bool SrsRtpHeaderExtensionMap::register_id(int id, SrsRtpExtensionType type, std::string uri) +bool SrsRtpExtensionTypes::register_id(int id, SrsRtpExtensionType type, std::string uri) { if (id < 1 || id > 255) { return false; @@ -81,7 +81,7 @@ bool SrsRtpHeaderExtensionMap::register_id(int id, SrsRtpExtensionType type, std return true; } -SrsRtpExtensionType SrsRtpHeaderExtensionMap::get_type(int id) const +SrsRtpExtensionType SrsRtpExtensionTypes::get_type(int id) const { for (int type = kRtpExtensionNone + 1; type < kRtpExtensionNumberOfExtensions; ++type) { if (ids_[type] == id) { @@ -91,85 +91,240 @@ SrsRtpExtensionType SrsRtpHeaderExtensionMap::get_type(int id) const return kInvalidType; } -SrsRtpHeaderExtension::SrsRtpHeaderExtension() + + +SrsRtpExtensionTwcc::SrsRtpExtensionTwcc(): has_twcc_(false), id_(0), sn_(0) { - has_transport_sequence_number = false; - transport_sequence_number = 0; - transport_cc_ext_id = 0; } -SrsRtpHeaderExtension::~SrsRtpHeaderExtension() +SrsRtpExtensionTwcc::~SrsRtpExtensionTwcc() { } +bool SrsRtpExtensionTwcc::has_twcc_ext() +{ + return has_twcc_; +} + +srs_error_t SrsRtpExtensionTwcc::decode(SrsBuffer* buf) +{ + srs_error_t err = srs_success; + + // 0 1 2 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | ID | L=1 |transport wide sequence number | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + if (!buf->require(1)) { + return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 1); + } + uint8_t v = buf->read_1bytes(); + + id_ = (v & 0xF0) >> 4; + uint8_t len = (v & 0x0F); + if(!id_ || len != 1) { + return srs_error_new(ERROR_RTC_RTP, "invalid twcc id=%d, len=%d", id_, len); + } + + if (!buf->require(3)) { + return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 3); + } + sn_ = buf->read_2bytes(); + buf->read_1bytes(); + + has_twcc_ = true; + return err; +} + +int SrsRtpExtensionTwcc::nb_bytes() +{ + return 4; +} + +srs_error_t SrsRtpExtensionTwcc::encode(SrsBuffer* buf) +{ + srs_error_t err = srs_success; + + uint8_t id_len = (id_ & 0x0F)<< 4| 0x01; + buf->write_1bytes(id_len); + buf->write_2bytes(sn_); + buf->write_1bytes(0x00); + + return err; +} + + +uint8_t SrsRtpExtensionTwcc::get_id() +{ + return id_; +} + +void SrsRtpExtensionTwcc::set_id(uint8_t id) +{ + id_ = id; + has_twcc_ = true; +} + +uint16_t SrsRtpExtensionTwcc::get_sn() +{ + return sn_; +} + +void SrsRtpExtensionTwcc::set_sn(uint16_t sn) +{ + sn_ = sn; + has_twcc_ = true; +} + +SrsRtpExtensions::SrsRtpExtensions() : has_ext_(false) +{ +} + +SrsRtpExtensions::~SrsRtpExtensions() +{ +} + +srs_error_t SrsRtpExtensions::decode(SrsBuffer* buf) +{ + srs_error_t err = srs_success; + + /* @see https://tools.ietf.org/html/rfc3550#section-5.3.1 + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | defined by profile | length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | header extension | + | .... | + */ + if (!buf->require(4)) { + return srs_error_new(ERROR_RTC_RTP_MUXER, "requires 4 bytes"); + } + uint16_t profile_id = buf->read_2bytes(); + uint16_t extension_length = buf->read_2bytes(); + + // @see: https://tools.ietf.org/html/rfc5285#section-4.2 + if (profile_id == 0xBEDE) { + SrsBuffer xbuf(buf->head(), extension_length * 4); + buf->skip(extension_length * 4); + return decode_0xbede(&xbuf); + } else if (profile_id == 0x1000) { + buf->skip(extension_length * 4); + } else { + return srs_error_new(ERROR_RTC_RTP_MUXER, "fail to parse extension"); + } + return err; +} + +srs_error_t SrsRtpExtensions::decode_0xbede(SrsBuffer* buf) +{ + srs_error_t err = srs_success; + + while (!buf->empty()) { + // The first byte maybe padding or id+len. + if (!buf->require(1)) { + return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 1); + } + uint8_t v = *((uint8_t*)buf->head()); + + // Padding, ignore + if(v == 0) { + buf->skip(1); + continue; + } + + // 0 + // 0 1 2 3 4 5 6 7 + // +-+-+-+-+-+-+-+-+ + // | ID | len | + // +-+-+-+-+-+-+-+-+ + // Note that 'len' is the header extension element length, which is the + // number of bytes - 1. + uint8_t id = (v & 0xF0) >> 4; + uint8_t len = (v & 0x0F); + + SrsRtpExtensionType xtype = types_.get_type(id); + if (xtype == kRtpExtensionTransportSequenceNumber) { + if(srs_success != (err = twcc_.decode(buf))) { + return srs_error_wrap(err, "decode twcc extension"); + } + has_ext_ = true; + } else { + buf->skip(1 + (len + 1)); + } + } + + return err; +} + +int SrsRtpExtensions::nb_bytes() +{ + return 4 + (twcc_.has_twcc_ext() ? twcc_.nb_bytes() : 0); +} + +srs_error_t SrsRtpExtensions::encode(SrsBuffer* buf) +{ + srs_error_t err = srs_success; + buf->write_2bytes(0xBEDE); + int len = 0; + //TODO: When add new rtp extension, it should add the extension length into len + if(twcc_.has_twcc_ext()) { + len += twcc_.nb_bytes(); + } + buf->write_2bytes(len / 4); + + if(twcc_.has_twcc_ext()) { + if(srs_success != (err = twcc_.encode(buf))) { + return srs_error_wrap(err, "encode twcc extension"); + } + } + return err; +} + +bool SrsRtpExtensions::exists() +{ + return has_ext_; +} + +void SrsRtpExtensions::set_types_(const SrsRtpExtensionTypes* types) +{ + if(types) { + types_ = *types; + } +} + +srs_error_t SrsRtpExtensions::get_twcc_sequence_number(uint16_t& twcc_sn) +{ + if(twcc_.has_twcc_ext()) { + twcc_sn = twcc_.get_sn(); + return srs_success; + } + return srs_error_new(ERROR_RTC_RTP_MUXER, "not find twcc sequence number"); +} + +srs_error_t SrsRtpExtensions::set_twcc_sequence_number(uint8_t id, uint16_t sn) +{ + has_ext_ = true; + twcc_.set_id(id); + twcc_.set_sn(sn); + return srs_success; +} + SrsRtpHeader::SrsRtpHeader() { padding_length = 0; - extension = false; cc = 0; marker = false; payload_type = 0; sequence = 0; timestamp = 0; ssrc = 0; - extension_length = 0; } SrsRtpHeader::~SrsRtpHeader() { } -srs_error_t SrsRtpHeader::parse_extension(SrsBuffer* buf) { - srs_error_t err = srs_success; - uint16_t profile_id = buf->read_2bytes(); - extension_length = buf->read_2bytes(); - - // @see: https://tools.ietf.org/html/rfc5285#section-4.2 - if (profile_id == 0xBEDE) { - uint32_t xlen = extension_length * 4; - while (xlen > 0) { - // parse id and len - uint8_t id_len = buf->read_1bytes(); - xlen--; - if(id_len == 0) { - // padding, ignore - continue; - } - // 0 - // 0 1 2 3 4 5 6 7 - // +-+-+-+-+-+-+-+-+ - // | ID | len | - // +-+-+-+-+-+-+-+-+ - // Note that 'len' is the header extension element length, which is the - // number of bytes - 1. - uint8_t id = (id_len & 0xF0) >> 4; - uint8_t len = (id_len & 0x0F); - - SrsRtpExtensionType xtype = extension_map_.get_type(id); - if (xtype == kRtpExtensionTransportSequenceNumber) { - // 0 1 2 - // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | ID | L=1 |transport wide sequence number | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - header_extension.has_transport_sequence_number = true; - header_extension.transport_sequence_number = buf->read_2bytes(); - header_extension.transport_cc_ext_id = id; - xlen -= 2; - } else { - buf->skip(len + 1); - xlen -= len + 1; - } - } - } else if (profile_id == 0x1000) { - buf->skip(extension_length * 4); - } else { - return srs_error_new(ERROR_RTC_RTP_MUXER, "fail to parse extension"); - } - - return err; -} - srs_error_t SrsRtpHeader::decode(SrsBuffer* buf) { srs_error_t err = srs_success; @@ -178,7 +333,7 @@ srs_error_t SrsRtpHeader::decode(SrsBuffer* buf) return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d+ bytes", kRtpHeaderFixedSize); } - /* + /* @see https://tools.ietf.org/html/rfc1889#section-5.1 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -195,7 +350,7 @@ srs_error_t SrsRtpHeader::decode(SrsBuffer* buf) uint8_t first = buf->read_1bytes(); bool padding = (first & 0x20); - extension = (first & 0x10); + bool extension = (first & 0x10); cc = (first & 0x0F); uint8_t second = buf->read_1bytes(); @@ -216,16 +371,7 @@ srs_error_t SrsRtpHeader::decode(SrsBuffer* buf) } if (extension) { - /* RTP header extension, RFC 3550. - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | defined by profile | length | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | header extension | - | .... | - */ - if ((err = parse_extension(buf)) != srs_success) { + if ((err = parse_extensions(buf)) != srs_success) { return srs_error_wrap(err, "fail to parse extension"); } } @@ -240,6 +386,16 @@ srs_error_t SrsRtpHeader::decode(SrsBuffer* buf) return err; } +srs_error_t SrsRtpHeader::parse_extensions(SrsBuffer* buf) { + srs_error_t err = srs_success; + + if(srs_success != (err = extensions_.decode(buf))) { + return srs_error_wrap(err, "decode rtp extension"); + } + + return err; +} + srs_error_t SrsRtpHeader::encode(SrsBuffer* buf) { srs_error_t err = srs_success; @@ -251,7 +407,7 @@ srs_error_t SrsRtpHeader::encode(SrsBuffer* buf) if (padding_length > 0) { v |= 0x20; } - if (extension) { + if (extensions_.exists()) { v |= 0x10; } buf->write_1bytes(v); @@ -277,40 +433,37 @@ srs_error_t SrsRtpHeader::encode(SrsBuffer* buf) buf->write_4bytes(csrc[i]); } - if (extension) { - buf->write_2bytes(0xBEDE); - // TODO: FIXME: extension_length should caculate by extension length - buf->write_2bytes(extension_length); - - if (header_extension.has_transport_sequence_number) { - uint8_t id_len = (header_extension.transport_cc_ext_id & 0x0F)<< 4| 0x01; - buf->write_1bytes(id_len); - buf->write_2bytes(header_extension.transport_sequence_number); - buf->write_1bytes(0x00); + if (extensions_.exists()) { + if(srs_success != (err = extensions_.encode(buf))) { + return srs_error_wrap(err, "encode rtp extension"); } } return err; } -void SrsRtpHeader::set_extensions(const SrsRtpHeaderExtensionMap* extmap) +void SrsRtpHeader::set_extensions(const SrsRtpExtensionTypes* extmap) { if (extmap) { - extension_map_ = *extmap; + extensions_.set_types_(extmap); } } srs_error_t SrsRtpHeader::get_twcc_sequence_number(uint16_t& twcc_sn) { - if (header_extension.has_transport_sequence_number == true) { - twcc_sn = header_extension.transport_sequence_number; - return srs_success; + if (extensions_.exists()) { + return extensions_.get_twcc_sequence_number(twcc_sn); } - return srs_error_new(ERROR_RTC_RTP_MUXER, "not find twcc sequence number"); + return srs_error_new(ERROR_RTC_RTP_MUXER, "no rtp extension"); +} + +srs_error_t SrsRtpHeader::set_twcc_sequence_number(uint8_t id, uint16_t sn) +{ + return extensions_.set_twcc_sequence_number(id, sn); } int SrsRtpHeader::nb_bytes() { - return kRtpHeaderFixedSize + cc * 4 + (extension ? (extension_length + 1) * 4 : 0); + return kRtpHeaderFixedSize + cc * 4 + (extensions_.exists() ? extensions_.nb_bytes() : 0); } void SrsRtpHeader::set_marker(bool v) @@ -449,9 +602,9 @@ SrsRtpPacket2* SrsRtpPacket2::copy() return cp; } -void SrsRtpPacket2::set_rtp_header_extensions(const SrsRtpHeaderExtensionMap* extmap) +void SrsRtpPacket2::set_extension_types(const SrsRtpExtensionTypes* v) { - return header.set_extensions(extmap); + return header.set_extensions(v); } int SrsRtpPacket2::nb_bytes() diff --git a/trunk/src/kernel/srs_kernel_rtc_rtp.hpp b/trunk/src/kernel/srs_kernel_rtc_rtp.hpp index d57d445b1..5d93e7193 100644 --- a/trunk/src/kernel/srs_kernel_rtc_rtp.hpp +++ b/trunk/src/kernel/srs_kernel_rtc_rtp.hpp @@ -99,7 +99,7 @@ const SrsExtensionInfo kExtensions[] = { {kRtpExtensionTransportSequenceNumber, std::string("http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01")} }; -class SrsRtpHeaderExtensionMap +class SrsRtpExtensionTypes { public: static const SrsRtpExtensionType kInvalidType = kRtpExtensionNone; @@ -108,30 +108,65 @@ public: bool register_by_uri(int id, std::string uri); SrsRtpExtensionType get_type(int id) const; public: - SrsRtpHeaderExtensionMap(); - virtual ~SrsRtpHeaderExtensionMap(); + SrsRtpExtensionTypes(); + virtual ~SrsRtpExtensionTypes(); private: bool register_id(int id, SrsRtpExtensionType type, std::string uri); private: uint8_t ids_[kRtpExtensionNumberOfExtensions]; }; -class SrsRtpHeaderExtension +class SrsRtpExtensionTwcc : public ISrsCodec { + bool has_twcc_; + uint8_t id_; + uint16_t sn_; public: - bool has_transport_sequence_number; - uint16_t transport_sequence_number; - uint8_t transport_cc_ext_id; -public: - SrsRtpHeaderExtension(); - virtual ~SrsRtpHeaderExtension(); + SrsRtpExtensionTwcc(); + virtual ~SrsRtpExtensionTwcc(); + + bool has_twcc_ext(); + uint8_t get_id(); + void set_id(uint8_t id); + uint16_t get_sn(); + void set_sn(uint16_t sn); + +public: + // ISrsCodec + virtual srs_error_t decode(SrsBuffer* buf); + virtual srs_error_t encode(SrsBuffer* buf); + virtual int nb_bytes(); }; -class SrsRtpHeader +class SrsRtpExtensions : public ISrsCodec +{ +private: + bool has_ext_; + SrsRtpExtensionTypes types_; + SrsRtpExtensionTwcc twcc_; +public: + SrsRtpExtensions(); + virtual ~SrsRtpExtensions(); + + bool exists(); + void set_types_(const SrsRtpExtensionTypes* types); + srs_error_t get_twcc_sequence_number(uint16_t& twcc_sn); + srs_error_t set_twcc_sequence_number(uint8_t id, uint16_t sn); + +// ISrsCodec +public: + virtual srs_error_t decode(SrsBuffer* buf); +private: + srs_error_t decode_0xbede(SrsBuffer* buf); +public: + virtual srs_error_t encode(SrsBuffer* buf); + virtual int nb_bytes(); +}; + +class SrsRtpHeader : public ISrsCodec { private: uint8_t padding_length; - bool extension; uint8_t cc; bool marker; uint8_t payload_type; @@ -139,16 +174,15 @@ private: uint32_t timestamp; uint32_t ssrc; uint32_t csrc[15]; - uint16_t extension_length; - SrsRtpHeaderExtensionMap extension_map_; - SrsRtpHeaderExtension header_extension; + SrsRtpExtensions extensions_; public: SrsRtpHeader(); virtual ~SrsRtpHeader(); -private: - srs_error_t parse_extension(SrsBuffer* buf); public: virtual srs_error_t decode(SrsBuffer* buf); +private: + srs_error_t parse_extensions(SrsBuffer* buf); +public: virtual srs_error_t encode(SrsBuffer* buf); virtual int nb_bytes(); public: @@ -164,8 +198,9 @@ public: uint32_t get_ssrc() const; void set_padding(uint8_t v); uint8_t get_padding() const; - void set_extensions(const SrsRtpHeaderExtensionMap* extmap); + void set_extensions(const SrsRtpExtensionTypes* extmap); srs_error_t get_twcc_sequence_number(uint16_t& twcc_sn); + srs_error_t set_twcc_sequence_number(uint8_t id, uint16_t sn); }; class ISrsRtpPayloader : public ISrsCodec @@ -222,7 +257,7 @@ public: // Copy the RTP packet. SrsRtpPacket2* copy(); // Set RTP header extensions for encoding or decoding header extension - void set_rtp_header_extensions(const SrsRtpHeaderExtensionMap* extmap); + void set_extension_types(const SrsRtpExtensionTypes* v); // interface ISrsEncoder public: virtual int nb_bytes(); From a6ade57ce59cfb4807464dd0c66f2ecd710efcc5 Mon Sep 17 00:00:00 2001 From: winlin Date: Fri, 26 Jun 2020 15:25:11 +0800 Subject: [PATCH 14/37] Refine comments --- trunk/src/kernel/srs_kernel_buffer.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trunk/src/kernel/srs_kernel_buffer.hpp b/trunk/src/kernel/srs_kernel_buffer.hpp index 6a3b4c7f3..821adc2b1 100644 --- a/trunk/src/kernel/srs_kernel_buffer.hpp +++ b/trunk/src/kernel/srs_kernel_buffer.hpp @@ -127,7 +127,7 @@ public: bool require(int required_size); public: // Skip some size. - // @param size can be any value. positive to forward; nagetive to backward. + // @param size can be any value. positive to forward; negative to backward. // @remark to skip(pos()) to reset buffer. // @remark assert initialized, the data() not NULL. void skip(int size); From 94ebcf63066130fff9005d502cb0a46605178ae3 Mon Sep 17 00:00:00 2001 From: winlin Date: Sat, 27 Jun 2020 11:13:53 +0800 Subject: [PATCH 15/37] RTC: Support config the DTLS role and version --- trunk/conf/full.conf | 6 +++ trunk/src/app/srs_app_config.cpp | 39 ++++++++++++++++- trunk/src/app/srs_app_config.hpp | 2 + trunk/src/app/srs_app_rtc_api.cpp | 14 ++++++- trunk/src/app/srs_app_rtc_conn.cpp | 18 +++++--- trunk/src/app/srs_app_rtc_conn.hpp | 7 ++-- trunk/src/app/srs_app_rtc_dtls.cpp | 62 ++++++++++++++++++++++------ trunk/src/app/srs_app_rtc_dtls.hpp | 31 ++++++++++++-- trunk/src/app/srs_app_rtc_sdp.hpp | 8 ++++ trunk/src/app/srs_app_rtc_server.cpp | 22 +++++----- 10 files changed, 171 insertions(+), 38 deletions(-) diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index a028598c2..f4b901b66 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -495,6 +495,12 @@ vhost rtc.vhost.srs.com { # If off, we will regenerate the sequence number for RTP packet. # default: off keep_sequence off; + # The role of dtls when peer is actpass: passive or active + # default: passive + dtls_role passive; + # The version of dtls, support dtls1.0, dtls1.2, and auto + # default: auto + dtls_version auto; } # whether enable min delay mode for vhost. # default: on, for RTC. diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index 302a068a5..bcc2a3d03 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -3935,7 +3935,7 @@ srs_error_t SrsConfig::check_normal_config() for (int j = 0; j < (int)conf->directives.size(); j++) { string m = conf->at(j)->name; if (m != "enabled" && m != "bframe" && m != "aac" && m != "stun_timeout" && m != "stun_strict_check" - && m != "keep_sequence") { + && m != "keep_sequence" && m != "dtls_role" && m != "dtls_version") { return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal vhost.rtc.%s of %s", m.c_str(), vhost->arg0().c_str()); } } @@ -5038,6 +5038,42 @@ bool SrsConfig::get_rtc_keep_sequence(string vhost) return SRS_CONF_PERFER_FALSE(conf->arg0()); } +std::string SrsConfig::get_rtc_dtls_role(string vhost) +{ + static std::string DEFAULT = "passive"; + + SrsConfDirective* conf = get_rtc(vhost); + + if (!conf) { + return DEFAULT; + } + + conf = conf->get("dtls_role"); + if (!conf || conf->arg0().empty()) { + return DEFAULT; + } + + return conf->arg0(); +} + +std::string SrsConfig::get_rtc_dtls_version(string vhost) +{ + static std::string DEFAULT = "auto"; + + SrsConfDirective* conf = get_rtc(vhost); + + if (!conf) { + return DEFAULT; + } + + conf = conf->get("dtls_version"); + if (!conf || conf->arg0().empty()) { + return DEFAULT; + } + + return conf->arg0(); +} + bool SrsConfig::get_rtc_nack_enabled(string vhost) { static bool DEFAULT = true; @@ -5078,6 +5114,7 @@ bool SrsConfig::get_rtc_twcc_enabled(string vhost) } return SRS_CONF_PERFER_TRUE(conf->arg0()); } + SrsConfDirective* SrsConfig::get_vhost(string vhost, bool try_default_vhost) { srs_assert(root); diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index 70ec389b6..cf7d60735 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -547,6 +547,8 @@ public: bool get_rtc_keep_sequence(std::string vhost); bool get_rtc_nack_enabled(std::string vhost); bool get_rtc_twcc_enabled(std::string vhost); + std::string get_rtc_dtls_role(std::string vhost); + std::string get_rtc_dtls_version(std::string vhost); // vhost specified section public: diff --git a/trunk/src/app/srs_app_rtc_api.cpp b/trunk/src/app/srs_app_rtc_api.cpp index 75bde95d5..a45ece557 100644 --- a/trunk/src/app/srs_app_rtc_api.cpp +++ b/trunk/src/app/srs_app_rtc_api.cpp @@ -169,6 +169,11 @@ srs_error_t SrsGoApiRtcPlay::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMe } SrsSdp local_sdp; + + // Config for SDP and session. + local_sdp.session_config_.dtls_role = _srs_config->get_rtc_dtls_role(request.vhost); + local_sdp.session_config_.dtls_version = _srs_config->get_rtc_dtls_version(request.vhost); + if ((err = exchange_sdp(&request, remote_sdp, local_sdp)) != srs_success) { return srs_error_wrap(err, "remote sdp have error or unsupport attributes"); } @@ -369,7 +374,7 @@ srs_error_t SrsGoApiRtcPlay::exchange_sdp(SrsRequest* req, const SrsSdp& remote_ } else if (remote_media_desc.session_info_.setup_ == "passive") { local_media_desc.session_info_.setup_ = "active"; } else if (remote_media_desc.session_info_.setup_ == "actpass") { - local_media_desc.session_info_.setup_ = "passive"; + local_media_desc.session_info_.setup_ = local_sdp.session_config_.dtls_role; } else { // @see: https://tools.ietf.org/html/rfc4145#section-4.1 // The default value of the setup attribute in an offer/answer exchange @@ -527,6 +532,11 @@ srs_error_t SrsGoApiRtcPublish::do_serve_http(ISrsHttpResponseWriter* w, ISrsHtt } SrsSdp local_sdp; + + // Config for SDP and session. + local_sdp.session_config_.dtls_role = _srs_config->get_rtc_dtls_role(request.vhost); + local_sdp.session_config_.dtls_version = _srs_config->get_rtc_dtls_version(request.vhost); + if ((err = exchange_sdp(&request, remote_sdp, local_sdp)) != srs_success) { return srs_error_wrap(err, "remote sdp have error or unsupport attributes"); } @@ -746,7 +756,7 @@ srs_error_t SrsGoApiRtcPublish::exchange_sdp(SrsRequest* req, const SrsSdp& remo } else if (remote_media_desc.session_info_.setup_ == "passive") { local_media_desc.session_info_.setup_ = "active"; } else if (remote_media_desc.session_info_.setup_ == "actpass") { - local_media_desc.session_info_.setup_ = "passive"; + local_media_desc.session_info_.setup_ = local_sdp.session_config_.dtls_role; } else { // @see: https://tools.ietf.org/html/rfc4145#section-4.1 // The default value of the setup attribute in an offer/answer exchange diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 2828d0baa..00013499a 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -130,14 +130,14 @@ SrsSecurityTransport::~SrsSecurityTransport() } } -srs_error_t SrsSecurityTransport::initialize(SrsRequest* r) +srs_error_t SrsSecurityTransport::initialize(SrsSessionConfig* cfg) { - return dtls_->initialize(r); + return dtls_->initialize(cfg->dtls_role, cfg->dtls_version); } -srs_error_t SrsSecurityTransport::do_handshake() +srs_error_t SrsSecurityTransport::start_active_handshake() { - return dtls_->do_handshake(); + return dtls_->start_active_handshake(); } srs_error_t SrsSecurityTransport::write_dtls_data(void* data, int size) @@ -1862,7 +1862,8 @@ srs_error_t SrsRtcSession::initialize(SrsRtcSource* source, SrsRequest* r, bool is_publisher_ = is_publisher; source_ = source; - if ((err = transport_->initialize(req)) != srs_success) { + SrsSessionConfig* cfg = &local_sdp.session_config_; + if ((err = transport_->initialize(cfg)) != srs_success) { return srs_error_wrap(err, "init"); } @@ -1872,7 +1873,8 @@ srs_error_t SrsRtcSession::initialize(SrsRtcSource* source, SrsRequest* r, bool blackhole = _srs_config->get_rtc_server_black_hole(); - srs_trace("RTC init session, timeout=%dms, blackhole=%d", srsu2msi(sessionStunTimeout), blackhole); + srs_trace("RTC init session, DTLS(role=%s, version=%s), timeout=%dms, blackhole=%d", + cfg->dtls_role.c_str(), cfg->dtls_version.c_str(), srsu2msi(sessionStunTimeout), blackhole); if (blackhole) { string blackhole_ep = _srs_config->get_rtc_server_black_hole_addr(); @@ -2150,6 +2152,10 @@ srs_error_t SrsRtcSession::on_binding_request(SrsStunPacket* r) state_ = DOING_DTLS_HANDSHAKE; srs_trace("rtc session=%s, STUN done, waitting DTLS handshake.", id().c_str()); + + if((err = transport_->start_active_handshake()) != srs_success) { + return srs_error_wrap(err, "fail to dtls handshake"); + } } if (blackhole && blackhole_addr && blackhole_stfd) { diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 7899821c3..fbaa473f8 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -117,9 +117,9 @@ public: SrsSecurityTransport(SrsRtcSession* s); virtual ~SrsSecurityTransport(); - srs_error_t initialize(SrsRequest* r); - - srs_error_t do_handshake(); + srs_error_t initialize(SrsSessionConfig* cfg); + // When play role of dtls client, it send handshake. + srs_error_t start_active_handshake(); srs_error_t on_dtls(char* data, int nb_data); public: // Encrypt the input plaintext to output cipher with nb_cipher bytes. @@ -377,6 +377,7 @@ public: void switch_to_context(); std::string context_id(); public: + // Before initialize, user must set the local SDP, which is used to inititlize DTLS. srs_error_t initialize(SrsRtcSource* source, SrsRequest* r, bool is_publisher, std::string username, std::string context_id); // The peer address may change, we can identify that by STUN messages. srs_error_t on_stun(SrsUdpMuxSocket* skt, SrsStunPacket* r); diff --git a/trunk/src/app/srs_app_rtc_dtls.cpp b/trunk/src/app/srs_app_rtc_dtls.cpp index 58953d3ae..199f1283f 100644 --- a/trunk/src/app/srs_app_rtc_dtls.cpp +++ b/trunk/src/app/srs_app_rtc_dtls.cpp @@ -31,6 +31,7 @@ using namespace std; #include #include #include +#include #include #include @@ -244,6 +245,9 @@ SrsDtls::SrsDtls(ISrsDtlsCallback* cb) { callback = cb; handshake_done = false; + + role_ = SrsDtlsRoleServer; + version_ = SrsDtlsVersionAuto; } SrsDtls::~SrsDtls() @@ -266,9 +270,14 @@ SSL_CTX* SrsDtls::build_dtls_ctx() #if OPENSSL_VERSION_NUMBER < 0x10002000L // v1.0.2 dtls_ctx = SSL_CTX_new(DTLSv1_method()); #else - dtls_ctx = SSL_CTX_new(DTLS_method()); - //dtls_ctx = SSL_CTX_new(DTLSv1_method()); - //dtls_ctx = SSL_CTX_new(DTLSv1_2_method()); + if (version_ == SrsDtlsVersion1_0) { + dtls_ctx = SSL_CTX_new(DTLSv1_method()); + } else if (version_ == SrsDtlsVersion1_2) { + dtls_ctx = SSL_CTX_new(DTLSv1_2_method()); + } else { + // SrsDtlsVersionAuto, use version-flexible DTLS methods + dtls_ctx = SSL_CTX_new(DTLS_method()); + } #endif if (_srs_rtc_dtls_certificate->is_ecdsa()) { // By ECDSA, https://stackoverflow.com/a/6006898 @@ -323,18 +332,38 @@ SSL_CTX* SrsDtls::build_dtls_ctx() return dtls_ctx; } -srs_error_t SrsDtls::initialize(SrsRequest* r) +srs_error_t SrsDtls::initialize(std::string role, std::string version) { srs_error_t err = srs_success; + role_ = SrsDtlsRoleServer; + if (role == "active") { + role_ = SrsDtlsRoleClient; + } + + if (version == "dtls1.0") { + version_ = SrsDtlsVersion1_0; + } else if (version == "dtls1.2") { + version_ = SrsDtlsVersion1_2; + } else { + version_ = SrsDtlsVersionAuto; + } + dtls_ctx = build_dtls_ctx(); + // TODO: FIXME: Leak for SSL_CTX* return by build_dtls_ctx. if ((dtls = SSL_new(dtls_ctx)) == NULL) { return srs_error_new(ERROR_OpenSslCreateSSL, "SSL_new dtls"); } - // Dtls setup passive, as server role. - SSL_set_accept_state(dtls); + if (role == "active") { + // Dtls setup active, as client role. + SSL_set_connect_state(dtls); + SSL_set_max_send_fragment(dtls, 1500); + } else { + // Dtls setup passive, as server role. + SSL_set_accept_state(dtls); + } if ((bio_in = BIO_new(BIO_s_mem())) == NULL) { return srs_error_new(ERROR_OpenSslBIONew, "BIO_new in"); @@ -350,7 +379,7 @@ srs_error_t SrsDtls::initialize(SrsRequest* r) return err; } -srs_error_t SrsDtls::handshake() +srs_error_t SrsDtls::do_handshake() { srs_error_t err = srs_success; @@ -406,7 +435,7 @@ srs_error_t SrsDtls::on_dtls(char* data, int nb_data) } if (!handshake_done) { - err = handshake(); + err = do_handshake(); } else { while (BIO_ctrl_pending(bio_in) > 0) { char dtls_read_buf[8092]; @@ -423,9 +452,13 @@ srs_error_t SrsDtls::on_dtls(char* data, int nb_data) return err; } -srs_error_t SrsDtls::do_handshake() +srs_error_t SrsDtls::start_active_handshake() { - return handshake(); + if (role_ == SrsDtlsRoleClient) { + return do_handshake(); + } + + return srs_success; } const int SRTP_MASTER_KEY_KEY_LEN = 16; @@ -450,8 +483,13 @@ srs_error_t SrsDtls::get_srtp_key(std::string& recv_key, std::string& send_key) offset += SRTP_MASTER_KEY_SALT_LEN; std::string server_master_salt(reinterpret_cast(material + offset), SRTP_MASTER_KEY_SALT_LEN); - recv_key = client_master_key + client_master_salt; - send_key = server_master_key + server_master_salt; + if (role_ == SrsDtlsRoleClient) { + recv_key = server_master_key + server_master_salt; + send_key = client_master_key + client_master_salt; + } else { + recv_key = client_master_key + client_master_salt; + send_key = server_master_key + server_master_salt; + } return err; } diff --git a/trunk/src/app/srs_app_rtc_dtls.hpp b/trunk/src/app/srs_app_rtc_dtls.hpp index 759042457..65ae8d708 100644 --- a/trunk/src/app/srs_app_rtc_dtls.hpp +++ b/trunk/src/app/srs_app_rtc_dtls.hpp @@ -62,6 +62,22 @@ public: // @global config object. extern SrsDtlsCertificate* _srs_rtc_dtls_certificate; +// @remark: play the role of DTLS_CLIENT, will send handshake +// packet first. +enum SrsDtlsRole { + SrsDtlsRoleClient, + SrsDtlsRoleServer +}; + +// @remark: DTLS_10 will all be ignored, and only DTLS1_2 will be accepted, +// DTLS_10 Support will be completely removed in M84 or later. +// TODO(https://bugs.webrtc.org/10261). +enum SrsDtlsVersion { + SrsDtlsVersionAuto = -1, + SrsDtlsVersion1_0, + SrsDtlsVersion1_2 +}; + class ISrsDtlsCallback { public: @@ -85,19 +101,26 @@ private: BIO* bio_out; ISrsDtlsCallback* callback; - bool handshake_done; + + // @remark: dtls_role_ default value is DTLS_SERVER. + SrsDtlsRole role_; + // @remark: dtls_version_ default value is SrsDtlsVersionAuto. + SrsDtlsVersion version_; public: SrsDtls(ISrsDtlsCallback* callback); virtual ~SrsDtls(); public: - srs_error_t initialize(SrsRequest* r); - srs_error_t do_handshake(); + srs_error_t initialize(std::string role, std::string version); + // As DTLS client, start handshake actively, send the ClientHello packet. + srs_error_t start_active_handshake(); + // When got DTLS packet, may handshake packets or application data. + // @remark When we are passive(DTLS server), we start handshake when got DTLS packet. srs_error_t on_dtls(char* data, int nb_data); srs_error_t get_srtp_key(std::string& recv_key, std::string& send_key); private: SSL_CTX* build_dtls_ctx(); - srs_error_t handshake(); + srs_error_t do_handshake(); }; class SrsSRTP diff --git a/trunk/src/app/srs_app_rtc_sdp.hpp b/trunk/src/app/srs_app_rtc_sdp.hpp index b50509f5d..b923affc5 100644 --- a/trunk/src/app/srs_app_rtc_sdp.hpp +++ b/trunk/src/app/srs_app_rtc_sdp.hpp @@ -34,6 +34,13 @@ #include const std::string kTWCCExt = "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01"; +struct SrsSessionConfig +{ +public: + std::string dtls_role; + std::string dtls_version; +}; + class SrsSessionInfo { public: @@ -212,6 +219,7 @@ public: int64_t end_time_; SrsSessionInfo session_info_; + SrsSessionConfig session_config_; std::vector groups_; std::string group_policy_; diff --git a/trunk/src/app/srs_app_rtc_server.cpp b/trunk/src/app/srs_app_rtc_server.cpp index 5ecc50d65..a44d82e7b 100644 --- a/trunk/src/app/srs_app_rtc_server.cpp +++ b/trunk/src/app/srs_app_rtc_server.cpp @@ -323,16 +323,6 @@ srs_error_t SrsRtcServer::create_session( } } - std::string cid = _srs_context->get_id(); - SrsRtcSession* session = new SrsRtcSession(this); - if ((err = session->initialize(source, req, publish, username, cid)) != srs_success) { - srs_freep(session); - return srs_error_wrap(err, "init"); - } - - map_username_session.insert(make_pair(username, session)); - *psession = session; - local_sdp.set_ice_ufrag(local_ufrag); local_sdp.set_ice_pwd(local_pwd); local_sdp.set_fingerprint_algo("sha-256"); @@ -348,10 +338,22 @@ srs_error_t SrsRtcServer::create_session( } } + SrsRtcSession* session = new SrsRtcSession(this); session->set_remote_sdp(remote_sdp); + // We must setup the local SDP, then initialize the session object. session->set_local_sdp(local_sdp); session->set_state(WAITING_STUN); + std::string cid = _srs_context->get_id(); + // Before session initialize, we must setup the local SDP. + if ((err = session->initialize(source, req, publish, username, cid)) != srs_success) { + srs_freep(session); + return srs_error_wrap(err, "init"); + } + + map_username_session.insert(make_pair(username, session)); + *psession = session; + return err; } From 121266ecbfe4b1502d5de80207da9a6f31e23b17 Mon Sep 17 00:00:00 2001 From: winlin Date: Sat, 27 Jun 2020 11:17:37 +0800 Subject: [PATCH 16/37] Refine code --- trunk/src/app/srs_app_config.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index cf7d60735..a804c4888 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -545,10 +545,10 @@ public: srs_utime_t get_rtc_stun_timeout(std::string vhost); bool get_rtc_stun_strict_check(std::string vhost); bool get_rtc_keep_sequence(std::string vhost); - bool get_rtc_nack_enabled(std::string vhost); - bool get_rtc_twcc_enabled(std::string vhost); std::string get_rtc_dtls_role(std::string vhost); std::string get_rtc_dtls_version(std::string vhost); + bool get_rtc_nack_enabled(std::string vhost); + bool get_rtc_twcc_enabled(std::string vhost); // vhost specified section public: From 6ff048ed35ce45e14636893ee690198332695206 Mon Sep 17 00:00:00 2001 From: "jinxue.cgh" Date: Sat, 27 Jun 2020 14:37:35 +0800 Subject: [PATCH 17/37] RTC: process twcc before srtp unprotected --- trunk/src/app/srs_app_rtc_conn.cpp | 31 +++++++++++++++---------- trunk/src/kernel/srs_kernel_rtc_rtp.cpp | 8 ++++++- trunk/src/kernel/srs_kernel_rtc_rtp.hpp | 2 ++ 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 00013499a..8f4a94bb4 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -1196,6 +1196,25 @@ srs_error_t SrsRtcPublisher::on_rtp(char* data, int nb_data) return err; } + if (0 != twcc_ext_id_) { + SrsBuffer b0(data, nb_data); SrsRtpHeader h0; + h0.set_decode_only_header(true); + h0.set_extensions(&extension_types_); + if ((err = h0.decode(&b0)) != srs_success) { + return srs_error_wrap(err, "process twcc to decode rtp header"); + } + + uint16_t twcc_sn = 0; + if ((err = h0.get_twcc_sequence_number(twcc_sn)) == srs_success) { + if((err = on_twcc(twcc_sn)) != srs_success) { + return srs_error_wrap(err, "fail to process twcc packet"); + } + } else { + // TODO: FIXME: process no twcc seq number for audio ssrc + srs_error_reset(err); + } + } + // Decrypt the cipher to plaintext RTP data. int nb_unprotected_buf = nb_data; char* unprotected_buf = new char[kRtpPacketSize]; @@ -1232,18 +1251,6 @@ srs_error_t SrsRtcPublisher::on_rtp(char* data, int nb_data) if ((err = pkt->decode(&b)) != srs_success) { return srs_error_wrap(err, "decode rtp packet"); } - - if (0 != twcc_ext_id_) { - uint16_t twcc_sn = 0; - if ((err = pkt->header.get_twcc_sequence_number(twcc_sn)) == srs_success) { - if((err = on_twcc(twcc_sn))) { - return srs_error_wrap(err, "fail to process twcc packet"); - } - } else { - // TODO: FIXME: process no twcc seq number for audio ssrc - srs_error_reset(err); - } - } } // For source to consume packet. diff --git a/trunk/src/kernel/srs_kernel_rtc_rtp.cpp b/trunk/src/kernel/srs_kernel_rtc_rtp.cpp index 840db3185..cdcd62e10 100644 --- a/trunk/src/kernel/srs_kernel_rtc_rtp.cpp +++ b/trunk/src/kernel/srs_kernel_rtc_rtp.cpp @@ -319,6 +319,7 @@ SrsRtpHeader::SrsRtpHeader() sequence = 0; timestamp = 0; ssrc = 0; + decode_only_header_ = false; } SrsRtpHeader::~SrsRtpHeader() @@ -376,7 +377,7 @@ srs_error_t SrsRtpHeader::decode(SrsBuffer* buf) } } - if (padding && !buf->empty()) { + if (padding && !buf->empty() && !decode_only_header_) { padding_length = *(reinterpret_cast(buf->data() + buf->size() - 1)); if (!buf->require(padding_length)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "padding requires %d bytes", padding_length); @@ -448,6 +449,11 @@ void SrsRtpHeader::set_extensions(const SrsRtpExtensionTypes* extmap) } } +void SrsRtpHeader::set_decode_only_header(bool only_header) +{ + decode_only_header_ = only_header; +} + srs_error_t SrsRtpHeader::get_twcc_sequence_number(uint16_t& twcc_sn) { if (extensions_.exists()) { diff --git a/trunk/src/kernel/srs_kernel_rtc_rtp.hpp b/trunk/src/kernel/srs_kernel_rtc_rtp.hpp index 5d93e7193..163d6f7a8 100644 --- a/trunk/src/kernel/srs_kernel_rtc_rtp.hpp +++ b/trunk/src/kernel/srs_kernel_rtc_rtp.hpp @@ -175,6 +175,7 @@ private: uint32_t ssrc; uint32_t csrc[15]; SrsRtpExtensions extensions_; + bool decode_only_header_; public: SrsRtpHeader(); virtual ~SrsRtpHeader(); @@ -199,6 +200,7 @@ public: void set_padding(uint8_t v); uint8_t get_padding() const; void set_extensions(const SrsRtpExtensionTypes* extmap); + void set_decode_only_header(bool only_header); srs_error_t get_twcc_sequence_number(uint16_t& twcc_sn); srs_error_t set_twcc_sequence_number(uint8_t id, uint16_t sn); }; From e9731fe0c1632c1150cb102084e9390db2d77b12 Mon Sep 17 00:00:00 2001 From: winlin Date: Sat, 27 Jun 2020 16:12:08 +0800 Subject: [PATCH 18/37] RTC: Support ignore padding for RTP header --- trunk/src/app/srs_app_rtc_conn.cpp | 11 +++++++---- trunk/src/kernel/srs_kernel_rtc_rtp.cpp | 8 ++++---- trunk/src/kernel/srs_kernel_rtc_rtp.hpp | 4 ++-- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 8f4a94bb4..a90de19cf 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -1196,21 +1196,24 @@ srs_error_t SrsRtcPublisher::on_rtp(char* data, int nb_data) return err; } + // We must parse the TWCC from RTP header before SRTP unprotect, because: + // 1. Client may send some padding packets with invalid SequenceNumber, which causes the SRTP fail. + // 2. Server may send multiple duplicated NACK to client, and got more than one ARQ packet, which also fail SRTP. + // so, we must parse the header before SRTP unprotect(which may fail and drop packet). if (0 != twcc_ext_id_) { SrsBuffer b0(data, nb_data); SrsRtpHeader h0; - h0.set_decode_only_header(true); + h0.ignore_padding(true); h0.set_extensions(&extension_types_); if ((err = h0.decode(&b0)) != srs_success) { - return srs_error_wrap(err, "process twcc to decode rtp header"); + return srs_error_wrap(err, "twcc decode header"); } uint16_t twcc_sn = 0; if ((err = h0.get_twcc_sequence_number(twcc_sn)) == srs_success) { if((err = on_twcc(twcc_sn)) != srs_success) { - return srs_error_wrap(err, "fail to process twcc packet"); + return srs_error_wrap(err, "on twcc"); } } else { - // TODO: FIXME: process no twcc seq number for audio ssrc srs_error_reset(err); } } diff --git a/trunk/src/kernel/srs_kernel_rtc_rtp.cpp b/trunk/src/kernel/srs_kernel_rtc_rtp.cpp index cdcd62e10..d4d43f486 100644 --- a/trunk/src/kernel/srs_kernel_rtc_rtp.cpp +++ b/trunk/src/kernel/srs_kernel_rtc_rtp.cpp @@ -319,7 +319,7 @@ SrsRtpHeader::SrsRtpHeader() sequence = 0; timestamp = 0; ssrc = 0; - decode_only_header_ = false; + ignore_padding_ = false; } SrsRtpHeader::~SrsRtpHeader() @@ -377,7 +377,7 @@ srs_error_t SrsRtpHeader::decode(SrsBuffer* buf) } } - if (padding && !buf->empty() && !decode_only_header_) { + if (padding && !ignore_padding_ && !buf->empty()) { padding_length = *(reinterpret_cast(buf->data() + buf->size() - 1)); if (!buf->require(padding_length)) { return srs_error_new(ERROR_RTC_RTP_MUXER, "padding requires %d bytes", padding_length); @@ -449,9 +449,9 @@ void SrsRtpHeader::set_extensions(const SrsRtpExtensionTypes* extmap) } } -void SrsRtpHeader::set_decode_only_header(bool only_header) +void SrsRtpHeader::ignore_padding(bool v) { - decode_only_header_ = only_header; + ignore_padding_ = v; } srs_error_t SrsRtpHeader::get_twcc_sequence_number(uint16_t& twcc_sn) diff --git a/trunk/src/kernel/srs_kernel_rtc_rtp.hpp b/trunk/src/kernel/srs_kernel_rtc_rtp.hpp index 163d6f7a8..8ba2fcc7f 100644 --- a/trunk/src/kernel/srs_kernel_rtc_rtp.hpp +++ b/trunk/src/kernel/srs_kernel_rtc_rtp.hpp @@ -175,7 +175,7 @@ private: uint32_t ssrc; uint32_t csrc[15]; SrsRtpExtensions extensions_; - bool decode_only_header_; + bool ignore_padding_; public: SrsRtpHeader(); virtual ~SrsRtpHeader(); @@ -200,7 +200,7 @@ public: void set_padding(uint8_t v); uint8_t get_padding() const; void set_extensions(const SrsRtpExtensionTypes* extmap); - void set_decode_only_header(bool only_header); + void ignore_padding(bool v); srs_error_t get_twcc_sequence_number(uint16_t& twcc_sn); srs_error_t set_twcc_sequence_number(uint8_t id, uint16_t sn); }; From 5b54ceadb1cbf6654c1fd0924418fac011d76ce3 Mon Sep 17 00:00:00 2001 From: winlin Date: Sat, 27 Jun 2020 16:14:11 +0800 Subject: [PATCH 19/37] RTC: Refactor code --- trunk/src/app/srs_app_rtc_conn.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index a90de19cf..88b976cc3 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -1191,8 +1191,8 @@ srs_error_t SrsRtcPublisher::on_rtp(char* data, int nb_data) // For NACK simulator, drop packet. if (nn_simulate_nack_drop) { - SrsBuffer b0(data, nb_data); SrsRtpHeader h0; h0.decode(&b0); - simulate_drop_packet(&h0, nb_data); + SrsBuffer b(data, nb_data); SrsRtpHeader h; h.decode(&b); + simulate_drop_packet(&h, nb_data); return err; } @@ -1201,15 +1201,15 @@ srs_error_t SrsRtcPublisher::on_rtp(char* data, int nb_data) // 2. Server may send multiple duplicated NACK to client, and got more than one ARQ packet, which also fail SRTP. // so, we must parse the header before SRTP unprotect(which may fail and drop packet). if (0 != twcc_ext_id_) { - SrsBuffer b0(data, nb_data); SrsRtpHeader h0; - h0.ignore_padding(true); - h0.set_extensions(&extension_types_); - if ((err = h0.decode(&b0)) != srs_success) { + SrsBuffer b(data, nb_data); SrsRtpHeader h; + h.ignore_padding(true); + h.set_extensions(&extension_types_); + if ((err = h.decode(&b)) != srs_success) { return srs_error_wrap(err, "twcc decode header"); } uint16_t twcc_sn = 0; - if ((err = h0.get_twcc_sequence_number(twcc_sn)) == srs_success) { + if ((err = h.get_twcc_sequence_number(twcc_sn)) == srs_success) { if((err = on_twcc(twcc_sn)) != srs_success) { return srs_error_wrap(err, "on twcc"); } @@ -1223,9 +1223,9 @@ srs_error_t SrsRtcPublisher::on_rtp(char* data, int nb_data) char* unprotected_buf = new char[kRtpPacketSize]; if ((err = session_->transport_->unprotect_rtp(data, unprotected_buf, nb_unprotected_buf)) != srs_success) { // We try to decode the RTP header for more detail error informations. - SrsBuffer b0(data, nb_data); SrsRtpHeader h0; h0.decode(&b0); - err = srs_error_wrap(err, "marker=%u, pt=%u, seq=%u, ts=%u, ssrc=%u, pad=%u, payload=%uB", h0.get_marker(), h0.get_payload_type(), - h0.get_sequence(), h0.get_timestamp(), h0.get_ssrc(), h0.get_padding(), nb_data - b0.pos()); + SrsBuffer b(data, nb_data); SrsRtpHeader h; h.decode(&b); + err = srs_error_wrap(err, "marker=%u, pt=%u, seq=%u, ts=%u, ssrc=%u, pad=%u, payload=%uB", h.get_marker(), h.get_payload_type(), + h.get_sequence(), h.get_timestamp(), h.get_ssrc(), h.get_padding(), nb_data - b.pos()); srs_freepa(unprotected_buf); return err; From 6662568c1154d1bc2a835255576dd258510ea8fb Mon Sep 17 00:00:00 2001 From: "jinxue.cgh" Date: Sat, 27 Jun 2020 17:06:33 +0800 Subject: [PATCH 20/37] RTC: sdp surpport ssrc group encode and decode --- trunk/src/app/srs_app_rtc_sdp.cpp | 52 +++++++++++++++++++++++++++++-- trunk/src/app/srs_app_rtc_sdp.hpp | 11 +++++++ 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_sdp.cpp b/trunk/src/app/srs_app_rtc_sdp.cpp index 4c3d9f53c..5e2a584fd 100644 --- a/trunk/src/app/srs_app_rtc_sdp.cpp +++ b/trunk/src/app/srs_app_rtc_sdp.cpp @@ -206,6 +206,40 @@ srs_error_t SrsSSRCInfo::encode(std::ostringstream& os) return err; } +SrsSSRCGroup::SrsSSRCGroup() +{ +} + +SrsSSRCGroup::~SrsSSRCGroup() +{ +} + +SrsSSRCGroup::SrsSSRCGroup(const std::string& semantic, const std::vector& ssrcs) +{ + semantic_ = semantic; + ssrcs_ = ssrcs; +} + +srs_error_t SrsSSRCGroup::encode(std::ostringstream& os) +{ + srs_error_t err = srs_success; + + if (semantic_.empty()) { + return srs_error_new(ERROR_RTC_SDP_DECODE, "invalid semantics"); + } + + if (ssrcs_.size() == 0) { + return srs_error_new(ERROR_RTC_SDP_DECODE, "invalid ssrcs"); + } + + os << "a=ssrc-group:" << semantic_; + for (int i = 0; i < (int)ssrcs_.size(); i++) { + os << " " << ssrcs_[i]; + } + + return err; +} + SrsMediaPayloadType::SrsMediaPayloadType(int payload_type) { payload_type_ = payload_type; @@ -589,6 +623,7 @@ srs_error_t SrsMediaDesc::parse_attr_ssrc(const std::string& value) ssrc_info.cname_ = ssrc_value; ssrc_info.ssrc_ = ssrc; } else if (ssrc_attr == "msid") { + // @see: https://tools.ietf.org/html/draft-alvestrand-mmusic-msid-00#section-2 std::vector vec = split_str(ssrc_value, " "); if (vec.empty()) { return srs_error_new(ERROR_RTC_SDP_DECODE, "invalid ssrc line=%s", value.c_str()); @@ -618,10 +653,23 @@ srs_error_t SrsMediaDesc::parse_attr_ssrc_group(const std::string& value) std::string semantics; FETCH(is, semantics); - // TODO: ssrc group process - if (semantics == "FID") { + std::string ssrc_ids = is.str().substr(is.tellg()); + skip_first_spaces(ssrc_ids); + + std::vector vec = split_str(ssrc_ids, " "); + if (vec.size() == 0) { + return srs_error_new(ERROR_RTC_SDP_DECODE, "invalid ssrc-group line=%s", value.c_str()); } + std::vector ssrcs; + for (size_t i = 0; i < vec.size(); ++i) { + std::istringstream in_stream(vec[i]); + uint32_t ssrc = 0; + in_stream >> ssrc; + ssrcs.push_back(ssrc); + } + ssrc_groups_.push_back(SrsSSRCGroup(semantics, ssrcs)); + return err; } diff --git a/trunk/src/app/srs_app_rtc_sdp.hpp b/trunk/src/app/srs_app_rtc_sdp.hpp index b923affc5..c09af3ee0 100644 --- a/trunk/src/app/srs_app_rtc_sdp.hpp +++ b/trunk/src/app/srs_app_rtc_sdp.hpp @@ -78,6 +78,17 @@ public: class SrsSSRCGroup { +public: + SrsSSRCGroup(); + SrsSSRCGroup(const std::string& usage, const std::vector& ssrcs); + virtual ~SrsSSRCGroup(); +public: + srs_error_t encode(std::ostringstream& os); +public: + // e.g FIX, FEC, SIM. + std::string semantic_; + // SSRCs of this type. + std::vector ssrcs_; }; struct H264SpecificParam From 75fbcba71db3d78a9e7110e214244ef38d22d109 Mon Sep 17 00:00:00 2001 From: winlin Date: Sun, 28 Jun 2020 11:40:49 +0800 Subject: [PATCH 21/37] RTC: Always keep and use original sequence. --- trunk/conf/full.conf | 4 ---- trunk/src/app/srs_app_config.cpp | 20 +--------------- trunk/src/app/srs_app_config.hpp | 1 - trunk/src/app/srs_app_rtc_api.cpp | 16 ++----------- trunk/src/app/srs_app_rtc_conn.cpp | 37 ++++-------------------------- trunk/src/app/srs_app_rtc_conn.hpp | 5 ---- 6 files changed, 7 insertions(+), 76 deletions(-) diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index f4b901b66..037b3fea3 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -491,10 +491,6 @@ vhost rtc.vhost.srs.com { # The strick check when process stun. # default: off stun_strict_check on; - # Whether keep original sequence number. - # If off, we will regenerate the sequence number for RTP packet. - # default: off - keep_sequence off; # The role of dtls when peer is actpass: passive or active # default: passive dtls_role passive; diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index bcc2a3d03..4bbcff951 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -3935,7 +3935,7 @@ srs_error_t SrsConfig::check_normal_config() for (int j = 0; j < (int)conf->directives.size(); j++) { string m = conf->at(j)->name; if (m != "enabled" && m != "bframe" && m != "aac" && m != "stun_timeout" && m != "stun_strict_check" - && m != "keep_sequence" && m != "dtls_role" && m != "dtls_version") { + && m != "dtls_role" && m != "dtls_version") { return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal vhost.rtc.%s of %s", m.c_str(), vhost->arg0().c_str()); } } @@ -5020,24 +5020,6 @@ bool SrsConfig::get_rtc_stun_strict_check(string vhost) return SRS_CONF_PERFER_FALSE(conf->arg0()); } -bool SrsConfig::get_rtc_keep_sequence(string vhost) -{ - static bool DEFAULT = false; - - SrsConfDirective* conf = get_rtc(vhost); - - if (!conf) { - return DEFAULT; - } - - conf = conf->get("keep_sequence"); - if (!conf || conf->arg0().empty()) { - return DEFAULT; - } - - return SRS_CONF_PERFER_FALSE(conf->arg0()); -} - std::string SrsConfig::get_rtc_dtls_role(string vhost) { static std::string DEFAULT = "passive"; diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index a804c4888..0f6bbba29 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -544,7 +544,6 @@ public: bool get_rtc_aac_discard(std::string vhost); srs_utime_t get_rtc_stun_timeout(std::string vhost); bool get_rtc_stun_strict_check(std::string vhost); - bool get_rtc_keep_sequence(std::string vhost); std::string get_rtc_dtls_role(std::string vhost); std::string get_rtc_dtls_version(std::string vhost); bool get_rtc_nack_enabled(std::string vhost); diff --git a/trunk/src/app/srs_app_rtc_api.cpp b/trunk/src/app/srs_app_rtc_api.cpp index a45ece557..4975b602b 100644 --- a/trunk/src/app/srs_app_rtc_api.cpp +++ b/trunk/src/app/srs_app_rtc_api.cpp @@ -136,16 +136,9 @@ srs_error_t SrsGoApiRtcPlay::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMe string eip = r->query_get("eip"); // For client to specifies whether encrypt by SRTP. string encrypt = r->query_get("encrypt"); - // If keep_sequence is off, for client to specifies the startup sequence. - string sequence_startup = r->query_get("sequence_startup"); - // If keep_sequence is on, for client to specifies the delta value for sequence. - string sequence_delta = r->query_get("sequence_delta"); - // Whether keep sequence, overwrite the config for debugging each session. - string sequence_keep = r->query_get("sequence_keep"); - srs_trace("RTC play %s, api=%s, clientip=%s, app=%s, stream=%s, offer=%dB, eip=%s, encrypt=%s, sequence(startup=%s,delta=%s,keep=%s)", - streamurl.c_str(), api.c_str(), clientip.c_str(), app.c_str(), stream_name.c_str(), remote_sdp_str.length(), eip.c_str(), encrypt.c_str(), - sequence_startup.c_str(), sequence_delta.c_str(), sequence_keep.c_str()); + srs_trace("RTC play %s, api=%s, clientip=%s, app=%s, stream=%s, offer=%dB, eip=%s, encrypt=%s", + streamurl.c_str(), api.c_str(), clientip.c_str(), app.c_str(), stream_name.c_str(), remote_sdp_str.length(), eip.c_str(), encrypt.c_str()); // TODO: FIXME: It seems remote_sdp doesn't represents the full SDP information. SrsSdp remote_sdp; @@ -200,11 +193,6 @@ srs_error_t SrsGoApiRtcPlay::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMe session->set_encrypt(encrypt != "false"); } - // Set the optional parameters from client. - session->sequence_startup = sequence_startup; - session->sequence_delta = sequence_delta; - session->sequence_keep = sequence_keep; - ostringstream os; if ((err = local_sdp.encode(os)) != srs_success) { return srs_error_wrap(err, "encode sdp"); diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 88b976cc3..679caac57 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -273,9 +273,6 @@ SrsRtcPlayer::SrsRtcPlayer(SrsRtcSession* s, string parent_cid) session_ = s; - audio_sequence = 0; - video_sequence = 0; - sequence_delta = 0; mw_msgs = 0; realtime = true; @@ -285,7 +282,6 @@ SrsRtcPlayer::SrsRtcPlayer(SrsRtcSession* s, string parent_cid) nn_simulate_nack_drop = 0; nack_enabled_ = false; - keep_sequence_ = false; _srs_config->subscribe(this); } @@ -311,18 +307,8 @@ srs_error_t SrsRtcPlayer::initialize(const uint32_t& vssrc, const uint32_t& assr // TODO: FIXME: Support reload. nack_enabled_ = _srs_config->get_rtc_nack_enabled(session_->req->vhost); - keep_sequence_ = _srs_config->get_rtc_keep_sequence(session_->req->vhost); - if (!session_->sequence_startup.empty()) { - audio_sequence = video_sequence = uint16_t(::atoi(session_->sequence_startup.c_str())); - } - if (!session_->sequence_delta.empty()) { - sequence_delta = uint16_t(::atoi(session_->sequence_delta.c_str())); - } - if (!session_->sequence_keep.empty()) { - keep_sequence_ = (session_->sequence_keep == "true"); - } - srs_trace("RTC player video(ssrc=%d, pt=%d), audio(ssrc=%d, pt=%d), nack=%d, keep-seq=%d, sequence(audio=%u,video=%u,delta=%u)", - video_ssrc, video_payload_type, audio_ssrc, audio_payload_type, nack_enabled_, keep_sequence_, audio_sequence, video_sequence, sequence_delta); + srs_trace("RTC player video(ssrc=%d, pt=%d), audio(ssrc=%d, pt=%d), nack=%d", + video_ssrc, video_payload_type, audio_ssrc, audio_payload_type, nack_enabled_); if (_srs_rtc_hijacker) { if ((err = _srs_rtc_hijacker->on_start_play(session_, this, session_->req)) != srs_success) { @@ -495,36 +481,21 @@ srs_error_t SrsRtcPlayer::send_packets(SrsRtcSource* source, const vectornb_bytes(); - uint16_t oseq = pkt->header.get_sequence(); if (pkt->is_audio()) { info.nn_audios++; - - if (!keep_sequence_) { - // TODO: FIXME: Should keep the order by original sequence. - pkt->header.set_sequence(sequence_delta + audio_sequence++); - } else { - pkt->header.set_sequence(sequence_delta + oseq); - } pkt->header.set_ssrc(audio_ssrc); pkt->header.set_payload_type(audio_payload_type); // TODO: FIXME: Padding audio to the max payload in RTP packets. } else { info.nn_videos++; - - if (!keep_sequence_) { - // TODO: FIXME: Should keep the order by original sequence. - pkt->header.set_sequence(sequence_delta + video_sequence++); - } else { - pkt->header.set_sequence(sequence_delta + oseq); - } pkt->header.set_ssrc(video_ssrc); pkt->header.set_payload_type(video_payload_type); } // Detail log, should disable it in release version. - srs_info("RTC: Update PT=%u, SSRC=%#x, OSEQ=%u, SEQ=%u, Time=%u, %u bytes", pkt->header.get_payload_type(), pkt->header.get_ssrc(), - oseq, pkt->header.get_sequence(), pkt->header.get_timestamp(), pkt->nb_bytes()); + srs_info("RTC: Update PT=%u, SSRC=%#x, Time=%u, %u bytes", pkt->header.get_payload_type(), pkt->header.get_ssrc(), + pkt->header.get_timestamp(), pkt->nb_bytes()); } // By default, we send packets by sendmmsg. diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index fbaa473f8..352bda071 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -191,18 +191,15 @@ protected: private: // TODO: FIXME: How to handle timestamp overflow? // Information for audio. - uint16_t audio_sequence; uint32_t audio_ssrc; uint16_t audio_payload_type; // Information for video. - uint16_t video_sequence; uint16_t video_payload_type; uint32_t video_ssrc; // NACK ARQ ring buffer. SrsRtpRingBuffer* audio_queue_; SrsRtpRingBuffer* video_queue_; // Simulators. - uint16_t sequence_delta; int nn_simulate_nack_drop; private: // For merged-write messages. @@ -210,8 +207,6 @@ private: bool realtime; // Whether enabled nack. bool nack_enabled_; - // Whether keep original sequence number. - bool keep_sequence_; public: SrsRtcPlayer(SrsRtcSession* s, std::string parent_cid); virtual ~SrsRtcPlayer(); From b9355c1cc349a1f49c11138a6e4e366ea32412fa Mon Sep 17 00:00:00 2001 From: winlin Date: Sun, 28 Jun 2020 16:58:14 +0800 Subject: [PATCH 22/37] Fix memory leak --- trunk/src/protocol/srs_service_rtmp_conn.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/trunk/src/protocol/srs_service_rtmp_conn.cpp b/trunk/src/protocol/srs_service_rtmp_conn.cpp index 268d098fc..2dbef733d 100644 --- a/trunk/src/protocol/srs_service_rtmp_conn.cpp +++ b/trunk/src/protocol/srs_service_rtmp_conn.cpp @@ -57,6 +57,7 @@ SrsBasicRtmpClient::~SrsBasicRtmpClient() close(); srs_freep(kbps); srs_freep(clk); + srs_freep(req); } srs_error_t SrsBasicRtmpClient::connect() From 848a073c5ce7b944e6bb4891b9e30de4c141fb6b Mon Sep 17 00:00:00 2001 From: "jinxue.cgh" Date: Sun, 28 Jun 2020 14:01:58 +0800 Subject: [PATCH 23/37] RTC: send twcc in hourglass notify --- trunk/src/app/srs_app_rtc_conn.cpp | 55 +++++++++++++++++------------- trunk/src/app/srs_app_rtc_conn.hpp | 1 + 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 679caac57..c52abad5c 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -1130,31 +1130,8 @@ srs_error_t SrsRtcPublisher::send_rtcp_fb_pli(uint32_t ssrc) } srs_error_t SrsRtcPublisher::on_twcc(uint16_t sn) { - srs_error_t err = srs_success; srs_utime_t now = srs_get_system_time(); - rtcp_twcc_.recv_packet(sn, now); - if(0 == last_twcc_feedback_time_) { - last_twcc_feedback_time_ = now; - return err; - } - srs_utime_t diff = now - last_twcc_feedback_time_; - if( diff >= 50 * SRS_UTIME_MILLISECONDS) { - last_twcc_feedback_time_ = now; - char pkt[kRtcpPacketSize]; - SrsBuffer *buffer = new SrsBuffer(pkt, sizeof(pkt)); - SrsAutoFree(SrsBuffer, buffer); - rtcp_twcc_.set_feedback_count(twcc_fb_count_); - twcc_fb_count_++; - if((err = rtcp_twcc_.encode(buffer)) != srs_success) { - return srs_error_wrap(err, "fail to generate twcc feedback packet"); - } - int nb_protected_buf = buffer->pos(); - char protected_buf[kRtpPacketSize]; - if (session_->transport_->protect_rtcp(pkt, protected_buf, nb_protected_buf) == srs_success) { - session_->sendonly_skt->sendto(protected_buf, nb_protected_buf, 0); - } - } - return err; + return rtcp_twcc_.recv_packet(sn, now); } srs_error_t SrsRtcPublisher::on_rtp(char* data, int nb_data) { @@ -1355,6 +1332,35 @@ srs_error_t SrsRtcPublisher::on_nack(SrsRtpPacket2* pkt) return err; } +srs_error_t SrsRtcPublisher::send_periodic_twcc() +{ + srs_error_t err = srs_success; + srs_utime_t now = srs_get_system_time(); + if(0 == last_twcc_feedback_time_) { + last_twcc_feedback_time_ = now; + return err; + } + srs_utime_t diff = now - last_twcc_feedback_time_; + if( diff >= 50 * SRS_UTIME_MILLISECONDS) { + last_twcc_feedback_time_ = now; + char pkt[kRtcpPacketSize]; + SrsBuffer *buffer = new SrsBuffer(pkt, sizeof(pkt)); + SrsAutoFree(SrsBuffer, buffer); + rtcp_twcc_.set_feedback_count(twcc_fb_count_); + twcc_fb_count_++; + if((err = rtcp_twcc_.encode(buffer)) != srs_success) { + return srs_error_wrap(err, "fail to generate twcc feedback packet"); + } + int nb_protected_buf = buffer->pos(); + char protected_buf[kRtpPacketSize]; + if (session_->transport_->protect_rtcp(pkt, protected_buf, nb_protected_buf) == srs_success) { + session_->sendonly_skt->sendto(protected_buf, nb_protected_buf, 0); + } + } + + return err; +} + srs_error_t SrsRtcPublisher::on_rtcp(char* data, int nb_data) { srs_error_t err = srs_success; @@ -1714,6 +1720,7 @@ srs_error_t SrsRtcPublisher::notify(int type, srs_utime_t interval, srs_utime_t send_rtcp_rr(audio_ssrc, audio_queue_); send_rtcp_xr_rrtr(video_ssrc); send_rtcp_xr_rrtr(audio_ssrc); + send_periodic_twcc(); return err; } diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 352bda071..abb64bc2e 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -290,6 +290,7 @@ private: srs_error_t on_audio(SrsRtpPacket2* pkt); srs_error_t on_video(SrsRtpPacket2* pkt); srs_error_t on_nack(SrsRtpPacket2* pkt); + srs_error_t send_periodic_twcc(); public: srs_error_t on_rtcp(char* data, int nb_data); private: From 747be9047c58aa5b45d79a9447ac9fc7c1e60c60 Mon Sep 17 00:00:00 2001 From: "jinxue.cgh" Date: Sun, 28 Jun 2020 14:23:05 +0800 Subject: [PATCH 24/37] RTC: refine twcc encode_chunk_two_bit --- trunk/src/kernel/srs_kernel_rtc_rtcp.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/trunk/src/kernel/srs_kernel_rtc_rtcp.cpp b/trunk/src/kernel/srs_kernel_rtc_rtcp.cpp index a4248a694..d6aa1eee4 100644 --- a/trunk/src/kernel/srs_kernel_rtc_rtcp.cpp +++ b/trunk/src/kernel/srs_kernel_rtc_rtcp.cpp @@ -682,15 +682,15 @@ srs_error_t SrsRtcpTWCC::encode_chunk_two_bit(SrsRtcpTWCC::SrsRtcpTWCCChunk& chu pkt_len += sizeof(encoded_chunk); if (shift) { + chunk.size -= size; chunk.all_same = true; chunk.has_large_delta = false; - for (i = size; i < chunk.size; ++i) { - delta_size = chunk.delta_sizes[i]; - chunk.delta_sizes[i - size] = delta_size; + for (i = 0; i < chunk.size; ++i) { + delta_size = chunk.delta_sizes[i + size]; + chunk.delta_sizes[i] = delta_size; chunk.all_same = (chunk.all_same && delta_size == chunk.delta_sizes[0]); chunk.has_large_delta = chunk.has_large_delta || delta_size == kTwccFbLargeRecvDeltaBytes; } - chunk.size -= size; } return srs_success; From b9bd12192bdd3520e832a1703eed44eb460fc336 Mon Sep 17 00:00:00 2001 From: winlin Date: Sun, 28 Jun 2020 19:39:42 +0800 Subject: [PATCH 25/37] Update comment --- trunk/src/app/srs_app_rtc_conn.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index c52abad5c..16fa7531d 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -1715,11 +1715,16 @@ void SrsRtcPublisher::request_keyframe() srs_error_t SrsRtcPublisher::notify(int type, srs_utime_t interval, srs_utime_t tick) { srs_error_t err = srs_success; + // TODO: FIXME: Check error. send_rtcp_rr(video_ssrc, video_queue_); send_rtcp_rr(audio_ssrc, audio_queue_); send_rtcp_xr_rrtr(video_ssrc); send_rtcp_xr_rrtr(audio_ssrc); + + // TODO: FIXME: Check error. + // We should not depends on the received packet, + // instead we should send feedback every Nms. send_periodic_twcc(); return err; From 3510c74cd459e34c027efdc7ba04824005c49fc3 Mon Sep 17 00:00:00 2001 From: winlin Date: Mon, 29 Jun 2020 10:59:39 +0800 Subject: [PATCH 26/37] RTC: Support drop for specified PT --- trunk/conf/full.conf | 3 +++ trunk/src/app/srs_app_config.cpp | 19 +++++++++++++++++- trunk/src/app/srs_app_config.hpp | 1 + trunk/src/app/srs_app_rtc_conn.cpp | 31 ++++++++++++++++++++---------- trunk/src/app/srs_app_rtc_conn.hpp | 5 +++-- 5 files changed, 46 insertions(+), 13 deletions(-) diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index 037b3fea3..e12ee39fc 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -497,6 +497,9 @@ vhost rtc.vhost.srs.com { # The version of dtls, support dtls1.0, dtls1.2, and auto # default: auto dtls_version auto; + # Drop the packet with the pt(payload type), 0 never drop. + # default: 0 + drop_for_pt 0; } # whether enable min delay mode for vhost. # default: on, for RTC. diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index 4bbcff951..11b4d93c3 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -3935,7 +3935,7 @@ srs_error_t SrsConfig::check_normal_config() for (int j = 0; j < (int)conf->directives.size(); j++) { string m = conf->at(j)->name; if (m != "enabled" && m != "bframe" && m != "aac" && m != "stun_timeout" && m != "stun_strict_check" - && m != "dtls_role" && m != "dtls_version") { + && m != "dtls_role" && m != "dtls_version" && m != "drop_for_pt") { return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal vhost.rtc.%s of %s", m.c_str(), vhost->arg0().c_str()); } } @@ -5056,6 +5056,23 @@ std::string SrsConfig::get_rtc_dtls_version(string vhost) return conf->arg0(); } +int SrsConfig::get_rtc_drop_for_pt(string vhost) +{ + static int DEFAULT = 0; + + SrsConfDirective* conf = get_vhost(vhost); + if (!conf) { + return DEFAULT; + } + + conf = conf->get("drop_for_pt"); + if (!conf || conf->arg0().empty()) { + return DEFAULT; + } + + return ::atoi(conf->arg0().c_str()); +} + bool SrsConfig::get_rtc_nack_enabled(string vhost) { static bool DEFAULT = true; diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index 0f6bbba29..5b083784a 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -546,6 +546,7 @@ public: bool get_rtc_stun_strict_check(std::string vhost); std::string get_rtc_dtls_role(std::string vhost); std::string get_rtc_dtls_version(std::string vhost); + int get_rtc_drop_for_pt(std::string vhost); bool get_rtc_nack_enabled(std::string vhost); bool get_rtc_twcc_enabled(std::string vhost); diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 16fa7531d..e4251e7d3 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -855,6 +855,7 @@ SrsRtcPublisher::SrsRtcPublisher(SrsRtcSession* session) source = NULL; nn_simulate_nack_drop = 0; nack_enabled_ = false; + pt_to_drop_ = 0; nn_audio_frames = 0; twcc_ext_id_ = 0; @@ -892,9 +893,10 @@ srs_error_t SrsRtcPublisher::initialize(uint32_t vssrc, uint32_t assrc, uint8_t } // TODO: FIXME: Support reload. nack_enabled_ = _srs_config->get_rtc_nack_enabled(session_->req->vhost); + pt_to_drop_ = (uint16_t)_srs_config->get_rtc_drop_for_pt(session_->req->vhost); - srs_trace("RTC publisher video(ssrc=%u), audio(ssrc=%u), nack=%d", - video_ssrc, audio_ssrc, nack_enabled_); + srs_trace("RTC publisher video(ssrc=%u), audio(ssrc=%u), nack=%d, pt-drop=%u", + video_ssrc, audio_ssrc, nack_enabled_, pt_to_drop_); if ((err = report_timer->tick(0 * SRS_UTIME_MILLISECONDS)) != srs_success) { return srs_error_wrap(err, "hourglass tick"); @@ -1133,6 +1135,7 @@ srs_error_t SrsRtcPublisher::on_twcc(uint16_t sn) { srs_utime_t now = srs_get_system_time(); return rtcp_twcc_.recv_packet(sn, now); } + srs_error_t SrsRtcPublisher::on_rtp(char* data, int nb_data) { srs_error_t err = srs_success; @@ -1144,18 +1147,21 @@ srs_error_t SrsRtcPublisher::on_rtp(char* data, int nb_data) return err; } + // Decode the header first. + SrsRtpHeader h; + if (pt_to_drop_ && twcc_ext_id_) { + SrsBuffer b(data, nb_data); + h.ignore_padding(true); h.set_extensions(&extension_types_); + if ((err = h.decode(&b)) != srs_success) { + return srs_error_wrap(err, "twcc decode header"); + } + } + // We must parse the TWCC from RTP header before SRTP unprotect, because: // 1. Client may send some padding packets with invalid SequenceNumber, which causes the SRTP fail. // 2. Server may send multiple duplicated NACK to client, and got more than one ARQ packet, which also fail SRTP. // so, we must parse the header before SRTP unprotect(which may fail and drop packet). - if (0 != twcc_ext_id_) { - SrsBuffer b(data, nb_data); SrsRtpHeader h; - h.ignore_padding(true); - h.set_extensions(&extension_types_); - if ((err = h.decode(&b)) != srs_success) { - return srs_error_wrap(err, "twcc decode header"); - } - + if (twcc_ext_id_) { uint16_t twcc_sn = 0; if ((err = h.get_twcc_sequence_number(twcc_sn)) == srs_success) { if((err = on_twcc(twcc_sn)) != srs_success) { @@ -1166,6 +1172,11 @@ srs_error_t SrsRtcPublisher::on_rtp(char* data, int nb_data) } } + // If payload type is configed to drop, ignore this packet. + if (pt_to_drop_ && pt_to_drop_ == h.get_payload_type()) { + return err; + } + // Decrypt the cipher to plaintext RTP data. int nb_unprotected_buf = nb_data; char* unprotected_buf = new char[kRtpPacketSize]; diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index abb64bc2e..96d6ccdd6 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -251,6 +251,9 @@ private: SrsRtcSession* session_; uint32_t video_ssrc; uint32_t audio_ssrc; + uint16_t pt_to_drop_; + // Whether enabled nack. + bool nack_enabled_; private: bool request_keyframe_; SrsRtpRingBuffer* video_queue_; @@ -260,8 +263,6 @@ private: private: SrsRequest* req; SrsRtcSource* source; - // Whether enabled nack. - bool nack_enabled_; // Simulators. int nn_simulate_nack_drop; private: From b72cfd240555e11b41f0509d3ce1c5ecaedafc06 Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 30 Jun 2020 09:53:47 +0800 Subject: [PATCH 27/37] Refine options --- trunk/auto/options.sh | 76 ------------------------------------------- 1 file changed, 76 deletions(-) diff --git a/trunk/auto/options.sh b/trunk/auto/options.sh index 39599e082..43f0e701a 100755 --- a/trunk/auto/options.sh +++ b/trunk/auto/options.sh @@ -450,82 +450,6 @@ function apply_detail_options() { SRS_X86_X64=YES; opt="--x86-x64 $opt"; fi - # all disabled. - if [ $SRS_DISABLE_ALL = YES ]; then - SRS_HDS=NO - SRS_UTEST=NO - SRS_STATIC=NO - fi - - # all enabled. - if [ $SRS_ENABLE_ALL = YES ]; then - SRS_HDS=YES - SRS_UTEST=YES - SRS_STATIC=NO - fi - - # only rtmp vp6 - if [ $SRS_FAST = YES ]; then - SRS_HDS=NO - SRS_UTEST=NO - SRS_STATIC=NO - fi - - # only ssl for RTMP with complex handshake. - if [ $SRS_PURE_RTMP = YES ]; then - SRS_HDS=NO - SRS_UTEST=NO - SRS_STATIC=NO - fi - - # defaults for x86/x64 - if [ $SRS_X86_X64 = YES ]; then - SRS_HDS=YES - SRS_UTEST=NO - SRS_STATIC=NO - fi - - # if dev specified, open features if possible. - if [ $SRS_DEV = YES ]; then - SRS_HDS=YES - SRS_UTEST=YES - SRS_STATIC=NO - fi - - # if fast dev specified, open main server features. - if [ $SRS_FAST_DEV = YES ]; then - SRS_HDS=YES - SRS_UTEST=NO - SRS_STATIC=NO - fi - - # for srs demo - if [ $SRS_DEMO = YES ]; then - SRS_HDS=YES - SRS_UTEST=NO - SRS_STATIC=NO - fi - - # if raspberry-pi specified, open ssl/hls/static features - if [ $SRS_PI = YES ]; then - SRS_HDS=YES - SRS_UTEST=NO - SRS_STATIC=NO - fi - - # if cubieboard specified, open features except ffmpeg/nginx. - if [ $SRS_CUBIE = YES ]; then - SRS_HDS=YES - SRS_UTEST=NO - SRS_STATIC=NO - fi - - # if crossbuild, disable research and librtmp. - if [[ $SRS_CROSS_BUILD == YES ]]; then - SRS_UTEST=NO - SRS_STATIC=NO - fi - # Enable c++11 for SRT. if [[ $SRS_SRT == YES ]]; then SRS_CXX11=YES From 9e447e541bca800b4375747463d8cdc9453a3b61 Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 30 Jun 2020 10:05:01 +0800 Subject: [PATCH 28/37] Fix utest failed --- trunk/src/utest/srs_utest_service.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/trunk/src/utest/srs_utest_service.cpp b/trunk/src/utest/srs_utest_service.cpp index 3611fd41e..5cc78b968 100644 --- a/trunk/src/utest/srs_utest_service.cpp +++ b/trunk/src/utest/srs_utest_service.cpp @@ -1000,8 +1000,6 @@ VOID TEST(TCPServerTest, CoverUtility) EXPECT_FALSE(srs_net_device_is_internet((sockaddr*)r->ai_addr)); } - EXPECT_FALSE(srs_net_device_is_internet("eth0")); - if (true) { sockaddr_in addr; addr.sin_family = AF_INET; From a273298e637da10334e6b48e1efecf16923ffcfa Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 30 Jun 2020 19:29:23 +0800 Subject: [PATCH 29/37] HTTP: Enable infinite_chunked by default --- trunk/src/app/srs_app_http_api.cpp | 5 +- trunk/src/protocol/srs_http_stack.hpp | 12 +- trunk/src/protocol/srs_service_http_conn.cpp | 38 +------ trunk/src/protocol/srs_service_http_conn.hpp | 7 -- trunk/src/utest/srs_utest_service.cpp | 113 +++++++++++-------- 5 files changed, 75 insertions(+), 100 deletions(-) diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index fd0f57c64..88b7dc235 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -1773,9 +1773,8 @@ srs_error_t SrsHttpApi::process_request(ISrsHttpResponseWriter* w, ISrsHttpMessa SrsHttpMessage* hm = dynamic_cast(r); srs_assert(hm); - srs_trace("HTTP API %s %s, content-length=%" PRId64 ", chunked=%d/%d", - r->method_str().c_str(), r->url().c_str(), r->content_length(), - hm->is_chunked(), hm->is_infinite_chunked()); + srs_trace("HTTP API %s %s, content-length=%" PRId64 ", chunked=%d", r->method_str().c_str(), r->url().c_str(), + r->content_length(), hm->is_chunked()); // use cors server mux to serve http request, which will proxy to mux. if ((err = cors->serve_http(w, r)) != srs_success) { diff --git a/trunk/src/protocol/srs_http_stack.hpp b/trunk/src/protocol/srs_http_stack.hpp index 6d5e6b336..0bd712714 100644 --- a/trunk/src/protocol/srs_http_stack.hpp +++ b/trunk/src/protocol/srs_http_stack.hpp @@ -449,15 +449,11 @@ public: // // There are some modes to determine the length of body: // 1. content-length and chunked. -// 2. user confirmed infinite chunked. -// 3. no body or user not confirmed infinite chunked. +// 2. infinite chunked. +// 3. no body. // For example: // ISrsHttpMessage* r = ...; // while (!r->eof()) r->read(); // Read in mode 1 or 3. -// For some server, we can confirm the body is infinite chunked: -// ISrsHttpMessage* r = ...; -// r->enter_infinite_chunked(); -// while (!r->eof()) r->read(); // Read in mode 2 // @rmark for mode 2, the infinite chunked, all left data is body. class ISrsHttpMessage { @@ -492,10 +488,6 @@ public: // @return the REST id; -1 if not matched. virtual std::string parse_rest_id(std::string pattern) = 0; public: - // The left all data is chunked body, the infinite chunked mode, - // which is chunked encoding without chunked header. - // @remark error when message is in chunked or content-length specified. - virtual srs_error_t enter_infinite_chunked() = 0; // Read body to string. // @remark for small http body. virtual srs_error_t body_read_all(std::string& body) = 0; diff --git a/trunk/src/protocol/srs_service_http_conn.cpp b/trunk/src/protocol/srs_service_http_conn.cpp index acaf7c935..de493f22c 100644 --- a/trunk/src/protocol/srs_service_http_conn.cpp +++ b/trunk/src/protocol/srs_service_http_conn.cpp @@ -291,7 +291,6 @@ SrsHttpMessage::SrsHttpMessage(ISrsReader* reader, SrsFastStream* buffer) : ISrs { owner_conn = NULL; chunked = false; - infinite_chunked = false; _uri = new SrsHttpUri(); _body = new SrsHttpResponseReader(this, reader, buffer); @@ -476,11 +475,6 @@ bool SrsHttpMessage::is_keep_alive() return _keep_alive; } -bool SrsHttpMessage::is_infinite_chunked() -{ - return infinite_chunked; -} - string SrsHttpMessage::uri() { std::string uri = _uri->get_schema(); @@ -550,23 +544,6 @@ std::string SrsHttpMessage::parse_rest_id(string pattern) return ""; } -srs_error_t SrsHttpMessage::enter_infinite_chunked() -{ - srs_error_t err = srs_success; - - if (infinite_chunked) { - return err; - } - - if (is_chunked() || content_length() != -1) { - return srs_error_new(ERROR_HTTP_DATA_INVALID, "not infinited chunked"); - } - - infinite_chunked = true; - - return err; -} - srs_error_t SrsHttpMessage::body_read_all(string& body) { srs_error_t err = srs_success; @@ -975,17 +952,10 @@ srs_error_t SrsHttpResponseReader::read(void* data, size_t nb_data, ssize_t* nb_ return read_specified(data, nb_data, nb_read); } - // infinite chunked mode, directly read. - if (owner->is_infinite_chunked()) { - srs_assert(!owner->is_chunked() && owner->content_length() == -1); - return read_specified(data, nb_data, nb_read); - } - - // infinite chunked mode, but user not set it, - // we think there is no data left. - is_eof = true; - - return err; + // Infinite chunked mode. + // If not chunked encoding, and no content-length, it's infinite chunked. + // In this mode, all body is data and never EOF util socket closed. + return read_specified(data, nb_data, nb_read); } srs_error_t SrsHttpResponseReader::read_chunked(void* data, size_t nb_data, ssize_t* nb_read) diff --git a/trunk/src/protocol/srs_service_http_conn.hpp b/trunk/src/protocol/srs_service_http_conn.hpp index fc49d10d5..5c8d9e0f1 100644 --- a/trunk/src/protocol/srs_service_http_conn.hpp +++ b/trunk/src/protocol/srs_service_http_conn.hpp @@ -99,8 +99,6 @@ private: // The body object, reader object. // @remark, user can get body in string by get_body(). SrsHttpResponseReader* _body; - // Whether the body is infinite chunked. - bool infinite_chunked; // Use a buffer to read and send ts file. // The transport connection, can be NULL. ISrsConnection* owner_conn; @@ -157,9 +155,6 @@ public: virtual bool is_http_options(); // Whether body is chunked encoding, for reader only. virtual bool is_chunked(); - // Whether body is infinite chunked encoding. - // @remark set by enter_infinite_chunked. - virtual bool is_infinite_chunked(); // Whether should keep the connection alive. virtual bool is_keep_alive(); // The uri contains the host and path. @@ -173,8 +168,6 @@ public: virtual std::string ext(); // Get the RESTful matched id. virtual std::string parse_rest_id(std::string pattern); -public: - virtual srs_error_t enter_infinite_chunked(); public: // Read body to string. // @remark for small http body. diff --git a/trunk/src/utest/srs_utest_service.cpp b/trunk/src/utest/srs_utest_service.cpp index 5cc78b968..df21fbc92 100644 --- a/trunk/src/utest/srs_utest_service.cpp +++ b/trunk/src/utest/srs_utest_service.cpp @@ -480,7 +480,7 @@ VOID TEST(TCPServerTest, WritevIOVC) } } -VOID TEST(TCPServerTest, MessageConnection) +VOID TEST(HTTPServerTest, MessageConnection) { srs_error_t err; @@ -534,7 +534,6 @@ VOID TEST(TCPServerTest, MessageConnection) if (true) { SrsHttpMessage m; EXPECT_TRUE(m.is_keep_alive()); - EXPECT_FALSE(m.is_infinite_chunked()); } if (true) { @@ -562,42 +561,7 @@ VOID TEST(TCPServerTest, MessageConnection) } } -VOID TEST(TCPServerTest, MessageInfinityChunked) -{ - srs_error_t err; - - if (true) { - SrsHttpMessage m; - EXPECT_FALSE(m.is_infinite_chunked()); - HELPER_EXPECT_SUCCESS(m.enter_infinite_chunked()); - EXPECT_TRUE(m.is_infinite_chunked()); - } - - if (true) { - SrsHttpMessage m; - HELPER_EXPECT_SUCCESS(m.enter_infinite_chunked()); - HELPER_EXPECT_SUCCESS(m.enter_infinite_chunked()); - EXPECT_TRUE(m.is_infinite_chunked()); - } - - if (true) { - SrsHttpMessage m; - SrsHttpHeader hdr; - hdr.set("Transfer-Encoding", "chunked"); - m.set_header(&hdr, false); - HELPER_EXPECT_FAILED(m.enter_infinite_chunked()); - } - - if (true) { - SrsHttpMessage m; - SrsHttpHeader hdr; - hdr.set("Content-Length", "100"); - m.set_header(&hdr, false); - HELPER_EXPECT_FAILED(m.enter_infinite_chunked()); - } -} - -VOID TEST(TCPServerTest, MessageTurnRequest) +VOID TEST(HTTPServerTest, MessageTurnRequest) { srs_error_t err; @@ -645,7 +609,65 @@ VOID TEST(TCPServerTest, MessageTurnRequest) } } -VOID TEST(TCPServerTest, MessageWritev) +VOID TEST(HTTPServerTest, ContentLength) +{ + srs_error_t err; + + // For infinite chunked mode, all data is content. + if (true) { + MockBufferIO io; + io.append("HTTP/1.1 200 OK\r\nContent-Length: 11\r\n\r\n"); + + SrsHttpParser hp; HELPER_ASSERT_SUCCESS(hp.initialize(HTTP_RESPONSE, false)); + ISrsHttpMessage* msg = NULL; HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &msg)); + + char buf[32]; ssize_t nread = 0; + ISrsHttpResponseReader* r = msg->body_reader(); + + io.append("Hello"); + HELPER_ARRAY_INIT(buf, sizeof(buf), 0); + HELPER_ASSERT_SUCCESS(r->read(buf, 5, &nread)); + EXPECT_EQ(5, nread); + EXPECT_STREQ("Hello", buf); + + io.append("World!"); + HELPER_ARRAY_INIT(buf, sizeof(buf), 0); + HELPER_ASSERT_SUCCESS(r->read(buf, 6, &nread)); + EXPECT_EQ(6, nread); + EXPECT_STREQ("World!", buf); + } +} + +VOID TEST(HTTPServerTest, HTTPChunked) +{ + srs_error_t err; + + // For infinite chunked mode, all data is content. + if (true) { + MockBufferIO io; + io.append("HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n"); + + SrsHttpParser hp; HELPER_ASSERT_SUCCESS(hp.initialize(HTTP_RESPONSE, false)); + ISrsHttpMessage* msg = NULL; HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &msg)); + + char buf[32]; ssize_t nread = 0; + ISrsHttpResponseReader* r = msg->body_reader(); + + io.append("5\r\nHello\r\n"); + HELPER_ARRAY_INIT(buf, sizeof(buf), 0); + HELPER_ASSERT_SUCCESS(r->read(buf, 5, &nread)); + EXPECT_EQ(5, nread); + EXPECT_STREQ("Hello", buf); + + io.append("6\r\nWorld!\r\n"); + HELPER_ARRAY_INIT(buf, sizeof(buf), 0); + HELPER_ASSERT_SUCCESS(r->read(buf, 6, &nread)); + EXPECT_EQ(6, nread); + EXPECT_STREQ("World!", buf); + } +} + +VOID TEST(HTTPServerTest, InfiniteChunked) { srs_error_t err; @@ -657,12 +679,6 @@ VOID TEST(TCPServerTest, MessageWritev) SrsHttpParser hp; HELPER_ASSERT_SUCCESS(hp.initialize(HTTP_RESPONSE, false)); ISrsHttpMessage* msg = NULL; HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &msg)); - if (true) { - SrsHttpMessage* hm = dynamic_cast(msg); - ASSERT_TRUE(hm != NULL); - hm->enter_infinite_chunked(); - } - char buf[32]; ssize_t nread = 0; ISrsHttpResponseReader* r = msg->body_reader(); @@ -678,6 +694,11 @@ VOID TEST(TCPServerTest, MessageWritev) EXPECT_EQ(8, nread); EXPECT_STREQ("\r\nWorld!", buf); } +} + +VOID TEST(HTTPServerTest, MessageWritev) +{ + srs_error_t err; // Directly writev, merge to one chunk. if (true) { @@ -1174,7 +1195,7 @@ public: } }; -VOID TEST(TCPServerTest, HTTPClientUtility) +VOID TEST(HTTPClientTest, HTTPClientUtility) { srs_error_t err; From 9ff8bff6011e471e1d0250739c1ceb580bd5de2e Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 2 Jul 2020 12:41:08 +0800 Subject: [PATCH 30/37] RTC: Fix the OPTIONS read, no infinited chunked mode --- trunk/src/protocol/srs_service_http_conn.cpp | 11 ++++ trunk/src/protocol/srs_service_http_conn.hpp | 5 ++ trunk/src/utest/srs_utest_service.cpp | 60 ++++++++++++++++++++ 3 files changed, 76 insertions(+) diff --git a/trunk/src/protocol/srs_service_http_conn.cpp b/trunk/src/protocol/srs_service_http_conn.cpp index de493f22c..dccca73a6 100644 --- a/trunk/src/protocol/srs_service_http_conn.cpp +++ b/trunk/src/protocol/srs_service_http_conn.cpp @@ -334,6 +334,12 @@ void SrsHttpMessage::set_header(SrsHttpHeader* header, bool keep_alive) if (!clv.empty()) { _content_length = ::atoll(clv.c_str()); } + + // If method is OPTIONS, and no size(content-length or chunked), it's not infinite chunked, + // it means there is no body, so we must close the body reader. + if (_method == SRS_CONSTS_HTTP_OPTIONS && !chunked && _content_length == -1) { + _body->close(); + } } srs_error_t SrsHttpMessage::set_url(string url, bool allow_jsonp) @@ -921,6 +927,11 @@ SrsHttpResponseReader::~SrsHttpResponseReader() { } +void SrsHttpResponseReader::close() +{ + is_eof = true; +} + bool SrsHttpResponseReader::eof() { return is_eof; diff --git a/trunk/src/protocol/srs_service_http_conn.hpp b/trunk/src/protocol/srs_service_http_conn.hpp index 5c8d9e0f1..ddddc022d 100644 --- a/trunk/src/protocol/srs_service_http_conn.hpp +++ b/trunk/src/protocol/srs_service_http_conn.hpp @@ -264,6 +264,11 @@ public: // while buffer is a fast cache which may have cached some data from reader. SrsHttpResponseReader(SrsHttpMessage* msg, ISrsReader* reader, SrsFastStream* buffer); virtual ~SrsHttpResponseReader(); +public: + // User close the HTTP response reader. + // For example, OPTIONS has no body, no content-length and not chunked, + // so we must close it(set to eof) to avoid reading the response body. + void close(); // Interface ISrsHttpResponseReader public: virtual bool eof(); diff --git a/trunk/src/utest/srs_utest_service.cpp b/trunk/src/utest/srs_utest_service.cpp index df21fbc92..497c48829 100644 --- a/trunk/src/utest/srs_utest_service.cpp +++ b/trunk/src/utest/srs_utest_service.cpp @@ -678,6 +678,7 @@ VOID TEST(HTTPServerTest, InfiniteChunked) SrsHttpParser hp; HELPER_ASSERT_SUCCESS(hp.initialize(HTTP_RESPONSE, false)); ISrsHttpMessage* msg = NULL; HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &msg)); + SrsAutoFree(ISrsHttpMessage, msg); char buf[32]; ssize_t nread = 0; ISrsHttpResponseReader* r = msg->body_reader(); @@ -696,6 +697,65 @@ VOID TEST(HTTPServerTest, InfiniteChunked) } } +VOID TEST(HTTPServerTest, OPTIONSRead) +{ + srs_error_t err; + + // If OPTIONS, it has no content-length, not chunkted, but not infinite chunked, + // instead, it has no body. + if (true) { + MockBufferIO io; + io.append("OPTIONS /rtc/v1/play HTTP/1.1\r\n\r\n"); + + SrsHttpParser hp; HELPER_ASSERT_SUCCESS(hp.initialize(HTTP_REQUEST, false)); + ISrsHttpMessage* req = NULL; HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &req)); + SrsAutoFree(ISrsHttpMessage, req); + + ISrsHttpResponseReader* br = req->body_reader(); + EXPECT_TRUE(br->eof()); + } + + // So if OPTIONS has body, with chunked or content-length, it's ok to parsing it. + if (true) { + MockBufferIO io; + io.append("OPTIONS /rtc/v1/play HTTP/1.1\r\nContent-Length: 5\r\n\r\nHello"); + + SrsHttpParser hp; HELPER_ASSERT_SUCCESS(hp.initialize(HTTP_REQUEST, false)); + ISrsHttpMessage* req = NULL; HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &req)); + SrsAutoFree(ISrsHttpMessage, req); + + ISrsHttpResponseReader* br = req->body_reader(); + EXPECT_FALSE(br->eof()); + + string b; HELPER_ASSERT_SUCCESS(req->body_read_all(b)); + EXPECT_STREQ("Hello", b.c_str()); + + // The body will use as next HTTP request message. + io.append("GET /rtc/v1/play HTTP/1.1\r\n\r\n"); + ISrsHttpMessage* req2 = NULL; HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &req2)); + SrsAutoFree(ISrsHttpMessage, req2); + } + + // So if OPTIONS has body, but not specified the size, we think it has no body, + // and the body is parsed fail as the next parsing. + if (true) { + MockBufferIO io; + io.append("OPTIONS /rtc/v1/play HTTP/1.1\r\n\r\n"); + + SrsHttpParser hp; HELPER_ASSERT_SUCCESS(hp.initialize(HTTP_REQUEST, false)); + ISrsHttpMessage* req = NULL; HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &req)); + SrsAutoFree(ISrsHttpMessage, req); + + ISrsHttpResponseReader* br = req->body_reader(); + EXPECT_TRUE(br->eof()); + + // The body will use as next HTTP request message. + io.append("Hello"); + ISrsHttpMessage* req2 = NULL; HELPER_ASSERT_FAILED(hp.parse_message(&io, &req2)); + SrsAutoFree(ISrsHttpMessage, req2); + } +} + VOID TEST(HTTPServerTest, MessageWritev) { srs_error_t err; From 69fc1ba71158385117e894f437da88aad90a0d0a Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 2 Jul 2020 14:51:11 +0800 Subject: [PATCH 31/37] RTC: Prevent DTLS ARQ packet to dup play/publish --- trunk/src/app/srs_app_rtc_conn.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index e4251e7d3..f42d330ea 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -2006,7 +2006,11 @@ srs_error_t SrsRtcSession::start_play() { srs_error_t err = srs_success; - srs_freep(player_); + // If player is initialized, we think the session is started. + // To prevent play multiple times for the DTLS ARQ packet. + if (player_) { + return err; + } player_ = new SrsRtcPlayer(this, _srs_context->get_id()); uint32_t video_ssrc = 0; @@ -2039,7 +2043,11 @@ srs_error_t SrsRtcSession::start_publish() { srs_error_t err = srs_success; - srs_freep(publisher_); + // If publisher is initialized, we think the session is started. + // To prevent publish multiple times for the DTLS ARQ packet. + if (publisher_) { + return err; + } publisher_ = new SrsRtcPublisher(this); // Request PLI for exists players? //publisher_->request_keyframe(); From 545a0efea3cbb8d076cda1dcc54610473b61021e Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 2 Jul 2020 14:51:32 +0800 Subject: [PATCH 32/37] RTC: Refine code --- trunk/src/app/srs_app_rtc_api.cpp | 33 ++++++++++++------------ trunk/src/app/srs_app_rtc_conn.cpp | 40 ++++++++++++++++++++---------- trunk/src/app/srs_app_rtc_conn.hpp | 6 ++--- 3 files changed, 47 insertions(+), 32 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_api.cpp b/trunk/src/app/srs_app_rtc_api.cpp index 4975b602b..8a28712d3 100644 --- a/trunk/src/app/srs_app_rtc_api.cpp +++ b/trunk/src/app/srs_app_rtc_api.cpp @@ -633,6 +633,21 @@ srs_error_t SrsGoApiRtcPublish::exchange_sdp(SrsRequest* req, const SrsSdp& remo SrsMediaDesc& local_media_desc = local_sdp.media_descs_.back(); + // Whether feature enabled in remote extmap. + int remote_twcc_id = 0; + if (true) { + map extmaps = remote_media_desc.get_extmaps(); + for(map::iterator it = extmaps.begin(); it != extmaps.end(); ++it) { + if (it->second == kTWCCExt) { + remote_twcc_id = it->first; + break; + } + } + } + if (twcc_enabled && remote_twcc_id) { + local_media_desc.extmaps_[remote_twcc_id] = kTWCCExt; + } + if (remote_media_desc.is_audio()) { // TODO: check opus format specific param std::vector payloads = remote_media_desc.find_media_with_encoding_name("opus"); @@ -649,7 +664,7 @@ srs_error_t SrsGoApiRtcPublish::exchange_sdp(SrsRequest* req, const SrsSdp& remo payload_type.rtcp_fb_.push_back(rtcp_fb.at(j)); } } - if (twcc_enabled) { + if (twcc_enabled && remote_twcc_id) { if (rtcp_fb.at(j) == "transport-cc") { payload_type.rtcp_fb_.push_back(rtcp_fb.at(j)); } @@ -659,13 +674,6 @@ srs_error_t SrsGoApiRtcPublish::exchange_sdp(SrsRequest* req, const SrsSdp& remo // Only choose one match opus codec. break; } - map extmaps = remote_media_desc.get_extmaps(); - for(map::iterator it_ext = extmaps.begin(); it_ext != extmaps.end(); ++it_ext) { - if (it_ext->second == kTWCCExt) { - local_media_desc.extmaps_[it_ext->first] = kTWCCExt; - break; - } - } if (local_media_desc.payload_types_.empty()) { return srs_error_new(ERROR_RTC_SDP_EXCHANGE, "no valid found opus payload type"); @@ -698,7 +706,7 @@ srs_error_t SrsGoApiRtcPublish::exchange_sdp(SrsRequest* req, const SrsSdp& remo payload_type.rtcp_fb_.push_back(rtcp_fb.at(j)); } } - if (twcc_enabled) { + if (twcc_enabled && remote_twcc_id) { if (rtcp_fb.at(j) == "transport-cc") { payload_type.rtcp_fb_.push_back(rtcp_fb.at(j)); } @@ -711,13 +719,6 @@ srs_error_t SrsGoApiRtcPublish::exchange_sdp(SrsRequest* req, const SrsSdp& remo backup_payloads.push_back(*iter); } - map extmaps = remote_media_desc.get_extmaps(); - for(map::iterator it_ext = extmaps.begin(); it_ext != extmaps.end(); ++it_ext) { - if (it_ext->second == kTWCCExt) { - local_media_desc.extmaps_[it_ext->first] = kTWCCExt; - break; - } - } // Try my best to pick at least one media payload type. if (local_media_desc.payload_types_.empty() && ! backup_payloads.empty()) { diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index f42d330ea..d0e523d68 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -295,7 +295,7 @@ SrsRtcPlayer::~SrsRtcPlayer() srs_freep(video_queue_); } -srs_error_t SrsRtcPlayer::initialize(const uint32_t& vssrc, const uint32_t& assrc, const uint16_t& v_pt, const uint16_t& a_pt) +srs_error_t SrsRtcPlayer::initialize(uint32_t vssrc, uint32_t assrc, uint16_t v_pt, uint16_t a_pt) { srs_error_t err = srs_success; @@ -481,6 +481,7 @@ srs_error_t SrsRtcPlayer::send_packets(SrsRtcSource* source, const vectornb_bytes(); + // For audio, we transcoded AAC to opus in extra payloads. if (pkt->is_audio()) { info.nn_audios++; pkt->header.set_ssrc(audio_ssrc); @@ -526,6 +527,7 @@ srs_error_t SrsRtcPlayer::do_send_packets(const std::vector& pkt iov->iov_base = iov_base; iov->iov_len = kRtpPacketSize; + uint16_t twcc_sn = 0; // Marshal packet to bytes in iovec. if (true) { SrsBuffer stream((char*)iov->iov_base, iov->iov_len); @@ -858,7 +860,7 @@ SrsRtcPublisher::SrsRtcPublisher(SrsRtcSession* session) pt_to_drop_ = 0; nn_audio_frames = 0; - twcc_ext_id_ = 0; + twcc_id_ = 0; last_twcc_feedback_time_ = 0; twcc_fb_count_ = 0; } @@ -878,25 +880,28 @@ SrsRtcPublisher::~SrsRtcPublisher() srs_freep(audio_queue_); } -srs_error_t SrsRtcPublisher::initialize(uint32_t vssrc, uint32_t assrc, uint8_t twcc_ext_id, SrsRequest* r) +srs_error_t SrsRtcPublisher::initialize(uint32_t vssrc, uint32_t assrc, int twcc_id, SrsRequest* r) { srs_error_t err = srs_success; video_ssrc = vssrc; audio_ssrc = assrc; - twcc_ext_id_ = twcc_ext_id; - rtcp_twcc_.set_media_ssrc(video_ssrc); req = r; - if (twcc_ext_id_ != 0) { - extension_types_.register_by_uri(twcc_ext_id_, kTWCCExt); - } // TODO: FIXME: Support reload. nack_enabled_ = _srs_config->get_rtc_nack_enabled(session_->req->vhost); pt_to_drop_ = (uint16_t)_srs_config->get_rtc_drop_for_pt(session_->req->vhost); + bool twcc_enabled = _srs_config->get_rtc_twcc_enabled(req->vhost); + if (twcc_enabled) { + twcc_id_ = twcc_id; + } + srs_trace("RTC publisher video(ssrc=%u), audio(ssrc=%u), nack=%d, pt-drop=%u, twcc=%u/%d", + video_ssrc, audio_ssrc, nack_enabled_, pt_to_drop_, twcc_enabled, twcc_id); - srs_trace("RTC publisher video(ssrc=%u), audio(ssrc=%u), nack=%d, pt-drop=%u", - video_ssrc, audio_ssrc, nack_enabled_, pt_to_drop_); + if (twcc_id_) { + extension_types_.register_by_uri(twcc_id_, kTWCCExt); + rtcp_twcc_.set_media_ssrc(video_ssrc); + } if ((err = report_timer->tick(0 * SRS_UTIME_MILLISECONDS)) != srs_success) { return srs_error_wrap(err, "hourglass tick"); @@ -1149,7 +1154,7 @@ srs_error_t SrsRtcPublisher::on_rtp(char* data, int nb_data) // Decode the header first. SrsRtpHeader h; - if (pt_to_drop_ && twcc_ext_id_) { + if (pt_to_drop_ && twcc_id_) { SrsBuffer b(data, nb_data); h.ignore_padding(true); h.set_extensions(&extension_types_); if ((err = h.decode(&b)) != srs_success) { @@ -1161,7 +1166,7 @@ srs_error_t SrsRtcPublisher::on_rtp(char* data, int nb_data) // 1. Client may send some padding packets with invalid SequenceNumber, which causes the SRTP fail. // 2. Server may send multiple duplicated NACK to client, and got more than one ARQ packet, which also fail SRTP. // so, we must parse the header before SRTP unprotect(which may fail and drop packet). - if (twcc_ext_id_) { + if (twcc_id_) { uint16_t twcc_sn = 0; if ((err = h.get_twcc_sequence_number(twcc_sn)) == srs_success) { if((err = on_twcc(twcc_sn)) != srs_success) { @@ -2017,6 +2022,7 @@ srs_error_t SrsRtcSession::start_play() uint32_t audio_ssrc = 0; uint16_t video_payload_type = 0; uint16_t audio_payload_type = 0; + int twcc_id = -1; for (size_t i = 0; i < local_sdp.media_descs_.size(); ++i) { const SrsMediaDesc& media_desc = local_sdp.media_descs_[i]; if (media_desc.is_audio()) { @@ -2025,10 +2031,17 @@ srs_error_t SrsRtcSession::start_play() } else if (media_desc.is_video()) { video_ssrc = media_desc.ssrc_infos_[0].ssrc_; video_payload_type = media_desc.payload_types_[0].payload_type_; + //TODO: just judgement video media whether to support twcc + std::map exts = media_desc.get_extmaps(); + for(std::map::iterator it = exts.begin(); it != exts.end(); ++it) { + if(kTWCCExt == it->second) { + twcc_id = it->first; + } + } } } - if ((err = player_->initialize(video_ssrc, audio_ssrc, video_payload_type, audio_payload_type)) != srs_success) { + if ((err = player_->initialize(video_ssrc, audio_ssrc, video_payload_type, audio_payload_type, twcc_id)) != srs_success) { return srs_error_wrap(err, "SrsRtcPlayer init"); } @@ -2049,6 +2062,7 @@ srs_error_t SrsRtcSession::start_publish() return err; } publisher_ = new SrsRtcPublisher(this); + // Request PLI for exists players? //publisher_->request_keyframe(); diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 96d6ccdd6..b2c9208ad 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -211,7 +211,7 @@ public: SrsRtcPlayer(SrsRtcSession* s, std::string parent_cid); virtual ~SrsRtcPlayer(); public: - srs_error_t initialize(const uint32_t& vssrc, const uint32_t& assrc, const uint16_t& v_pt, const uint16_t& a_pt); + srs_error_t initialize(uint32_t vssrc, uint32_t assrc, uint16_t v_pt, uint16_t a_pt); // interface ISrsReloadHandler public: virtual srs_error_t on_reload_vhost_play(std::string vhost); @@ -270,7 +270,7 @@ private: std::map last_sender_report_ntp; private: srs_utime_t last_twcc_feedback_time_; - uint8_t twcc_ext_id_; + int twcc_id_; uint8_t twcc_fb_count_; SrsRtcpTWCC rtcp_twcc_; SrsRtpExtensionTypes extension_types_; @@ -278,7 +278,7 @@ public: SrsRtcPublisher(SrsRtcSession* session); virtual ~SrsRtcPublisher(); public: - srs_error_t initialize(uint32_t vssrc, uint32_t assrc, uint8_t twcc_ext_id, SrsRequest* req); + srs_error_t initialize(uint32_t vssrc, uint32_t assrc, int twcc_id, SrsRequest* req); private: void check_send_nacks(SrsRtpNackForReceiver* nack, uint32_t ssrc); srs_error_t send_rtcp_rr(uint32_t ssrc, SrsRtpRingBuffer* rtp_queue); From df9efb6486b0754f40ae15a849b45d8dddecb802 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 2 Jul 2020 16:20:32 +0800 Subject: [PATCH 33/37] RTC: Infinite chunk handle read error as EOF. --- trunk/src/protocol/srs_service_http_conn.cpp | 10 +++++++- trunk/src/utest/srs_utest_service.cpp | 26 ++++++++++++++++++-- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/trunk/src/protocol/srs_service_http_conn.cpp b/trunk/src/protocol/srs_service_http_conn.cpp index dccca73a6..e161d167d 100644 --- a/trunk/src/protocol/srs_service_http_conn.cpp +++ b/trunk/src/protocol/srs_service_http_conn.cpp @@ -966,7 +966,15 @@ srs_error_t SrsHttpResponseReader::read(void* data, size_t nb_data, ssize_t* nb_ // Infinite chunked mode. // If not chunked encoding, and no content-length, it's infinite chunked. // In this mode, all body is data and never EOF util socket closed. - return read_specified(data, nb_data, nb_read); + if ((err = read_specified(data, nb_data, nb_read)) != srs_success) { + // For infinite chunked, the socket close event is EOF. + if (srs_error_code(err) == ERROR_SOCKET_READ) { + srs_freep(err); is_eof = true; + return err; + } + } + + return err; } srs_error_t SrsHttpResponseReader::read_chunked(void* data, size_t nb_data, ssize_t* nb_read) diff --git a/trunk/src/utest/srs_utest_service.cpp b/trunk/src/utest/srs_utest_service.cpp index 497c48829..b4e85c591 100644 --- a/trunk/src/utest/srs_utest_service.cpp +++ b/trunk/src/utest/srs_utest_service.cpp @@ -613,7 +613,6 @@ VOID TEST(HTTPServerTest, ContentLength) { srs_error_t err; - // For infinite chunked mode, all data is content. if (true) { MockBufferIO io; io.append("HTTP/1.1 200 OK\r\nContent-Length: 11\r\n\r\n"); @@ -642,7 +641,6 @@ VOID TEST(HTTPServerTest, HTTPChunked) { srs_error_t err; - // For infinite chunked mode, all data is content. if (true) { MockBufferIO io; io.append("HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n"); @@ -694,6 +692,30 @@ VOID TEST(HTTPServerTest, InfiniteChunked) HELPER_ASSERT_SUCCESS(r->read(buf, 8, &nread)); EXPECT_EQ(8, nread); EXPECT_STREQ("\r\nWorld!", buf); + + EXPECT_FALSE(r->eof()); + } + + // If read error, it's EOF. + if (true) { + MockBufferIO io; + io.append("HTTP/1.1 200 OK\r\n\r\n"); + + SrsHttpParser hp; HELPER_ASSERT_SUCCESS(hp.initialize(HTTP_RESPONSE, false)); + ISrsHttpMessage* msg = NULL; HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &msg)); + + char buf[32]; ssize_t nread = 0; + ISrsHttpResponseReader* r = msg->body_reader(); + + io.append("Hello"); + HELPER_ARRAY_INIT(buf, sizeof(buf), 0); + HELPER_ASSERT_SUCCESS(r->read(buf, 10, &nread)); + EXPECT_EQ(5, nread); + EXPECT_STREQ("Hello", buf); + + io.in_err = srs_error_new(ERROR_SOCKET_READ, "EOF"); + HELPER_ASSERT_SUCCESS(r->read(buf, 10, &nread)); + EXPECT_TRUE(r->eof()); } } From 1c3e4c71ee1b3b4e82923abc6866cb3c26cef844 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 2 Jul 2020 16:28:26 +0800 Subject: [PATCH 34/37] Fix utest fail --- trunk/src/utest/srs_utest.hpp | 2 +- trunk/src/utest/srs_utest_service.cpp | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/trunk/src/utest/srs_utest.hpp b/trunk/src/utest/srs_utest.hpp index 22d0d70e2..bf2f26c8a 100644 --- a/trunk/src/utest/srs_utest.hpp +++ b/trunk/src/utest/srs_utest.hpp @@ -67,7 +67,7 @@ extern srs_utime_t _srs_tmp_timeout; // For init array data. #define HELPER_ARRAY_INIT(buf, sz, val) \ - for (int i = 0; i < (int)sz; i++) (buf)[i]=val + memset(buf, val, sz) // Dump simple stream to string. #define HELPER_BUFFER2STR(io) \ diff --git a/trunk/src/utest/srs_utest_service.cpp b/trunk/src/utest/srs_utest_service.cpp index b4e85c591..e93816eab 100644 --- a/trunk/src/utest/srs_utest_service.cpp +++ b/trunk/src/utest/srs_utest_service.cpp @@ -1379,6 +1379,7 @@ VOID TEST(TCPServerTest, ContextUtility) int base_size = 0; if (true) { + errno = 0; int size = 0; char buf[1024]; HELPER_ARRAY_INIT(buf, 1024, 0); ASSERT_TRUE(srs_log_header(buf, 1024, true, true, "SRS", "100", "Trace", &size)); base_size = size; @@ -1386,6 +1387,7 @@ VOID TEST(TCPServerTest, ContextUtility) } if (true) { + errno = 0; int size = 0; char buf[1024]; HELPER_ARRAY_INIT(buf, 1024, 0); ASSERT_TRUE(srs_log_header(buf, 1024, false, true, "SRS", "100", "Trace", &size)); EXPECT_EQ(base_size, size); @@ -1399,6 +1401,7 @@ VOID TEST(TCPServerTest, ContextUtility) } if (true) { + errno = 0; int size = 0; char buf[1024]; HELPER_ARRAY_INIT(buf, 1024, 0); ASSERT_TRUE(srs_log_header(buf, 1024, false, false, NULL, "100", "Trace", &size)); EXPECT_EQ(base_size - 8, size); From 5d561b1915ec61c372390aeb9541b73b2b8bca5d Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 2 Jul 2020 16:28:37 +0800 Subject: [PATCH 35/37] RTC: Fix build fail --- trunk/src/app/srs_app_rtc_conn.cpp | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index d0e523d68..ba8b46a34 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -527,7 +527,6 @@ srs_error_t SrsRtcPlayer::do_send_packets(const std::vector& pkt iov->iov_base = iov_base; iov->iov_len = kRtpPacketSize; - uint16_t twcc_sn = 0; // Marshal packet to bytes in iovec. if (true) { SrsBuffer stream((char*)iov->iov_base, iov->iov_len); @@ -2022,7 +2021,6 @@ srs_error_t SrsRtcSession::start_play() uint32_t audio_ssrc = 0; uint16_t video_payload_type = 0; uint16_t audio_payload_type = 0; - int twcc_id = -1; for (size_t i = 0; i < local_sdp.media_descs_.size(); ++i) { const SrsMediaDesc& media_desc = local_sdp.media_descs_[i]; if (media_desc.is_audio()) { @@ -2031,17 +2029,10 @@ srs_error_t SrsRtcSession::start_play() } else if (media_desc.is_video()) { video_ssrc = media_desc.ssrc_infos_[0].ssrc_; video_payload_type = media_desc.payload_types_[0].payload_type_; - //TODO: just judgement video media whether to support twcc - std::map exts = media_desc.get_extmaps(); - for(std::map::iterator it = exts.begin(); it != exts.end(); ++it) { - if(kTWCCExt == it->second) { - twcc_id = it->first; - } - } } } - if ((err = player_->initialize(video_ssrc, audio_ssrc, video_payload_type, audio_payload_type, twcc_id)) != srs_success) { + if ((err = player_->initialize(video_ssrc, audio_ssrc, video_payload_type, audio_payload_type)) != srs_success) { return srs_error_wrap(err, "SrsRtcPlayer init"); } From 3bab0ad3452427801033fb7ec74f357d81d0ce6b Mon Sep 17 00:00:00 2001 From: xiaozhihong Date: Thu, 2 Jul 2020 21:59:51 +0800 Subject: [PATCH 36/37] rtc merge_nalu default value off --- trunk/src/app/srs_app_config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index 11b4d93c3..984dd95a6 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -4848,7 +4848,7 @@ int SrsConfig::get_rtc_server_reuseport2() bool SrsConfig::get_rtc_server_merge_nalus() { - static int DEFAULT = true; + static int DEFAULT = false; SrsConfDirective* conf = root->get("rtc_server"); if (!conf) { From 62cadd244ad46c11641c361466069e0a932ef5bf Mon Sep 17 00:00:00 2001 From: winlin Date: Fri, 3 Jul 2020 09:23:02 +0800 Subject: [PATCH 37/37] RTC: Disable merge_nalus by default --- trunk/conf/full.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index e12ee39fc..b53766ef2 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -444,8 +444,8 @@ rtc_server { reuseport 1; # Whether merge multiple NALUs into one. # @see https://github.com/ossrs/srs/issues/307#issuecomment-612806318 - # default: on - merge_nalus on; + # default: off + merge_nalus off; # Whether enable the perf stat at http://localhost:1985/api/v1/perf # default: on perf_stat on;