全面支持ipv6

This commit is contained in:
ziyue 2022-05-08 16:33:33 +08:00
parent a95bf960e0
commit a44334acaf
11 changed files with 125 additions and 114 deletions

@ -1 +1 @@
Subproject commit de2ca7e61cb3154199d909088d8c12e91ecda577 Subproject commit 74ddbaa7e7c6995e94062a5ba1c7f0f2adef43f4

@ -1 +1 @@
Subproject commit 4a3cfe9edf0d72b249fb75a855b61be35a8c853a Subproject commit d6034e7e3572bcd557fd88438c10b98c5fabdd13

View File

@ -8,7 +8,10 @@
* may be found in the AUTHORS file in the root of the source tree. * may be found in the AUTHORS file in the root of the source tree.
*/ */
#include <inttypes.h>
#include "Parser.h" #include "Parser.h"
#include "macros.h"
#include "Network/sockutil.h"
using namespace std; using namespace std;
using namespace toolkit; 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); return string(msg_start, msg_end);
} }
Parser::Parser() {}
Parser::~Parser() {}
void Parser::Parse(const char *buf) { void Parser::Parse(const char *buf) {
//解析 //解析
const char *start = buf; const char *start = buf;
@ -160,4 +160,81 @@ StrCaseMap Parser::parseArgs(const string &str, const char *pair_delim, const ch
return ret; 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 }//namespace mediakit

View File

@ -17,7 +17,10 @@
namespace mediakit { namespace mediakit {
//从字符串中提取子字符串
std::string FindField(const char *buf, const char *start, const char *end, size_t bufSize = 0); 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 { struct StrCaseCompare {
bool operator()(const std::string &__x, const std::string &__y) const { bool operator()(const std::string &__x, const std::string &__y) const {
@ -57,8 +60,8 @@ public:
//rtsp/http/sip解析类 //rtsp/http/sip解析类
class Parser { class Parser {
public: public:
Parser(); Parser() = default;
~Parser(); ~Parser() = default;
//解析信令 //解析信令
void Parse(const char *buf); void Parse(const char *buf);
@ -113,6 +116,25 @@ private:
mutable StrCaseMap _mapUrlArgs; 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 }//namespace mediakit
#endif //ZLMEDIAKIT_PARSER_H #endif //ZLMEDIAKIT_PARSER_H

View File

@ -22,13 +22,13 @@ void HttpClient::sendRequest(const string &url) {
clearResponse(); clearResponse();
_url = url; _url = url;
auto protocol = FindField(url.data(), NULL, "://"); auto protocol = FindField(url.data(), NULL, "://");
uint16_t default_port; uint16_t port;
bool is_https; bool is_https;
if (strcasecmp(protocol.data(), "http") == 0) { if (strcasecmp(protocol.data(), "http") == 0) {
default_port = 80; port = 80;
is_https = false; is_https = false;
} else if (strcasecmp(protocol.data(), "https") == 0) { } else if (strcasecmp(protocol.data(), "https") == 0) {
default_port = 443; port = 443;
is_https = true; is_https = true;
} else { } else {
auto strErr = StrPrinter << "非法的http url:" << url << endl; auto strErr = StrPrinter << "非法的http url:" << url << endl;
@ -53,14 +53,7 @@ void HttpClient::sendRequest(const string &url) {
_header.emplace("Authorization", "Basic " + encodeBase64(authStr)); _header.emplace("Authorization", "Basic " + encodeBase64(authStr));
} }
auto host_header = host; auto host_header = host;
uint16_t port = atoi(FindField(host.data(), ":", NULL).data()); splitUrl(host, host, port);
if (port <= 0) {
//默认端口
port = default_port;
} else {
//服务器域名
host = FindField(host.data(), NULL, ":");
}
_header.emplace("Host", host_header); _header.emplace("Host", host_header);
_header.emplace("User-Agent", kServerName); _header.emplace("User-Agent", kServerName);
_header.emplace("Connection", "keep-alive"); _header.emplace("Connection", "keep-alive");

View File

@ -57,14 +57,9 @@ void RtmpPlayer::play(const string &strUrl) {
} }
DebugL << host_url << " " << _app << " " << _stream_id; DebugL << host_url << " " << _app << " " << _stream_id;
auto iPort = atoi(FindField(host_url.data(), ":", NULL).data()); uint16_t port = 1935;
if (iPort <= 0) { splitUrl(host_url, host_url, port);
//rtmp 默认端口1935
iPort = 1935;
} else {
//服务器域名
host_url = FindField(host_url.data(), NULL, ":");
}
if (!(*this)[Client::kNetAdapter].empty()) { if (!(*this)[Client::kNetAdapter].empty()) {
setNetAdapter((*this)[Client::kNetAdapter]); setNetAdapter((*this)[Client::kNetAdapter]);
} }
@ -81,7 +76,7 @@ void RtmpPlayer::play(const string &strUrl) {
}, getPoller())); }, getPoller()));
_metadata_got = false; _metadata_got = false;
startConnect(host_url, iPort, play_timeout_sec); startConnect(host_url, port, play_timeout_sec);
} }
void RtmpPlayer::onErr(const SockException &ex){ void RtmpPlayer::onErr(const SockException &ex){

View File

@ -74,14 +74,8 @@ void RtmpPusher::publish(const string &url) {
} }
DebugL << host_url << " " << _app << " " << _stream_id; DebugL << host_url << " " << _app << " " << _stream_id;
auto iPort = atoi(FindField(host_url.data(), ":", NULL).data()); uint16_t port = 1935;
if (iPort <= 0) { splitUrl(host_url, host_url, port);
//rtmp 默认端口1935
iPort = 1935;
} else {
//服务器域名
host_url = FindField(host_url.data(), NULL, ":");
}
weak_ptr<RtmpPusher> weakSelf = dynamic_pointer_cast<RtmpPusher>(shared_from_this()); weak_ptr<RtmpPusher> weakSelf = dynamic_pointer_cast<RtmpPusher>(shared_from_this());
float publishTimeOutSec = (*this)[Client::kTimeoutMS].as<int>() / 1000.0f; float publishTimeOutSec = (*this)[Client::kTimeoutMS].as<int>() / 1000.0f;
@ -98,7 +92,7 @@ void RtmpPusher::publish(const string &url) {
setNetAdapter((*this)[Client::kNetAdapter]); setNetAdapter((*this)[Client::kNetAdapter]);
} }
startConnect(host_url, iPort); startConnect(host_url, port);
} }
void RtmpPusher::onErr(const SockException &ex){ void RtmpPusher::onErr(const SockException &ex){

View File

@ -312,59 +312,6 @@ string SdpParser::toString() const {
return title + video + audio; 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<PortManager> { class PortManager : public std::enable_shared_from_this<PortManager> {
public: public:
PortManager() { PortManager() {

View File

@ -252,27 +252,6 @@ private:
std::vector<SdpTrack::Ptr> _track_vec; std::vector<SdpTrack::Ptr> _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基类 * rtsp sdp基类
*/ */

View File

@ -66,8 +66,10 @@ void RtspPlayer::teardown(){
void RtspPlayer::play(const string &strUrl){ void RtspPlayer::play(const string &strUrl){
RtspUrl url; RtspUrl url;
if(!url.parse(strUrl)){ try {
onPlayResult_l(SockException(Err_other,StrPrinter << "illegal rtsp url:" << strUrl),false); url.parse(strUrl);
} catch (std::exception &ex) {
onPlayResult_l(SockException(Err_other, StrPrinter << "illegal rtsp url:" << ex.what()), false);
return; return;
} }

View File

@ -56,8 +56,10 @@ void RtspPusher::teardown() {
void RtspPusher::publish(const string &url_str) { void RtspPusher::publish(const string &url_str) {
RtspUrl url; RtspUrl url;
if (!url.parse(url_str)) { try {
onPublishResult_l(SockException(Err_other, StrPrinter << "illegal rtsp url:" << url_str), false); url.parse(url_str);
} catch (std::exception &ex) {
onPublishResult_l(SockException(Err_other, StrPrinter << "illegal rtsp url:" << ex.what()), false);
return; return;
} }