diff --git a/3rdpart/ZLToolKit b/3rdpart/ZLToolKit index de2ca7e6..74ddbaa7 160000 --- a/3rdpart/ZLToolKit +++ b/3rdpart/ZLToolKit @@ -1 +1 @@ -Subproject commit de2ca7e61cb3154199d909088d8c12e91ecda577 +Subproject commit 74ddbaa7e7c6995e94062a5ba1c7f0f2adef43f4 diff --git a/3rdpart/media-server b/3rdpart/media-server index 4a3cfe9e..d6034e7e 160000 --- a/3rdpart/media-server +++ b/3rdpart/media-server @@ -1 +1 @@ -Subproject commit 4a3cfe9edf0d72b249fb75a855b61be35a8c853a +Subproject commit d6034e7e3572bcd557fd88438c10b98c5fabdd13 diff --git a/src/Common/Parser.cpp b/src/Common/Parser.cpp index 669b7798..3b76adc5 100644 --- a/src/Common/Parser.cpp +++ b/src/Common/Parser.cpp @@ -8,7 +8,10 @@ * may be found in the AUTHORS file in the root of the source tree. */ +#include #include "Parser.h" +#include "macros.h" +#include "Network/sockutil.h" using namespace std; using namespace toolkit; @@ -38,9 +41,6 @@ string FindField(const char* buf, const char* start, const char *end ,size_t buf return string(msg_start, msg_end); } -Parser::Parser() {} -Parser::~Parser() {} - void Parser::Parse(const char *buf) { //解析 const char *start = buf; @@ -160,4 +160,81 @@ StrCaseMap Parser::parseArgs(const string &str, const char *pair_delim, const ch return ret; } +void RtspUrl::parse(const string &strUrl) { + auto schema = FindField(strUrl.data(), nullptr, "://"); + bool is_ssl = strcasecmp(schema.data(), "rtsps") == 0; + //查找"://"与"/"之间的字符串,用于提取用户名密码 + auto middle_url = FindField(strUrl.data(), "://", "/"); + if (middle_url.empty()) { + middle_url = FindField(strUrl.data(), "://", nullptr); + } + auto pos = middle_url.rfind('@'); + if (pos == string::npos) { + //并没有用户名密码 + return setup(is_ssl, strUrl, "", ""); + } + + //包含用户名密码 + auto user_pwd = middle_url.substr(0, pos); + auto suffix = strUrl.substr(schema.size() + 3 + pos + 1); + auto url = StrPrinter << "rtsp://" << suffix << endl; + if (user_pwd.find(":") == string::npos) { + return setup(is_ssl, url, user_pwd, ""); + } + auto user = FindField(user_pwd.data(), nullptr, ":"); + auto pwd = FindField(user_pwd.data(), ":", nullptr); + return setup(is_ssl, url, user, pwd); +} + +void RtspUrl::setup(bool is_ssl, const string &url, const string &user, const string &passwd) { + auto ip = FindField(url.data(), "://", "/"); + if (ip.empty()) { + ip = split(FindField(url.data(), "://", NULL), "?")[0]; + } + uint16_t port = is_ssl ? 322 : 554; + splitUrl(ip, ip, port); + + _url = std::move(url); + _user = std::move(user); + _passwd = std::move(passwd); + _host = std::move(ip); + _port = port; + _is_ssl = is_ssl; +} + +static void inline checkHost(std::string &host) { + if (host.back() == ']' && host.front() == '[') { + // ipv6去除方括号 + host.pop_back(); + host.erase(0, 1); + CHECK(SockUtil::is_ipv6(host.data()), "not a ipv6 address:", host); + } +} + +void splitUrl(const std::string &url, std::string &host, uint16_t &port) { + auto pos = url.rfind(':'); + if (pos == string::npos || url.back() == ']') { + //没有冒号,未指定端口;或者是纯粹的ipv6地址 + host = url; + checkHost(host); + return; + } + CHECK(pos > 0, "invalid url:", port); + CHECK(sscanf(url.data() + pos + 1, "%" SCNu16, &port) == 1, "parse port from url failed:", url); + host = url.substr(0, pos); + checkHost(host); +} + +#if 0 +//测试代码 +static onceToken token([](){ + string host; + uint16_t port; + splitUrl("www.baidu.com:8880", host, port); + splitUrl("192.168.1.1:8880", host, port); + splitUrl("[::]:8880", host, port); + splitUrl("[fe80::604d:4173:76e9:1009]:8880", host, port); +}); +#endif + }//namespace mediakit \ No newline at end of file diff --git a/src/Common/Parser.h b/src/Common/Parser.h index b0c53bb2..4e0485a2 100644 --- a/src/Common/Parser.h +++ b/src/Common/Parser.h @@ -17,7 +17,10 @@ namespace mediakit { +//从字符串中提取子字符串 std::string FindField(const char *buf, const char *start, const char *end, size_t bufSize = 0); +//把url解析为主机地址和端口号,兼容ipv4/ipv6/dns +void splitUrl(const std::string &url, std::string &host, uint16_t& port); struct StrCaseCompare { bool operator()(const std::string &__x, const std::string &__y) const { @@ -57,8 +60,8 @@ public: //rtsp/http/sip解析类 class Parser { public: - Parser(); - ~Parser(); + Parser() = default; + ~Parser() = default; //解析信令 void Parse(const char *buf); @@ -113,6 +116,25 @@ private: mutable StrCaseMap _mapUrlArgs; }; +//解析rtsp url的工具类 +class RtspUrl{ +public: + bool _is_ssl; + uint16_t _port; + std::string _url; + std::string _user; + std::string _passwd; + std::string _host; + +public: + RtspUrl() = default; + ~RtspUrl() = default; + void parse(const std::string &url); + +private: + void setup(bool,const std::string &, const std::string &, const std::string &); +}; + }//namespace mediakit #endif //ZLMEDIAKIT_PARSER_H diff --git a/src/Http/HttpClient.cpp b/src/Http/HttpClient.cpp index 30fe327d..ab5da258 100644 --- a/src/Http/HttpClient.cpp +++ b/src/Http/HttpClient.cpp @@ -22,13 +22,13 @@ void HttpClient::sendRequest(const string &url) { clearResponse(); _url = url; auto protocol = FindField(url.data(), NULL, "://"); - uint16_t default_port; + uint16_t port; bool is_https; if (strcasecmp(protocol.data(), "http") == 0) { - default_port = 80; + port = 80; is_https = false; } else if (strcasecmp(protocol.data(), "https") == 0) { - default_port = 443; + port = 443; is_https = true; } else { auto strErr = StrPrinter << "非法的http url:" << url << endl; @@ -53,14 +53,7 @@ void HttpClient::sendRequest(const string &url) { _header.emplace("Authorization", "Basic " + encodeBase64(authStr)); } auto host_header = host; - uint16_t port = atoi(FindField(host.data(), ":", NULL).data()); - if (port <= 0) { - //默认端口 - port = default_port; - } else { - //服务器域名 - host = FindField(host.data(), NULL, ":"); - } + splitUrl(host, host, port); _header.emplace("Host", host_header); _header.emplace("User-Agent", kServerName); _header.emplace("Connection", "keep-alive"); diff --git a/src/Rtmp/RtmpPlayer.cpp b/src/Rtmp/RtmpPlayer.cpp index fa3ec496..440a91a7 100644 --- a/src/Rtmp/RtmpPlayer.cpp +++ b/src/Rtmp/RtmpPlayer.cpp @@ -57,14 +57,9 @@ void RtmpPlayer::play(const string &strUrl) { } DebugL << host_url << " " << _app << " " << _stream_id; - auto iPort = atoi(FindField(host_url.data(), ":", NULL).data()); - if (iPort <= 0) { - //rtmp 默认端口1935 - iPort = 1935; - } else { - //服务器域名 - host_url = FindField(host_url.data(), NULL, ":"); - } + uint16_t port = 1935; + splitUrl(host_url, host_url, port); + if (!(*this)[Client::kNetAdapter].empty()) { setNetAdapter((*this)[Client::kNetAdapter]); } @@ -81,7 +76,7 @@ void RtmpPlayer::play(const string &strUrl) { }, getPoller())); _metadata_got = false; - startConnect(host_url, iPort, play_timeout_sec); + startConnect(host_url, port, play_timeout_sec); } void RtmpPlayer::onErr(const SockException &ex){ diff --git a/src/Rtmp/RtmpPusher.cpp b/src/Rtmp/RtmpPusher.cpp index 016796a8..8725b088 100644 --- a/src/Rtmp/RtmpPusher.cpp +++ b/src/Rtmp/RtmpPusher.cpp @@ -74,14 +74,8 @@ void RtmpPusher::publish(const string &url) { } DebugL << host_url << " " << _app << " " << _stream_id; - auto iPort = atoi(FindField(host_url.data(), ":", NULL).data()); - if (iPort <= 0) { - //rtmp 默认端口1935 - iPort = 1935; - } else { - //服务器域名 - host_url = FindField(host_url.data(), NULL, ":"); - } + uint16_t port = 1935; + splitUrl(host_url, host_url, port); weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); float publishTimeOutSec = (*this)[Client::kTimeoutMS].as() / 1000.0f; @@ -98,7 +92,7 @@ void RtmpPusher::publish(const string &url) { setNetAdapter((*this)[Client::kNetAdapter]); } - startConnect(host_url, iPort); + startConnect(host_url, port); } void RtmpPusher::onErr(const SockException &ex){ diff --git a/src/Rtsp/Rtsp.cpp b/src/Rtsp/Rtsp.cpp index 188ec14e..0aeeb63a 100644 --- a/src/Rtsp/Rtsp.cpp +++ b/src/Rtsp/Rtsp.cpp @@ -312,59 +312,6 @@ string SdpParser::toString() const { return title + video + audio; } -bool RtspUrl::parse(const string &strUrl) { - auto schema = FindField(strUrl.data(), nullptr, "://"); - bool isSSL = strcasecmp(schema.data(), "rtsps") == 0; - //查找"://"与"/"之间的字符串,用于提取用户名密码 - auto middle_url = FindField(strUrl.data(), "://", "/"); - if (middle_url.empty()) { - middle_url = FindField(strUrl.data(), "://", nullptr); - } - auto pos = middle_url.rfind('@'); - if (pos == string::npos) { - //并没有用户名密码 - return setup(isSSL, strUrl, "", ""); - } - - //包含用户名密码 - auto user_pwd = middle_url.substr(0, pos); - auto suffix = strUrl.substr(schema.size() + 3 + pos + 1); - auto url = StrPrinter << "rtsp://" << suffix << endl; - if (user_pwd.find(":") == string::npos) { - return setup(isSSL, url, user_pwd, ""); - } - auto user = FindField(user_pwd.data(), nullptr, ":"); - auto pwd = FindField(user_pwd.data(), ":", nullptr); - return setup(isSSL, url, user, pwd); -} - -bool RtspUrl::setup(bool isSSL, const string &strUrl, const string &strUser, const string &strPwd) { - auto ip = FindField(strUrl.data(), "://", "/"); - if (ip.empty()) { - ip = split(FindField(strUrl.data(), "://", NULL), "?")[0]; - } - auto port = atoi(FindField(ip.data(), ":", NULL).data()); - if (port <= 0 || port > UINT16_MAX) { - //rtsp 默认端口554 - port = isSSL ? 322 : 554; - } else { - //服务器域名 - ip = FindField(ip.data(), NULL, ":"); - } - - if (ip.empty()) { - return false; - } - - _url = std::move(strUrl); - _user = std::move(strUser); - _passwd = std::move(strPwd); - _host = std::move(ip); - _port = port; - _is_ssl = isSSL; - return true; -} - class PortManager : public std::enable_shared_from_this { public: PortManager() { diff --git a/src/Rtsp/Rtsp.h b/src/Rtsp/Rtsp.h index 8743add0..31e0c79b 100644 --- a/src/Rtsp/Rtsp.h +++ b/src/Rtsp/Rtsp.h @@ -252,27 +252,6 @@ private: std::vector _track_vec; }; -/** - * 解析rtsp url的工具类 - */ -class RtspUrl{ -public: - bool _is_ssl; - uint16_t _port; - std::string _url; - std::string _user; - std::string _passwd; - std::string _host; - -public: - RtspUrl() = default; - ~RtspUrl() = default; - bool parse(const std::string &url); - -private: - bool setup(bool,const std::string &, const std::string &, const std::string &); -}; - /** * rtsp sdp基类 */ diff --git a/src/Rtsp/RtspPlayer.cpp b/src/Rtsp/RtspPlayer.cpp index da8530b5..4924522b 100644 --- a/src/Rtsp/RtspPlayer.cpp +++ b/src/Rtsp/RtspPlayer.cpp @@ -66,8 +66,10 @@ void RtspPlayer::teardown(){ void RtspPlayer::play(const string &strUrl){ RtspUrl url; - if(!url.parse(strUrl)){ - onPlayResult_l(SockException(Err_other,StrPrinter << "illegal rtsp url:" << strUrl),false); + try { + url.parse(strUrl); + } catch (std::exception &ex) { + onPlayResult_l(SockException(Err_other, StrPrinter << "illegal rtsp url:" << ex.what()), false); return; } diff --git a/src/Rtsp/RtspPusher.cpp b/src/Rtsp/RtspPusher.cpp index 7b9cb3e2..a1fc6e48 100644 --- a/src/Rtsp/RtspPusher.cpp +++ b/src/Rtsp/RtspPusher.cpp @@ -56,8 +56,10 @@ void RtspPusher::teardown() { void RtspPusher::publish(const string &url_str) { RtspUrl url; - if (!url.parse(url_str)) { - onPublishResult_l(SockException(Err_other, StrPrinter << "illegal rtsp url:" << url_str), false); + try { + url.parse(url_str); + } catch (std::exception &ex) { + onPublishResult_l(SockException(Err_other, StrPrinter << "illegal rtsp url:" << ex.what()), false); return; }