// // 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 "../common_header.h" #include "./Utils/HTTPDigest.h" #include #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); } static bool isntspace(const char &ch) { return !isspace(ch); } static std::string trim(const std::string &s) { std::string::const_iterator iter1 = find_if(s.begin(), s.end(), isntspace); std::string::const_iterator iter2 = find_if(s.rbegin(), s.rend(), isntspace).base(); return iter1 < iter2 ? string(iter1, iter2) : std::string(""); } SipServer::SipServer(): mQuit(false), mSipCtx(nullptr){ #ifdef WIN32 WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { LOG_ERROR("WSAStartup Error"); return; } #endif // WIN32 } 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) { if (pInfo == nullptr) { std::ifstream cfgFile("./sip_server_cfg.xml"); if(cfgFile.is_open()) { string strConfig; string str; int char_count = 0; while(cfgFile >> str) { strConfig += str; } CCatalogParser catPaser; mInfo = catPaser.DecodeServerConfig(strConfig.c_str()); } else { LOG_ERROR("read sip server config file failed!"); return false; } cfgFile.close(); } else { mInfo = *pInfo; } LOG_INFO("{}:{}", mInfo.getIp(), mInfo.getPort()); m_event_loop_thread = new std::thread(event_loop_thread, this); return true; } int SipServer::GetMinRtpPort(){ return mInfo.getMinRtpPort(); } int SipServer::GetMaxRtpPort(){ return mInfo.getMaxRtpPort(); } 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); 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)) { this->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); break; case EXOSIP_CALL_SERVERFAILURE: LOG_INFO("EXOSIP_CALL_SERVERFAILURE type={}", evtp->type); break; case EXOSIP_IN_SUBSCRIPTION_NEW: LOG_INFO("EXOSIP_IN_SUBSCRIPTION_NEW type={}", evtp->type); break; default: LOG_INFO("type={} unknown", evtp->type); break; } return 0; } 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 (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; } 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(eXosip_event_t *evtp) { osip_authorization_t * auth = nullptr; osip_message_get_authorization(evtp->request, 0, &auth); if(auth && auth->username){ 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 osip_contact_t *contact = nullptr; osip_message_get_contact (evtp->request, 0, &contact); 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); Client* client = new Client(strdup(contact->url->host), atoi(contact->url->port), strdup(username)); LOG_INFO("Camera registration succee,ip={},port={},device={}",client->getIp(),client->getPort(),client->getDevice()); std::lock_guard l(m_client_map_mtx); auto it_client = mClientMap.find(client->getDevice()); if (it_client != mClientMap.end()) { Client* c = it_client->second; delete c; c = nullptr; mClientMap.erase(it_client); } mClientMap.insert(std::make_pair(client->getDevice(),client)); // NVR注册成功,立即请求设备目录 RequestCatalog(client); } 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); } } 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) { LOG_INFO("-----start print----"); for (size_t i = 0; i < vec_device.size(); i++) { LOG_INFO("{} {}", vec_device[i].id, vec_device[i].parentid); } LOG_INFO("-----end print----"); } 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); } 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, "Keepalive")){ this->response_message_answer(evtp,200); // LOG_INFO("CmdType={},DeviceID={}", CmdType, DeviceID); std::lock_guard l_c(m_client_map_mtx); Client* client = mClientMap[DeviceID]; if (client != nullptr) { client->updateHeartBeat(UtilTools::get_cur_time_ms()); } }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 = trim(it_info->second.status); // status = std::tolower(status.c_str()); 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::RequestInvite_UDP(const char* dst_channel, 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 UDP"); char session_exp[1024] = { 0 }; osip_message_t* msg = nullptr; char from[1024] = { 0 }; char to[1024] = { 0 }; char sdp[2048] = { 0 }; char head[1024] = { 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(), 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); } 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, 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 }; char head[1024] = { 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); } 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){ cout << "no IPC" << endl; return ; } cout << "client size:" << mClientMap.size() << endl; for (auto it = mClientMap.begin(); it != mClientMap.end(); it++) { RequestCatalog(it->second); } } 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); } 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 ; } 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; size_t len; osip_message_to_str(evtp->request, &s, &len); LOG_INFO("\nprint request start\ntype={}\n{}\nprint request end\n",evtp->type,s); } void SipServer::dump_response(eXosip_event_t *evtp) { char *s; size_t len; osip_message_to_str(evtp->response, &s, &len); LOG_INFO("\nprint response start\ntype={}\n{}\nprint response end\n",evtp->type,s); }