diff --git a/sip/Message/CatalogParser.cpp b/sip/Message/CatalogParser.cpp index 3413297..ef7cc58 100644 --- a/sip/Message/CatalogParser.cpp +++ b/sip/Message/CatalogParser.cpp @@ -632,6 +632,45 @@ std::vector< DeviceInfo > CCatalogParser::DecodeCatlog(const char* body) return cat_list; } +DeviceInfo CCatalogParser::DecodeDeviceInfo(const char* body) +{ + DeviceInfo info; + + tinyxml2::XMLDocument doc; + doc.Parse(body); + tinyxml2::XMLElement* pRoot = doc.RootElement(); + if (pRoot == NULL) { + return info; + } + + tinyxml2::XMLNode* pChild = 0; + std::vector< tinyxml2::XMLNode* > nodes; + for (tinyxml2::XMLNode* pNode = pRoot->FirstChild(); pNode != 0; pNode = pNode->NextSibling()) + { + std::string value = pNode->Value(); + pChild = pNode->FirstChild(); + if (value == "DeviceID") + { + info.id = pChild->Value(); + info.parentid = info.id; + } + else if (value == "DeviceName") + { + info.name = pChild->Value(); + } + else if (value == "Manufacturer") + { + info.manufacturer = pChild->Value(); + } + else if (value == "Model") + { + info.model = pChild->Value(); + } + } + + return info; +} + string CCatalogParser::getItemValue(tinyxml2::XMLNode *pItem) { tinyxml2::XMLNode *pValue = pItem->FirstChild(); diff --git a/sip/Message/CatalogParser.h b/sip/Message/CatalogParser.h index d419c01..f336c1d 100644 --- a/sip/Message/CatalogParser.h +++ b/sip/Message/CatalogParser.h @@ -18,6 +18,8 @@ public: std::vector DecodeCatlog(const char* body); + DeviceInfo DecodeDeviceInfo(const char* body); + ServerInfo DecodeServerConfig(const char* body); static std::string GetStrName(EEventType eType) diff --git a/sip/SipServer.cpp b/sip/SipServer.cpp index 357f523..60cf414 100644 --- a/sip/SipServer.cpp +++ b/sip/SipServer.cpp @@ -22,8 +22,6 @@ #include #include -#include "WebSocketServer.h" - using namespace std; @@ -132,7 +130,11 @@ int SipServer::sip_event_handle(eXosip_event_t *evtp) { // LOG_INFO("EXOSIP_MESSAGE_NEW type={}",evtp->type); if (MSG_IS_REGISTER(evtp->request)) { - this->response_register(evtp); + if (mInfo.isNoAuth()) { + response_register_noauth(evtp); + } else { + response_register(evtp); + } } else if (MSG_IS_MESSAGE(evtp->request)) { this->response_message(evtp); @@ -250,9 +252,12 @@ int SipServer::init_sip_server() { return -1; } eXosip_set_user_agent(mSipCtx, mInfo.getUa().c_str()); - if (eXosip_add_authentication_info(mSipCtx, mInfo.getSipId().c_str(), mInfo.getSipId().c_str(), mInfo.getSipPass().c_str(), NULL, mInfo.getSipRealm().c_str())) { - LOG_ERROR("eXosip_add_authentication_info error"); - return -1; + + if (!mInfo.isNoAuth()) { + if (eXosip_add_authentication_info(mSipCtx, mInfo.getSipId().c_str(), mInfo.getSipId().c_str(), mInfo.getSipPass().c_str(), NULL, mInfo.getSipRealm().c_str())) { + LOG_ERROR("eXosip_add_authentication_info error"); + return -1; + } } return 0; @@ -325,12 +330,38 @@ void SipServer::response_message_answer(eXosip_event_t *evtp,int code){ else{ LOG_ERROR("code={},returnCode={},bRegister={}",code,returnCode,bRegister); } +} + +void SipServer::response_register_noauth(eXosip_event_t *evtp) { + int expire = -1; + osip_header_t* header = NULL; + osip_message_header_get_byname(evtp->request, "expires", 0, &header); + if (NULL != header && NULL != header->hvalue) { + expire = atoi(header->hvalue); + } + + osip_contact_t *contact = nullptr; + osip_message_get_contact (evtp->request, 0, &contact); + if (!(contact && contact->url)) { + LOG_WARN("contact is null."); + return ; + } + + if (expire <= 0) { + std::lock_guard l(m_client_map_mtx); + string sip_id = strdup(contact->url->username); + deleteClientByDevice(sip_id); + LOG_INFO("unregister succeed:{}", sip_id); + return ; + } + + dump_request(evtp); + response_message_answer(evtp,200); + cacheClient(contact->url, expire); } -void SipServer::response_register(eXosip_event_t *evtp) { - osip_authorization_t * auth = nullptr; - osip_message_get_authorization(evtp->request, 0, &auth); +void SipServer::response_register(eXosip_event_t *evtp) { int expire = -1; osip_header_t* header = NULL; @@ -347,13 +378,18 @@ void SipServer::response_register(eXosip_event_t *evtp) { } if (expire <= 0) { + std::lock_guard l(m_client_map_mtx); string sip_id = strdup(contact->url->username); deleteClientByDevice(sip_id); LOG_INFO("unregister succeed:{}", sip_id); return ; } - if(auth && auth->username){ + dump_request(evtp); + + osip_authorization_t * auth = nullptr; + osip_message_get_authorization(evtp->request, 0, &auth); + if(auth && auth->uri){ char *method = NULL, // REGISTER *algorithm = NULL, // MD5 @@ -405,30 +441,63 @@ void SipServer::response_register(eXosip_event_t *evtp) { } } +int SipServer::check_device_type(string sip_id) { + if (sip_id.length() != 20) { + LOG_ERROR("sip id error:{}", sip_id); + return -1; + } + string strType = sip_id.substr(10, 3); + + int type = atoi(strType.c_str()); + + LOG_DEBUG("device type: {}", type); + + return type; +} + void SipServer::cacheClient(osip_uri_t *url, int expiry) { string sip_id = strdup(url->username); + int type = check_device_type(sip_id); + if (-1 == type) { + return; + } + long cur_ts = Utools::get_cur_time_ms(); // 已经注册的不再注册 std::lock_guard l(m_client_map_mtx); auto it = mClientMap.find(sip_id); if (it != mClientMap.end()) { - it->second->setExpiry(expiry); - it->second->updateHeartBeat(cur_ts); - return ; + if (cur_ts - it->second->getHeartBeat() < 5*60*1000) { + it->second->setExpiry(expiry); + it->second->updateHeartBeat(cur_ts); + return ; + } else { + deleteClientByDevice(sip_id); + LOG_INFO("与上次注册时间超过5分钟,重新缓存:{}", sip_id); + } } - Client* client = new Client(strdup(url->host), atoi(url->port), strdup(url->username)); + Client* client = new Client(strdup(url->host), atoi(url->port), sip_id); client->setExpiry(expiry); client->updateHeartBeat(cur_ts); LOG_INFO("Camera registration succee,ip={},port={},device={}",client->getIp(),client->getPort(),client->getDevice()); mClientMap.insert(std::make_pair(client->getDevice(),client)); - // NVR注册成功,立即请求设备目录 - RequestCatalog(client); + + if (type >= 111 && type <= 130) { + // NVR注册成功,立即请求设备目录 + RequestCatalog(client); + } else if (type >= 131 && type <= 199) { + RequestDeviceInfo(client); + } + else { + LOG_WARN("device type is not supported:{}",type); + } + } void SipServer::response_register_401unauthorized(eXosip_event_t *evtp) { @@ -475,6 +544,11 @@ void SipServer::response_message(eXosip_event_t *evtp) { parse_xml(body->body, "", false, "", false, CmdType); parse_xml(body->body, "", false, "", false, DeviceID); } + else { + return; + } + + // std::cout << CmdType << std::endl; if(!strcmp(CmdType, "Catalog")) { this->response_message_answer(evtp,200); @@ -488,8 +562,17 @@ void SipServer::response_message(eXosip_event_t *evtp) { DeviceInfo info = vec_device[i]; m_device_map[info.id] = info; } - } - else if(!strcmp(CmdType, "Keepalive")){ + } else if (!strcmp(CmdType, "DeviceInfo")) { + this->response_message_answer(evtp, 200); + // 需要根据对方的Catelog请求,做一些相应的应答请求 + CCatalogParser catPaser; + DeviceInfo info = catPaser.DecodeDeviceInfo(body->body); + info.status = "on"; // 有值返回就已经可以表明设备状态在线了 + + std::lock_guard l(m_device_map_mtx); + m_device_map[info.id] = info; + + } else if(!strcmp(CmdType, "Keepalive")){ this->response_message_answer(evtp,200); // LOG_INFO("CmdType={},DeviceID={}", CmdType, DeviceID); std::lock_guard l_c(m_client_map_mtx); @@ -616,7 +699,7 @@ int SipServer::reInvite(int cid) { if (ret <= 0) { LOG_ERROR("reInvite failed!"); - m_pWsServer->response_client(strChannelId, iPort, cmd, ret); + //m_pWsServer->response_client(strChannelId, iPort, cmd, ret); } } } @@ -624,10 +707,6 @@ int SipServer::reInvite(int cid) { return -1; } -int SipServer::inviteFailedResponse(int cid) { - -} - int SipServer::RequestInvite_UDP(const char* dst_channel, const char* rtpIp, int rtpPort) { // 检查设备是否在线 @@ -765,9 +844,44 @@ void SipServer::cacheCatalog() { return ; } + long cur_ts = Utools::get_cur_time_ms(); + + vector vec_sip_id; + LOG_INFO("client size:{}", mClientMap.size()); for (auto it = mClientMap.begin(); it != mClientMap.end(); it++) { - RequestCatalog(it->second); + //RequestCatalog(it->second); + Client* client = it->second; + if (!client) { + continue; + } + + string sip_id = client->getDevice(); + + unsigned long gap = client->getHeartBeatGap(); + if (gap > 0 && (cur_ts - client->getHeartBeat()) > 10 * gap) { + LOG_WARN("{}:超过10个心跳周期未收到心跳", sip_id); + vec_sip_id.push_back(sip_id); + continue; + } + + int type = check_device_type(sip_id); + if (-1 == type) { + continue; + } + + if (type >= 111 && type <= 130) { + // NVR注册成功,立即请求设备目录 + RequestCatalog(client); + } + else if (type >= 131 && type <= 199) { + RequestDeviceInfo(client); + } + } + + // 超过10个心跳周期未收到心跳,做下线处理 + for (size_t i = 0; i < vec_sip_id.size(); i++) { + deleteClientByDevice(vec_sip_id[i]); } } @@ -803,6 +917,37 @@ void SipServer::RequestCatalog(Client* client) { eXosip_unlock(mSipCtx); } +void SipServer::RequestDeviceInfo(Client* client) { + eXosip_lock(mSipCtx); + + osip_message_t* catlog_msg = NULL; + char to[100];/*sip:主叫用户名@被叫IP地址*/ + char from[100];/*sip:被叫IP地址:被叫IP端口*/ + char xml_body[4096]; + + memset(to, 0, 100); + memset(from, 0, 100); + memset(xml_body, 0, 4096); + + sprintf(from, "sip:%s@%s:%d", mInfo.getSipId().c_str(), mInfo.getIp().c_str(), mInfo.getPort()); + sprintf(to, "sip:%s@%s:%d", client->getDevice().c_str(), client->getIp().c_str(), client->getPort()); + eXosip_message_build_request(mSipCtx, &catlog_msg, "MESSAGE", to, from, NULL);/*构建"MESSAGE"请求*/ + + snprintf(xml_body, 4096, + "" + "" + "DeviceInfo" + "%d" + "%s" + "", rand() % (99999 - 10000 + 1) + 10000, client->getDevice().c_str()); + + osip_message_set_body(catlog_msg, xml_body, strlen(xml_body)); + osip_message_set_content_type(catlog_msg, "Application/MANSCDP+xml"); + eXosip_message_send_request(mSipCtx, catlog_msg); + + eXosip_unlock(mSipCtx); +} + int SipServer::clearClientMap(){ std::lock_guard l(m_client_map_mtx); for (auto iter=mClientMap.begin(); iter!=mClientMap.end(); iter++) { @@ -815,7 +960,7 @@ int SipServer::clearClientMap(){ } void SipServer::deleteClientByDevice(string device) { - std::lock_guard l(m_client_map_mtx); + // std::lock_guard l(m_client_map_mtx); 外部调用函数的时候注意加锁,这里去掉加锁 auto it = mClientMap.find(device); if (it == mClientMap.end()) { return ; diff --git a/sip/SipServer.h b/sip/SipServer.h index c7b712f..a28cfec 100644 --- a/sip/SipServer.h +++ b/sip/SipServer.h @@ -53,6 +53,18 @@ public: void updateHeartBeat(unsigned long ts) { mHeartBeatTime = ts; + mHeartBeatCount++; + if (mHeartBeatFirst <= 0){ + mHeartBeatFirst = ts; + } + } + + unsigned long getHeartBeatGap() { + if (mHeartBeatCount >= 2) + { + return (mHeartBeatTime - mHeartBeatFirst)/mHeartBeatCount ; + } + return 0; } long getExpiry() { @@ -70,6 +82,9 @@ private: bool mIsReg; int mRtpPort; unsigned long mHeartBeatTime{0}; + unsigned long mHeartBeatFirst{0}; + unsigned long mHeartBeatGap{1}; + unsigned long mHeartBeatCount{0}; long mExipry{0}; }; @@ -102,10 +117,13 @@ private: void RequestCatalog(Client* client); void cacheCatalog(); + void RequestDeviceInfo(Client* client); + void cacheClient(osip_uri_t *url, int expiry); void response_message_answer(eXosip_event_t *evtp,int code); void response_register(eXosip_event_t *evtp); + void response_register_noauth(eXosip_event_t *evtp); void response_register_401unauthorized(eXosip_event_t *evt); void response_message(eXosip_event_t *evtp); void response_invite_ack(eXosip_event_t *evtp); @@ -124,7 +142,7 @@ private: int reInvite(int cid); - int inviteFailedResponse(int cid); + int check_device_type(string sip_id); private: bool mQuit{ false }; diff --git a/sip/WebSocketServer.cpp b/sip/WebSocketServer.cpp index 198cfc4..1cd336f 100644 --- a/sip/WebSocketServer.cpp +++ b/sip/WebSocketServer.cpp @@ -30,9 +30,8 @@ int WebSocketServer::parse_invite(vector& vec_msg, std::string ip) { int ret = -100; if ("udp" == net_type) { ret = sip_server.RequestInvite_UDP(vec_msg[2].c_str(), ip.c_str(), atoi(vec_msg[3].c_str())); - } else if ("tcp" == net_type) - { - /* code */ + } else if ("tcp" == net_type) { + ret = sip_server.RequestInvite_TCP_a(vec_msg[2].c_str(), ip.c_str(), atoi(vec_msg[3].c_str())); } return ret; diff --git a/sip/sip_header.h b/sip/sip_header.h index aef628c..c493e12 100644 --- a/sip/sip_header.h +++ b/sip/sip_header.h @@ -21,7 +21,7 @@ enum EEventType struct DeviceInfo { EEventType event; - std::string id; + std::string id{""}; std::string name; std::string manufacturer; std::string model; @@ -109,6 +109,14 @@ public: void setSipPass(string s) { mSipPass = s; } + + bool isNoAuth() { + if (mSipPass.empty()) { + return true; + } + return false; + } + int getTimeout() const { return mSipTimeout; } @@ -147,7 +155,7 @@ private: int mPort{0};//SIP服务端口 string mSipId; //SIP服务器ID string mSipRealm;//SIP服务器域 - string mSipPass;//SIP password + string mSipPass{""};//SIP password int mSipTimeout; //SIP timeout int mSipExpiry;// SIP到期 int mMinRtpPort;