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, ®);
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文件
代碼下載:點擊打開鏈接