Files
gb28181/GB28181Device/sip/sip_reg.cpp
2024-12-15 20:42:32 +08:00

497 lines
14 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/***************************************************************************************
*
* 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;
}