diff --git a/trunk/conf/rtc.conf b/trunk/conf/rtc.conf new file mode 100644 index 000000000..5af4172b0 --- /dev/null +++ b/trunk/conf/rtc.conf @@ -0,0 +1,38 @@ +# main config for srs. +# @see full.conf for detail config. + +listen 1935; +max_connections 1000; +srs_log_tank file; +srs_log_file ./objs/srs.log; +http_api { + enabled on; + listen 1985; + raw_api { + enabled on; + allow_reload on; + allow_query on; + allow_update on; + } +} +http_server { + enabled on; + listen 8080; + dir ./objs/nginx/html; +} +rtc { + enabled on; + listen 9527; +} +stats { + network 0; + disk sda sdb xvda xvdb; +} +vhost __defaultVhost__ { + http_remux { + enabled on; + mount [vhost]/[app]/[stream].flv; + } +} + + diff --git a/trunk/configure b/trunk/configure index 5efe7eb59..5de5bc31d 100755 --- a/trunk/configure +++ b/trunk/configure @@ -214,7 +214,7 @@ ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSSLRoot}) MODULE_FILES=("srs_protocol_amf0" "srs_protocol_io" "srs_rtmp_stack" "srs_rtmp_handshake" "srs_protocol_utility" "srs_rtmp_msg_array" "srs_protocol_stream" "srs_raw_avc" "srs_rtsp_stack" "srs_http_stack" "srs_protocol_kbps" "srs_protocol_json" - "srs_protocol_format") + "srs_stun_stack" "srs_protocol_format") PROTOCOL_INCS="src/protocol"; MODULE_DIR=${PROTOCOL_INCS} . auto/modules.sh PROTOCOL_OBJS="${MODULE_OBJS[@]}" # diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index 634ba647c..570d14662 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -46,6 +46,7 @@ using namespace std; #include #include #include +#include string test_sdp = "v=0\\r\\n" @@ -847,8 +848,9 @@ srs_error_t SrsGoApiStreams::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessa return srs_api_response(w, r, obj->dumps()); } -SrsGoApiSdp::SrsGoApiSdp() +SrsGoApiSdp::SrsGoApiSdp(SrsServer* svr) { + server = svr; } SrsGoApiSdp::~SrsGoApiSdp() @@ -872,6 +874,14 @@ srs_error_t SrsGoApiSdp::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* SrsJsonObject* obj = SrsJsonAny::object(); SrsAutoFree(SrsJsonObject, obj); + + SrsRtcListener* rtc_listener = dynamic_cast(server->find_listener(SrsListenerRtcOverUdp)); + if (rtc_listener == NULL) { + return srs_go_http_error(w, SRS_CONSTS_HTTP_Unauthorized); + } + + SrsRtcOverUdp* rtc = rtc_listener->get_rtc(); + rtc->create_rtc_session("192.168.170.169", "xiaozhihongjohn", "ok"); obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS)); obj->set("server", SrsJsonAny::integer(stat->server_id())); diff --git a/trunk/src/app/srs_app_http_api.hpp b/trunk/src/app/srs_app_http_api.hpp index 367edabab..d77ba517b 100644 --- a/trunk/src/app/srs_app_http_api.hpp +++ b/trunk/src/app/srs_app_http_api.hpp @@ -166,8 +166,10 @@ public: class SrsGoApiSdp : public ISrsHttpHandler { +private: + SrsServer* server; public: - SrsGoApiSdp(); + SrsGoApiSdp(SrsServer* svr); virtual ~SrsGoApiSdp(); public: virtual srs_error_t serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r); diff --git a/trunk/src/app/srs_app_rtc_udp.cpp b/trunk/src/app/srs_app_rtc_udp.cpp index 4866c387a..190c8b2c1 100644 --- a/trunk/src/app/srs_app_rtc_udp.cpp +++ b/trunk/src/app/srs_app_rtc_udp.cpp @@ -36,21 +36,39 @@ using namespace std; #include #include #include -#include #include -#include #include #include -#include #include #include +#include +#include #include -#include -#include #include -#include #include +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) { + return data != NULL && size > 0 && (data[0] >= 128 && data[0] <= 191); +} + +static bool is_dtls(const char* data, const int size) { + return data != NULL && size > 0 && (data[0] >= 20 && data[0] <= 64); +} + +SrsRtcUserInfo::SrsRtcUserInfo(const std::string& u, const std::string& p) +{ + username = u; + password = p; +} + +SrsRtcUserInfo::~SrsRtcUserInfo() +{ +} + SrsRtcOverUdp::SrsRtcOverUdp() { } @@ -59,6 +77,30 @@ SrsRtcOverUdp::~SrsRtcOverUdp() { } +SrsRtcSession* SrsRtcOverUdp::create_rtc_session(const std::string& peer_ip, const std::string& remote_username, const std::string& remote_password) +{ + SrsRtcSession* rtc_session = new SrsRtcSession(); + // TODO: process exception when session already exist + user_session_map[peer_ip].insert(make_pair(SrsRtcUserInfo(remote_username, remote_password), rtc_session)).second; + + return rtc_session; +} + +SrsRtcSession* SrsRtcOverUdp::find_rtc_session_by_user_info(const std::string& peer_ip, const std::string& remote_username, const std::string& remote_password) +{ + std::map >::iterator iter = user_session_map.find(peer_ip); + if (iter == user_session_map.end()) { + return NULL; + } + + std::map::iterator sub_iter = iter->second.find(SrsRtcUserInfo(remote_username, remote_password)); + if (sub_iter == iter->second.end()) { + return NULL; + } + + return sub_iter->second; +} + srs_error_t SrsRtcOverUdp::on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf) { char address_string[64]; @@ -71,19 +113,120 @@ srs_error_t SrsRtcOverUdp::on_udp_packet(const sockaddr* from, const int fromlen } std::string peer_ip = std::string(address_string); int peer_port = atoi(port_string); - - srs_error_t err = on_udp_bytes(peer_ip, peer_port, buf, nb_buf); - if (err != srs_success) { - return srs_error_wrap(err, "process udp"); - } - return err; + + std::string peer_id = peer_ip + ":" + std::string(port_string); + + return on_udp_bytes(peer_ip, peer_port, peer_id, buf, nb_buf); } -srs_error_t SrsRtcOverUdp::on_udp_bytes(string host, int port, char* buf, int nb_buf) +SrsRtcSession* SrsRtcOverUdp::find_rtc_session_by_peer_id(const std::string& peer_id) +{ + map::iterator iter = id_session_map.find(peer_id); + if (iter == id_session_map.end()) { + return NULL; + } + + return iter->second; +} + +srs_error_t SrsRtcOverUdp::on_udp_bytes(const string& host, const int& port, const string& peer_id, char* buf, int nb_buf) { srs_error_t err = srs_success; - srs_trace("recv rtc udp packet from %s:%d, nb_buf=%d", host.c_str(), port, nb_buf); + srs_trace("recv rtc udp packet from %s:%d, peer_id=%s, nb_buf=%d", host.c_str(), port, peer_id.c_str(), nb_buf); + + if (is_rtp_or_rtcp(buf, nb_buf)) { + err = on_rtp_or_rtcp(host, port, peer_id, buf, nb_buf); + } else if (is_stun(buf, nb_buf)) { + err = on_stun(host, port, peer_id, buf, nb_buf); + } else if (is_dtls(buf, nb_buf)) { + err = on_dtls(host, port, peer_id, buf, nb_buf); + } else { + return srs_error_wrap(err, "unknown udp packet"); + } return err; } + +srs_error_t SrsRtcOverUdp::on_rtp_or_rtcp(const string& host, const int& port, const string& peer_id, const char* buf, int nb_buf) { + srs_error_t err = srs_success; + + SrsRtcSession* rtc_session = find_rtc_session_by_peer_id(peer_id); + if (rtc_session == NULL) { + return srs_error_wrap(err, "can't find rtc session in rtp/rtcp host=%s, port=%d", + host.c_str(), port); + } + + SrsRtpPacket rtp_packet; + SrsBuffer buffer(const_cast(buf), nb_buf); + rtp_packet.decode(&buffer); + + rtc_session->on_rtp_or_rtcp(&rtp_packet); + + return err; +} + +srs_error_t SrsRtcOverUdp::on_stun(const string& host, const int& port, const string& peer_id, const char* buf, int nb_buf) { + srs_error_t err = srs_success; + + SrsStunPacket stun_packet; + stun_packet.decode(buf, nb_buf); + + SrsRtcSession* rtc_session = find_rtc_session_by_user_info(host, stun_packet.username(), stun_packet.password()); + if (rtc_session == NULL) { + return err; + return srs_error_wrap(err, "can't find rtc session in stun host=%s, port=%d, username=%s, password=%s", + host.c_str(), port, stun_packet.username().c_str(), stun_packet.password().c_str()); + } + + // TODO: process when session mismatch + id_session_map[peer_id] = rtc_session; + + rtc_session->on_stun(&stun_packet); + + return err; +} + +srs_error_t SrsRtcOverUdp::on_dtls(const string& host, const int& port, const string& peer_id, const char* buf, int nb_buf) { + srs_error_t err = srs_success; + + SrsRtcSession* rtc_session = find_rtc_session_by_peer_id(peer_id); + if (rtc_session == NULL) { + return srs_error_wrap(err, "can't find rtc session in dtls host=%s, port=%d", + host.c_str(), port); + } + + rtc_session->on_dtls(); + + return err; +} + +SrsRtcSession::SrsRtcSession() +{ +} + +SrsRtcSession::~SrsRtcSession() +{ +} + +srs_error_t SrsRtcSession::on_rtp_or_rtcp(SrsRtpPacket* rtp_packet) +{ + srs_error_t err = srs_success; + + return err; +} + +srs_error_t SrsRtcSession::on_stun(SrsStunPacket* stun_packet) +{ + srs_error_t err = srs_success; + + return err; +} + +srs_error_t SrsRtcSession::on_dtls() +{ + srs_error_t err = srs_success; + + return err; +} + diff --git a/trunk/src/app/srs_app_rtc_udp.hpp b/trunk/src/app/srs_app_rtc_udp.hpp index 707b6b830..405805549 100644 --- a/trunk/src/app/srs_app_rtc_udp.hpp +++ b/trunk/src/app/srs_app_rtc_udp.hpp @@ -34,18 +34,62 @@ struct sockaddr; #include #include +class SrsRtcSession; + +class SrsRtcUserInfo { +private: + std::string username; + std::string password; +public: + SrsRtcUserInfo(const std::string& u, const std::string& p); + ~SrsRtcUserInfo(); + + bool operator<(const SrsRtcUserInfo& rhs) const + { + return username < rhs.username && password < rhs.password; + } +}; + // The rtc over udp stream receiver class SrsRtcOverUdp : virtual public ISrsUdpHandler { private: + std::map id_session_map; // ip:port => session + std::map > user_session_map; public: SrsRtcOverUdp(); virtual ~SrsRtcOverUdp(); + + SrsRtcSession* create_rtc_session(const std::string& peer_ip, const std::string& remote_username, const std::string& remote_password); + SrsRtcSession* find_rtc_session_by_user_info(const std::string& peer_ip, const std::string& remote_username, const std::string& remote_password); + SrsRtcSession* find_rtc_session_by_peer_id(const std::string& peer_id); // Interface ISrsUdpHandler public: virtual srs_error_t on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf); private: - virtual srs_error_t on_udp_bytes(std::string host, int port, char* buf, int nb_buf); + virtual srs_error_t on_udp_bytes(const std::string& host, const int& port, const std::string& peer_id, char* buf, int nb_buf); + srs_error_t on_rtp_or_rtcp(const std::string& host, const int& port, const std::string& peer_id, const char* buf, int nb_buf); + srs_error_t on_stun(const std::string& host, const int& port, const std::string& peer_id, const char* buf, int nb_buf); + srs_error_t on_dtls(const std::string& host, const int& port, const std::string& peer_id, const char* buf, int nb_buf); +}; + +class SrsRtpPacket; +class SrsStunPacket; + +class SrsRtcSession +{ +private: + std::string local_username; + std::string local_password; + std::string remote_username; + std::string remote_password; +public: + SrsRtcSession(); + virtual ~SrsRtcSession(); + + srs_error_t on_rtp_or_rtcp(SrsRtpPacket* rtp_packet); + srs_error_t on_stun(SrsStunPacket* stun_packet); + srs_error_t on_dtls(); }; #endif diff --git a/trunk/src/app/srs_app_server.cpp b/trunk/src/app/srs_app_server.cpp index 85483a5b9..b833803f2 100644 --- a/trunk/src/app/srs_app_server.cpp +++ b/trunk/src/app/srs_app_server.cpp @@ -348,6 +348,12 @@ SrsRtcListener::~SrsRtcListener() { } + +SrsRtcOverUdp* SrsRtcListener::get_rtc() +{ + return dynamic_cast(rtc); +} + srs_error_t SrsRtcListener::listen(std::string i, int p) { srs_error_t err = srs_success; @@ -836,7 +842,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())) != srs_success) { + if ((err = http_api_mux->handle("/api/v1/sdp/", new SrsGoApiSdp(this))) != srs_success) { return srs_error_wrap(err, "handle sdp"); } if ((err = http_api_mux->handle("/api/v1/clients/", new SrsGoApiClients())) != srs_success) { @@ -1282,6 +1288,23 @@ void SrsServer::close_listeners(SrsListenerType type) } } +SrsListener* SrsServer::find_listener(SrsListenerType type) +{ + std::vector::iterator it; + for (it = listeners.begin(); it != listeners.end();) { + SrsListener* listener = *it; + + if (listener->listen_type() != type) { + ++it; + continue; + } + + return *it; + } + + return NULL; +} + void SrsServer::resample_kbps() { SrsStatistic* stat = SrsStatistic::instance(); diff --git a/trunk/src/app/srs_app_server.hpp b/trunk/src/app/srs_app_server.hpp index 77b8964df..a8ac87d78 100644 --- a/trunk/src/app/srs_app_server.hpp +++ b/trunk/src/app/srs_app_server.hpp @@ -157,6 +157,8 @@ public: virtual ~SrsUdpCasterListener(); }; +class SrsRtcOverUdp; + // A UDP listener, for udp stream caster server. class SrsRtcListener : public SrsListener { @@ -166,6 +168,8 @@ protected: public: SrsRtcListener(SrsServer* svr, SrsListenerType t); virtual ~SrsRtcListener(); + + SrsRtcOverUdp* get_rtc(); public: virtual srs_error_t listen(std::string i, int p); }; @@ -335,6 +339,8 @@ public: public: virtual srs_error_t on_publish(SrsSource* s, SrsRequest* r); virtual void on_unpublish(SrsSource* s, SrsRequest* r); +// listeners commuction + virtual SrsListener* find_listener(SrsListenerType type); }; #endif diff --git a/trunk/src/protocol/srs_stun_stack.cpp b/trunk/src/protocol/srs_stun_stack.cpp new file mode 100644 index 000000000..5273f5ee0 --- /dev/null +++ b/trunk/src/protocol/srs_stun_stack.cpp @@ -0,0 +1,28 @@ +#include + +using namespace std; + +SrsStunPacket::SrsStunPacket() +{ +} + +SrsStunPacket::~SrsStunPacket() +{ +} + +string SrsStunPacket::username() +{ + return ""; +} + +string SrsStunPacket::password() +{ + return ""; +} + +srs_error_t SrsStunPacket::decode(const char* buf, const int& nb_buf) +{ + srs_error_t err = srs_success; + + return err; +} diff --git a/trunk/src/protocol/srs_stun_stack.hpp b/trunk/src/protocol/srs_stun_stack.hpp new file mode 100644 index 000000000..7f1522c2a --- /dev/null +++ b/trunk/src/protocol/srs_stun_stack.hpp @@ -0,0 +1,43 @@ +/** + * 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_PROTOCOL_STUN_HPP +#define SRS_PROTOCOL_STUN_HPP + +#include + +#include +#include + +class SrsStunPacket { +public: + SrsStunPacket(); + virtual ~SrsStunPacket(); + + std::string username(); + std::string password(); + + srs_error_t decode(const char* buf, const int& nb_buf); +}; + +#endif