视频监控安防平台-GB28181_2016版-注册、心跳、注销

版权声明:本文为博主原创文章,未经博主允许不得转载。QQ/微信联系:123011785 https://blog.csdn.net/songxiao1988918/article/details/79063692

                    视频监控安防平台-GB28181_2016版-注册、心跳、注销

前段时间好几个项目在同时进行,整天忙的不可开交,尤其是项目上的雪亮工程项目需求太多了(而且是各种奇葩的需求,估计也是招投标为了限制其他公司的吧,很多功能都没有实际用处),也没用静下心来好好整理下GB28181相关内容,我准备从头整理一下相关信息,主要以28181检测项为索引来整理,下面我简单介绍下注册、心跳和注销这几个协议,注册和注销很好理解,就是Expires: 0的时候为注销,心跳也很简单就是一个简单的无应答message。

下面将注册的流程图简单摘出来一下:


根据流程图还是比较容易读懂,下面粘贴一下抓包信息:

REGISTER sip:[email protected]:5060 SIP/2.0
Via: SIP/2.0/UDP 192.168.1.93:5060;rport;branch=z9hG4bK-3d09000-23b5dfc-TFyCL5ME
From: <sip:[email protected]:5060>;tag=pck2i7pI
To: <sip:[email protected]:5060>
Call-ID: [email protected]
CSeq: 5 REGISTER
Contact: <sip:[email protected]:5060>
Authorization: Digest username="34020000002000000001", realm="3402000000", nonce="bd2e4df9e3d9b280", uri="sip:[email protected]:5060", response="9c8411f2b96c5aef55eb136ba3f34655", algorithm=MD5
Max-Forwards: 70
User-Agent: iVMS 1.0
Expires: 200
Content-Length: 0

SIP/2.0 401 Unauthorized
To: <sip:[email protected]:5060>;tag=67239569_53173353_7ce4590f-587d-4d44-9690-96498367c675
Via: SIP/2.0/UDP 192.168.1.93:5060;rport=5060;branch=z9hG4bK-3d09000-23b5dfc-TFyCL5ME;received=192.168.1.93
CSeq: 5 REGISTER
Call-ID: [email protected]
From: <sip:[email protected]:5060>;tag=pck2i7pI
WWW-Authenticate: Digest realm="3402000000",nonce="31ada55697307236"
Content-Length: 0

REGISTER sip:[email protected]:5060 SIP/2.0
Via: SIP/2.0/UDP 192.168.1.93:5060;rport;branch=z9hG4bK-3d09000-3068be5-lnl05y0C
From: <sip:[email protected]:5060>;tag=pck2i7pI
To: <sip:[email protected]:5060>
Call-ID: [email protected]
CSeq: 6 REGISTER
Contact: <sip:[email protected]:5060>
Authorization: Digest username="34020000002000000001", realm="3402000000", nonce="31ada55697307236", uri="sip:[email protected]:5060", response="3526a5a5dd91a45e19d1e6a65704457f", algorithm=MD5
Max-Forwards: 70
User-Agent: iVMS 1.0
Expires: 200
Content-Length: 0

SIP/2.0 200 OK
To: <sip:[email protected]:5060>;tag=86156704_53173353_d7fb589f-4357-4fae-ae32-47c38d81fff1
Via: SIP/2.0/UDP 192.168.1.93:5060;rport=5060;branch=z9hG4bK-3d09000-3068be5-lnl05y0C;received=192.168.1.93
CSeq: 6 REGISTER
Call-ID: [email protected]
From: <sip:[email protected]:5060>;tag=pck2i7pI
Contact: <sip:[email protected]:5060>
Expires: 200
Date: 2017-05-19T18:09:17.033
Content-Length: 0
其中注册要注意的是,注册的时候有个回复时间格式需要进行上下级和设备之间校时功能:

Date: 2017-05-19T18:09:17.033

心跳:

MESSAGE sip:[email protected]:5060 SIP/2.0
Via: SIP/2.0/UDP 192.168.1.93:5060;rport;branch=z9hG4bK-3d09000-2a2b21b-nddru7fy
From: <sip:[email protected]:5060>;tag=UL61Qycy
To: <sip:[email protected]:5060>
Call-ID: [email protected]
CSeq: 35 MESSAGE
Contact: <sip:192.168.1.93:5060>
Content-Type: Application/MANSCDP+xml
Max-Forwards: 70
User-Agent: iVMS 1.0
Content-Length:   151

<?xml version="1.0"?>
<Notify>
<CmdType>Keepalive</CmdType>
<SN>26</SN>
<DeviceID>64000000002000000001</DeviceID>
<Status>OK</Status>
</Notify>
SIP/2.0 200 OK
To: <sip:[email protected]:5060>;tag=69112542_53173353_89bb4bc2-7f74-42a8-a102-6b6490b6daa2
Via: SIP/2.0/UDP 192.168.1.93:5060;rport=5060;branch=z9hG4bK-3d09000-2a2b21b-nddru7fy;received=192.168.1.93
CSeq: 35 MESSAGE
Call-ID: [email protected]
From: <sip:[email protected]:5060>;tag=UL61Qycy
Content-Length: 0


注销:

REGISTER sip:[email protected]:5060 SIP/2.0
Via: SIP/2.0/UDP 192.168.1.93:5060;rport;branch=z9hG4bK-3d09000-23b5dfc-TFyCL5ME
From: <sip:[email protected]:5060>;tag=pck2i7pI
To: <sip:[email protected]:5060>
Call-ID: [email protected]
CSeq: 5 REGISTER
Contact: <sip:[email protected]:5060>
Authorization: Digest username="34020000002000000001", realm="3402000000", nonce="bd2e4df9e3d9b280", uri="sip:[email protected]:5060", response="9c8411f2b96c5aef55eb136ba3f34655", algorithm=MD5
Max-Forwards: 70
User-Agent: iVMS 1.0
Expires: 0
Content-Length: 0

SIP/2.0 401 Unauthorized
To: <sip:[email protected]:5060>;tag=67239569_53173353_7ce4590f-587d-4d44-9690-96498367c675
Via: SIP/2.0/UDP 192.168.1.93:5060;rport=5060;branch=z9hG4bK-3d09000-23b5dfc-TFyCL5ME;received=192.168.1.93
CSeq: 5 REGISTER
Call-ID: [email protected]
From: <sip:[email protected]:5060>;tag=pck2i7pI
WWW-Authenticate: Digest realm="3402000000",nonce="31ada55697307236"
Content-Length: 0

REGISTER sip:[email protected]:5060 SIP/2.0
Via: SIP/2.0/UDP 192.168.1.93:5060;rport;branch=z9hG4bK-3d09000-3068be5-lnl05y0C
From: <sip:[email protected]:5060>;tag=pck2i7pI
To: <sip:[email protected]:5060>
Call-ID: [email protected]
CSeq: 6 REGISTER
Contact: <sip:[email protected]:5060>
Authorization: Digest username="34020000002000000001", realm="3402000000", nonce="31ada55697307236", uri="sip:[email protected]:5060", response="3526a5a5dd91a45e19d1e6a65704457f", algorithm=MD5
Max-Forwards: 70
User-Agent: iVMS 1.0
Expires: 0
Content-Length: 0

SIP/2.0 200 OK
To: <sip:[email protected]:5060>;tag=86156704_53173353_d7fb589f-4357-4fae-ae32-47c38d81fff1
Via: SIP/2.0/UDP 192.168.1.93:5060;rport=5060;branch=z9hG4bK-3d09000-3068be5-lnl05y0C;received=192.168.1.93
CSeq: 6 REGISTER
Call-ID: [email protected]
From: <sip:[email protected]:5060>;tag=pck2i7pI
Contact: <sip:[email protected]:5060>
Expires: 0
Date: 2017-05-19T18:09:17.033
Content-Length: 0

下面粘贴一下部分注册的代码,由于使用c++写的代码,所有只能裁剪一部分出来:

#include <stdlib.h>
#include <stdio.h>
#include "eXosip2/eXosip.h"
#include "osipparser2/osip_uri.h"
#include "osipparser2/osip_message.h"
#include "eXosip2.h"

//初始化 监听端口
int Init(int listenport)
{
	int iRet = eXosip_init();
	if (iRet != OSIP_SUCCESS)
	{
		//DBGPrint(M_SipUA, ERROR_LEVEL, "eXosip2 fail!");
		//return -1;
		printf("eXosip2 fail! \n");
		exit(1);
	}
	iRet = eXosip_listen_addr(IPPROTO_UDP, NULL, listenport, AF_INET, 0);
	if (iRet != OSIP_SUCCESS)
	{
		eXosip_quit();
		//DBGPrint(M_SipUA, ERROR_LEVEL, "eXosip2 could not initialize transport layer!");
		//return -1;
		DBGPrint(M_SipUA, BREAK_LEVEL, "eXosip2 could not initialize transport layer! \n");
		exit(1);
	}

	DBGPrint(M_SipUA, BREAK_LEVEL, "%s: SipSvr Listen Port:%d Sucess!!!!", __FUNCTION__, listenport);
	return 0;	
}

/*******************************************************************************
* Function: 
*	Digest MD5 authorization validate process.
*******************************************************************************/
//MD5鉴权
bool MD5AuthValidate(char *pMethod, osip_authorization_t *pAuthEcho)
{
	if (NULL == pAuthEcho)
	{
		DBGPrint(M_SipUA, ERROR_LEVEL, "pAuthField is null pointer!");
		return false;
	}

	char *pAlgorithm  = NULL;
	char *pUsername   = NULL;
	char *pRealm      = NULL;
	char *pPasswd     = NULL;
	char *pNonce      = NULL;
	char *pNonceCount = NULL;
	char *pCNonce     = NULL;
	char *pQop        = NULL;
	char *pCMethod     = NULL;
	char *pUri        = NULL;
	char sNullAlg[]   = "";  //"MD5";
	char sNullQop[]   = "";  //"auth";
	char SessionKey[MD5_SESSION_KEY_LEN+1] = {0};
	char Response[MD5_RESPONSE_LEN] = {0};
	char *pResponse2  = NULL;
	
	if (NULL == pAuthEcho->algorithm)
		pAlgorithm = unquote(sNullAlg);
	else
		pAlgorithm = unquote(pAuthEcho->algorithm);
	
	pUsername  = unquote(pAuthEcho->username);
	pRealm     = unquote(pAuthEcho->realm);
	pPasswd    = unquote(CSBase::m_SipRegPasswd);
	pNonce     = unquote(pAuthEcho->nonce);
	pCNonce    = unquote(pAuthEcho->cnonce);

	if (NULL == pUsername)
	{
		DBGPrint(M_SipUA, ERROR_LEVEL, "%s Get username is null error!",__FUNCTION__);
		return false;
	}
	if(strcmp(pUsername, CSBase::m_SipRegUserName) != 0)
	{
	//	DBGPrint(M_SipUA, ERROR_LEVEL, "%s %s username error!",__FUNCTION__,pAuthEcho->username);
	//	return false;
	}
	
	//calculate session key
	DigestCalcHA1(pAlgorithm, pUsername, pRealm, pPasswd, pNonce, pCNonce, SessionKey);
	
	pNonceCount = unquote(pAuthEcho->nonce_count);
	
	if (NULL == pAuthEcho->message_qop)
		pQop = unquote(sNullQop);
	else
		pQop = unquote(pAuthEcho->message_qop);
	
	pCMethod = unquote(pMethod);
	pUri    = unquote(pAuthEcho->uri);
	
	//calculate response
	DigestCalcResponse(SessionKey, pNonce, pNonceCount, pCNonce, pQop, pCMethod, pUri, (char*)"", Response);
	
	pResponse2  = unquote(pAuthEcho->response);
	if (strcmp(Response, pResponse2) != 0)
	{
		DBGPrint(M_SipUA, ERROR_LEVEL, "Authorization failed <%s, %s>!", Response, pResponse2);
		return false;
	}
	
	return true;
}

//回复没有包体的响应
int SendRegisterAnswer(int Tid, int Code, bool bSetTime)
{
    osip_message_t * pMsgAnswer = NULL;
	int ret = eXosip_message_build_answer(Tid, Code,&pMsgAnswer);
	if(ret == OSIP_SUCCESS && pMsgAnswer != NULL )
	{
		if (bSetTime == true)
		{
			osip_header_t*  pHeader = NULL;
			char            TmpBuf[CLIP_BUFFER_SIZE+1];
			//initialize Date header
			int iRet = osip_header_init(&pHeader);
			if (OSIP_SUCCESS == iRet)
			{
				time_t now;
				struct timeval tv;
				//Get current time
				gettimeofday(&tv,NULL);

				now = tv.tv_sec;
	//			time(&now);
				//struct tm* pTmVal = localtime(&now);
				struct tm STm = {0};
				struct tm* pTmVal = localtime_r(&now, &STm);  //使用线程安全函数
				if (pTmVal != NULL)
				{
					//系统启用夏令时,需要减去一个小时。
					if (1 == pTmVal->tm_isdst)
					{
						now -= 3600;
						//pTmVal = localtime(&now);
						pTmVal = localtime_r(&now, &STm);  //使用线程安全函数
						if (NULL == pTmVal)
							return -1;
					}
					
					//2010-07-26 16:05:10
					snprintf(TmpBuf, CLIP_BUFFER_SIZE, "%4d-%02d-%02dT%02d:%02d:%02d.%03d", pTmVal->tm_year+1900, pTmVal->tm_mon+1, pTmVal->tm_mday, pTmVal->tm_hour, \
						pTmVal->tm_min, pTmVal->tm_sec,(int)(tv.tv_usec/1000));
				
					//set Date field
					osip_header_set_name(pHeader, osip_strdup("Date") );
					osip_header_set_value(pHeader, osip_strdup(TmpBuf) );
					osip_list_add(&pMsgAnswer->headers, pHeader, -1);
				}
			}
		}
		
		eXosip_message_send_answer(Tid, Code, pMsgAnswer);
	}
	else
	{
		DBGPrint(M_SipUA, ERROR_LEVEL, "%s:Build Message Answer Failed Tid<%d> Code<%d>!", __FUNCTION__, Tid, Code);
	}
	return 0;
}

//初始接收的注册信息
int ProceRegister(const eXosip_event_t* pSipEvt)
{
	int iReturnCode = -1;
	int iRet = -1;
	osip_authorization_t *pWWWAuEcho = NULL;
	iRet = osip_message_get_authorization(pSipEvt->request, 0, &pWWWAuEcho);
	if (iRet != -1)
	{
		//鉴权, 鉴权成功回复200OK
		if (MD5AuthValidate(pSipEvt->request->sip_method, pWWWAuEcho))
		{
			//鉴权成功,回复200成功
			//添加用户信息
			SendRegisterAnswer(pSipEvt->tid, SIP_OK, true);
		}
		else
		{
			//鉴权失败,回复403
			SendRegisterAnswer(pSipEvt->tid, SIP_FORBIDDEN, false);
		}
	}
	else
	{
		//回复401 , 待认证
		osip_www_authenticate_t *pWWWAuth = NULL;
		iRet = osip_www_authenticate_init(&pWWWAuth);
		if (-1 == iRet)
		{
			DBGPrint(M_SipUA, ERROR_LEVEL, "Failed to init www-authenticate header");
			return -1;	
		}
		char RTag[RANDOM_TAG_LEN+1] = {0};
		char Nonce[DIGEST_NONCE_LEN+1] = {0};
		char TmpBuf[CLIP_BUFFER_SIZE/2+1] = {0};
		SIPGenerateNonce(Nonce, 0, GenerateRandomTag(RTag) );
		osip_www_authenticate_set_auth_type(pWWWAuth, osip_strdup("Digest") );
		memcpy(TmpBuf, CSBase::m_SipSvrPubID, 10);
		char realm[CLIP_BUFFER_SIZE];
		snprintf(realm, CLIP_BUFFER_SIZE/2, "\"%s\"", TmpBuf);
		osip_www_authenticate_set_realm(pWWWAuth, osip_strdup(realm) );
		snprintf(TmpBuf, CLIP_BUFFER_SIZE/2, "\"%s\"", Nonce);
		osip_www_authenticate_set_nonce(pWWWAuth, osip_strdup(TmpBuf) );

		char *pDest = NULL;
    	osip_www_authenticate_to_str(pWWWAuth, &pDest);

		osip_message_t * pSRegister = NULL;
	    iReturnCode = eXosip_message_build_answer(pSipEvt->tid,SIP_UNAUTHORIZED,&pSRegister);
	    if ( iReturnCode == 0 && pSRegister != NULL )
	    {
	        osip_message_set_www_authenticate(pSRegister,pDest);
	        osip_message_set_content_type(pSRegister,"Application/MANSCDP+xml");
	        eXosip_message_send_answer(pSipEvt->tid,SIP_UNAUTHORIZED,pSRegister);
	    }

	    osip_www_authenticate_free(pWWWAuth);
	    osip_free(pDest);		
	}

	return 0;
}


int ProceXsipEvt(eXosip_event_t* pSipEvt)
{
	//Check input parameter exception
	if (NULL == pSipEvt)
	{
		DBGPrint(M_SipUA, ERROR_LEVEL, "%s: pSipEvt is null pointer!", __FUNCTION__);
		return -1;
	}
	//Check eXosip event type
	switch (pSipEvt->type) 
	{
	case EXOSIP_MESSAGE_NEW: 
		if (MSG_IS_NOTIFY(pSipEvt->request)) 
		{	
			//ProceNotify(pSipEvt);
		}
		else if(MSG_IS_MESSAGE(pSipEvt->request))
		{
			//ProceMessage(pSipEvt);
		}
		else if(MSG_IS_REGISTER(pSipEvt->request))
		{
			ProceRegister(pSipEvt);
		}
		break;
	case EXOSIP_SUBSCRIPTION_ANSWERED:
	case EXOSIP_SUBSCRIPTION_REQUESTFAILURE:
		{
			//ProcSubScribleAnswer(pSipEvt);	
		}
		break;
	case EXOSIP_SUBSCRIPTION_NOTIFY:
		{
			//ProceNotify(pSipEvt);
		}
		break;
	case EXOSIP_CALL_PROCEEDING:
	case EXOSIP_CALL_RINGING:
		break;
		
	case EXOSIP_CALL_ANSWERED:
		{	
			eXosip_call_t* pJCall = NULL;
			if (OSIP_SUCCESS == eXosip_call_find(pSipEvt->cid, &pJCall) )
			{	
				//ProcCallAnswer(pSipEvt);
			}
		}
		break;
		
	case EXOSIP_CALL_NOANSWER:
	case EXOSIP_CALL_REDIRECTED:
	case EXOSIP_CALL_REQUESTFAILURE:
	case EXOSIP_CALL_SERVERFAILURE:
	case EXOSIP_CALL_GLOBALFAILURE:
	case EXOSIP_CALL_TIMEOUT:
		{
			if (pSipEvt->request == NULL || pSipEvt->response == NULL)
			{
				DBGPrint(M_SipUA, ERROR_LEVEL, "%s: Recv Sip Type<%d:%s> Error!", __FUNCTION__, pSipEvt->type, GetRecvSipType(pSipEvt->type));
				break;
			}
			DBGPrint(M_SipUA, ERROR_LEVEL, "%s: ******** receive device:<%s> error !response status code:<%d> username:<%s>!", __FUNCTION__, pSipEvt->request->to->url->username, pSipEvt->response->status_code, pSipEvt->request->req_uri->username );
			eXosip_call_t* pJCall = NULL;
			if (OSIP_SUCCESS == eXosip_call_find(pSipEvt->cid, &pJCall) )
			{
				//ProcCallAnswer(pSipEvt);
			}
		}
		break;
		
	case EXOSIP_CALL_MESSAGE_NEW:
		if (MSG_IS_BYE(pSipEvt->request) )
		{
			DBGPrint(M_SipUA, ERROR_LEVEL, "%s: ******** imcoming BYE for DevAor<%s>!", __FUNCTION__, CSBase::URIToAOR(pSipEvt->request->from->url) );
		}
		break;
		
	case EXOSIP_CALL_MESSAGE_ANSWERED:
		//BYE response
		break;
		
	case EXOSIP_CALL_CLOSED:
		break;
		
	case EXOSIP_CALL_RELEASED:
		break;
		
	case EXOSIP_MESSAGE_REQUESTFAILURE:
		break;
	case EXOSIP_MESSAGE_ANSWERED:
		break;
	default:
		DBGPrint(M_SipUA, ERROR_LEVEL, "%s: not handle <%d:%s> event type!", __FUNCTION__, pSipEvt->type, GetRecvSipType(pSipEvt->type));
		return -1;
	}
}

int main()
{
	//初始化exosip协议栈端口
	Init(5060);
	//等待接收sip数据
	while(1)
	{
		//---------------- eXosip running process ----------------//
		eXosip_execute();
		eXosip_event_t* pSipEvt = eXosip_event_wait(0, 50);
		while (pSipEvt != NULL)
		{
			eXosip_lock();
			ProceXsipEvt(pSipEvt);
			eXosip_default_action(pSipEvt);
			eXosip_unlock();
			eXosip_event_free(pSipEvt);
			pSipEvt = eXosip_event_wait(0, 50);
		}
		
		usleep(50000);	
	}
	
}






















猜你喜欢

转载自blog.csdn.net/songxiao1988918/article/details/79063692
今日推荐