// // Created bxc on 2022/11/25. // #include "SipServer.h" #ifndef WIN32 // Linux系统 #include #else #include #pragma comment(lib, "ws2_32.lib") #endif // !WIN32 #include #include "./Utils/HTTPDigest.h" #include "./Utils/Utools.hpp" #include "./Utils/logger.hpp" #include "./Utils/StringTools.hpp" #include #include using namespace std; static void event_loop_thread(void* arg) { SipServer* _this = (SipServer*)arg; if (_this != nullptr) { _this->event_loop(); } else { LOG_ERROR("event_loop线程启动失败 !"); } } static void timing_getcatlog_thread(void* arg) { SipServer* _this = (SipServer*)arg; if (_this != nullptr) { _this->timing_getcatlog(); } else { LOG_ERROR("timing_getcatlog 线程启动失败 !"); } } static void dt_printSipMsg(osip_message_t* msg) { osip_message_t* clone_event = NULL; size_t length = 0; char* message = NULL; osip_message_clone(msg, &clone_event); osip_message_to_str(clone_event, &message, &length); LOG_INFO("{}", message); } SipServer::SipServer(): mQuit(false), mSipCtx(nullptr){ #ifdef WIN32 WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { LOG_ERROR("WSAStartup Error"); return; } #endif // WIN32 mClientMap.clear(); m_device_map.clear(); } SipServer::~SipServer() { LOG_INFO("~SipServer"); if (m_event_loop_thread) { mQuit = true; m_event_loop_thread->join(); delete m_event_loop_thread; m_event_loop_thread = nullptr; } this->clearClientMap(); #ifdef WIN32 WSACleanup(); #endif // WIN32 } bool SipServer::Init(ServerInfo* pInfo, WebSocketServer* pServer) { if (pInfo == nullptr || pServer == nullptr) { return false; } mInfo = *pInfo; if (mInfo.isNoAuth()) { LOG_INFO("do not need password"); } else { LOG_INFO("need password"); } m_pWsServer = pServer; m_event_loop_thread = new std::thread(event_loop_thread, this); return true; } int SipServer::sip_event_handle(eXosip_event_t *evtp) { switch(evtp->type) { case EXOSIP_CALL_MESSAGE_NEW://14 // LOG_INFO("EXOSIP_CALL_MESSAGE_NEW type={}", evtp->type); this->dump_request(evtp); this->dump_response(evtp); break; case EXOSIP_CALL_CLOSED://21 LOG_INFO("EXOSIP_CALL_CLOSED type={}",evtp->type); // this->dump_request(evtp); // this->dump_response(evtp); break; case EXOSIP_CALL_RELEASED://22 LOG_INFO("EXOSIP_CALL_RELEASED type={}", evtp->type); reInvite(evtp->cid); // this->dump_request(evtp); // this->dump_response(evtp); // this->clearClientMap(); break; case EXOSIP_MESSAGE_NEW://23 // LOG_INFO("EXOSIP_MESSAGE_NEW type={}",evtp->type); if (MSG_IS_REGISTER(evtp->request)) { if (mInfo.isNoAuth()) { response_register_noauth(evtp); } else { response_register(evtp); } } else if (MSG_IS_MESSAGE(evtp->request)) { this->response_message(evtp); } else if(MSG_IS_BYE(evtp->request)){ LOG_ERROR("BYE"); } else{ LOG_ERROR("unknown2"); } break; case EXOSIP_MESSAGE_ANSWERED: this->dump_request(evtp); break; case EXOSIP_MESSAGE_REQUESTFAILURE: LOG_INFO("EXOSIP_MESSAGE_REQUESTFAILURE type={}: Receive feedback on sending failure after actively sending a message", evtp->type); this->dump_request(evtp); this->dump_response(evtp); break; case EXOSIP_CALL_INVITE: LOG_INFO("EXOSIP_CALL_INVITE type={}: The server receives the Invite request actively sent by the client", evtp->type); break; case EXOSIP_CALL_PROCEEDING://5 LOG_INFO("EXOSIP_CALL_PROCEEDING type={}: When the server receives the Invite (SDP) confirmation reply from the client", evtp->type); this->dump_request(evtp); this->dump_response(evtp); break; case EXOSIP_CALL_ANSWERED:// 7 LOG_INFO("EXOSIP_CALL_ANSWERED type={}: The server receives an invite (SDP) confirmation reply from the client", evtp->type); this->dump_request(evtp); this->dump_response(evtp); this->response_invite_ack(evtp); cache_invite_callinfo(evtp); break; case EXOSIP_CALL_SERVERFAILURE: LOG_INFO("EXOSIP_CALL_SERVERFAILURE cid={}", evtp->cid); break; case EXOSIP_IN_SUBSCRIPTION_NEW: LOG_INFO("EXOSIP_IN_SUBSCRIPTION_NEW cid={}", evtp->cid); break; case EXOSIP_CALL_MESSAGE_ANSWERED: LOG_INFO("EXOSIP_CALL_MESSAGE_ANSWERED cid={}", evtp->cid); break; default: LOG_INFO("type={} unknown", evtp->type); break; } return 0; } string contract_ip_from_message(string str_msg) { str_msg = StringTools::to_lower(str_msg); string c = str_msg.substr(str_msg.find("c=")+2); string c1 = c.substr(0, c.find_first_of("=") - 1); string c2 = c1.substr(c1.find_first_of("4")+1); return StringTools::trim(c2); } string contract_port_from_message(string str_msg) { str_msg = StringTools::to_lower(str_msg); string c = str_msg.substr(str_msg.find("video")+6); string c1 = c.substr(0, c.find_first_of(" ")); return StringTools::trim(c1); } void SipServer::cache_invite_callinfo(eXosip_event_t *evtp) { CallInfo call_info; call_info.cid = evtp->cid; call_info.did = evtp->did; try { char *s; size_t len; osip_message_to_str(evtp->request, &s, &len); string ip = contract_ip_from_message(s); string port = contract_port_from_message(s); LOG_INFO("ip:{} port:{}", ip, port); string channel_id = evtp->response->to->url->username; auto key = std::make_tuple(channel_id, ip, atoi(port.c_str())); std::lock_guard l(m_invite_callinfo_map_mtx); m_invite_callinfo_map[key] = call_info; } catch(const std::exception& e) { std::cerr << e.what() << '\n'; } } int SipServer::init_sip_server() { mSipCtx = eXosip_malloc(); if (!mSipCtx) { LOG_ERROR("eXosip_malloc error"); return -1; } if (eXosip_init(mSipCtx)) { LOG_ERROR("eXosip_init error"); return -1; } if (eXosip_listen_addr(mSipCtx, IPPROTO_UDP, nullptr, mInfo.getPort(), AF_INET, 0)) { LOG_ERROR("eXosip_listen_addr error"); return -1; } eXosip_set_user_agent(mSipCtx, mInfo.getUa().c_str()); 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; } void SipServer::event_loop() { if(this->init_sip_server() !=0 ){ return; } LOG_INFO("sip server init succeed: {}:{}", mInfo.getIp(), mInfo.getPort()); thread* timing_getcatlog_threadptr = new std::thread(timing_getcatlog_thread, this); while(!mQuit) { eXosip_event_t *evtp = eXosip_event_wait(mSipCtx, 0, 20); if (!evtp){ eXosip_automatic_action(mSipCtx); osip_usleep(100000); continue; } eXosip_automatic_action(mSipCtx); this->sip_event_handle(evtp); eXosip_event_free(evtp); } mQuit = true; if (timing_getcatlog_threadptr) { timing_getcatlog_threadptr->join(); delete timing_getcatlog_threadptr; timing_getcatlog_threadptr = nullptr; } } void SipServer::Close() { mQuit = true; if (m_event_loop_thread) { m_event_loop_thread->join(); delete m_event_loop_thread; m_event_loop_thread = nullptr; } } void SipServer::timing_getcatlog() { while(!mQuit) { // 5分钟更新一次 std::this_thread::sleep_for(std::chrono::minutes(5)); cacheCatalog(); } } void SipServer::response_message_answer(eXosip_event_t *evtp,int code){ int returnCode = 0 ; osip_message_t * pRegister = nullptr; returnCode = eXosip_message_build_answer (mSipCtx,evtp->tid,code,&pRegister); bool bRegister = false; if(pRegister){ bRegister = true; } if (returnCode == 0 && bRegister) { eXosip_lock(mSipCtx); eXosip_message_send_answer (mSipCtx,evtp->tid,code,pRegister); eXosip_unlock(mSipCtx); } 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) { 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); osip_authorization_t * auth = nullptr; osip_message_get_authorization(evtp->request, 0, &auth); if(auth && auth->uri){ char *method = NULL, // REGISTER *algorithm = NULL, // MD5 *username = NULL,// 340200000013200000024 *realm = NULL, // sip服务器传给客户端,客户端携带并提交上来的sip服务域 *nonce = NULL, //sip服务器传给客户端,客户端携带并提交上来的nonce *nonce_count = NULL, *uri = NULL; // sip:34020000002000000001@3402000000 method = evtp->request->sip_method; char calc_response[HASHHEXLEN]; HASHHEX HA1, HA2 = "", Response; #define SIP_STRDUP(field) if (auth->field) (field) = osip_strdup_without_quote(auth->field) SIP_STRDUP(algorithm); SIP_STRDUP(username); SIP_STRDUP(realm); SIP_STRDUP(nonce); SIP_STRDUP(nonce_count); SIP_STRDUP(uri); DigestCalcHA1(algorithm, username, realm, mInfo.getSipPass().c_str(), nonce, nonce_count, HA1); DigestCalcResponse(HA1, nonce, nonce_count, auth->cnonce, auth->message_qop, 0, method, uri, HA2, Response); HASHHEX temp_HA1; HASHHEX temp_response; DigestCalcHA1("REGISTER", username, mInfo.getSipRealm().c_str(), mInfo.getSipPass().c_str(), mInfo.getNonce().c_str(), NULL, temp_HA1); DigestCalcResponse(temp_HA1, mInfo.getNonce().c_str(), NULL, NULL, NULL, 0, method, uri, NULL, temp_response); memcpy(calc_response, temp_response, HASHHEXLEN); if (!memcmp(calc_response, Response, HASHHEXLEN)) { this->response_message_answer(evtp,200); cacheClient(contact->url, expire); } else { this->response_message_answer(evtp,401); LOG_INFO("Camera registration error, p={},port={},device={}", strdup(contact->url->host), atoi(contact->url->port), strdup(username)); } osip_free(algorithm); osip_free(username); osip_free(realm); osip_free(nonce); osip_free(nonce_count); osip_free(uri); } else { response_register_401unauthorized(evtp); cacheClient(contact->url, expire); } } 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()) { 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), 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)); if (type >= 111 && type <= 130) { // NVR注册成功,立即请求设备目录 RequestCatalog(client); } else if (type >= 131 && type <= 199) { RequestDeviceInfo(client); } else if (type >= 200 && type <= 299) { RequestCatalog(client); } else { LOG_WARN("device type is not supported:{}",type); } } void SipServer::response_register_401unauthorized(eXosip_event_t *evtp) { char *dest = nullptr; osip_message_t * reg = nullptr; osip_www_authenticate_t * header = nullptr; osip_www_authenticate_init(&header); osip_www_authenticate_set_auth_type (header, osip_strdup("Digest")); osip_www_authenticate_set_realm(header,osip_enquote(mInfo.getSipRealm().c_str())); osip_www_authenticate_set_nonce(header,osip_enquote(mInfo.getNonce().c_str())); osip_www_authenticate_to_str(header, &dest); int ret = eXosip_message_build_answer (mSipCtx, evtp->tid, 401, ®); if ( ret == 0 && reg != nullptr ) { osip_message_set_www_authenticate(reg, dest); osip_message_set_content_type(reg, "Application/MANSCDP+xml"); eXosip_lock(mSipCtx); eXosip_message_send_answer (mSipCtx, evtp->tid,401, reg); eXosip_unlock(mSipCtx); LOG_INFO("response_register_401unauthorized success"); }else { LOG_INFO("response_register_401unauthorized error"); } osip_www_authenticate_free(header); osip_free(dest); } void printDevice(std::vector vec_device) { for (size_t i = 0; i < vec_device.size(); i++) { LOG_INFO("{} {}", vec_device[i].id, vec_device[i].parentid); } } void SipServer::response_message(eXosip_event_t *evtp) { osip_body_t* body = nullptr; char CmdType[64] = {0}; char DeviceID[64] = {0}; osip_message_get_body(evtp->request, 0, &body); if(body){ parse_xml(body->body, "", false, "", false, CmdType); parse_xml(body->body, "", false, "", false, DeviceID); } else { return; } LOG_INFO("CmdType={},DeviceID={}", CmdType, DeviceID); if(!strcmp(CmdType, "Catalog")) { this->response_message_answer(evtp,200); // 需要根据对方的Catelog请求,做一些相应的应答请求 CCatalogParser catPaser; std::vector vec_device = catPaser.DecodeCatlog(body->body); printDevice(vec_device); std::lock_guard l(m_device_map_mtx); for (size_t i = 0; i < vec_device.size(); i++) { DeviceInfo info = vec_device[i]; m_device_map[info.id] = info; } } 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")){ std::lock_guard l_c(m_client_map_mtx); auto it = mClientMap.find(DeviceID); if (it != mClientMap.end()) { response_message_answer(evtp,200); it->second->updateHeartBeat(Utools::get_cur_time_ms()); return ; } else { // 未注册设备发保活信息,超过设备的最大超时次数后,设备将进行初始注册 response_message_answer(evtp,408); } }else{ this->response_message_answer(evtp,200); } } bool SipServer::check_device_status(string id) { std::lock_guard l(m_device_map_mtx); auto it_info = m_device_map.find(id); if (it_info == m_device_map.end()) { return false; } string status = StringTools::trim(it_info->second.status); transform(status.begin(), status.end(), status.begin(),::tolower); if (status == "on"){ return true; } return false; } Client* SipServer::get_parent_by_id(string id) { std::lock_guard l(m_device_map_mtx); auto it_info = m_device_map.find(id); if (it_info == m_device_map.end()) { return nullptr; } string parent_id = it_info->second.parentid; std::lock_guard l_c(m_client_map_mtx); auto it_client = mClientMap.find(parent_id); if (it_client == mClientMap.end()) { return nullptr; } return mClientMap[parent_id]; } void SipServer::response_invite_ack(eXosip_event_t *evtp){ osip_message_t* msg = nullptr; int ret = eXosip_call_build_ack(mSipCtx, evtp->did, &msg); if (!ret && msg) { eXosip_call_send_ack(mSipCtx, evtp->did, msg); } else { LOG_ERROR("eXosip_call_send_ack error={}", ret); } } int SipServer::request_bye(eXosip_event_t* evtp) { eXosip_lock(mSipCtx); int ret = eXosip_call_terminate(mSipCtx, evtp->cid, evtp->did); eXosip_unlock(mSipCtx); return ret; } int SipServer::ByeInvite(std::string channel_id, string ip, int rtpPort) { std::lock_guard l(m_invite_callinfo_map_mtx); auto key = std::make_tuple(channel_id, ip, rtpPort); auto it = m_invite_callinfo_map.find(key); if (it == m_invite_callinfo_map.end()) { return -1; } CallInfo info = it->second; eXosip_lock(mSipCtx); eXosip_call_terminate(mSipCtx, info.cid, info.did); eXosip_unlock(mSipCtx); m_invite_callinfo_map.erase(it); std::lock_guard l_cmd(m_invite_cmd_map_mtx); m_invite_cmd_map.erase(it->first); return 0; } int SipServer::reInvite(int cid) { std::lock_guard l(m_invite_callinfo_map_mtx); bool bFound = false; auto it = m_invite_callinfo_map.begin(); for (; it != m_invite_callinfo_map.end(); it++) { CallInfo info = it->second; if (info.cid == cid) { bFound = true; break; } } if (bFound) { auto key = it->first; std::lock_guard l_cmd(m_invite_cmd_map_mtx); auto it_cmd = m_invite_cmd_map.find(key); if(it_cmd != m_invite_cmd_map.end()) { string strChannelId = std::get<0>(key); string strIp = std::get<1>(key); int iPort = std::get<2>(key); int ret = -1; string cmd = it_cmd->second; if (cmd == "udp") { ret = RequestInvite_UDP(strChannelId.c_str(), strIp.c_str(), iPort); } else if (cmd == "tcp_a") { ret = RequestInvite_TCP_a(strChannelId.c_str(), strIp.c_str(), iPort); } if (ret <= 0) { LOG_ERROR("reInvite failed!"); //m_pWsServer->response_client(strChannelId, iPort, cmd, ret); } } } return -1; } int SipServer::RequestInvite_UDP(const char* dst_channel, const char* rtpIp, int rtpPort) { // 检查设备是否在线 if (!check_device_status(dst_channel)) { LOG_ERROR("{} is not online!", dst_channel); return -2; } Client* client = get_parent_by_id(dst_channel); if (client == nullptr) { LOG_ERROR("do not get parent device:{}", dst_channel); return -1; } LOG_INFO("INVITE UDP: {} {}:{}", dst_channel, rtpIp, rtpPort); char session_exp[1024] = { 0 }; osip_message_t* msg = nullptr; char from[1024] = { 0 }; char to[1024] = { 0 }; char sdp[2048] = { 0 }; sprintf(from, "sip:%s@%s:%d", mInfo.getSipId().c_str(), mInfo.getIp().c_str(), mInfo.getPort()); sprintf(to, "sip:%s@%s:%d", dst_channel, client->getIp().c_str(), client->getPort()); snprintf(sdp, 2048, "v=0\r\n" "o=%s 0 0 IN IP4 %s\r\n" "s=Play\r\n" "c=IN IP4 %s\r\n" "t=0 0\r\n" "m=video %d RTP/AVP 96 98 97\r\n" "a=recvonly\r\n" "a=rtpmap:96 PS/90000\r\n" "a=rtpmap:98 H264/90000\r\n" "a=rtpmap:97 MPEG4/90000\r\n" "a=setup:passive\r\n" "a=connection:new\r\n" "y=0100000001\r\n" "f=\r\n", mInfo.getSipId().c_str(), rtpIp, rtpIp, rtpPort); int ret = eXosip_call_build_initial_invite(mSipCtx, &msg, to, from, nullptr, nullptr); if (ret) { LOG_ERROR("eXosip_call_build_initial_invite error: {} {} ret:{}", from, to, ret); return -1; } osip_message_set_body(msg, sdp, strlen(sdp)); osip_message_set_content_type(msg, "application/sdp"); snprintf(session_exp, sizeof(session_exp) - 1, "%i;refresher=uac", mInfo.getTimeout()); osip_message_set_header(msg, "Session-Expires", session_exp); osip_message_set_supported(msg, "timer"); int call_id = eXosip_call_send_initial_invite(mSipCtx, msg); if (call_id > 0) { LOG_INFO("eXosip_call_send_initial_invite success: call_id={}", call_id); auto key = std::make_tuple(string(dst_channel), string(rtpIp), rtpPort); m_invite_cmd_map[key] = "udp"; } else { LOG_ERROR("eXosip_call_send_initial_invite error: call_id={}", call_id); } return call_id; } int SipServer::RequestInvite_TCP_a(const char* dst_channel, const char* rtpIp, int rtpPort) { // 检查设备是否在线 if (!check_device_status(dst_channel)) { return -2; } Client* client = get_parent_by_id(dst_channel); if (client == nullptr) { return -1; } LOG_INFO("INVITE TCP active"); char session_exp[1024] = { 0 }; osip_message_t* msg = nullptr; char from[1024] = { 0 }; char to[1024] = { 0 }; char sdp[2048] = { 0 }; // const char* dst_channel = "34020000001320000001"; sprintf(from, "sip:%s@%s:%d", mInfo.getSipId().c_str(), mInfo.getIp().c_str(), mInfo.getPort()); sprintf(to, "sip:%s@%s:%d", dst_channel, client->getIp().c_str(), client->getPort()); snprintf(sdp, 2048, "v=0\r\n" "o=%s 0 0 IN IP4 %s\r\n" "s=Play\r\n" "c=IN IP4 %s\r\n" "t=0 0\r\n" "m=video %d TCP/RTP/AVP 96 98 97\r\n" "a=recvonly\r\n" "a=rtpmap:96 PS/90000\r\n" "a=rtpmap:98 H264/90000\r\n" "a=rtpmap:97 MPEG4/90000\r\n" "a=setup:active\r\n" "a=connection:new\r\n" "y=0100000001\r\n" "f=\r\n", mInfo.getSipId().c_str(), mInfo.getIp().c_str(), mInfo.getIp().c_str(), rtpPort); int ret = eXosip_call_build_initial_invite(mSipCtx, &msg, to, from, nullptr, nullptr); if (ret) { LOG_ERROR("eXosip_call_build_initial_invite error: {} {} ret:{}", from, to, ret); return -1; } osip_message_set_body(msg, sdp, strlen(sdp)); osip_message_set_content_type(msg, "application/sdp"); snprintf(session_exp, sizeof(session_exp) - 1, "%i;refresher=uac", mInfo.getTimeout()); osip_message_set_header(msg, "Session-Expires", session_exp); osip_message_set_supported(msg, "timer"); int call_id = eXosip_call_send_initial_invite(mSipCtx, msg); if (call_id > 0) { LOG_INFO("eXosip_call_send_initial_invite success: call_id={}", call_id); auto key = std::make_tuple(string(dst_channel), string(rtpIp), rtpPort); m_invite_cmd_map[key] = "tcp_a"; } else { LOG_ERROR("eXosip_call_send_initial_invite error: call_id={}", call_id); } return call_id; } void SipServer::cacheCatalog() { std::lock_guard l(m_client_map_mtx); if (mClientMap.size() <= 0){ LOG_WARN("NO IPC"); 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); 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); } else if (type >= 200 && type <= 299) { RequestCatalog(client); } else { LOG_WARN("device type is not supported:{}",type); } } // 超过10个心跳周期未收到心跳,做下线处理 for (size_t i = 0; i < vec_sip_id.size(); i++) { deleteClientByDevice(vec_sip_id[i]); } } void SipServer::RequestCatalog(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, "" "" "Catalog" "%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); } 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++) { delete iter->second; iter->second = nullptr; } mClientMap.clear(); return 0; } void SipServer::deleteClientByDevice(string device) { // std::lock_guard l(m_client_map_mtx); 外部调用函数的时候注意加锁,这里去掉加锁 auto it = mClientMap.find(device); if (it == mClientMap.end()) { return ; } std::lock_guard l_d(m_device_map_mtx); for (auto it_device = m_device_map.begin(); it_device != m_device_map.end(); ) { string parent_id = it_device->second.parentid; if (parent_id == device) { it_device = m_device_map.erase(it_device); continue; } it_device++; } delete it->second; it->second = nullptr; mClientMap.erase(it); } int SipServer::parse_xml(const char *data, const char *s_mark, bool with_s_make, const char *e_mark, bool with_e_make, char *dest) { const char* satrt = strstr( data, s_mark ); if(satrt != NULL) { const char* end = strstr(satrt, e_mark); if(end != NULL){ int s_pos = with_s_make ? 0 : strlen(s_mark); int e_pos = with_e_make ? strlen(e_mark) : 0; strncpy( dest, satrt+s_pos, (end+e_pos) - (satrt+s_pos) ); } return 0; } return -1; } void SipServer::dump_request(eXosip_event_t *evtp) { char *s = nullptr; size_t len; osip_message_to_str(evtp->request, &s, &len); if (s) { // LOG_INFO("\nprint request start\ntype={}\n{}\nprint request end\n",evtp->type,s); } } void SipServer::dump_response(eXosip_event_t *evtp) { char *s = nullptr; size_t len; osip_message_to_str(evtp->response, &s, &len); if (s) { // LOG_INFO("\nprint response start\ntype={}\n{}\nprint response end\n",evtp->type,s); } }