1
0
Fork 0
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:
Pieere Pi 2020-11-02 10:18:53 +08:00 committed by winlin
parent fe65c7bf84
commit ffae1720ec
8 changed files with 370 additions and 53 deletions

View file

@ -215,7 +215,9 @@ srs_error_t SrsGb28181PsRtpProcessor::on_rtp_packet(const sockaddr* from, const
(char*)&address_string, sizeof(address_string),
(char*)&port_string, sizeof(port_string),
NI_NUMERICHOST|NI_NUMERICSERV)){
return srs_error_new(ERROR_SYSTEM_IP_INVALID, "bad address");
// return srs_error_new(ERROR_SYSTEM_IP_INVALID, "bad address");
srs_warn("gb28181 ps rtp: bad address");
return srs_success;
}
int peer_port = atoi(port_string);
@ -225,7 +227,10 @@ srs_error_t SrsGb28181PsRtpProcessor::on_rtp_packet(const sockaddr* from, const
SrsPsRtpPacket pkt;
if ((err = pkt.decode(&stream)) != srs_success) {
return srs_error_wrap(err, "ps rtp decode error");
// return srs_error_wrap(err, "ps rtp decode error");
srs_warn("gb28181 ps rtp: decode error");
srs_freep(err);
return srs_success;
}
//TODO: fixme: the same device uses the same SSRC to send with different local ports
@ -432,7 +437,9 @@ srs_error_t SrsGb28181PsRtpProcessor::on_rtp_packet_jitter(const sockaddr* from,
(char*)&address_string, sizeof(address_string),
(char*)&port_string, sizeof(port_string),
NI_NUMERICHOST|NI_NUMERICSERV)){
return srs_error_new(ERROR_SYSTEM_IP_INVALID, "bad address");
// return srs_error_new(ERROR_SYSTEM_IP_INVALID, "bad address");
srs_warn("gb28181 ps rtp: bad address");
return srs_success;
}
int peer_port = atoi(port_string);
@ -443,7 +450,10 @@ srs_error_t SrsGb28181PsRtpProcessor::on_rtp_packet_jitter(const sockaddr* from,
if ((err = pkt->decode(&stream)) != srs_success) {
srs_freep(pkt);
return srs_error_wrap(err, "ps rtp decode error");
// return srs_error_wrap(err, "ps rtp decode error");
srs_warn("gb28181 ps rtp: decode error");
srs_freep(err);
return srs_success;
}
std::stringstream ss3;
@ -1588,6 +1598,9 @@ void SrsGb28181RtmpMuxer::insert_jitterbuffer(SrsPsRtpPacket *pkt)
recv_rtp_stream_time = srs_get_system_time();
char *payload = pkt->payload->bytes();
if (!payload) {
return;
}
uint8_t p1 = (uint8_t)(payload[0]);
uint8_t p2 = (uint8_t)(payload[1]);
@ -1765,13 +1778,12 @@ srs_error_t SrsGb28181RtmpMuxer::write_h264_ipb_frame2(char *frame, int frame_si
std::list<int> list_index;
for(; index < size; index++){
if (index > (size-4))
break;
if (video_data[index] == 0x00 && video_data[index+1] == 0x00 &&
video_data[index+2] == 0x00 && video_data[index+3] == 0x01){
list_index.push_back(index);
}
if (index > (size-4))
break;
}
if (list_index.size() == 1){
@ -2153,6 +2165,8 @@ void SrsGb28181RtmpMuxer::close()
h264_pps = "";
aac_specific_config = "";
// BUGFIX: if don't unpublish, it will always be in the /api/v1/streams list
//if (source_publish && !source){
if (source_publish && source){
source->on_unpublish();
}
@ -2347,6 +2361,28 @@ SrsGb28181RtmpMuxer* SrsGb28181Manger::fetch_rtmpmuxer(std::string id)
return muxer;
}
void SrsGb28181Manger::update_rtmpmuxer_to_newssrc_by_id(std::string id, uint32_t ssrc)
{
SrsGb28181RtmpMuxer* muxer = NULL;
if (rtmpmuxers.find(id) == rtmpmuxers.end()) {
return;
}
muxer = rtmpmuxers[id];
SrsGb28181StreamChannel mc = muxer->get_channel();
uint32_t old_ssrc = mc.get_ssrc();
if (old_ssrc == ssrc) {
return;
} else {
srs_trace("gb28181: update ssrc of muxer %s from %x to %x", id.c_str(), old_ssrc, ssrc);
}
rtmpmuxer_unmap_by_ssrc(old_ssrc);
mc.set_ssrc(ssrc);
muxer->copy_channel(&mc);
rtmpmuxer_map_by_ssrc(muxer, ssrc);
}
SrsGb28181RtmpMuxer* SrsGb28181Manger::fetch_rtmpmuxer_by_ssrc(uint32_t ssrc)
{
SrsGb28181RtmpMuxer* muxer = NULL;
@ -2602,17 +2638,19 @@ srs_error_t SrsGb28181Manger::create_stream_channel(SrsGb28181StreamChannel *cha
return err;
}
srs_error_t SrsGb28181Manger::delete_stream_channel(std::string id)
srs_error_t SrsGb28181Manger::delete_stream_channel(std::string id, std::string chid)
{
srs_error_t err = srs_success;
//notify the device to stop streaming
//if an internal sip service controlled channel
notify_sip_bye(id, id);
notify_sip_bye(id, chid);
SrsGb28181RtmpMuxer *muxer = fetch_rtmpmuxer(id);
string channel_id = id + "@" + chid;
SrsGb28181RtmpMuxer *muxer = fetch_rtmpmuxer(channel_id);
if (muxer){
stop_rtp_listen(id);
stop_rtp_listen(channel_id);
muxer->stop();
return err;
}else {
@ -2727,7 +2765,11 @@ srs_error_t SrsGb28181Manger::notify_sip_unregister(std::string id)
return srs_error_new(ERROR_GB28181_SIP_NOT_RUN, "sip not run");
}
sip_service->remove_session(id);
return delete_stream_channel(id);
return srs_success;
// useless, because
// sip session has been removed
// id is not channel id like id@chid
//return delete_stream_channel(id);
}
srs_error_t SrsGb28181Manger::notify_sip_query_catalog(std::string id)
@ -2738,6 +2780,12 @@ srs_error_t SrsGb28181Manger::notify_sip_query_catalog(std::string id)
SrsSipRequest req;
req.sip_auth_id = id;
SrsGb28181SipSession *sip_session = sip_service->fetch(req.sip_auth_id);
if (sip_session) {
sip_session->item_list.clear();
sip_session->clear_device_list();
srs_trace("notify_sip_query_catalog, clear sip session item and device list");
}
return sip_service->send_query_catalog(&req);
}
@ -2750,8 +2798,14 @@ srs_error_t SrsGb28181Manger::query_sip_session(std::string id, SrsJsonArray* ar
return sip_service->query_sip_session(id, arr);
}
srs_error_t SrsGb28181Manger::query_device_list(std::string id, SrsJsonArray* arr)
{
if (!sip_service){
return srs_error_new(ERROR_GB28181_SIP_NOT_RUN, "sip not run");
}
return sip_service->query_device_list(id, arr);
}
#define SRS_RTSP_BUFFER 262144
SrsGb28181Conn::SrsGb28181Conn(SrsGb28181Caster* c, srs_netfd_t fd, SrsGb28181TcpPsRtpProcessor *rtp_processor)
@ -2970,3 +3024,4 @@ void SrsGb28181Caster::remove(SrsGb28181Conn* conn)
manager->remove(conn);
}

View file

@ -518,6 +518,7 @@ public:
srs_error_t fetch_or_create_rtmpmuxer(std::string id, SrsRequest *req, SrsGb28181RtmpMuxer** gb28181);
SrsGb28181RtmpMuxer* fetch_rtmpmuxer(std::string id);
SrsGb28181RtmpMuxer* fetch_rtmpmuxer_by_ssrc(uint32_t ssrc);
void update_rtmpmuxer_to_newssrc_by_id(std::string id, uint32_t ssrc);
void rtmpmuxer_map_by_ssrc(SrsGb28181RtmpMuxer*muxer, uint32_t ssrc);
void rtmpmuxer_unmap_by_ssrc(uint32_t ssrc);
uint32_t generate_ssrc(std::string id);
@ -525,11 +526,12 @@ public:
void set_sip_service(SrsGb28181SipService *s) { sip_service = s; }
SrsGb28181SipService* get_sip_service() { return sip_service; }
SrsGb28181Config* get_gb28181_config_ptr() { return config;}
public:
//stream channel api
srs_error_t create_stream_channel(SrsGb28181StreamChannel *channel);
srs_error_t delete_stream_channel(std::string id);
srs_error_t delete_stream_channel(std::string id, std::string chid);
srs_error_t query_stream_channel(std::string id, SrsJsonArray* arr);
//sip api
srs_error_t notify_sip_invite(std::string id, std::string ip, int port, uint32_t ssrc, std::string chid);
@ -539,6 +541,7 @@ public:
srs_error_t notify_sip_query_catalog(std::string id);
srs_error_t notify_sip_ptz(std::string id, std::string chid, std::string cmd, uint8_t speed, int priority);
srs_error_t query_sip_session(std::string id, SrsJsonArray* arr);
srs_error_t query_device_list(std::string id, SrsJsonArray* arr);
private:
void destroy();

View file

@ -68,6 +68,7 @@ std::string srs_get_sip_session_status_str(SrsGb28181SipSessionStatusType status
SrsGb28181Device::SrsGb28181Device()
{
device_id = "";
device_name = "";
invite_status = SrsGb28181SipSessionUnkonw;
invite_time = 0;
device_status = "";
@ -102,6 +103,8 @@ SrsGb28181SipSession::SrsGb28181SipSession(SrsGb28181SipService *c, SrsSipReques
_fromlen = 0;
_sip_cseq = 100;
item_list_sumnum = 0;
}
SrsGb28181SipSession::~SrsGb28181SipSession()
@ -338,19 +341,42 @@ void SrsGb28181SipSession::update_device_list(std::map<std::string, std::string>
if (_device_list.find(id) == _device_list.end()){
SrsGb28181Device *device = new SrsGb28181Device();
device->device_id = id;
device->device_status = status;
if (status.find(",") != std::string::npos) {
device->device_status = status.substr(0,status.find(","));
device->device_name = status.substr(status.find(",")+1);
} else {
device->device_status = status;
device->device_name = "NONAME";
}
device->invite_status = SrsGb28181SipSessionUnkonw;
device->invite_time = 0;
_device_list[id] = device;
}else {
SrsGb28181Device *device = _device_list[id];
device->device_status = status;
if (status.find(",") != std::string::npos) {
device->device_status = status.substr(0,status.find(","));
device->device_name = status.substr(status.find(",")+1);
} else {
device->device_status = status;
device->device_name = "NONAME";
}
}
}
}
void SrsGb28181SipSession::clear_device_list()
{
//destory all device
std::map<std::string, SrsGb28181Device*>::iterator it;
for (it = _device_list.begin(); it != _device_list.end(); ++it) {
srs_freep(it->second);
}
_device_list.clear();
}
SrsGb28181Device* SrsGb28181SipSession::get_device_info(std::string chid)
{
if (_device_list.find(chid) != _device_list.end()){
@ -372,12 +398,33 @@ void SrsGb28181SipSession::dumps(SrsJsonObject* obj)
SrsJsonObject* obj = SrsJsonAny::object();
arr->append(obj);
obj->set("device_id", SrsJsonAny::str(device->device_id.c_str()));
obj->set("device_name", SrsJsonAny::str(device->device_name.c_str()));
obj->set("device_status", SrsJsonAny::str(device->device_status.c_str()));
obj->set("invite_status", SrsJsonAny::str(srs_get_sip_session_status_str(device->invite_status).c_str()));
obj->set("invite_time", SrsJsonAny::integer(device->invite_time/SRS_UTIME_SECONDS));
}
}
void SrsGb28181SipSession::dumpItemList(SrsJsonObject* obj)
{
obj->set("TopDeviceID", SrsJsonAny::str(_session_id.c_str()));
obj->set("SumNum", SrsJsonAny::integer(item_list_sumnum));
obj->set("RealSumNum", SrsJsonAny::integer(item_list.size()));
SrsJsonArray* arr = SrsJsonAny::array();
obj->set("ItemList", arr);
std::map<std::string, std::map<std::string, std::string> >::iterator it;
for (it = item_list.begin(); it != item_list.end(); ++it) {
std::map<std::string, std::string> device = it->second;
SrsJsonObject* obj2 = SrsJsonAny::object();
arr->append(obj2);
std::map<std::string, std::string>::iterator it2;
for (it2 = device.begin(); it2 != device.end(); ++it2) {
obj2->set(it2->first, SrsJsonAny::str(it2->second.c_str()));
}
}
}
//gb28181 sip Service
SrsGb28181SipService::SrsGb28181SipService(SrsConfDirective* c)
{
@ -419,7 +466,9 @@ srs_error_t SrsGb28181SipService::on_udp_packet(const sockaddr* from, const int
(char*)&address_string, sizeof(address_string),
(char*)&port_string, sizeof(port_string),
NI_NUMERICHOST|NI_NUMERICSERV)) {
return srs_error_new(ERROR_SYSTEM_IP_INVALID, "bad address");
// return srs_error_new(ERROR_SYSTEM_IP_INVALID, "bad address");
srs_warn("gb28181: bad address");
return srs_success;
}
std::string peer_ip = std::string(address_string);
int peer_port = atoi(port_string);
@ -427,7 +476,10 @@ srs_error_t SrsGb28181SipService::on_udp_packet(const sockaddr* from, const int
std::string recv_msg(buf, nb_buf);
srs_error_t err = on_udp_sip(peer_ip, peer_port, recv_msg, (sockaddr*)from, fromlen);
if (err != srs_success) {
return srs_error_wrap(err, "process udp");
// return srs_error_wrap(err, "process udp");
srs_warn("gb28181: process udp");
srs_freep(err);
return srs_success;
}
return err;
}
@ -465,11 +517,11 @@ srs_error_t SrsGb28181SipService::on_udp_sip(string peer_ip, int peer_port,
return srs_error_new(ERROR_GB28181_SIP_PRASE_FAILED, "register string split");
}
if (serial.at(0) != config->sip_serial){
srs_warn("gb28181: client:%s request serial and server serial inconformity(%s:%s)",
req->sip_auth_id.c_str(), serial.at(0).c_str(), config->sip_serial.c_str());
return err;
}
//if (serial.at(0) != config->sip_serial){
// srs_warn("gb28181: client:%s request serial and server serial inconformity(%s:%s)",
// req->sip_auth_id.c_str(), serial.at(0).c_str(), config->sip_serial.c_str());
// return err;
//}
srs_trace("gb28181: request client id=%s peer(%s, %d)", req->sip_auth_id.c_str(), peer_ip.c_str(), peer_port);
srs_trace("gb28181: %s method=%s, uri=%s, version=%s expires=%d",
@ -519,6 +571,24 @@ srs_error_t SrsGb28181SipService::on_udp_sip(string peer_ip, int peer_port,
if (req->device_list_map.size() > 0){
sip_session->update_device_list(req->device_list_map);
}
if (!strcasecmp(req->content_type.c_str(),"application/manscdp+xml")
&& req->xml_body_map.find("Response@CmdType") != req->xml_body_map.end()
&& req->xml_body_map["Response@CmdType"] == "Catalog") {
if (req->xml_body_map.find("Response@SumNum") != req->xml_body_map.end()) {
sip_session->item_list_sumnum = atoi(req->xml_body_map["Response@SumNum"].c_str());
}
std::vector<std::map<std::string, std::string> >::iterator it;
for (it = req->item_list.begin(); it != req->item_list.end(); ++it) {
std::map<std::string, std::string> device = *it;
std::map<std::string, std::map<std::string, std::string> >::iterator it2 = sip_session->item_list.find(device["DeviceID"]);
if (it2 != sip_session->item_list.end()) {
sip_session->item_list.erase(it2);
sip_session->item_list[device["DeviceID"]] = device;
} else {
sip_session->item_list[device["DeviceID"]] = device;
}
}
}
}
}else if (req->is_invite()) {
@ -547,6 +617,14 @@ srs_error_t SrsGb28181SipService::on_udp_sip(string peer_ip, int peer_port,
srs_trace("gb28181: INVITE response %s client status=%s", req->sip_auth_id.c_str(), req->status.c_str());
if (req->status == "200") {
srs_trace("gb28181: device unique id is %s@%s", sip_session->session_id().c_str(), req->sip_auth_id.c_str());
// if srs is external realm, ssrc is generated by source realm rather than srs
// so update ssrc to the y line in source realm '200 OK' response
// actually, we should do this all the time
if (req->y_ssrc != 0) {
_srs_gb28181->update_rtmpmuxer_to_newssrc_by_id(sip_session->session_id()+"@"+req->sip_auth_id, req->y_ssrc);
req->y_ssrc = 0;
}
send_ack(req, from, fromlen);
SrsGb28181Device *device = sip_session->get_device_info(req->sip_auth_id);
if (device){
@ -919,6 +997,31 @@ srs_error_t SrsGb28181SipService::query_sip_session(std::string sid, SrsJsonArr
return err;
}
srs_error_t SrsGb28181SipService::query_device_list(std::string sid, SrsJsonArray* arr)
{
srs_error_t err = srs_success;
if (!sid.empty()){
SrsGb28181SipSession* sess = fetch(sid);
if (!sess){
return srs_error_new(ERROR_GB28181_SESSION_IS_NOTEXIST, "sip session not exist");
}
SrsJsonObject* obj = SrsJsonAny::object();
arr->append(obj);
sess->dumpItemList(obj);
}else {
std::map<std::string, SrsGb28181SipSession*>::iterator it;
for (it = sessions.begin(); it != sessions.end(); ++it) {
SrsGb28181SipSession* sess = it->second;
SrsJsonObject* obj = SrsJsonAny::object();
arr->append(obj);
sess->dumpItemList(obj);
}
}
return err;
}
srs_error_t SrsGb28181SipService::fetch_or_create_sip_session(SrsSipRequest *req, SrsGb28181SipSession** sip_session)
{
srs_error_t err = srs_success;

View file

@ -59,6 +59,7 @@ public:
virtual ~SrsGb28181Device();
public:
std::string device_id;
std::string device_name;
std::string device_status;
SrsGb28181SipSessionStatusType invite_status;
srs_utime_t invite_time;
@ -132,10 +133,14 @@ public:
int sip_cseq(){ return _sip_cseq++;}
std::string session_id() { return _session_id;}
std::map<std::string, std::map<std::string, std::string> > item_list;
int item_list_sumnum;
public:
void update_device_list(std::map<std::string, std::string> devlist);
void clear_device_list();
SrsGb28181Device *get_device_info(std::string chid);
void dumps(SrsJsonObject* obj);
void dumpItemList(SrsJsonObject* obj);
public:
virtual srs_error_t serve();
@ -201,6 +206,7 @@ public:
//
srs_error_t send_sip_raw_data(SrsSipRequest *req, std::string data);
srs_error_t query_sip_session(std::string sid, SrsJsonArray* arr);
srs_error_t query_device_list(std::string sid, SrsJsonArray* arr);
public:
srs_error_t fetch_or_create_sip_session(SrsSipRequest *req, SrsGb28181SipSession** sess);

View file

@ -1476,11 +1476,12 @@ srs_error_t SrsGoApiGb28181::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMe
return srs_api_response(w, r, obj->dumps());
} else if(action == "delete_channel"){
if (id.empty()){
return srs_error_new(ERROR_GB28181_VALUE_EMPTY, "no id");
string chid = r->query_get("chid");
if (id.empty() || chid.empty()){
return srs_error_new(ERROR_GB28181_VALUE_EMPTY, "no id or chid");
}
if ((err = _srs_gb28181->delete_stream_channel(id)) != srs_success) {
if ((err = _srs_gb28181->delete_stream_channel(id, chid)) != srs_success) {
return srs_error_wrap(err, "delete stream channel");
}
@ -1573,6 +1574,16 @@ srs_error_t SrsGoApiGb28181::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMe
}
return srs_api_response_code(w, r, 0);
} else if(action == "sip_query_devicelist"){
SrsJsonArray* arr = SrsJsonAny::array();
data->set("PlatformID", SrsJsonAny::str(_srs_gb28181->get_gb28181_config_ptr()->sip_serial.c_str()));
data->set("DeviceList", arr);
if ((err = _srs_gb28181->query_device_list("", arr)) != srs_success) {
return srs_error_wrap(err, "query device list");
}
return srs_api_response(w, r, obj->dumps());
} else if(action == "sip_query_session"){
SrsJsonArray* arr = SrsJsonAny::array();
data->set("sessions", arr);