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; }