sip註冊流程

sip註冊流程圖

1. 客戶端發送一條不帶認證信息的REGISTER

Request-Line: REGISTER sip:[email protected]:10086 SIP/2.0
Via: SIP/2.0/UDP 10.13.1.160:10010;rport;branch=z9hG4bK1888195010
From: <sip:[email protected]:10086>;tag=4200600149
To: <sip:[email protected]:10086>
Call-ID: 1285184780
CSeq: 1 REGISTER
Contact: <sip:[email protected]:10010;line=36f35c382e1b336>
Max-Forwards: 70
User-Agent: eXosip/3.6.0
Expires: 180
Content-Length: 0

From: 該REGISTER請求由uas控制的uac發起
To: 該REGISTER請求接收方地址
Call-ID: 自動生成, 唯一, 後續都需要
CSeq: 遞增
Contact: 在REGISTER請求中的Contact字段指明用戶可達位置
Expires: 生存週期

2. 服務器返回401(未授權)

Status-Line: SIP/2.0 401 Unauthorized
Via: SIP/2.0/UDP 10.13.1.160:10010;rport=10010;branch=z9hG4bK1888195010
From: <sip:[email protected]:10086>;tag=4200600149
To: <sip:[email protected]:10086>;tag=2255890837
Call-ID: 1285184780
CSeq: 1 REGISTER
WWW-Authenticate: Digest realm="SipServer", nonce="4d3b742079a50c064f8fb89add02966d", opaque="4d3b742079a50c064f8fb89add02966d", qop="auth,auth-int"
Content-Type: Application/TIME
User-Agent: eXosip/3.6.0
Content-Length:    28
time=2016-02-29 15:34:02.072

WWW-Authenticate: Digest 
realm="SipServer", 主機名或域名
nonce="4d3b742079a50c064f8fb89add02966d", 服務器端指定的數據字符, 401
opaque="4d3b742079a50c064f8fb89add02966d", 可以不用
qop="auth,auth-int" auth: 鑑別方式, auth-int: 鑑別保護的完整性

3. 客戶端發送帶有認證信息的REGISTER

Request-Line: REGISTER sip:[email protected]:10086 SIP/2.0
Via: SIP/2.0/UDP 10.13.1.160:10010;rport;branch=z9hG4bK748991580
From: <sip:[email protected]:10086>;tag=4200600149
To: <sip:[email protected]:10086>
Call-ID: 1285184780
CSeq: 2 REGISTER
Contact: <sip:[email protected]:10010;line=36f35c382e1b336>
 [truncated]Authorization: Digest username="user2", realm="SipServer", nonce="4d3b742079a50c064f8fb89add02966d", uri="sip:[email protected]:10086", response="b1f806137f96dfc211c35d6cb4476e13", algorithm=MD5, cnonce="0a4f113b", opaque="4d3b74
Max-Forwards: 70
User-Agent: eXosip/3.6.0
Expires: 180
Content-Length: 0

Authorization: Digest 
username="user2", 
realm="SipServer", 
nonce="4d3b742079a50c064f8fb89add02966d", 
uri="sip:[email protected]:10086", 
response="b1f806137f96dfc211c35d6cb4476e13", 
algorithm=MD5, 
cnonce="0a4f113b", 
opaque="4d3b742079a50c064f8fb89add02966d", 
qop=auth, 
nc=00000001


4. 服務器進行驗證, 合格返回200OK

Status-Line: SIP/2.0 200 OK
Via: SIP/2.0/UDP 10.13.1.160:10010;rport=10010;branch=z9hG4bK748991580
From: <sip:[email protected]:10086>;tag=4200600149
To: <sip:[email protected]:10086>;tag=2438687717
Call-ID: 1285184780
CSeq: 2 REGISTER
Content-Type: Application/TIME
User-Agent: eXosip/3.6.0
Content-Length:    28
time=2016-02-29 15:34:02.082

uac代碼:

const char *const uac_addr = "10.13.1.160";
const int uac_port = 10010;
const char *const user = "user";
const char *const password = "password";
const char *const realm = "SipServer";
const char *const uas_addr = "10.13.5.1";
const int uas_port = 10086;

void SendRegister()
{
	char from[128] = {0}; // 該register請求由uas控制的uac發起
	sprintf(from, "sip:%s@%s:%d", user, uas_addr, uas_port);
	char proxy[128] = {0}; // 該register請求接收方地址
	sprintf(proxy, "sip:%s@%s:%d", user, uas_addr, uas_port);
	char contact[128] = {0}; // 用戶的可達位置
	sprintf(contact, "sip:%s@%s:%d", user, uac_addr, uac_port);

	osip_message_t *reg = NULL;
	eXosip_lock();
	eXosip_clear_authentication_info();
	HASHHEX pwd_md5;
	DigestCalcMD5(password, pwd_md5); // MD5加密函數, 複製的osip_md5c文件
	eXosip_add_authentication_info(user, user, pwd_md5, NULL, NULL);
	int rid = eXosip_register_build_initial_register(from, proxy, NULL/*contact*/, 180, &reg);
	if (rid < 0)
	{
		eXosip_unlock();
		return;
	}
	eXosip_register_send_register(rid, reg);
	eXosip_unlock();
}

{
	eXosip_event_t *je = NULL;
	for (;;)
	{
		je = eXosip_event_wait(0, 200);
		eXosip_lock();
		eXosip_default_action(je);
		eXosip_automatic_refresh();
		eXosip_unlock();
		if (NULL == je)
		{
			continue;
		}

		switch (je->type)
		{
		case EXOSIP_REGISTRATION_SUCCESS:
			{
				if (je->response)
				{
					printf("EXOSIP_REGISTRATION_SUCCESS status_code:%d\n", je->response->status_code);
				}
				bRegistered = true;
			}
			break;
		case EXOSIP_REGISTRATION_FAILURE:
			{
				// 第一次註冊返回401, 403表示用戶名密碼錯誤
				if (je->response)
				{
					printf("EXOSIP_REGISTRATION_FAILURE status_code:%d\n", je->response->status_code);
				}
			}
			break;
		default:
			{
				printf("the sip event type:%d\n", je->type);
			}
			break;
		}
		eXosip_event_free(je);
		je = NULL;
	}
}
uas代碼:

void SendRegisterAnswer(eXosip_event_t *je, int status)
{
	osip_message_t *answer = NULL;
	eXosip_lock();
	int ret = eXosip_message_build_answer(je->tid, status, &answer);
	if (status == 401)
	{
		char hvalue[128] = {0};
		char now[128] = {0};
		HASHHEX nonce;
		sprintf(now, "%d", time(NULL));
		DigestCalcMD5(now, nonce);
		HASHHEX opaque;
		sprintf(now, "%d", time(NULL));
		DigestCalcMD5(now, opaque);
		sprintf(hvalue, "Digest realm=\"%s\",qop=\"%s\",nonce=\"%s\",opaque=\"%s\"", realm, "auth,auth-int", nonce, opaque);
		osip_message_set_www_authenticate(answer, hvalue);

		SYSTEMTIME st;
		GetLocalTime(&st);
		sprintf(now, "time=%.4d-%.2d-%.2d %.2d:%.2d:%.2d.%.3d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
		osip_message_set_body(answer, now, strlen(now));
		osip_message_set_content_type(answer, "Application/TIME");
		printf("發送401報文\n");
	}
	else if (status == 200)
	{
		SYSTEMTIME st;
		GetLocalTime(&st);
		char time[128] = {0};
		sprintf(time, "time=%.4d-%.2d-%.2d %.2d:%.2d:%.2d.%.3d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
		osip_message_set_body(answer, time, strlen(time));
		osip_message_set_content_type(answer, "Application/TIME");
		printf("發送200報文\n");
	}

	if (ret != 0)
	{
		eXosip_message_send_answer(je->tid, 400, NULL);
	}
	else
	{
		eXosip_message_send_answer(je->tid, status, answer);
	}
	eXosip_unlock();
}

{
	eXosip_event_t *je = NULL;
	for (;;)
	{
		je = eXosip_event_wait(0, 200);
		eXosip_lock();
		eXosip_default_action(je);
		eXosip_automatic_refresh();
		eXosip_unlock();
		if (NULL == je)
		{
			continue;
		}

		switch (je->type)
		{
		case EXOSIP_REGISTRATION_NEW:
			{
				printf("EXOSIP_REGISTRATION_NEW\n");
			}
			break;
		case EXOSIP_REGISTRATION_SUCCESS:
			{
				if (je->response)
				{
					printf("EXOSIP_REGISTRATION_SUCCESS status_code:%d\n", je->response->status_code);
				}
			}
			break;
		case EXOSIP_REGISTRATION_FAILURE:
			{
				// 第一次註冊返回401, 403表示用戶名密碼錯誤
				if (je->response)
				{
					printf("EXOSIP_REGISTRATION_FAILURE status_code:%d\n", je->response->status_code);
				}
			}
			break;
		case EXOSIP_MESSAGE_NEW:
			{
				if (MSG_IS_REGISTER(je->request))
				{
					osip_authorization_t *auth = NULL;
					osip_message_get_authorization(je->request, 0, &auth);
					if (auth == NULL) // 401
					{
						SendRegisterAnswer(je, 401);
					}
					else
					{
						char *username = NULL;
						char *realm = NULL;
						char *nonce = NULL;
						char *nonce_count = NULL;
						char *cnonce = NULL;
						char *qop = NULL;
						char *uri = NULL;
						char *response = NULL;

						char *pszAlg = "MD5";
						char *pszUserName = NULL;
						char *pszRealm = NULL;
						HASHHEX pszPassword;
						DigestCalcMD5(password, pszPassword);
						char *pszNonce = NULL;
						char *pszNonceCount = NULL;
						char *pszCNonce = NULL;
						char *pszQop = NULL;
						char *pszDigestUri = NULL;
						char *pszResponse = NULL;

						username = osip_authorization_get_username(auth);
						if (username)
						{
							pszUserName = osip_strdup_without_quote(username);
						}
						realm = osip_authorization_get_realm(auth);
						if (realm)
						{
							pszRealm = osip_strdup_without_quote(realm);
						}
						nonce = osip_authorization_get_nonce(auth);
						if (nonce)
						{
							pszNonce = osip_strdup_without_quote(nonce);
						}
						nonce_count = osip_authorization_get_nonce_count(auth);
						if (nonce_count)
						{
							pszNonceCount = osip_strdup_without_quote(nonce_count);
						}
						cnonce = osip_authorization_get_cnonce(auth);
						if (cnonce)
						{
							pszCNonce = osip_strdup_without_quote(cnonce);
						}
						qop = osip_authorization_get_message_qop(auth);
						if (qop)
						{
							pszQop = osip_strdup_without_quote(qop);
						}
						uri = osip_authorization_get_uri(auth);
						if (uri)
						{
							pszDigestUri = osip_strdup_without_quote(uri);
						}

						HASHHEX HA1;
						HASHHEX Response;
						DigestCalcHA1(pszAlg, pszUserName, pszRealm, pszPassword, pszNonce, pszCNonce, HA1);
						DigestCalcResponse(HA1, pszNonce, pszNonceCount, pszCNonce, pszQop, 0, je->request->sip_method, pszDigestUri, NULL, Response);
						response = osip_authorization_get_response(auth);
						if (response)
						{
							pszResponse = osip_strdup_without_quote(response);
						}
						printf("%s\n%s\n", pszResponse, Response);
						if (stricmp(pszResponse, Response) == 0)
						{
							osip_via_t *via = NULL;
							osip_message_get_via(je->request, 0, &via);
							if (via)
							{
								printf("user:%s, host:%s, port:%s\n", pszUserName, via->host, via->port);
								osip_generic_param_t *received = NULL;
								osip_generic_param_t *rport = NULL;
								osip_via_param_get_byname(via, "received", &received);
								osip_via_param_get_byname(via, "rport", &rport);
								if (received && rport)
								{
									printf("ip:%d, port:%d\n", received->gvalue, rport->gvalue);
								}
							}
							SendRegisterAnswer(je, 200);
						}
						else
						{
							printf("用戶名密碼錯誤\n");
							SendRegisterAnswer(je, 403);
						}
					}
				}
			}
			break;
		default:
			{
				printf("the sip event type:%d\n", je->type);
			}
			break;
		}
		eXosip_event_free(je);
		je = NULL;
	}
}

md5加密方法直接使用的osip_md5c.c文件

代碼下載:點擊打開鏈接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章