497 lines
14 KiB
C++
497 lines
14 KiB
C++
/***************************************************************************************
|
||
*
|
||
* IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||
*
|
||
* By downloading, copying, installing or using the software you agree to this license.
|
||
* If you do not agree to this license, do not download, install,
|
||
* copy or use the software.
|
||
*
|
||
* Copyright (C) 2014-2022, Happytimesoft Corporation, all rights reserved.
|
||
*
|
||
* Redistribution and use in binary forms, with or without modification, are permitted.
|
||
*
|
||
* Unless required by applicable law or agreed to in writing, software distributed
|
||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
|
||
* language governing permissions and limitations under the License.
|
||
*
|
||
****************************************************************************************/
|
||
|
||
#include "sys_inc.h"
|
||
#include "hqueue.h"
|
||
#include "linked_list.h"
|
||
#include "rfc_md5.h"
|
||
#include "word_analyse.h"
|
||
#include "digcalc.h"
|
||
#include "ppstack.h"
|
||
#include "hsip.h"
|
||
#include "sua.h"
|
||
#include "sip_parse.h"
|
||
#include "sip_tx.h"
|
||
#include "sip_reg.h"
|
||
#include "gb28181.h"
|
||
|
||
|
||
/*******************************************************/
|
||
extern HSIP_CLASS hsip;
|
||
|
||
/*******************************************************\
|
||
建立注册消息实用函数
|
||
\*******************************************************/
|
||
void sip_reg_build_from(HSIP_MSG * tx_msg, HSIP_USER * p_user)
|
||
{
|
||
int offset = 0;
|
||
char tmp_buf[512];
|
||
|
||
if (p_user->user_disp_name[0] != '\0')
|
||
{
|
||
offset += sprintf(tmp_buf+offset, "\"%s\" ", p_user->user_disp_name);
|
||
}
|
||
|
||
offset += sprintf(tmp_buf+offset, "<%s>", p_user->user_sip_addr);
|
||
|
||
if (p_user->auth_f_tag[0] != '\0')
|
||
{
|
||
offset += sprintf(tmp_buf+offset, ";%s", p_user->auth_f_tag);
|
||
}
|
||
|
||
sip_add_tx_msg_line(tx_msg, "From", "%s", tmp_buf);
|
||
}
|
||
|
||
void sip_reg_build_to(HSIP_MSG * tx_msg, HSIP_USER * p_user)
|
||
{
|
||
int offset = 0;
|
||
char tmp_buf[512];
|
||
|
||
if (p_user->user_disp_name[0] != '\0')
|
||
{
|
||
offset += sprintf(tmp_buf+offset, "\"%s\" ", p_user->user_disp_name);
|
||
}
|
||
|
||
offset += sprintf(tmp_buf+offset, "<%s>", p_user->user_sip_addr);
|
||
|
||
sip_add_tx_msg_line(tx_msg, "To", "%s", tmp_buf);
|
||
}
|
||
|
||
void sip_reg_build_contact(HSIP_MSG * tx_msg, HSIP_USER * p_user)
|
||
{
|
||
if (p_user->user_disp_name[0] == '\0')
|
||
{
|
||
sip_add_tx_msg_line(tx_msg, "Contact", "<sip:%s@%s:%u>", p_user->user_name, p_user->user_ip, p_user->user_port);
|
||
}
|
||
else
|
||
{
|
||
sip_add_tx_msg_line(tx_msg, "Contact", "\"%s\" <sip:%s@%s:%u>", p_user->user_disp_name, p_user->user_name,
|
||
p_user->user_ip, p_user->user_port);
|
||
}
|
||
}
|
||
|
||
/*******************************************************\
|
||
建立普通注册消息
|
||
\*******************************************************/
|
||
HSIP_MSG * sip_build_register_normal_msg(HSIP_USER * p_user, uint32 srv_ip, uint16 srv_port)
|
||
{
|
||
HSIP_MSG * tx_msg = sip_get_msg_buf();
|
||
if (NULL == tx_msg)
|
||
{
|
||
log_print(HT_LOG_ERR, "%s, get message buffer failed\r\n", __FUNCTION__);
|
||
return NULL;
|
||
}
|
||
|
||
tx_msg->msg_type = 0;
|
||
tx_msg->msg_sub_type = SIP_MT_REG;
|
||
tx_msg->msg_crpty_mode = p_user->user_crpty_mode;
|
||
tx_msg->local_port = p_user->sip_port;
|
||
|
||
// sip_add_tx_msg_fline(tx_msg, "REGISTER", "sip:%s@%s:%d SIP/2.0", p_user->server_id, p_user->server_ipstr, p_user->server_port);
|
||
sip_add_tx_msg_fline(tx_msg, "REGISTER", "%s SIP/2.0", p_user->server_sip_addr);
|
||
|
||
sprintf(p_user->auth_via.branch, "z9hG4bK%x", sys_os_get_uptime());
|
||
|
||
if (p_user->usrf_tcp_sip == 1)
|
||
{
|
||
sip_add_tx_msg_via(tx_msg, "SIP/2.0/TCP %s:%u;rport;branch=%s", p_user->user_ip, p_user->user_port, p_user->auth_via.branch);
|
||
}
|
||
else
|
||
{
|
||
sip_add_tx_msg_via(tx_msg, "SIP/2.0/UDP %s:%u;rport;branch=%s", p_user->user_ip, p_user->user_port, p_user->auth_via.branch);
|
||
}
|
||
|
||
if (p_user->auth_f_tag[0] == '\0')
|
||
{
|
||
sprintf(p_user->auth_f_tag, "tag=%08x", rand());
|
||
}
|
||
|
||
sip_reg_build_from(tx_msg,p_user);
|
||
sip_reg_build_to(tx_msg,p_user);
|
||
sip_reg_build_contact(tx_msg,p_user);
|
||
|
||
if (p_user->auth_call_id[0] == '\0')
|
||
{
|
||
sprintf(p_user->auth_call_id, "%08X%08X@%s", rand(), rand(), p_user->user_ip);
|
||
}
|
||
|
||
sip_add_tx_msg_line(tx_msg, "Call-ID", "%s", p_user->auth_call_id);
|
||
|
||
p_user->auth_cseq++;
|
||
if (p_user->auth_cseq == 0)
|
||
{
|
||
p_user->auth_cseq = 1;
|
||
}
|
||
|
||
sip_add_tx_msg_line(tx_msg, "CSeq", "%d REGISTER", p_user->auth_cseq);
|
||
sip_add_tx_msg_line(tx_msg, "Max-Forwards", "70");
|
||
sip_add_tx_msg_line(tx_msg, "Expires", "%u", p_user->expires_time);
|
||
sip_add_tx_msg_line(tx_msg, "User-Agent", "%s", p_user->user_agent_desc);
|
||
sip_add_tx_msg_line(tx_msg, "Content-Length", "0");
|
||
|
||
tx_msg->remote_ip = srv_ip;
|
||
tx_msg->remote_port = srv_port;
|
||
|
||
p_user->last_reg_time = sys_os_get_uptime();
|
||
|
||
return tx_msg;
|
||
}
|
||
|
||
/*******************************************************\
|
||
建立带HTTP摘要认证信息的注册消息
|
||
\*******************************************************/
|
||
HSIP_MSG * sip_build_register_digest_msg(HSIP_MSG * rx_msg, HSIP_USER * p_user)
|
||
{
|
||
HSIP_MSG * tx_msg = sip_get_msg_buf();
|
||
if (NULL == tx_msg)
|
||
{
|
||
log_print(HT_LOG_ERR, "%s, get message buffer failed\r\n", __FUNCTION__);
|
||
return NULL;
|
||
}
|
||
|
||
tx_msg->msg_type = 0;
|
||
tx_msg->msg_sub_type = SIP_MT_REG;
|
||
tx_msg->msg_crpty_mode = rx_msg->msg_crpty_mode;
|
||
tx_msg->local_port = p_user->sip_port;
|
||
|
||
// sip_add_tx_msg_fline(tx_msg, "REGISTER", "sip:%s@%s:%d SIP/2.0", p_user->server_id, p_user->server_ipstr, p_user->server_port);
|
||
sip_add_tx_msg_fline(tx_msg, "REGISTER", "%s SIP/2.0", p_user->server_sip_addr);
|
||
|
||
sprintf(p_user->auth_via.branch, "z9hG4bK%x", sys_os_get_uptime());
|
||
|
||
if (p_user->usrf_tcp_sip == 1)
|
||
{
|
||
sip_add_tx_msg_via(tx_msg, "SIP/2.0/TCP %s:%u;rport;branch=%s", p_user->user_ip, p_user->user_port, p_user->auth_via.branch);
|
||
}
|
||
else
|
||
{
|
||
sip_add_tx_msg_via(tx_msg, "SIP/2.0/UDP %s:%u;rport;branch=%s", p_user->user_ip, p_user->user_port, p_user->auth_via.branch);
|
||
}
|
||
|
||
sip_reg_build_from(tx_msg, p_user);
|
||
sip_reg_build_to(tx_msg, p_user);
|
||
sip_reg_build_contact(tx_msg, p_user);
|
||
|
||
sip_add_tx_msg_line(tx_msg, "Call-ID", "%s", p_user->auth_call_id);
|
||
|
||
char cseq_buf[256];
|
||
sip_get_msg_cseq(rx_msg, cseq_buf, sizeof(cseq_buf));
|
||
p_user->auth_cseq = atoi(cseq_buf) + 1;
|
||
|
||
sip_add_tx_msg_line(tx_msg, "CSeq", "%d REGISTER", p_user->auth_cseq);
|
||
sip_add_tx_msg_line(tx_msg, "Max-Forwards", "70");
|
||
sip_add_tx_msg_line(tx_msg, "Expires", "%u", p_user->expires_time);
|
||
sip_add_tx_msg_line(tx_msg, "User-Agent", "%s", p_user->user_agent_desc);
|
||
|
||
char auth_field_name[MAX_USRL];
|
||
if (rx_msg->msg_sub_type == 401)
|
||
{
|
||
strcpy(auth_field_name, "Authorization");
|
||
}
|
||
else if (rx_msg->msg_sub_type == 407)
|
||
{
|
||
strcpy(auth_field_name, "Proxy-Authorization");
|
||
}
|
||
else
|
||
{
|
||
auth_field_name[0] = '\0';
|
||
}
|
||
|
||
if (p_user->user_auth_info.auth_qop[0] != '\0')
|
||
{
|
||
sip_add_tx_msg_line(tx_msg, auth_field_name, "Digest username=\"%s\",realm=\"%s\",nonce=\"%s\",response=\"%s\","
|
||
" uri=\"%s\",qop=auth,algorithm=MD5,cnonce=\"%s\",nc=%s",
|
||
p_user->user_auth_info.auth_name, p_user->user_auth_info.auth_realm,
|
||
p_user->user_auth_info.auth_nonce, p_user->user_auth_info.auth_response,
|
||
p_user->user_auth_info.auth_uri, p_user->user_auth_info.auth_cnonce, p_user->user_auth_info.auth_ncstr);
|
||
}
|
||
else
|
||
{
|
||
sip_add_tx_msg_line(tx_msg,auth_field_name, "Digest username=\"%s\",realm=\"%s\",uri=\"%s\",nonce=\"%s\",response=\"%s\",algorithm=MD5",
|
||
p_user->user_auth_info.auth_name, p_user->user_auth_info.auth_realm,
|
||
p_user->user_auth_info.auth_uri, p_user->user_auth_info.auth_nonce, p_user->user_auth_info.auth_response);
|
||
}
|
||
|
||
sip_add_tx_msg_line(tx_msg, "Content-Length", "0");
|
||
|
||
tx_msg->remote_ip = rx_msg->remote_ip;
|
||
tx_msg->remote_port = rx_msg->remote_port;
|
||
|
||
return tx_msg;
|
||
}
|
||
|
||
/*******************************************************\
|
||
从消息中获取服务器发送的digest chap 信息
|
||
\*******************************************************/
|
||
BOOL sip_get_digest_info(HSIP_MSG * rx_msg, HD_AUTH_INFO * auth_info)
|
||
{
|
||
HDRV * chap_id = NULL;
|
||
|
||
if (rx_msg->msg_sub_type == 401)
|
||
{
|
||
chap_id = sip_find_headline(rx_msg, "WWW-Authenticate");
|
||
}
|
||
|
||
if (rx_msg->msg_sub_type == 407)
|
||
{
|
||
chap_id = sip_find_headline(rx_msg, "Proxy-Authenticate");
|
||
}
|
||
|
||
if (chap_id == NULL)
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
char word_buf[128];
|
||
int next_offset;
|
||
|
||
auth_info->auth_response[0] = '\0';
|
||
auth_info->auth_uri[0] = '\0';
|
||
|
||
word_buf[0] = '\0';
|
||
GetLineWord(chap_id->value_string, 0, strlen(chap_id->value_string),
|
||
word_buf, sizeof(word_buf), &next_offset, WORD_TYPE_STRING);
|
||
if (strcasecmp(word_buf, "digest") != 0)
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
word_buf[0] = '\0';
|
||
if (GetNameValuePair(chap_id->value_string+next_offset,
|
||
strlen(chap_id->value_string)-next_offset, "realm", word_buf, sizeof(word_buf)) == FALSE)
|
||
{
|
||
return FALSE;
|
||
}
|
||
strcpy(auth_info->auth_realm, word_buf);
|
||
|
||
word_buf[0] = '\0';
|
||
if (GetNameValuePair(chap_id->value_string+next_offset,
|
||
strlen(chap_id->value_string)-next_offset, "nonce", word_buf, sizeof(word_buf)) == FALSE)
|
||
{
|
||
return FALSE;
|
||
}
|
||
strcpy(auth_info->auth_nonce, word_buf);
|
||
|
||
word_buf[0] = '\0';
|
||
if (GetNameValuePair(chap_id->value_string+next_offset,
|
||
strlen(chap_id->value_string)-next_offset,"qop",word_buf,sizeof(word_buf)))
|
||
{
|
||
// strcpy(auth_info->auth_qop, word_buf);
|
||
strcpy(auth_info->auth_qop, "auth");
|
||
}
|
||
else
|
||
{
|
||
auth_info->auth_qop[0] = '\0';
|
||
}
|
||
|
||
sprintf(auth_info->auth_cnonce, "%08X%08X", rand(),rand());
|
||
auth_info->auth_nc++;
|
||
|
||
sprintf(auth_info->auth_ncstr, "%08X", auth_info->auth_nc);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/*******************************************************\
|
||
计算HTTP摘要认证响应
|
||
method_type值:"REGISTER","INVITE",...
|
||
\*******************************************************/
|
||
BOOL sip_sua_digest_calc(const char * method_type, SUA * p_sua)
|
||
{
|
||
HASHHEX HA1;
|
||
HASHHEX HA2 = "";
|
||
|
||
HSIP_USER * p_user = p_sua->p_user;
|
||
if (p_user == NULL)
|
||
{
|
||
log_print(HT_LOG_ERR, "%s, p_user == NULL!!!\r\n", __FUNCTION__);
|
||
return FALSE;
|
||
}
|
||
|
||
sprintf(p_sua->user_auth_info.auth_ncstr,"%08X", p_sua->user_auth_info.auth_nc);
|
||
DigestCalcHA1("md5",p_sua->user_auth_info.auth_name, p_sua->user_auth_info.auth_realm, p_user->user_auth_passwd,
|
||
p_sua->user_auth_info.auth_nonce, p_sua->user_auth_info.auth_cnonce, HA1);
|
||
|
||
DigestCalcResponse(HA1, p_sua->user_auth_info.auth_nonce, p_sua->user_auth_info.auth_ncstr, p_sua->user_auth_info.auth_cnonce,
|
||
p_sua->user_auth_info.auth_qop, method_type,p_sua->user_auth_info.auth_uri, HA2, p_sua->user_auth_info.auth_response);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/*******************************************************\
|
||
UA注册响应消息接收处理
|
||
\*******************************************************/
|
||
void sip_register_response_rx(HSIP_MSG * rx_msg, HSIP_USER * p_user)
|
||
{
|
||
char expires_buf[16];
|
||
|
||
switch (rx_msg->msg_sub_type)
|
||
{
|
||
case 401:
|
||
case 407:
|
||
{
|
||
char tmp_auth_name[MAX_USRL];
|
||
strcpy(tmp_auth_name, p_user->user_auth_info.auth_name); // 暂存认证用户名
|
||
|
||
if (sip_get_digest_info(rx_msg, &(p_user->user_auth_info))) // 获取WWW-Authentication信息
|
||
{
|
||
strcpy(p_user->user_auth_info.auth_name, tmp_auth_name);
|
||
sprintf(p_user->user_auth_info.auth_uri, "sip:%s@%s", p_user->server_id, p_user->user_domain);
|
||
http_digest_auth(p_user, &(p_user->user_auth_info), "REGISTER"); // 计算出Authorization部分信息
|
||
|
||
usleep(500*1000); // 休眠500ms
|
||
|
||
HSIP_MSG * tx_msg = sip_build_register_digest_msg(rx_msg, p_user);
|
||
if (tx_msg)
|
||
{
|
||
user_tx_free_msg(p_user,tx_msg);
|
||
}
|
||
|
||
p_user->user_state = HSIP_AUTH_CHAP_RX;
|
||
|
||
sip_reg_notify(p_user, PUEVT_REGING);
|
||
}
|
||
else
|
||
{
|
||
p_user->usrf_auth = 0;
|
||
p_user->user_state = HSIP_AUTH_FAIL;
|
||
|
||
sip_reg_notify(p_user, PUEVT_REG_FAIL);
|
||
}
|
||
|
||
p_user->last_reg_time = sys_os_get_uptime();
|
||
}
|
||
break;
|
||
|
||
case 200:
|
||
// 注册成功,改变相应状态
|
||
p_user->user_state = HSIP_AUTH_200;
|
||
p_user->last_reg_time = sys_os_get_uptime();
|
||
|
||
// 获取注册超期时长,如果没有指定可能需要在每个呼叫中进行认证
|
||
if (sip_get_msg_expires(rx_msg, expires_buf, sizeof(expires_buf)))
|
||
{
|
||
p_user->expires_time = atol(expires_buf);
|
||
}
|
||
|
||
if (p_user->expires_time == 0) // 用户注销的情况
|
||
{
|
||
p_user->user_state = HSIP_AUTH_IDLE;
|
||
p_user->usrf_auth = 0;
|
||
}
|
||
else
|
||
{
|
||
// SIP注册校时
|
||
HDRV * data_line = sip_find_headline(rx_msg, "Date");
|
||
if (data_line && data_line->value_string)
|
||
{
|
||
gb28181_time_update(data_line->value_string);
|
||
}
|
||
|
||
HDRV * srvid_line = sip_find_headline(rx_msg, "SRV-ID");
|
||
if (srvid_line && srvid_line->value_string)
|
||
{
|
||
strncpy(p_user->server_id, srvid_line->value_string, sizeof(p_user->server_id));
|
||
}
|
||
|
||
// 获取 To 字段的显示名称
|
||
char disp_name[128];
|
||
|
||
if (sip_get_disp_name(rx_msg, "To", disp_name, sizeof(disp_name)))
|
||
{
|
||
strcpy(p_user->user_disp_name, disp_name);
|
||
}
|
||
|
||
sip_get_server_info(rx_msg, p_user->server_agent, sizeof(p_user->server_agent) - 1);
|
||
|
||
if (0 == p_user->usrf_auth)
|
||
{
|
||
p_user->usrf_auth = 1;
|
||
p_user->last_hb_time = sys_os_get_uptime();
|
||
sip_reg_notify(p_user, PUEVT_REG_PASS);
|
||
}
|
||
}
|
||
break;
|
||
|
||
case 404:
|
||
p_user->user_state = HSIP_AUTH_FAIL;
|
||
p_user->usrf_auth = 0;
|
||
|
||
sip_reg_notify(p_user, PUEVT_REG_FAIL);
|
||
break;
|
||
}
|
||
}
|
||
|
||
/***********************************************************************\
|
||
从HSIP_USER结构中取信息进行计算:
|
||
如果response为空,则将计算出来的值以字符 串方式填入response中,返回TRUE
|
||
如果非空,则与之进行比较,返回比较结果
|
||
\***********************************************************************/
|
||
BOOL http_digest_auth(HSIP_USER * p_user, HD_AUTH_INFO * auth_info, const char * method)
|
||
{
|
||
HASHHEX HA1;
|
||
HASHHEX HA2 = "";
|
||
|
||
DigestCalcHA1("md5",auth_info->auth_name, auth_info->auth_realm, p_user->user_auth_passwd,
|
||
auth_info->auth_nonce, auth_info->auth_cnonce, HA1);
|
||
|
||
if (auth_info->auth_response[0] == '\0')
|
||
{
|
||
sprintf(auth_info->auth_ncstr,"%08X", auth_info->auth_nc);
|
||
DigestCalcResponse(HA1, auth_info->auth_nonce, auth_info->auth_ncstr, auth_info->auth_cnonce,
|
||
auth_info->auth_qop, method/*"REGISTER"*/,auth_info->auth_uri, HA2, auth_info->auth_response);
|
||
return TRUE;
|
||
}
|
||
else
|
||
{
|
||
char calc_response[36];
|
||
DigestCalcResponse(HA1, auth_info->auth_nonce, auth_info->auth_ncstr, auth_info->auth_cnonce,
|
||
auth_info->auth_qop, method/*"REGISTER"*/,auth_info->auth_uri, HA2, calc_response);
|
||
if (strcmp(calc_response, auth_info->auth_response) == 0)
|
||
return TRUE;
|
||
else
|
||
return FALSE;
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
/***********************************************************************\
|
||
注册状态向上通知
|
||
\***********************************************************************/
|
||
BOOL sip_reg_notify(HSIP_USER * p_user, PUAEVT evt)
|
||
{
|
||
if (p_user == NULL)
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
sys_os_mutex_enter(hsip.mutex_cb);
|
||
if (hsip.ext_ntf_func)
|
||
{
|
||
(*hsip.ext_ntf_func)(0, evt, NULL, 0, hsip.user_data);
|
||
}
|
||
sys_os_mutex_leave(hsip.mutex_cb);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
|