From 9d5495c0c20fe8b499b6723b2c94e664b7a8b324 Mon Sep 17 00:00:00 2001 From: xiaozhihong Date: Fri, 6 Mar 2020 23:01:48 +0800 Subject: [PATCH] "stun and dtls done" --- trunk/3rdparty/libsrtp-2.0.0.zip | Bin 0 -> 178 bytes trunk/auto/depends.sh | 21 ++ trunk/configure | 23 +- trunk/src/app/srs_app_dtls.cpp | 131 +++++++ trunk/src/app/srs_app_dtls.hpp | 52 +++ trunk/src/app/srs_app_http_api.cpp | 100 ++--- trunk/src/app/srs_app_http_api.hpp | 4 +- trunk/src/app/srs_app_listener.cpp | 57 ++- trunk/src/app/srs_app_listener.hpp | 30 +- trunk/src/app/srs_app_rtc.cpp | 4 +- trunk/src/app/srs_app_rtc.hpp | 4 +- trunk/src/app/srs_app_rtc_conn.cpp | 525 +++++++++++++++++++++++--- trunk/src/app/srs_app_rtc_conn.hpp | 84 ++++- trunk/src/app/srs_app_server.cpp | 2 +- trunk/src/app/srs_app_server.hpp | 4 +- trunk/src/protocol/srs_stun_stack.cpp | 264 ++++++++++++- trunk/src/protocol/srs_stun_stack.hpp | 69 +++- trunk/src/service/srs_service_st.cpp | 5 + trunk/src/service/srs_service_st.hpp | 1 + 19 files changed, 1220 insertions(+), 160 deletions(-) create mode 100644 trunk/3rdparty/libsrtp-2.0.0.zip create mode 100644 trunk/src/app/srs_app_dtls.cpp create mode 100644 trunk/src/app/srs_app_dtls.hpp diff --git a/trunk/3rdparty/libsrtp-2.0.0.zip b/trunk/3rdparty/libsrtp-2.0.0.zip new file mode 100644 index 0000000000000000000000000000000000000000..c149013ac25bd5e7e3d4714a6cdb3fa3035bf4e7 GIT binary patch literal 178 zcmWIWW@h1H0D+kb&K_U}l;C5KVaUl$DlRH1&^6LC&@<2v4dG;9e#E^ojPHM9TxkV2 x10%}|W(Ec@5#Y_pB*%=)BnhaQ0t|m0K}>XWSs~_Pn90fpQq2g2AwU}9JODC)96SI3 literal 0 HcmV?d00001 diff --git a/trunk/auto/depends.sh b/trunk/auto/depends.sh index a4c8730df..998a4fddb 100755 --- a/trunk/auto/depends.sh +++ b/trunk/auto/depends.sh @@ -242,6 +242,27 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then if [ ! -f ${SRS_OBJS}/st/libst.a ]; then echo "Build state-threads static lib failed."; exit -1; fi fi +##################################################################################### +# srtp +##################################################################################### +if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then + # Patched ST from https://github.com/ossrs/state-threads/tree/srs + if [[ -f ${SRS_OBJS}/srtp2/lib/libsrtp2.a ]]; then + echo "The srtp2 is ok."; + else + echo "Building srtp2."; + ( + rm -rf ${SRS_OBJS}/srtp2 && cd ${SRS_OBJS} && + ln -sf ../3rdparty/libsrtp-2.0.0 && cd libsrtp-2.0.0 && + ./configure --prefix=`pwd`/_release && make ${SRS_JOBS} && make install && + cd .. && rm -f srtp2 && ln -sf libsrtp-2.0.0/_release srtp2 + ) + fi + # check status + ret=$?; if [[ $ret -ne 0 ]]; then echo "Build srtp2 failed, ret=$ret"; exit $ret; fi + if [ ! -f ${SRS_OBJS}/srtp2/lib/libsrtp2.a ]; then echo "Build srtp2 static lib failed."; exit -1; fi +fi + ##################################################################################### # nginx for HLS, nginx-1.5.0 ##################################################################################### diff --git a/trunk/configure b/trunk/configure index a29047e72..047f41883 100755 --- a/trunk/configure +++ b/trunk/configure @@ -148,6 +148,9 @@ END # st(state-threads) the basic network library for SRS. LibSTRoot="${SRS_OBJS_DIR}/st"; LibSTfile="${LibSTRoot}/libst.a" if [[ $SRS_SHARED_ST == YES ]]; then LibSTfile="-lst"; fi +# srtp +LibSrtpRoot="${SRS_OBJS_DIR}/srtp2"; LibSrtpFile="${LibSrtpRoot}/lib/libsrtp2.a" +if [[ $SRS_SHARED_SRTP == YES ]]; then LibSrtpFile="-lsrtp2"; fi # openssl-1.1.0e, for the RTMP complex handshake. LibSSLRoot="";LibSSLfile="" if [[ $SRS_SSL == YES && $SRS_USE_SYS_SSL == NO ]]; then @@ -233,7 +236,7 @@ fi if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then MODULE_ID="SERVICE" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL") - ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibSSLRoot}) + ModuleLibIncs=(${LibSTRoot} ${LibSrtpRoot} ${SRS_OBJS_DIR} ${LibSSLRoot}) MODULE_FILES=("srs_service_log" "srs_service_st" "srs_service_http_client" "srs_service_http_conn" "srs_service_rtmp_conn" "srs_service_utility" "srs_service_conn") @@ -246,7 +249,7 @@ fi if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then MODULE_ID="APP" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE") - ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibSSLRoot}) + ModuleLibIncs=(${LibSTRoot} ${LibSrtpRoot} ${SRS_OBJS_DIR} ${LibSSLRoot}) MODULE_FILES=("srs_app_server" "srs_app_conn" "srs_app_rtmp_conn" "srs_app_source" "srs_app_refer" "srs_app_hls" "srs_app_forward" "srs_app_encoder" "srs_app_http_stream" "srs_app_thread" "srs_app_bandwidth" "srs_app_st" "srs_app_log" "srs_app_config" @@ -254,7 +257,7 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then "srs_app_ingest" "srs_app_ffmpeg" "srs_app_utility" "srs_app_edge" "srs_app_heartbeat" "srs_app_empty" "srs_app_http_client" "srs_app_http_static" "srs_app_recv_thread" "srs_app_security" "srs_app_statistic" "srs_app_hds" - "srs_app_mpegts_udp" "srs_app_rtc" "srs_app_rtc_conn" "srs_app_rtsp" "srs_app_listener" "srs_app_async_call" + "srs_app_mpegts_udp" "srs_app_rtc" "srs_app_rtc_conn" "srs_app_dtls" "srs_app_rtsp" "srs_app_listener" "srs_app_async_call" "srs_app_caster_flv" "srs_app_process" "srs_app_ng_exec" "srs_app_hourglass" "srs_app_dash" "srs_app_fragment" "srs_app_dvr" "srs_app_coworkers" "srs_app_hybrid") @@ -284,7 +287,7 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then if [[ $SRS_SRT == YES ]]; then MODULE_DEPENDS+=("SRT") fi - ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) + ModuleLibIncs=(${LibSTRoot} ${LibSrtpRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) if [[ $SRS_SRT == YES ]]; then ModuleLibIncs+=("${LibSRTRoot[*]}") fi @@ -297,7 +300,7 @@ fi if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then MODULE_ID="MAIN" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE") - ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) + ModuleLibIncs=(${LibSTRoot} ${LibSrtpRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) MODULE_FILES=() DEFINES="" # add each modules for main @@ -324,13 +327,13 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then done # # all depends libraries - ModuleLibFiles=(${LibSTfile} ${LibSSLfile} ${LibGperfFile}) + ModuleLibFiles=(${LibSTfile} ${LibSrtpFile} ${LibSSLfile} ${LibGperfFile}) if [[ $SRS_SRT == YES ]]; then ModuleLibFiles+=("${LibSRTfile[*]}") fi # all depends objects MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${SERVICE_OBJS[@]} ${APP_OBJS[@]} ${SERVER_OBJS[@]}" - ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) + ModuleLibIncs=(${LibSTRoot} ${LibSrtpRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) if [[ $SRS_SRT == YES ]]; then MODULE_OBJS="${MODULE_OBJS} ${SRT_OBJS[@]}" fi @@ -341,7 +344,7 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then # # For modules, without the app module. MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${SERVICE_OBJS[@]} ${MAIN_OBJS[@]}" - ModuleLibFiles=(${LibSTfile} ${LibSSLfile} ${LibGperfFile}) + ModuleLibFiles=(${LibSTfile} ${LibSrtpFile} ${LibSSLfile} ${LibGperfFile}) # for SRS_MODULE in ${SRS_MODULES[*]}; do . $SRS_MODULE/config @@ -361,11 +364,11 @@ if [ $SRS_UTEST = YES ]; then MODULE_FILES=("srs_utest" "srs_utest_amf0" "srs_utest_protocol" "srs_utest_kernel" "srs_utest_core" "srs_utest_config" "srs_utest_rtmp" "srs_utest_http" "srs_utest_avc" "srs_utest_reload" "srs_utest_mp4" "srs_utest_service" "srs_utest_app") - ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSTRoot} ${LibSSLRoot}) + ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSTRoot} ${LibSrtpRoot} ${LibSSLRoot}) if [[ $SRS_SRT == YES ]]; then ModuleLibIncs+=("${LibSRTRoot[*]}") fi - ModuleLibFiles=(${LibSTfile} ${LibSSLfile}) + ModuleLibFiles=(${LibSTfile} ${LibSrtpFile} ${LibSSLfile}) if [[ $SRS_SRT == YES ]]; then ModuleLibFiles+=("${LibSRTfile[*]}") fi diff --git a/trunk/src/app/srs_app_dtls.cpp b/trunk/src/app/srs_app_dtls.cpp new file mode 100644 index 000000000..af09dcb2f --- /dev/null +++ b/trunk/src/app/srs_app_dtls.cpp @@ -0,0 +1,131 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2013-2020 Winlin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +using namespace std; + +#include + +#include + +SrsDtls* SrsDtls::_instance = NULL; + +SrsDtls::SrsDtls() +{ +} + +SrsDtls::~SrsDtls() +{ +} + +SrsDtls* SrsDtls::instance() +{ + if (!_instance) { + _instance = new SrsDtls(); + _instance->init(); + } + return _instance; +} + +void SrsDtls::init() +{ + EVP_PKEY* dtls_private_key = EVP_PKEY_new(); + srs_assert(dtls_private_key); + + RSA* rsa = RSA_new(); + srs_assert(rsa); + + BIGNUM* exponent = BN_new(); + srs_assert(exponent); + + BN_set_word(exponent, RSA_F4); + + const std::string& aor = "www.hw.com"; + int expire_day = 365; + int private_key_len = 1024; + + RSA_generate_key_ex(rsa, private_key_len, exponent, NULL); + + srs_assert(EVP_PKEY_set1_RSA(dtls_private_key, rsa) == 1); + + X509* dtls_cert = X509_new(); + srs_assert(dtls_cert); + + X509_NAME* subject = X509_NAME_new(); + srs_assert(subject); + + int serial = rand(); + ASN1_INTEGER_set(X509_get_serialNumber(dtls_cert), serial); + + X509_NAME_add_entry_by_txt(subject, "CN", MBSTRING_ASC, (unsigned char *) aor.data(), aor.size(), -1, 0); + + X509_set_issuer_name(dtls_cert, subject); + X509_set_subject_name(dtls_cert, subject); + + const long cert_duration = 60*60*24*expire_day; + + X509_gmtime_adj(X509_get_notBefore(dtls_cert), 0); + X509_gmtime_adj(X509_get_notAfter(dtls_cert), cert_duration); + + srs_assert(X509_set_pubkey(dtls_cert, dtls_private_key) == 1); + + srs_assert(X509_sign(dtls_cert, dtls_private_key, EVP_sha1()) != 0); + + // cleanup + RSA_free(rsa); + BN_free(exponent); + X509_NAME_free(subject); + + dtls_ctx = SSL_CTX_new(DTLSv1_2_method()); + srs_assert(SSL_CTX_use_certificate(dtls_ctx, dtls_cert) == 1); + + srs_assert(SSL_CTX_use_PrivateKey(dtls_ctx, dtls_private_key) == 1); + srs_assert(SSL_CTX_set_cipher_list(dtls_ctx, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH") == 1); + srs_assert(SSL_CTX_set_tlsext_use_srtp(dtls_ctx, "SRTP_AES128_CM_SHA1_80") == 0); + + SSL_CTX_set_verify_depth (dtls_ctx, 4); + SSL_CTX_set_read_ahead(dtls_ctx, 1); + + // dtls fingerprint + char fp[100] = {0}; + char *p = fp; + unsigned char md[EVP_MAX_MD_SIZE]; + unsigned int n = 0; + + int r = X509_digest(dtls_cert, EVP_sha256(), md, &n); + + for (unsigned int i = 0; i < n; i++, ++p) { + sprintf(p, "%02X", md[i]); + p += 2; + + if(i < (n-1)) { + *p = ':'; + } else { + *p = '\0'; + } + } + + fingerprint.assign(fp, strlen(fp)); + srs_trace("fingerprint=%s", fingerprint.c_str()); +} diff --git a/trunk/src/app/srs_app_dtls.hpp b/trunk/src/app/srs_app_dtls.hpp new file mode 100644 index 000000000..5853f91b3 --- /dev/null +++ b/trunk/src/app/srs_app_dtls.hpp @@ -0,0 +1,52 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2013-2020 Winlin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef SRS_APP_DTLS_HPP +#define SRS_APP_DTLS_HPP + +#include + +#include + +#include + +class SrsDtls +{ +private: + static SrsDtls* _instance; +private: + std::string fingerprint; + SSL_CTX* dtls_ctx; +private: + SrsDtls(); + virtual ~SrsDtls(); + + void init(); +public: + static SrsDtls* instance(); + SSL_CTX* get_dtls_ctx() { return dtls_ctx; } +public: + std::string get_fingerprint() const { return fingerprint; } +}; + +#endif diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index 9273f4bd4..fb33382d2 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -49,73 +49,6 @@ using namespace std; #include #include -string test_sdp = -"v=0\\r\\n" -"o=- 0 0 IN IP4 127.0.0.1\\r\\n" -"s=-\\r\\n" -"t=0 0\\r\\n" -"a=ice-lite\\r\\n" -"a=group:BUNDLE 0 1\\r\\n" -"a=msid-semantic: WMS 6VrfBKXrwK\\r\\n" -"m=audio 9 UDP/TLS/RTP/SAVPF 111\\r\\n" -"c=IN IP4 0.0.0.0\\r\\n" -"a=candidate:10 1 udp 2115783679 192.168.170.129 9527 typ host generation 0\\r\\n" -"a=rtcp:9 IN IP4 0.0.0.0\\r\\n" -"a=ice-ufrag:xiaozhihongjohn\\r\\n" -"a=ice-pwd:simple_rtmp_server__john\\r\\n" -"a=ice-options:trickle\\r\\n" -"a=fingerprint:sha-256 76:E8:6A:6D:48:F0:86:58:30:2E:69:56:0F:C6:A1:B8:69:98:5D:73:45:93:37:8E:C4:2B:C7:97:04:18:E4:24\\r\\n" -"a=sendrecv\\r\\n" -"a=mid:0\\r\\n" -"a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\\r\\n" -"a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\\r\\n" -"a=rtcp-mux\\r\\n" -"a=rtpmap:111 opus/48000/2\\r\\n" -"a=fmtp:111 minptime=10;useinbandfec=1\\r\\n" -"a=maxptime:60\\r\\n" -"a=ssrc:3233846890 cname:o/i14u9pJrxRKAsu\\r\\n" -"a=ssrc:3233846890 msid:6VrfBKXrwK a0\\r\\n" -"a=ssrc:3233846890 mslabel:6VrfBKXrwK\\r\\n" -"a=ssrc:3233846890 label:6VrfBKXrwKa0\\r\\n" -"m=video 9 UDP/TLS/RTP/SAVPF 96 98 102\\r\\n" -"c=IN IP4 0.0.0.0\\r\\n" -"a=candidate:10 1 udp 2115783679 192.168.170.129 9527 typ host generation 0\\r\\n" -"a=rtcp:9 IN IP4 0.0.0.0\\r\\n" -"b=as:2000000\\r\\n" -"a=ice-ufrag:xiaozhihongjohn\\r\\n" -"a=ice-pwd:simple_rtmp_server__john\\r\\n" -"a=ice-options:trickle\\r\\n" -"a=extmap:2 urn:ietf:params:rtp-hdrext:toffset\\r\\n" -"a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\\r\\n" -"a=extmap:4 urn:3gpp:video-orientation\\r\\n" -"a=fingerprint:sha-256 76:E8:6A:6D:48:F0:86:58:30:2E:69:56:0F:C6:A1:B8:69:98:5D:73:45:93:37:8E:C4:2B:C7:97:04:18:E4:24\\r\\n" -"a=sendrecv\\r\\n" -"a=mid:1\\r\\n" -"a=rtcp-mux\\r\\n" -"a=rtpmap:96 VP8/90000\\r\\n" -"a=rtcp-fb:96 ccm fir\\r\\n" -"a=rtcp-fb:96 nack\\r\\n" -"a=rtcp-fb:96 nack pli\\r\\n" -"a=rtcp-fb:96 goog-remb\\r\\n" -"a=rtcp-fb:96 transport-cc\\r\\n" -"a=rtpmap:98 VP9/90000\\r\\n" -"a=rtcp-fb:98 ccm fir\\r\\n" -"a=rtcp-fb:98 nack\\r\\n" -"a=rtcp-fb:98 nack pli\\r\\n" -"a=rtcp-fb:98 goog-remb\\r\\n" -"a=rtcp-fb:98 transport-cc\\r\\n" -"a=rtpmap:102 H264/90000\\r\\n" -"a=rtcp-fb:102 goog-remb\\r\\n" -"a=rtcp-fb:102 transport-cc\\r\\n" -"a=rtcp-fb:102 ccm fir \\r\\n" -"a=rtcp-fb:102 nack\\r\\n" -"a=rtcp-fb:102 nack pli \\r\\n" -"a=fmtp:102 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\\r\\n" -"a=ssrc:3233846889 cname:o/i14u9pJrxRKAsu\\r\\n" -"a=ssrc:3233846889 msid:6VrfBKXrwK v0\\r\\n" -"a=ssrc:3233846889 mslabel:6VrfBKXrwK\\r\\n" -"a=ssrc:3233846889 label:6VrfBKXrwKv0\\r\\n"; - srs_error_t srs_api_response_jsonp(ISrsHttpResponseWriter* w, string callback, string data) { srs_error_t err = srs_success; @@ -849,9 +782,10 @@ srs_error_t SrsGoApiStreams::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessa return srs_api_response(w, r, obj->dumps()); } -SrsGoApiSdp::SrsGoApiSdp(SrsServer* svr) +SrsGoApiSdp::SrsGoApiSdp(SrsServer* svr, SrsRtcServer* rtc_svr) { server = svr; + rtc_server = rtc_svr; } SrsGoApiSdp::~SrsGoApiSdp() @@ -888,15 +822,24 @@ srs_error_t SrsGoApiSdp::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* return srs_api_response_code(w, r, SRS_CONSTS_HTTP_BadRequest); } - string remote_sdp = remote_sdp_obj->to_str(); + string remote_sdp_str = remote_sdp_obj->to_str(); string app = app_obj->to_str(); string stream_name = stream_name_obj->to_str(); - srs_trace("remote_sdp=%s", remote_sdp.c_str()); + srs_trace("remote_sdp_str=%s", remote_sdp_str.c_str()); srs_trace("app=%s, stream=%s", app.c_str(), stream_name.c_str()); - SrsSdp srs_sdp; - err = srs_sdp.parse(remote_sdp); + SrsSdp remote_sdp; + err = remote_sdp.decode(remote_sdp_str); + if (err != srs_success) { + return srs_api_response_code(w, r, SRS_CONSTS_HTTP_BadRequest); + } + + SrsSdp local_sdp; + rtc_server->create_rtc_session(remote_sdp, local_sdp); + + string local_sdp_str = ""; + err = local_sdp.encode(local_sdp_str); if (err != srs_success) { return srs_api_response_code(w, r, SRS_CONSTS_HTTP_BadRequest); } @@ -906,9 +849,20 @@ srs_error_t SrsGoApiSdp::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS)); obj->set("server", SrsJsonAny::integer(stat->server_id())); + + string candidate_str = "candidate:1 1 udp 2115783679 192.168.170.129:9527 typ host generation 0 ufrag " + + local_sdp.get_ice_ufrag() + "netwrok-cost 50"; + + SrsJsonObject* candidate_obj = SrsJsonAny::object(); + //SrsAutoFree(SrsJsonObject, candidate_obj); + + candidate_obj->set("candidate", SrsJsonAny::str(candidate_str.c_str())); + candidate_obj->set("sdpMid", SrsJsonAny::str("0")); + candidate_obj->set("sdpMLineIndex", SrsJsonAny::str("0")); if (r->is_http_post()) { - obj->set("sdp", SrsJsonAny::str(test_sdp.c_str())); + obj->set("sdp", SrsJsonAny::str(local_sdp_str.c_str())); + obj->set("candidate", candidate_obj); } else { return srs_go_http_error(w, SRS_CONSTS_HTTP_MethodNotAllowed); } diff --git a/trunk/src/app/srs_app_http_api.hpp b/trunk/src/app/srs_app_http_api.hpp index d77ba517b..c4cf02a6c 100644 --- a/trunk/src/app/srs_app_http_api.hpp +++ b/trunk/src/app/srs_app_http_api.hpp @@ -31,6 +31,7 @@ class ISrsHttpMessage; class SrsHttpParser; class SrsHttpHandler; class SrsServer; +class SrsRtcServer; #include #include @@ -168,8 +169,9 @@ class SrsGoApiSdp : public ISrsHttpHandler { private: SrsServer* server; + SrsRtcServer* rtc_server; public: - SrsGoApiSdp(SrsServer* svr); + SrsGoApiSdp(SrsServer* svr, SrsRtcServer* rtc_svr); virtual ~SrsGoApiSdp(); public: virtual srs_error_t serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r); diff --git a/trunk/src/app/srs_app_listener.cpp b/trunk/src/app/srs_app_listener.cpp index 0cd389df5..2c1703250 100755 --- a/trunk/src/app/srs_app_listener.cpp +++ b/trunk/src/app/srs_app_listener.cpp @@ -59,6 +59,19 @@ srs_error_t ISrsUdpHandler::on_stfd_change(srs_netfd_t /*fd*/) return srs_success; } +ISrsUdpRemuxHandler::ISrsUdpRemuxHandler() +{ +} + +ISrsUdpRemuxHandler::~ISrsUdpRemuxHandler() +{ +} + +srs_error_t ISrsUdpRemuxHandler::on_stfd_change(srs_netfd_t /*fd*/) +{ + return srs_success; +} + ISrsTcpHandler::ISrsTcpHandler() { } @@ -207,12 +220,51 @@ srs_error_t SrsTcpListener::cycle() return err; } -SrsUdpRemuxListener::SrsUdpRemuxListener(ISrsUdpHandler* h, std::string i, int p) : SrsUdpListener(h, i, p) +SrsUdpRemuxListener::SrsUdpRemuxListener(ISrsUdpRemuxHandler* h, std::string i, int p) { + handler = h; + ip = i; + port = p; + lfd = NULL; + + nb_buf = SRS_UDP_MAX_PACKET_SIZE; + buf = new char[nb_buf]; + + trd = new SrsDummyCoroutine(); } SrsUdpRemuxListener::~SrsUdpRemuxListener() { + srs_freep(trd); + srs_close_stfd(lfd); + srs_freepa(buf); +} + +int SrsUdpRemuxListener::fd() +{ + return srs_netfd_fileno(lfd); +} + +srs_netfd_t SrsUdpRemuxListener::stfd() +{ + return lfd; +} + +srs_error_t SrsUdpRemuxListener::listen() +{ + srs_error_t err = srs_success; + + if ((err = srs_udp_listen(ip, port, &lfd)) != srs_success) { + return srs_error_wrap(err, "listen %s:%d", ip.c_str(), port); + } + + srs_freep(trd); + trd = new SrsSTCoroutine("udp", this); + if ((err = trd->start()) != srs_success) { + return srs_error_wrap(err, "start thread"); + } + + return err; } srs_error_t SrsUdpRemuxListener::cycle() @@ -233,9 +285,10 @@ srs_error_t SrsUdpRemuxListener::cycle() continue; } - if ((err = handler->on_udp_packet((const sockaddr*)&from, nb_from, buf, nread)) != srs_success) { + if ((err = handler->on_udp_packet(lfd, (const sockaddr*)&from, nb_from, buf, nread)) != srs_success) { //srs_error("udp handle packet error"); // remux udp never return + srs_error("udp remux error:%s", srs_error_desc(err).c_str()); continue; } diff --git a/trunk/src/app/srs_app_listener.hpp b/trunk/src/app/srs_app_listener.hpp index a667af94d..3b4d96b80 100644 --- a/trunk/src/app/srs_app_listener.hpp +++ b/trunk/src/app/srs_app_listener.hpp @@ -54,6 +54,16 @@ public: virtual srs_error_t on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf) = 0; }; +class ISrsUdpRemuxHandler +{ +public: + ISrsUdpRemuxHandler(); + virtual ~ISrsUdpRemuxHandler(); +public: + virtual srs_error_t on_stfd_change(srs_netfd_t fd); + virtual srs_error_t on_udp_packet(srs_netfd_t fd, const sockaddr* from, const int fromlen, char* buf, int nb_buf) = 0; +}; + // The tcp connection handler. class ISrsTcpHandler { @@ -113,11 +123,27 @@ public: virtual srs_error_t cycle(); }; -class SrsUdpRemuxListener : public SrsUdpListener +class SrsUdpRemuxListener : public ISrsCoroutineHandler { +protected: + srs_netfd_t lfd; + SrsCoroutine* trd; +protected: + char* buf; + int nb_buf; +protected: + ISrsUdpRemuxHandler* handler; + std::string ip; + int port; public: - SrsUdpRemuxListener(ISrsUdpHandler* h, std::string i, int p); + SrsUdpRemuxListener(ISrsUdpRemuxHandler* h, std::string i, int p); virtual ~SrsUdpRemuxListener(); +public: + virtual int fd(); + virtual srs_netfd_t stfd(); +public: + virtual srs_error_t listen(); +// Interface ISrsReusableThreadHandler. public: virtual srs_error_t cycle(); }; diff --git a/trunk/src/app/srs_app_rtc.cpp b/trunk/src/app/srs_app_rtc.cpp index 6f5378125..e7fbf7fc2 100644 --- a/trunk/src/app/srs_app_rtc.cpp +++ b/trunk/src/app/srs_app_rtc.cpp @@ -69,7 +69,7 @@ SrsRtc::~SrsRtc() { } -srs_error_t SrsRtc::on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf) +srs_error_t SrsRtc::on_udp_packet(srs_netfd_t fd, const sockaddr* from, const int fromlen, char* buf, int nb_buf) { char address_string[64]; char port_string[16]; @@ -82,5 +82,5 @@ srs_error_t SrsRtc::on_udp_packet(const sockaddr* from, const int fromlen, char* std::string peer_ip = std::string(address_string); int peer_port = atoi(port_string); - return rtc_server->on_udp_packet(peer_ip, peer_port, buf, nb_buf); + return rtc_server->on_udp_packet(fd, peer_ip, peer_port, from, fromlen, buf, nb_buf); } diff --git a/trunk/src/app/srs_app_rtc.hpp b/trunk/src/app/srs_app_rtc.hpp index 6e1fb0651..8c15bbf16 100644 --- a/trunk/src/app/srs_app_rtc.hpp +++ b/trunk/src/app/srs_app_rtc.hpp @@ -37,7 +37,7 @@ struct sockaddr; class SrsRtcServer; // The rtc over udp stream receiver -class SrsRtc : virtual public ISrsUdpHandler +class SrsRtc : virtual public ISrsUdpRemuxHandler { private: SrsRtcServer* rtc_server; @@ -46,7 +46,7 @@ public: virtual ~SrsRtc(); // Interface ISrsUdpHandler public: - virtual srs_error_t on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf); + virtual srs_error_t on_udp_packet(srs_netfd_t fd, const sockaddr* from, const int fromlen, char* buf, int nb_buf); }; #endif diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 93fca7f8c..2a570b4a9 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -25,24 +25,52 @@ using namespace std; +#include +#include +#include + +#include + #include -#include +#include +#include #include +#include #include +#include -static bool is_stun(const char* data, const int size) { +static bool is_stun(const char* data, const int size) +{ return data != NULL && size > 0 && (data[0] == 0 || data[0] == 1); } -static bool is_rtp_or_rtcp(const char* data, const int size) { +static bool is_rtp_or_rtcp(const char* data, const int size) +{ return data != NULL && size > 0 && (data[0] >= 128 && data[0] <= 191); } -static bool is_dtls(const char* data, const int size) { +static bool is_dtls(const char* data, const int size) +{ return data != NULL && size > 0 && (data[0] >= 20 && data[0] <= 64); } +static string gen_random_str(int len) +{ + static string random_table = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + string ret; + ret.reserve(len); + for (int i = 0; i < len; ++i) { + ret.append(1, random_table[random() % random_table.size()]); + } + + return ret; +} + +const int SRTP_MASTER_KEY_KEY_LEN = 16; +const int SRTP_MASTER_KEY_SALT_LEN = 14; + SrsSdpMediaInfo::SrsSdpMediaInfo() { } @@ -59,16 +87,16 @@ SrsSdp::~SrsSdp() { } -srs_error_t SrsSdp::parse(const string& sdp) +srs_error_t SrsSdp::decode(const string& sdp_str) { srs_error_t err = srs_success; - if (sdp.size() < 2 || sdp[0] != 'v' || sdp[1] != '=') { - return srs_error_wrap(err, "invalid sdp"); + if (sdp_str.size() < 2 || sdp_str[0] != 'v' || sdp_str[1] != '=') { + return srs_error_wrap(err, "invalid sdp_str"); } string line; - istringstream is(sdp); + istringstream is(sdp_str); while (getline(is, line)) { srs_trace("line=%s", line.c_str()); @@ -76,7 +104,7 @@ srs_error_t SrsSdp::parse(const string& sdp) return srs_error_wrap(err, "invalid sdp line=%s", line.c_str()); } - switch (line[1]) { + switch (line[0]) { case 'v' :{ break; } @@ -94,7 +122,7 @@ srs_error_t SrsSdp::parse(const string& sdp) } case 'a' :{ if (parse_attr(line) != srs_success) { - return srs_error_wrap(err, "parse sdp line=%s failed", line.c_str()); + return srs_error_wrap(err, "decode sdp line=%s failed", line.c_str()); } break; } @@ -107,29 +135,354 @@ srs_error_t SrsSdp::parse(const string& sdp) return err; } +srs_error_t SrsSdp::encode(string& sdp_str) +{ + srs_error_t err = srs_success; + + // FIXME: + sdp_str = + "v=0\\r\\n" + "o=- 0 0 IN IP4 127.0.0.1\\r\\n" + "s=-\\r\\n" + "t=0 0\\r\\n" + "a=ice-lite\\r\\n" + "a=group:BUNDLE 0 1\\r\\n" + "a=msid-semantic: WMS 6VrfBKXrwK\\r\\n" + "m=audio 9 UDP/TLS/RTP/SAVPF 111\\r\\n" + "c=IN IP4 0.0.0.0\\r\\n" + "a=candidate:10 1 udp 2115783679 192.168.170.129 9527 typ host generation 0\\r\\n" + "a=rtcp:9 IN IP4 0.0.0.0\\r\\n" + "a=ice-ufrag:" + ice_ufrag + "\\r\\n" + "a=ice-pwd:" + ice_pwd + "\\r\\n" + "a=ice-options:trickle\\r\\n" + "a=fingerprint:sha-256 " + SrsDtls::instance()->get_fingerprint() + "\\r\\n" + "a=sendrecv\\r\\n" + "a=mid:0\\r\\n" + "a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\\r\\n" + "a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\\r\\n" + "a=rtcp-mux\\r\\n" + "a=rtpmap:111 opus/48000/2\\r\\n" + "a=fmtp:111 minptime=10;useinbandfec=1\\r\\n" + "a=maxptime:60\\r\\n" + "a=ssrc:3233846890 cname:o/i14u9pJrxRKAsu\\r\\n" + "a=ssrc:3233846890 msid:6VrfBKXrwK a0\\r\\n" + "a=ssrc:3233846890 mslabel:6VrfBKXrwK\\r\\n" + "a=ssrc:3233846890 label:6VrfBKXrwKa0\\r\\n" + "m=video 9 UDP/TLS/RTP/SAVPF 96 98 102\\r\\n" + "c=IN IP4 0.0.0.0\\r\\n" + "a=candidate:10 1 udp 2115783679 192.168.170.129 9527 typ host generation 0\\r\\n" + "a=rtcp:9 IN IP4 0.0.0.0\\r\\n" + "b=as:2000000\\r\\n" + "a=ice-ufrag:" + ice_ufrag + "\\r\\n" + "a=ice-pwd:" + ice_pwd + "\\r\\n" + "a=ice-options:trickle\\r\\n" + "a=extmap:2 urn:ietf:params:rtp-hdrext:toffset\\r\\n" + "a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\\r\\n" + "a=extmap:4 urn:3gpp:video-orientation\\r\\n" + "a=fingerprint:sha-256 " + SrsDtls::instance()->get_fingerprint() + "\\r\\n" + "a=sendrecv\\r\\n" + "a=mid:1\\r\\n" + "a=rtcp-mux\\r\\n" + "a=rtpmap:96 VP8/90000\\r\\n" + "a=rtcp-fb:96 ccm fir\\r\\n" + "a=rtcp-fb:96 nack\\r\\n" + "a=rtcp-fb:96 nack pli\\r\\n" + "a=rtcp-fb:96 goog-remb\\r\\n" + "a=rtcp-fb:96 transport-cc\\r\\n" + "a=rtpmap:98 VP9/90000\\r\\n" + "a=rtcp-fb:98 ccm fir\\r\\n" + "a=rtcp-fb:98 nack\\r\\n" + "a=rtcp-fb:98 nack pli\\r\\n" + "a=rtcp-fb:98 goog-remb\\r\\n" + "a=rtcp-fb:98 transport-cc\\r\\n" + "a=rtpmap:102 H264/90000\\r\\n" + "a=rtcp-fb:102 goog-remb\\r\\n" + "a=rtcp-fb:102 transport-cc\\r\\n" + "a=rtcp-fb:102 ccm fir \\r\\n" + "a=rtcp-fb:102 nack\\r\\n" + "a=rtcp-fb:102 nack pli \\r\\n" + "a=fmtp:102 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\\r\\n" + "a=ssrc:3233846889 cname:o/i14u9pJrxRKAsu\\r\\n" + "a=ssrc:3233846889 msid:6VrfBKXrwK v0\\r\\n" + "a=ssrc:3233846889 mslabel:6VrfBKXrwK\\r\\n" + "a=ssrc:3233846889 label:6VrfBKXrwKv0\\r\\n"; + + return err; +} + srs_error_t SrsSdp::parse_attr(const string& line) { srs_error_t err = srs_success; + string key = ""; + string val = ""; + string* p = &key; + for (int i = 2; i < line.size(); ++i) { + if (line[i] == ':' && p == &key) { + p = &val; + } else { + if (line[i] != '\r' && line[i] != '\n') { + p->append(1, line[i]); + } + } + } + + srs_trace("sdp attribute key=%s, val=%s", key.c_str(), val.c_str()); + + if (key == "ice-ufrag") { + ice_ufrag = val; + } else if (key == "ice-pwd") { + ice_pwd = val; + } else if (key == "fingerprint") { + + } else { + } + + return err; +} + +SrsDtlsSession::SrsDtlsSession(srs_netfd_t lfd, const sockaddr* f, int fl) +{ + dtls = NULL; + bio_in = NULL; + bio_out = NULL; + + client_key = ""; + server_key = ""; + + srtp_send = NULL; + srtp_recv = NULL; + + fd = lfd; + from = f; + fromlen = fl; + + handshake_done = false; +} + +SrsDtlsSession::~SrsDtlsSession() +{ +} + +srs_error_t SrsDtlsSession::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: { + srs_trace("dtls handshake done"); + handshake_done = true; + srtp_init(); + srtp_sender_side_init(); + srtp_receiver_side_init(); + } + break; + + case SSL_ERROR_WANT_READ: { + break; + } + + case SSL_ERROR_WANT_WRITE: { + break; + } + + default: { + break; + } + } + + if (out_bio_len) { + srs_trace("send dtls handshake data"); + srs_sendto(fd, out_bio_data, out_bio_len, from, fromlen, 0); + } + + return err; +} + +srs_error_t SrsDtlsSession::on_dtls(const char* data, const int len) +{ + srs_error_t err = srs_success; + if (! handshake_done) { + BIO_reset(bio_in); + BIO_reset(bio_out); + BIO_write(bio_in, data, len); + + handshake(); + } else { + BIO_reset(bio_in); + BIO_reset(bio_out); + BIO_write(bio_in, data, len); + + 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) { + on_dtls_application_data(dtls_read_buf, nb); + } + } + } + + return err; +} + +srs_error_t SrsDtlsSession::on_dtls_application_data(const char* buf, const int nb_buf) +{ + srs_error_t err = srs_success; + + return err; +} + + +void SrsDtlsSession::send_client_hello() +{ + if (dtls == NULL) { + srs_trace("send client hello"); + + dtls = SSL_new(SrsDtls::instance()->get_dtls_ctx()); + SSL_set_connect_state(dtls); + + bio_in = BIO_new(BIO_s_mem()); + bio_out = BIO_new(BIO_s_mem()); + + SSL_set_bio(dtls, bio_in, bio_out); + + handshake(); + } +} + +srs_error_t SrsDtlsSession::srtp_init() +{ + 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 + char dtls_srtp_lable[] = "EXTRACTOR-dtls_srtp"; + if (! SSL_export_keying_material(dtls, material, sizeof(material), dtls_srtp_lable, strlen(dtls_srtp_lable), NULL, 0, 0)) { + return srs_error_wrap(err, "SSL_export_keying_material failed"); + } + + size_t offset = 0; + + std::string sClientMasterKey(reinterpret_cast(material), SRTP_MASTER_KEY_KEY_LEN); + offset += SRTP_MASTER_KEY_KEY_LEN; + std::string sServerMasterKey(reinterpret_cast(material + offset), SRTP_MASTER_KEY_KEY_LEN); + offset += SRTP_MASTER_KEY_KEY_LEN; + std::string sClientMasterSalt(reinterpret_cast(material + offset), SRTP_MASTER_KEY_SALT_LEN); + offset += SRTP_MASTER_KEY_SALT_LEN; + std::string sServerMasterSalt(reinterpret_cast(material + offset), SRTP_MASTER_KEY_SALT_LEN); + + client_key = sClientMasterKey + sClientMasterSalt; + server_key = sServerMasterKey + sServerMasterSalt; + + srtp_sender_side_init(); + srtp_receiver_side_init(); +} + +srs_error_t SrsDtlsSession::srtp_sender_side_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_outbound; + + policy.ssrc.value = 0; + policy.window_size = 8192; // seq 相差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; + + if (srtp_create(&srtp_send, &policy) != 0) { + return srs_error_wrap(err, "srtp_create failed"); + } + + delete [] key; + + return err; +} + +srs_error_t SrsDtlsSession::srtp_receiver_side_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; + policy.window_size = 8192; // seq 相差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_recv, &policy) != 0) { + return srs_error_wrap(err, "srtp_create failed"); + } + + delete [] key; + return err; } SrsRtcSession::SrsRtcSession() { session_state = INIT; + dtls_session = NULL; } SrsRtcSession::~SrsRtcSession() { } -srs_error_t SrsRtcSession::on_stun(const SrsStunPacket& stun_packet) +srs_error_t SrsRtcSession::on_binding_request(const SrsStunPacket& stun_packet, const string& peer_ip, const uint16_t peer_port, + SrsStunPacket& stun_binding_response) { srs_error_t err = srs_success; + stun_binding_response.set_message_type(BindingResponse); + stun_binding_response.set_local_ufrag(stun_packet.get_remote_ufrag()); + stun_binding_response.set_remote_ufrag(stun_packet.get_local_ufrag()); + stun_binding_response.set_transcation_id(stun_packet.get_transcation_id()); + stun_binding_response.set_mapped_address(be32toh(inet_addr(peer_ip.c_str()))); + stun_binding_response.set_mapped_port(peer_port); + return err; } +srs_error_t SrsRtcSession::send_client_hello(srs_netfd_t fd, const sockaddr* from, int fromlen) +{ + if (dtls_session == NULL) { + dtls_session = new SrsDtlsSession(fd, from, fromlen); + } + + dtls_session->send_client_hello(); +} + +srs_error_t SrsRtcSession::on_dtls(const char* buf, const int nb_buf) +{ + dtls_session->on_dtls(buf, nb_buf); +} + srs_error_t SrsRtcSession::send_packet() { } @@ -150,59 +503,147 @@ srs_error_t SrsRtcServer::initialize() return err; } -srs_error_t SrsRtcServer::on_udp_packet(const string& peer_ip, const int peer_port, const char* data, const int size) +srs_error_t SrsRtcServer::on_udp_packet(srs_netfd_t fd, const string& peer_ip, const int peer_port, + const sockaddr* from, const int fromlen, const char* data, const int size) { srs_error_t err = srs_success; if (is_stun(data, size)) { - return on_stun(peer_ip, peer_port, data, size); + return on_stun(fd, peer_ip, peer_port, from, fromlen, data, size); } else if (is_dtls(data, size)) { - return on_dtls(peer_ip, peer_port, data, size); + srs_trace("dtls"); + return on_dtls(fd, peer_ip, peer_port, from, fromlen, data, size); } else if (is_rtp_or_rtcp(data, size)) { - return on_rtp_or_rtcp(peer_ip, peer_port, data, size); + return on_rtp_or_rtcp(fd, peer_ip, peer_port, from, fromlen, data, size); } return srs_error_wrap(err, "unknown packet type"); } -srs_error_t SrsRtcServer::on_stun(const string& peer_ip, const int peer_port, const char* data, const int size) +SrsRtcSession* SrsRtcServer::create_rtc_session(const SrsSdp& remote_sdp, SrsSdp& local_sdp) { - srs_error_t err = srs_success; + SrsRtcSession* session = new SrsRtcSession(); - srs_trace("peer %s:%d stun", peer_ip.c_str(), peer_port); + std::string local_ufrag = gen_random_str(8); + std::string local_pwd = gen_random_str(32); - SrsStunPacket stun_packet; - if (stun_packet.decode(data, size) != srs_success) { - return srs_error_wrap(err, "decode stun failed"); + while (true) { + bool ret = map_ufrag_sessions.insert(make_pair(remote_sdp.get_ice_ufrag(), session)).second; + if (ret) { + break; + } } - std::string peer_ufrag = stun_packet.ufrag(); - SrsRtcSession* rtc_session = find_rtc_session(peer_ufrag); - if (rtc_session == NULL) { - return srs_error_wrap(err, "can not find rtc_session, ufrag=%s", peer_ufrag.c_str()); - } + local_sdp.set_ice_ufrag(local_ufrag); + local_sdp.set_ice_pwd(local_pwd); - return rtc_session->on_stun(stun_packet); + session->set_remote_sdp(remote_sdp); + session->set_local_sdp(local_sdp); + + session->set_session_state(WAITING_STUN); + + return session; } -srs_error_t SrsRtcServer::on_dtls(const string& peer_ip, const int peer_port, const char* data, const int size) +SrsRtcSession* SrsRtcServer::find_rtc_session_by_ip_port(const string& peer_ip, const uint16_t peer_port) { - srs_error_t err = srs_success; - return err; -} - -srs_error_t SrsRtcServer::on_rtp_or_rtcp(const string& peer_ip, const int peer_port, const char* data, const int size) -{ - srs_error_t err = srs_success; - return err; -} - -SrsRtcSession* SrsRtcServer::find_rtc_session(const std::string& ufrag) -{ - map::iterator iter = map_sessions.find(ufrag); - if (iter == map_sessions.end()) { + ostringstream os; + os << peer_ip << ":" << peer_port; + string key = os.str(); + map::iterator iter = map_ip_port_sessions.find(key); + if (iter == map_ip_port_sessions.end()) { return NULL; } return iter->second; } + +srs_error_t SrsRtcServer::on_stun(srs_netfd_t fd, const string& peer_ip, const int peer_port, + const sockaddr* from, const int fromlen, const char* data, const int size) +{ + srs_error_t err = srs_success; + + srs_trace("peer %s:%d stun", peer_ip.c_str(), peer_port); + + SrsStunPacket stun_req; + if (stun_req.decode(data, size) != srs_success) { + return srs_error_wrap(err, "decode stun failed"); + } + + std::string remote_ufrag = stun_req.get_remote_ufrag(); + SrsRtcSession* rtc_session = find_rtc_session_by_ufrag(remote_ufrag); + if (rtc_session == NULL) { + return srs_error_wrap(err, "can not find rtc_session, ufrag=%s", remote_ufrag.c_str()); + } + + SrsStunPacket stun_rsp; + char buf[1460]; + SrsBuffer* stream = new SrsBuffer(buf, sizeof(buf)); + SrsAutoFree(SrsBuffer, stream); + + if (stun_req.is_binding_request()) { + if (rtc_session->on_binding_request(stun_req, peer_ip, peer_port, stun_rsp) != srs_success) { + return srs_error_wrap(err, "stun binding request failed"); + } + } + + if (stun_rsp.encode(rtc_session->get_local_sdp()->get_ice_pwd(), stream) != srs_success) { + return srs_error_wrap(err, "stun rsp encode failed"); + } + + srs_sendto(fd, stream->data(), stream->pos(), from, fromlen, 0); + + if (rtc_session->get_session_state() == WAITING_STUN) { + rtc_session->set_session_state(DOING_DTLS_HANDSHAKE); + rtc_session->send_client_hello(fd, from, fromlen); + + insert_into_ip_port_sessions(peer_ip, peer_port, rtc_session); + } + + return err; +} + +srs_error_t SrsRtcServer::on_dtls(srs_netfd_t fd, const string& peer_ip, const int peer_port, + const sockaddr* from, const int fromlen, const char* data, const int size) +{ + srs_error_t err = srs_success; + srs_trace("on dtls"); + + // FIXME + SrsRtcSession* rtc_session = find_rtc_session_by_ip_port(peer_ip, peer_port); + + if (rtc_session == NULL) { + return srs_error_wrap(err, "can not find rtc session by ip=%s, port=%u", peer_ip.c_str(), peer_port); + } + + rtc_session->on_dtls(data, size); + + return err; +} + +srs_error_t SrsRtcServer::on_rtp_or_rtcp(srs_netfd_t fd, const string& peer_ip, const int peer_port, + const sockaddr* from, const int fromlen, const char* data, const int size) +{ + srs_error_t err = srs_success; + srs_trace("on rtp/rtcp"); + return err; +} + +SrsRtcSession* SrsRtcServer::find_rtc_session_by_ufrag(const std::string& ufrag) +{ + map::iterator iter = map_ufrag_sessions.find(ufrag); + if (iter == map_ufrag_sessions.end()) { + return NULL; + } + + return iter->second; +} + +bool SrsRtcServer::insert_into_ip_port_sessions(const string& peer_ip, const uint16_t peer_port, SrsRtcSession* rtc_session) +{ + ostringstream os; + os << peer_ip << ":" << peer_port; + string key = os.str(); + + return map_ip_port_sessions.insert(make_pair(key, rtc_session)).second; +} diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index df370d585..c40076686 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -25,11 +25,15 @@ #define SRS_APP_RTC_CONN_HPP #include +#include #include #include #include +#include +#include + class SrsServer; class SrsStunPacket; @@ -55,7 +59,14 @@ public: SrsSdp(); virtual ~SrsSdp(); - srs_error_t parse(const std::string& sdp); + srs_error_t decode(const std::string& sdp_str); + srs_error_t encode(std::string& sdp_str); + + std::string get_ice_ufrag() const { return ice_ufrag; } + std::string get_ice_pwd() const { return ice_pwd; } + + void set_ice_ufrag(const std::string& u) { ice_ufrag = u; } + void set_ice_pwd(const std::string& p) { ice_pwd = p; } private: srs_error_t parse_attr(const std::string& line); }; @@ -69,19 +80,63 @@ enum SrsRtcSessionStateType CLOSED = 4, }; +class SrsDtlsSession +{ +private: + SSL* dtls; + BIO* bio_in; + BIO* bio_out; + + std::string client_key; + std::string server_key; + + srtp_t srtp_send; + srtp_t srtp_recv; + + srs_netfd_t fd; + const sockaddr* from; + int fromlen; + + bool handshake_done; + +public: + SrsDtlsSession(srs_netfd_t lfd, const sockaddr* f, int fl); + virtual ~SrsDtlsSession(); + + srs_error_t on_dtls(const char* data, const int len); + srs_error_t on_dtls_application_data(const char* data, const int len); + + void send_client_hello(); + srs_error_t handshake(); + srs_error_t srtp_init(); + srs_error_t srtp_sender_side_init(); + srs_error_t srtp_receiver_side_init(); +}; + class SrsRtcSession { -public: private: - SrsSdp peer_sdp; - SrsSdp offer_sdp; + SrsSdp remote_sdp; + SrsSdp local_sdp; SrsRtcSessionStateType session_state; + SrsDtlsSession* dtls_session; public: SrsRtcSession(); virtual ~SrsRtcSession(); + SrsSdp* get_local_sdp() { return &local_sdp; } + SrsSdp* get_remote_sdp() { return &remote_sdp; } + SrsRtcSessionStateType get_session_state() { return session_state; } + + void set_local_sdp(const SrsSdp& sdp) { local_sdp = sdp; } + void set_remote_sdp(const SrsSdp& sdp) { remote_sdp = sdp; } + void set_session_state(SrsRtcSessionStateType state) { session_state = state; } + srs_error_t on_udp_packet(const std::string& peer_ip, const int peer_port, const char* data, const int size); - srs_error_t on_stun(const SrsStunPacket& stun_packet); + srs_error_t on_binding_request(const SrsStunPacket& stun_packet, const std::string& peer_ip, const uint16_t peer_port, + SrsStunPacket& stun_binding_response); + srs_error_t on_dtls(const char* buf, const int nb_buf); + srs_error_t send_client_hello(srs_netfd_t fd, const sockaddr* from, int fromlen); srs_error_t send_packet(); }; @@ -89,19 +144,26 @@ class SrsRtcServer { private: SrsServer* server; - std::map map_sessions; + std::map map_ufrag_sessions; + std::map map_ip_port_sessions; public: SrsRtcServer(SrsServer* svr); virtual ~SrsRtcServer(); public: virtual srs_error_t initialize(); - virtual srs_error_t on_udp_packet(const std::string& peer_ip, const int peer_port, const char* data, const int size); + virtual srs_error_t on_udp_packet(srs_netfd_t fd, const std::string& peer_ip, const int peer_port, + const sockaddr* from, const int fromlen, const char* data, const int size); + + SrsRtcSession* create_rtc_session(const SrsSdp& remote_sdp, SrsSdp& local_sdp); + bool insert_into_ip_port_sessions(const std::string& peer_ip, const uint16_t peer_port, SrsRtcSession* rtc_session); private: - srs_error_t on_stun(const std::string& peer_ip, const int peer_port, const char* data, const int size); - srs_error_t on_dtls(const std::string& peer_ip, const int peer_port, const char* data, const int size); - srs_error_t on_rtp_or_rtcp(const std::string& peer_ip, const int peer_port, const char* data, const int size); + srs_error_t on_stun(srs_netfd_t fd, const std::string& peer_ip, const int peer_port, const sockaddr* from, const int fromlen, const char* data, const int size); + srs_error_t on_dtls(srs_netfd_t fd, const std::string& peer_ip, const int peer_port, const sockaddr* from, const int fromlen, const char* data, const int size); + srs_error_t on_rtp_or_rtcp(srs_netfd_t fd, const std::string& peer_ip, const int peer_port, + const sockaddr* from, const int fromlen, const char* data, const int size); private: - SrsRtcSession* find_rtc_session(const std::string& ufrag); + SrsRtcSession* find_rtc_session_by_ufrag(const std::string& ufrag); + SrsRtcSession* find_rtc_session_by_ip_port(const std::string& peer_ip, const uint16_t peer_port); }; #endif diff --git a/trunk/src/app/srs_app_server.cpp b/trunk/src/app/srs_app_server.cpp index 548ee3cdd..cdd939408 100644 --- a/trunk/src/app/srs_app_server.cpp +++ b/trunk/src/app/srs_app_server.cpp @@ -838,7 +838,7 @@ srs_error_t SrsServer::http_handle() if ((err = http_api_mux->handle("/api/v1/streams/", new SrsGoApiStreams())) != srs_success) { return srs_error_wrap(err, "handle streams"); } - if ((err = http_api_mux->handle("/api/v1/sdp/", new SrsGoApiSdp(this))) != srs_success) { + if ((err = http_api_mux->handle("/api/v1/sdp/", new SrsGoApiSdp(this, rtc_server))) != srs_success) { return srs_error_wrap(err, "handle sdp"); } if ((err = http_api_mux->handle("/api/v1/clients/", new SrsGoApiClients())) != srs_success) { diff --git a/trunk/src/app/srs_app_server.hpp b/trunk/src/app/srs_app_server.hpp index 36e4c8b3f..8fa17ff9d 100644 --- a/trunk/src/app/srs_app_server.hpp +++ b/trunk/src/app/srs_app_server.hpp @@ -162,8 +162,8 @@ public: class SrsRtcListener : public SrsListener { protected: - SrsUdpListener* listener; - ISrsUdpHandler* rtc; + SrsUdpRemuxListener* listener; + ISrsUdpRemuxHandler* rtc; public: SrsRtcListener(SrsServer* svr, SrsRtcServer* rtc_svr, SrsListenerType t); virtual ~SrsRtcListener(); diff --git a/trunk/src/protocol/srs_stun_stack.cpp b/trunk/src/protocol/srs_stun_stack.cpp index 38c8c00a2..50284c785 100644 --- a/trunk/src/protocol/srs_stun_stack.cpp +++ b/trunk/src/protocol/srs_stun_stack.cpp @@ -2,27 +2,271 @@ using namespace std; +#include +#include +#include +#include + +#include +#include +#include +#include + +static string dump_string_hex(const std::string& str, const int& max_len = 128) +{ + char buf[1024*16]; + int len = 0; + + for (int i = 0; i < str.size() && i < max_len; ++i) { + int nb = snprintf(buf + len, sizeof(buf) - len - 1, "%02X ", (uint8_t)str[i]); + if (nb <= 0) + break; + + len += nb; + } + buf[len] = '\0'; + + return string(buf, len); +} + +static srs_error_t hmac_encode(const std::string& algo, const char* key, const int& key_length, + const char* input, const int input_length, char* output, unsigned int& output_length) +{ + srs_error_t err = srs_success; + + const EVP_MD* engine = NULL; + if (algo == "sha512") { + engine = EVP_sha512(); + } else if(algo == "sha256") { + engine = EVP_sha256(); + } else if(algo == "sha1") { + engine = EVP_sha1(); + } else if(algo == "md5") { + engine = EVP_md5(); + } else if(algo == "sha224") { + engine = EVP_sha224(); + } else if(algo == "sha384") { + engine = EVP_sha384(); + } else { + return srs_error_wrap(err, "unknown algo=%s", algo.c_str()); + } + + HMAC_CTX* ctx = HMAC_CTX_new(); + if (HMAC_Init_ex(ctx, key, key_length, engine, NULL) < 0) { + HMAC_CTX_free(ctx); + return srs_error_wrap(err, "hmac init faied"); + } + + if (HMAC_Update(ctx, (const unsigned char*)input, input_length) < 0) { + HMAC_CTX_free(ctx); + return srs_error_wrap(err, "hmac update faied"); + } + + if (HMAC_Final(ctx, (unsigned char*)output, &output_length) < 0) { + HMAC_CTX_free(ctx); + return srs_error_wrap(err, "hmac final faied"); + } + + HMAC_CTX_free(ctx); + + return err; +} + + SrsStunPacket::SrsStunPacket() { + message_type = 0; + local_ufrag = ""; + remote_ufrag = ""; } SrsStunPacket::~SrsStunPacket() { } -string SrsStunPacket::ufrag() -{ - return ""; -} - -string SrsStunPacket::pwd() -{ - return ""; -} - srs_error_t SrsStunPacket::decode(const char* buf, const int nb_buf) { srs_error_t err = srs_success; + SrsBuffer* stream = new SrsBuffer(const_cast(buf), nb_buf); + SrsAutoFree(SrsBuffer, stream); + + if (stream->left() < 20) { + return srs_error_wrap(err, "invalid stun packet, size=%d", stream->size()); + } + + srs_trace("stun packet, nb_buf=%d", nb_buf); + + message_type = stream->read_2bytes(); + uint16_t message_len = stream->read_2bytes(); + string magic_cookie = stream->read_string(4); + transcation_id = stream->read_string(12); + + srs_trace("message_type=%u, message_len=%u, magic_cookie=%s, transcation_id=%s", + message_type, message_len, magic_cookie.c_str(), transcation_id.c_str()); + + if (nb_buf != 20 + message_len) { + return srs_error_wrap(err, "invalid stun packet, message_len=%d, nb_buf=%d", message_len, nb_buf); + } + + while (stream->left() >= 4) { + uint16_t type = stream->read_2bytes(); + uint16_t len = stream->read_2bytes(); + + srs_trace("type=%u, len=%u", type, len); + + if (stream->left() < len) { + return srs_error_wrap(err, "invalid stun packet"); + } + + string val = stream->read_string(len); + // padding + if (len % 4 != 0) { + stream->read_string(4 - (len % 4)); + } + //srs_trace("val=%s", val.c_str()); + + switch (type) { + // FIXME: enum + case 6: { + size_t p = val.find(":"); + if (p != string::npos) { + local_ufrag = val.substr(0, p); + remote_ufrag = val.substr(p + 1); + srs_trace("stun packet local_ufrag=%s, remote_ufrag=%s", local_ufrag.c_str(), remote_ufrag.c_str()); + } + break; + } + + default: { + break; + } + } + } + return err; } + +srs_error_t SrsStunPacket::encode(const string& pwd, SrsBuffer* stream) +{ + srs_error_t err = srs_success; + if (is_binding_response()) { + return encode_binding_response(pwd, stream); + } + + return srs_error_wrap(err, "unknown stun type=%d", get_message_type()); +} + +// FIXME: make this function easy to read +srs_error_t SrsStunPacket::encode_binding_response(const string& pwd, SrsBuffer* stream) +{ + srs_error_t err = srs_success; + + string property_username = encode_username(); + string mapped_address = encode_mapped_address(); + + stream->write_2bytes(BindingResponse); + stream->write_2bytes(property_username.size() + mapped_address.size()); + stream->write_4bytes(0x2112A442); + stream->write_string(transcation_id); + stream->write_string(property_username); + stream->write_string(mapped_address); + + stream->data()[2] = ((stream->pos() - 20 + 20 + 4) & 0x0000FF00) >> 8; + stream->data()[3] = ((stream->pos() - 20 + 20 + 4) & 0x000000FF); + + char hmac_buf[20] = {0}; + unsigned int hmac_buf_len = 0; + if (hmac_encode("sha1", pwd.c_str(), pwd.size(), stream->data(), stream->pos(), hmac_buf, hmac_buf_len) != srs_success) { + return srs_error_wrap(err, "hmac encode failed"); + } + + string hmac = encode_hmac(hmac_buf, hmac_buf_len); + + stream->write_string(hmac); + stream->data()[2] = ((stream->pos() - 20 + 8) & 0x0000FF00) >> 8; + stream->data()[3] = ((stream->pos() - 20 + 8) & 0x000000FF); + + uint32_t crc32 = srs_crc32_ieee(stream->data(), stream->pos(), 0) ^ 0x5354554E; + + string fingerprint = encode_fingerprint(crc32); + + stream->write_string(fingerprint); + + stream->data()[2] = ((stream->pos() - 20) & 0x0000FF00) >> 8; + stream->data()[3] = ((stream->pos() - 20) & 0x000000FF); + + return err; +} + +string SrsStunPacket::encode_username() +{ + char buf[1460]; + SrsBuffer* stream = new SrsBuffer(buf, sizeof(buf)); + SrsAutoFree(SrsBuffer, stream); + + string username = remote_ufrag + ":" + local_ufrag; + + stream->write_2bytes(Username); + stream->write_2bytes(username.size()); + stream->write_string(username); + + if (stream->pos() % 4 != 0) { + static char padding[4] = {0}; + stream->write_bytes(padding, 4 - (stream->pos() % 4)); + } + + return string(stream->data(), stream->pos()); +} + +string SrsStunPacket::encode_mapped_address() +{ + char buf[1460]; + SrsBuffer* stream = new SrsBuffer(buf, sizeof(buf)); + SrsAutoFree(SrsBuffer, stream); + + uint32_t magic_cookie = 0x2112A442; +#if 1 + stream->write_2bytes(XorMappedAddress); + stream->write_2bytes(8); + stream->write_1bytes(0); // ignore this bytes + stream->write_1bytes(1); // ipv4 family + stream->write_2bytes(mapped_port ^ (magic_cookie >> 16)); + stream->write_4bytes(mapped_address ^ magic_cookie); +#else + stream->write_2bytes(MappedAddress); + stream->write_2bytes(8); + stream->write_1bytes(0); // ignore this bytes + stream->write_1bytes(1); // ipv4 family + stream->write_2bytes(mapped_port); + stream->write_4bytes(mapped_address); +#endif + + return string(stream->data(), stream->pos()); +} + +string SrsStunPacket::encode_hmac(char* hmac_buf, const int hmac_buf_len) +{ + char buf[1460]; + SrsBuffer* stream = new SrsBuffer(buf, sizeof(buf)); + SrsAutoFree(SrsBuffer, stream); + + stream->write_2bytes(MessageIntegrity); + stream->write_2bytes(hmac_buf_len); + stream->write_bytes(hmac_buf, hmac_buf_len); + + return string(stream->data(), stream->pos()); +} + +string SrsStunPacket::encode_fingerprint(uint32_t crc32) +{ + char buf[1460]; + SrsBuffer* stream = new SrsBuffer(buf, sizeof(buf)); + SrsAutoFree(SrsBuffer, stream); + + stream->write_2bytes(Fingerprint); + stream->write_2bytes(4); + stream->write_4bytes(crc32); + + return string(stream->data(), stream->pos()); +} diff --git a/trunk/src/protocol/srs_stun_stack.hpp b/trunk/src/protocol/srs_stun_stack.hpp index 61269050a..80bba8a15 100644 --- a/trunk/src/protocol/srs_stun_stack.hpp +++ b/trunk/src/protocol/srs_stun_stack.hpp @@ -29,16 +29,81 @@ #include #include +class SrsBuffer; + +enum SrsStunMessageType +{ + // see @ https://tools.ietf.org/html/rfc3489#section-11.1 + BindingRequest = 0x0001, + BindingResponse = 0x0101, + BindingErrorResponse = 0x0111, + SharedSecretRequest = 0x0002, + SharedSecretResponse = 0x0102, + SharedSecretErrorResponse = 0x0112, +}; + +enum SrsStunMessageAttribute +{ + // see @ https://tools.ietf.org/html/rfc3489#section-11.2 + MappedAddress = 0x0001, + ResponseAddress = 0x0002, + ChangeRequest = 0x0003, + SourceAddress = 0x0004, + ChangedAddress = 0x0005, + Username = 0x0006, + Password = 0x0007, + MessageIntegrity = 0x0008, + ErrorCode = 0x0009, + UnknownAttributes = 0x000A, + ReflectedFrom = 0x000B, + + // see @ https://tools.ietf.org/html/rfc5389#section-18.2 + Realm = 0x0014, + Nonce = 0x0015, + XorMappedAddress = 0x0020, + Software = 0x8022, + AlternateServer = 0x8023, + Fingerprint = 0x8028, +}; + class SrsStunPacket { +private: + uint16_t message_type; + std::string local_ufrag; + std::string remote_ufrag; + std::string transcation_id; + uint32_t mapped_address; + uint16_t mapped_port; public: SrsStunPacket(); virtual ~SrsStunPacket(); - std::string ufrag(); - std::string pwd(); + bool is_binding_request() const { return message_type == BindingRequest; } + bool is_binding_response() const { return message_type == BindingResponse; } + + uint16_t get_message_type() const { return message_type; } + std::string get_local_ufrag() const { return local_ufrag; } + std::string get_remote_ufrag() const { return remote_ufrag; } + std::string get_transcation_id() const { return transcation_id; } + uint32_t get_mapped_address() const { return mapped_address; } + uint16_t get_mapped_port() const { return mapped_port; } + + void set_message_type(const uint16_t& m) { message_type = m; } + void set_local_ufrag(const std::string& u) { local_ufrag = u; } + void set_remote_ufrag(const std::string& u) { remote_ufrag = u; } + void set_transcation_id(const std::string& t) { transcation_id = t; } + void set_mapped_address(const uint32_t& addr) { mapped_address = addr; } + void set_mapped_port(const uint32_t& port) { mapped_port = port; } srs_error_t decode(const char* buf, const int nb_buf); + srs_error_t encode(const std::string& pwd, SrsBuffer* stream); +private: + srs_error_t encode_binding_response(const std::string& pwd, SrsBuffer* stream); + std::string encode_username(); + std::string encode_mapped_address(); + std::string encode_hmac(char* hamc_buf, const int hmac_buf_len); + std::string encode_fingerprint(uint32_t crc32); }; #endif diff --git a/trunk/src/service/srs_service_st.cpp b/trunk/src/service/srs_service_st.cpp index f63cd4279..555ff5a33 100644 --- a/trunk/src/service/srs_service_st.cpp +++ b/trunk/src/service/srs_service_st.cpp @@ -397,6 +397,11 @@ int srs_recvfrom(srs_netfd_t stfd, void *buf, int len, struct sockaddr *from, in return st_recvfrom((st_netfd_t)stfd, buf, len, from, fromlen, (st_utime_t)timeout); } +int srs_sendto(srs_netfd_t stfd, void *buf, int len, const struct sockaddr * to, int tolen, srs_utime_t timeout) +{ + return st_sendto((st_netfd_t)stfd, buf, len, to, tolen, (st_utime_t)timeout); +} + srs_netfd_t srs_accept(srs_netfd_t stfd, struct sockaddr *addr, int *addrlen, srs_utime_t timeout) { return (srs_netfd_t)st_accept((st_netfd_t)stfd, addr, addrlen, (st_utime_t)timeout); diff --git a/trunk/src/service/srs_service_st.hpp b/trunk/src/service/srs_service_st.hpp index 510b9ba8a..4894e7049 100644 --- a/trunk/src/service/srs_service_st.hpp +++ b/trunk/src/service/srs_service_st.hpp @@ -88,6 +88,7 @@ extern srs_netfd_t srs_netfd_open_socket(int osfd); extern srs_netfd_t srs_netfd_open(int osfd); extern int srs_recvfrom(srs_netfd_t stfd, void *buf, int len, struct sockaddr *from, int *fromlen, srs_utime_t timeout); +extern int srs_sendto(srs_netfd_t stfd, void *buf, int len, const struct sockaddr *to, int tolen, srs_utime_t timeout); extern srs_netfd_t srs_accept(srs_netfd_t stfd, struct sockaddr *addr, int *addrlen, srs_utime_t timeout);