mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
gb28181模块可用性增强
主要改动, 1. 支持作为GB/T 28181上级平台 2. 新的目录接口sip_query_devicelist (/api/v1/gb28181?action=sip_query_devicelist) 3. 各种异常和问题修复 4. 其他一些小改动 以上改动基于feature/rtc分支,因为需要网页用WebRTC来拉GB28181的监控流,gb28181分支代码有点老了。 下面的序号n是指第n个差异块("@@ -"之间的内容)。 srs_gb28181.html 1. 原页面上多加了一个端口号 2-4. 给摄像头加上名称显示 5. 查询目录去掉chid 6. 删除通道参数分解为id和chid 7. API端口固定为1985 srs_app_gb28181.cpp 1-4. 四处因为错误而退出GB28181媒体处理循环,修改为不退出 5. payload为空异常 6. 修正判断startcode越界一个字符导致内存写越界的问题 ps流有可能末尾是全零填充,而且越界的那个字符正好是0x01,这样会多出一个nalu(末尾的三个0x00和一个越界的0x01),后面写video_data内存越界(if (first_pos != pre_pos){块,此处size - pre_pos - 4为-1,uint32_t naluLen得到的值为0,video_data[pre_pos+3] = p[0];写越界)破坏了其他数据,后续video_stream析构出错程序异常退出。 7. 此处srs后来已修复 8. 更新ssrc为被叫返回的值 原代码只支持标准中的《点播域内设备媒体流SSRC处理方式》(设备注册上来),不支持《点播外域设备媒体流SSRC处理方式》(即作为上级平台)。 这是因为如果srs作为上级平台,ssrc不是自己生成的,而是下级平台生成的。 9. 删除通道参数分解为id和chid 10. notify_sip_unregister后delete_stream_channel无效 11. notify_sip_query_catalog清空内存中的设备列表 12. 新函数query_device_list srs_app_gb28181.hpp 1. update_rtmpmuxer_to_newssrc_by_id声明 2. 新函数get_gb28181_config_ptr和函数delete_stream_channel声明修改 3. 新函数query_device_list srs_app_gb28181_sip.cpp 1-4. 在调试界面给摄像头加上名称显示;新函数clear_device_list和新函数dumpItemList 5-6. 两处因为错误而退出GB28181信令处理循环,修改为不退出 7. 设备注册上来,不检查服务器ID匹不匹配(支持作为上级平台) 8. 收到一个目录上报消息,更新内存中的数据 9. 更新ssrc为被叫返回的值 10. 新函数query_device_list srs_app_gb28181_sip.hpp 1. 在调试界面给摄像头加上名称显示 2. 每个设备加上item_list,用于存储目录;新函数clear_device_list和新函数dumpItemList 3. 新函数clear_device_list srs_app_http_api.cpp 1. 删除通道参数分解为id和chid 2. 新的接口sip_query_devicelist,用于查询所有设备的目录 srs_sip_stack.cpp 1. GB2312转UTF-8类 2. 被叫返回的ssrc初始化 3. parse_xml声明修改 4. 对XML内容进行字符集检测和转换 5-7. parse_xml定义修改 8. SIP BODY里面也有可能有\r\n 9-10. 防止恶意SIP消息 by vicious sip prober 11-12. 新的XML解析目录代码 13. 获取被叫返回的ssrc srs_sip_stack.hpp 1. 依赖vector 2. 每个设备加上item_list,用于存储目录 3. 被叫返回的ssrc 4. parse_xml声明修改
This commit is contained in:
parent
fe65c7bf84
commit
ffae1720ec
8 changed files with 370 additions and 53 deletions
|
@ -43,6 +43,66 @@ using namespace std;
|
|||
#include <srs_kernel_codec.hpp>
|
||||
#include <srs_rtsp_stack.hpp>
|
||||
|
||||
#include <iconv.h>
|
||||
|
||||
/* Code (GB2312 <--> UTF-8) Convert Class */
|
||||
class CodeConverter
|
||||
{
|
||||
private:
|
||||
iconv_t cd;
|
||||
public:
|
||||
CodeConverter(const char *pFromCharset, const char *pToCharset)
|
||||
{
|
||||
cd = iconv_open(pToCharset, pFromCharset);
|
||||
if ((iconv_t)(-1) == cd)
|
||||
srs_warn("CodeConverter: iconv_open failed <%s --> %s>", pFromCharset, pToCharset);
|
||||
}
|
||||
~CodeConverter()
|
||||
{
|
||||
if ((iconv_t)(-1) != cd)
|
||||
iconv_close(cd);
|
||||
}
|
||||
int Convert(char *pInBuf, size_t InLen, char *pOutBuf, size_t OutLen)
|
||||
{
|
||||
return iconv(cd, &pInBuf, (size_t *)&InLen, &pOutBuf, (size_t *)&OutLen);
|
||||
}
|
||||
static bool IsUTF8(const char *pInBuf, int InLen)
|
||||
{
|
||||
if (InLen < 0)
|
||||
return false;
|
||||
int i = 0;
|
||||
int nBytes = 0; //UTF8可用1-6个字节编码
|
||||
unsigned char chr = 0;
|
||||
|
||||
while (i < InLen)
|
||||
{
|
||||
chr = *(pInBuf + i);
|
||||
if (nBytes == 0) //计算字节数
|
||||
{
|
||||
if ((chr & 0x80) != 0)
|
||||
{
|
||||
while ((chr & 0x80) != 0)
|
||||
{
|
||||
chr <<= 1;
|
||||
nBytes++;
|
||||
}
|
||||
if (nBytes < 2 || nBytes > 6)
|
||||
return false; //第一个字节最少为110x xxxx
|
||||
nBytes--; //减去自身占的一个字节
|
||||
}
|
||||
}
|
||||
else //多字节除了第一个字节外剩下的字节
|
||||
{
|
||||
if ((chr & 0xc0) != 0x80)
|
||||
return false; //剩下的字节都是10xx xxxx的形式
|
||||
nBytes--;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
return nBytes == 0;
|
||||
}
|
||||
};
|
||||
|
||||
unsigned int srs_sip_random(int min,int max)
|
||||
{
|
||||
//it is possible to duplicate data with time(0)
|
||||
|
@ -202,6 +262,7 @@ SrsSipRequest::SrsSipRequest()
|
|||
|
||||
from_realm = "";
|
||||
to_realm = "";
|
||||
y_ssrc = 0;
|
||||
}
|
||||
|
||||
SrsSipRequest::~SrsSipRequest()
|
||||
|
@ -321,7 +382,7 @@ srs_error_t SrsSipStack::parse_request(SrsSipRequest** preq, const char* recv_ms
|
|||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsSipStack::parse_xml(std::string xml_msg, std::map<std::string, std::string> &json_map)
|
||||
srs_error_t SrsSipStack::parse_xml(std::string xml_msg, std::map<std::string, std::string> &json_map, std::vector<std::map<std::string, std::string> > &item_list)
|
||||
{
|
||||
/*
|
||||
<?xml version="1.0" encoding="gb2312"?>
|
||||
|
@ -340,7 +401,16 @@ srs_error_t SrsSipStack::parse_xml(std::string xml_msg, std::map<std::string, st
|
|||
</Info>
|
||||
</Notify>
|
||||
*/
|
||||
|
||||
|
||||
if (CodeConverter::IsUTF8(xml_msg.c_str(), xml_msg.size()) == false) {
|
||||
char *outBuf = (char *)calloc(1, xml_msg.size() * 2);
|
||||
CodeConverter cc("gb2312", "utf-8");
|
||||
if (cc.Convert((char *)xml_msg.c_str(), xml_msg.size(), (char *)outBuf, xml_msg.size() * 2 - 1) != -1)
|
||||
xml_msg = string(outBuf);
|
||||
if (outBuf)
|
||||
free(outBuf);
|
||||
}
|
||||
|
||||
const char* start = xml_msg.c_str();
|
||||
const char* end = start + xml_msg.size();
|
||||
char* p = (char*)start;
|
||||
|
@ -349,9 +419,11 @@ srs_error_t SrsSipStack::parse_xml(std::string xml_msg, std::map<std::string, st
|
|||
|
||||
std::string xml_header;
|
||||
int xml_layer = 0;
|
||||
int in_item_tag = 0;
|
||||
|
||||
//std::map<string, string> json_map;
|
||||
std::map<int, string> json_key;
|
||||
std::map<std::string, std::string> one_item;
|
||||
while (p < end) {
|
||||
if (p[0] == '\n'){
|
||||
p +=1;
|
||||
|
@ -409,10 +481,26 @@ srs_error_t SrsSipStack::parse_xml(std::string xml_msg, std::map<std::string, st
|
|||
json_map[mkey] = json_map[mkey] + ","+ value;
|
||||
}
|
||||
}
|
||||
|
||||
if (in_item_tag && value != "" && (xml_layer - in_item_tag) == 2) {
|
||||
// (xml_layer - in_item_tag) == 2, this condition filters all deeper tags under tag "Item"
|
||||
one_item[key] = value;
|
||||
}
|
||||
|
||||
value_start = NULL;
|
||||
xml_layer--;
|
||||
|
||||
if (json_key[xml_layer] == "Item") {
|
||||
// std::map<string, string>::iterator it2;
|
||||
// for (it2 = one_item.begin(); it2 != one_item.end(); ++it2) {
|
||||
// srs_trace("========one_item========%s:%s", it2->first.c_str(), it2->second.c_str());
|
||||
// }
|
||||
// srs_trace("========one_item end========");
|
||||
in_item_tag = 0;
|
||||
// all items (DeviceList, Alarmstatus, RecordList) have "DeviceID"
|
||||
if (one_item.find("DeviceID") != one_item.end())
|
||||
item_list.push_back(one_item);
|
||||
}
|
||||
} else if (p[0] == '<') { //<Notify> xml item begin flag
|
||||
//skip <
|
||||
p +=1;
|
||||
|
@ -443,6 +531,11 @@ srs_error_t SrsSipStack::parse_xml(std::string xml_msg, std::map<std::string, st
|
|||
//json_key[0] = "Notify"
|
||||
//json_key[1] = "info"
|
||||
json_key[xml_layer] = key;
|
||||
if (json_key[xml_layer] == "Item") {
|
||||
// "Item" won't be the first layer (xml_layer is 0)
|
||||
in_item_tag = xml_layer;
|
||||
one_item.clear();
|
||||
}
|
||||
xml_layer++;
|
||||
}
|
||||
|
||||
|
@ -476,7 +569,10 @@ srs_error_t SrsSipStack::do_parse_request(SrsSipRequest* req, const char* recv_m
|
|||
std::string body = "";
|
||||
|
||||
if (header_body.size() > 1){
|
||||
body = header_body.at(1);
|
||||
// SRS_RTSP_CRLFCRLF may exist in content body (h3c)
|
||||
string recv_str(recv_msg);
|
||||
body = recv_str.substr(recv_str.find(SRS_RTSP_CRLFCRLF) + strlen(SRS_RTSP_CRLFCRLF));
|
||||
//body = header_body.at(1);
|
||||
}
|
||||
|
||||
srs_info("sip: header=%s\n", header.c_str());
|
||||
|
@ -588,15 +684,15 @@ srs_error_t SrsSipStack::do_parse_request(SrsSipRequest* req, const char* recv_m
|
|||
|
||||
std::vector<std::string> method_uri_ver = srs_string_split(firstline, " ");
|
||||
|
||||
if (method_uri_ver.empty()) {
|
||||
return srs_error_new(ERROR_GB28181_SIP_PRASE_FAILED, "parse request firstline is empty");
|
||||
if (method_uri_ver.empty() || method_uri_ver.size() < 3) {
|
||||
return srs_error_new(ERROR_GB28181_SIP_PRASE_FAILED, "parse request firstline is empty or less than 3 fields");
|
||||
}
|
||||
|
||||
//respone first line text:SIP/2.0 200 OK
|
||||
if (!strcasecmp(method_uri_ver.at(0).c_str(), "sip/2.0")) {
|
||||
req->cmdtype = SrsSipCmdRespone;
|
||||
//req->method= vec_seq.at(1);
|
||||
req->status = method_uri_ver.size() > 0 ? method_uri_ver.at(1) : "";
|
||||
req->status = method_uri_ver.size() > 1 ? method_uri_ver.at(1) : "";
|
||||
req->version = method_uri_ver.at(0);
|
||||
req->uri = req->from;
|
||||
|
||||
|
@ -607,8 +703,8 @@ srs_error_t SrsSipStack::do_parse_request(SrsSipRequest* req, const char* recv_m
|
|||
}else {//request first line text :MESSAGE sip:34020000002000000001@3402000000 SIP/2.0
|
||||
req->cmdtype = SrsSipCmdRequest;
|
||||
req->method= method_uri_ver.at(0);
|
||||
req->uri = method_uri_ver.size() > 0 ? method_uri_ver.at(1) : "";
|
||||
req->version = method_uri_ver.size() > 1 ? method_uri_ver.at(2) : "";
|
||||
req->uri = method_uri_ver.size() > 1 ? method_uri_ver.at(1) : "";
|
||||
req->version = method_uri_ver.size() > 2 ? method_uri_ver.at(2) : "";
|
||||
|
||||
vector<string> str = srs_string_split(req->from, "@");
|
||||
std::string ss = str.empty() ? "" : str.at(0);
|
||||
|
@ -619,20 +715,20 @@ srs_error_t SrsSipStack::do_parse_request(SrsSipRequest* req, const char* recv_m
|
|||
|
||||
//Content-Type: Application/MANSCDP+xml
|
||||
if (!strcasecmp(req->content_type.c_str(),"application/manscdp+xml")){
|
||||
std::map<std::string, std::string> body_map;
|
||||
//xml to map
|
||||
if ((err = parse_xml(body, body_map)) != srs_success) {
|
||||
if ((err = parse_xml(body, req->xml_body_map, req->item_list)) != srs_success) {
|
||||
return srs_error_wrap(err, "sip parse xml");
|
||||
};
|
||||
|
||||
//Response Cmd
|
||||
if (body_map.find("Response") != body_map.end()){
|
||||
std::string cmdtype = body_map["Response@CmdType"];
|
||||
if (req->xml_body_map.find("Response") != req->xml_body_map.end()){
|
||||
std::string cmdtype = req->xml_body_map["Response@CmdType"];
|
||||
if (cmdtype == "Catalog"){
|
||||
#if 0
|
||||
//Response@DeviceList@Item@DeviceID:3000001,3000002
|
||||
std::vector<std::string> vec_device_id = srs_string_split(body_map["Response@DeviceList@Item@DeviceID"], ",");
|
||||
std::vector<std::string> vec_device_id = srs_string_split(req->xml_body_map["Response@DeviceList@Item@DeviceID"], ",");
|
||||
//Response@DeviceList@Item@Status:ON,OFF
|
||||
std::vector<std::string> vec_device_status = srs_string_split(body_map["Response@DeviceList@Item@Status"], ",");
|
||||
std::vector<std::string> vec_device_status = srs_string_split(req->xml_body_map["Response@DeviceList@Item@Status"], ",");
|
||||
|
||||
//map key:devicd_id value:status
|
||||
for(int i=0 ; i< (int)vec_device_id.size(); i++){
|
||||
|
@ -643,16 +739,28 @@ srs_error_t SrsSipStack::do_parse_request(SrsSipRequest* req, const char* recv_m
|
|||
|
||||
req->device_list_map[vec_device_id.at(i)] = status;
|
||||
}
|
||||
#endif
|
||||
for(int i=0 ; i< (int)req->item_list.size(); i++){
|
||||
std::map<std::string, std::string> one_item = req->item_list.at(i);
|
||||
std::string status;
|
||||
if (one_item.find("Status") != one_item.end() && one_item.find("Name") != one_item.end()) {
|
||||
status = one_item["Status"] + "," + one_item["Name"];
|
||||
} else {
|
||||
// if no Status, it's not a camera but a group
|
||||
continue;
|
||||
}
|
||||
req->device_list_map[one_item["DeviceID"]] = status;
|
||||
}
|
||||
}else{
|
||||
//TODO: fixme
|
||||
srs_trace("sip: Response cmdtype=%s not processed", cmdtype.c_str());
|
||||
}
|
||||
} //Notify Cmd
|
||||
else if (body_map.find("Notify") != body_map.end()){
|
||||
std::string cmdtype = body_map["Notify@CmdType"];
|
||||
else if (req->xml_body_map.find("Notify") != req->xml_body_map.end()){
|
||||
std::string cmdtype = req->xml_body_map["Notify@CmdType"];
|
||||
if (cmdtype == "Keepalive"){
|
||||
//TODO: ????
|
||||
std::vector<std::string> vec_device_id = srs_string_split(body_map["Notify@Info@DeviceID"], ",");
|
||||
std::vector<std::string> vec_device_id = srs_string_split(req->xml_body_map["Notify@Info@DeviceID"], ",");
|
||||
for(int i=0; i< (int)vec_device_id.size(); i++){
|
||||
//req->device_list_map[vec_device_id.at(i)] = "OFF";
|
||||
}
|
||||
|
@ -660,8 +768,20 @@ srs_error_t SrsSipStack::do_parse_request(SrsSipRequest* req, const char* recv_m
|
|||
//TODO: fixme
|
||||
srs_trace("sip: Notify cmdtype=%s not processed", cmdtype.c_str());
|
||||
}
|
||||
}// end if(body_map)
|
||||
}// end if(req->xml_body_map)
|
||||
}//end if (!strcasecmp)
|
||||
else if (!strcasecmp(req->content_type.c_str(),"application/sdp")) {
|
||||
std::vector<std::string> sdp_lines = srs_string_split(body.c_str(), SRS_RTSP_CRLF);
|
||||
for(int i=0 ; i< (int)sdp_lines.size(); i++){
|
||||
if (!strncasecmp(sdp_lines.at(i).c_str(), "y=", 2)) {
|
||||
string yline = sdp_lines.at(i);
|
||||
string ssrc = yline.substr(2);
|
||||
req->y_ssrc = strtoul(ssrc.c_str(), NULL, 10);
|
||||
srs_trace("gb28181: ssrc in y line is %u:%x", req->y_ssrc, req->y_ssrc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
srs_info("sip: method=%s uri=%s version=%s cmdtype=%s",
|
||||
req->method.c_str(), req->uri.c_str(), req->version.c_str(), req->get_cmdtype_str().c_str());
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include <srs_kernel_consts.hpp>
|
||||
|
@ -105,6 +106,9 @@ public:
|
|||
|
||||
std::map<std::string, std::string> xml_body_map;
|
||||
std::map<std::string, std::string> device_list_map;
|
||||
// add an item_list, you can do a lot of other things
|
||||
// used by DeviceList, Alarmstatus, RecordList in "GB/T 28181—2016"
|
||||
std::vector<std::map<std::string, std::string> > item_list;
|
||||
|
||||
public:
|
||||
std::string serial;
|
||||
|
@ -120,6 +124,7 @@ public:
|
|||
|
||||
std::string from_realm;
|
||||
std::string to_realm;
|
||||
uint32_t y_ssrc;
|
||||
|
||||
public:
|
||||
SrsRtspSdp* sdp;
|
||||
|
@ -152,7 +157,7 @@ public:
|
|||
virtual srs_error_t parse_request(SrsSipRequest** preq, const char *recv_msg, int nb_buf);
|
||||
protected:
|
||||
virtual srs_error_t do_parse_request(SrsSipRequest* req, const char *recv_msg);
|
||||
virtual srs_error_t parse_xml(std::string xml_msg, std::map<std::string, std::string> &json_map);
|
||||
virtual srs_error_t parse_xml(std::string xml_msg, std::map<std::string, std::string> &json_map, std::vector<std::map<std::string, std::string> > &item_list);
|
||||
|
||||
private:
|
||||
//response from
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue