/******************************************************************************
Copyright © 2018-2018 TP-Link Systems Inc.
Filename: soap.c
Version: 1.0
Description: soap 处理函数
Author: liyijieliyijie@tp-link.com.cn
Date: 2018-12-03
******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include “onvif_passthrough.h”
#include “soap_global.h”
#include “soap_parse.h”
#include “soap_pack.h”
#define SOAP_TAG_NUM 256 /定义最多可以注册256个标签处理函数/
typedef struct _SOAP_TAG_HANDLE
{
char tag[LEN_TAG];
S32 (*handle)(SOAP_CONTEXT *soap);
}SOAP_TAG_HANDLE; /SOAP_TAG_HANDLE:结构体,包含一个标签字符串和一个处理函数指针/
LOCAL SOAP_TAG_HANDLE g_soap_tag_handle[SOAP_TAG_NUM]; /全局数组,用于存储注册的标签处理函数。/
/******************************************************************************
函数名称: new_soap()
函数描述: 申请soap结构体
输 入: N/A
输 出: N/A
返 回 值: soap结构体地址
******************************************************************************/
SOAP_CONTEXT *new_soap()
{
SOAP_CONTEXT *soap = NULL;
soap = (SOAP_CONTEXT *)ONVIF_MALLOC(sizeof(SOAP_CONTEXT));
if (soap == NULL)
{
ONVIF_ERROR(“malloc g_soap_for_discv failed”);
return NULL;
}
memset(soap, 0, sizeof(SOAP_CONTEXT));
if (OK != onvif_create_buf(&soap->xml_buf, ONVIF_DISCV_BUF_LEN))
{
ONVIF_FREE(soap);
return NULL;
}
return soap;
}
/******************************************************************************
函数名称: free_soap()
函数描述: 释放soap结构体
输 入: soap – soap结构体地址
输 出: N/A
返 回 值: N/A
******************************************************************************/
void free_soap(SOAP_CONTEXT *soap)
{
if (soap == NULL)
{
return;
}
if (soap->fault != NULL)
{
ONVIF_FREE(soap->fault->soap_env_value);
ONVIF_FREE(soap->fault->soap_env_subcode_1);
ONVIF_FREE(soap->fault->soap_env_subcode_2);
ONVIF_FREE(soap->fault->soap_env_reason);
ONVIF_FREE(soap->fault);
}
onvif_free_buf(&soap->xml_buf);
ONVIF_FREE(soap);
return;
}
/******************************************************************************
函数名称: soap_init()
函数描述: 初始化soap结构体
输 入: soap – soap结构体地址
输 出: N/A
返 回 值: N/A
******************************************************************************/
void soap_init(SOAP_CONTEXT *soap)
{
if (soap == NULL)
{
ONVIF_WARN(“soap == NULL.”);
return;
}
soap->error = OK;
soap->in_ip = 0;
soap->ifindex = -1;
soap->has_header = FALSE;
memset(&soap->header, 0, sizeof(SOAP_ENV_HEADER));
if (soap->fault != NULL)
{
ONVIF_FREE(soap->fault->soap_env_value);
ONVIF_FREE(soap->fault->soap_env_subcode_1);
ONVIF_FREE(soap->fault->soap_env_subcode_2);
ONVIF_FREE(soap->fault->soap_env_reason);
ONVIF_FREE(soap->fault);
soap->fault = NULL;
}
soap->tag[0] = ‘\0’;
soap->request_begin = NULL;
soap->request_end = NULL;
soap->types[0] = ‘\0’;
soap->scopes_item[0] = ‘\0’;
soap->scopes_matchby[0] = ‘\0’;
if (soap->xml_buf.start == NULL ||
(soap->xml_buf.end - soap->xml_buf.start) > ONVIF_DISCV_BUF_LEN)
{
if (OK != onvif_create_buf(&soap->xml_buf, ONVIF_DISCV_BUF_LEN))
{
soap->xml_buf.start = NULL;
soap->xml_buf.last = NULL;
soap->xml_buf.end = NULL;
}
}
soap->xml_buf.last = soap->xml_buf.start;
return;
}
/******************************************************************************
函数名称: soap_out_env_fault()
函数描述: 组装错误信息报文内容
输 入: xml_buf – 存放输出xml字串的内存地址
fault_data -- 错误信息
输 出: N/A
返 回 值: ERROR/OK
******************************************************************************/
LOCAL S32 soap_out_env_fault(ONVIF_BUF *xml_buf, SOAP_ENV_FAULT *fault_data)
{
char attr[LEN_ANY] = {0};
if (xml_buf == NULL)
{
ONVIF_WARN(“xml_buf == NULL.”);
return ERROR;
}
/* SOAP-ENV:Fault begin */
SOAP_IF_FAIL_RET(soap_element_begin_out(xml_buf, G_SOAP_ENV_FAULT_STR, NULL));
/* SOAP-ENV:Code begin */
SOAP_IF_FAIL_RET(soap_element_begin_out(xml_buf, “SOAP-ENV:Code”, NULL));
/* SOAP-ENV:Value */
SOAP_IF_FAIL_RET(soap_element(xml_buf, “SOAP-ENV:Value”, fault_data->soap_env_value, NULL));
if (fault_data && fault_data->soap_env_subcode_1)
{
/* SOAP-ENV:Subcode begin */
SOAP_IF_FAIL_RET(soap_element_begin_out(xml_buf, “SOAP-ENV:Subcode”, NULL));
/* SOAP-ENV:Value */ SOAP_IF_FAIL_RET(soap_element(xml_buf, "SOAP-ENV:Value", fault_data->soap_env_subcode_1, NULL)); if (fault_data->soap_env_subcode_2) { /* SOAP-ENV:Subcode begin */ SOAP_IF_FAIL_RET(soap_element_begin_out(xml_buf, "SOAP-ENV:Subcode", NULL)); /* SOAP-ENV:Value */ SOAP_IF_FAIL_RET(soap_element(xml_buf, "SOAP-ENV:Value", fault_data->soap_env_subcode_2, NULL)); /* SOAP-ENV:Subcode end */ SOAP_IF_FAIL_RET(soap_element_end_out(xml_buf, "SOAP-ENV:Subcode")); } /* SOAP-ENV:Subcode end */ SOAP_IF_FAIL_RET(soap_element_end_out(xml_buf, "SOAP-ENV:Subcode"));
}
/* SOAP-ENV:Code end */
SOAP_IF_FAIL_RET(soap_element_end_out(xml_buf, “SOAP-ENV:Code”));
/* SOAP-ENV:Reason begin */
SOAP_IF_FAIL_RET(soap_element_begin_out(xml_buf, “SOAP-ENV:Reason”, NULL));
/* SOAP-ENV:Text */
snprintf(attr, sizeof(attr), “xml:lang="en"”);
SOAP_IF_FAIL_RET(soap_element(xml_buf, “SOAP-ENV:Text”, fault_data->soap_env_reason, attr));
/* SOAP-ENV:Reason end */
SOAP_IF_FAIL_RET(soap_element_end_out(xml_buf, “SOAP-ENV:Reason”));
/* SOAP-ENV:Fault end */
SOAP_IF_FAIL_RET(soap_element_end_out(xml_buf, G_SOAP_ENV_FAULT_STR));
return OK;
}
/******************************************************************************
函数名称: soap_fault()
函数描述: 填充错误信息结构体内容
输 入: soap – soap结构体地址
code -- 错误码
subcode1 -- 子错误码1
subcode2 -- 子错误码2
reason -- 错误原因
输 出: N/A
返 回 值: ERROR/OK
******************************************************************************/
S32 soap_fault(SOAP_CONTEXT *soap, char *code, char *subcode1, char *subcode2, char *reason)
{
ONVIF_TRACE(“Onvif_fault\n”);
if (soap == NULL || code == NULL || subcode1 == NULL)
{
ONVIF_TRACE(“soap == NULL || code == NULL || subcode1 == NULL.”);
return ERROR;
}
if (soap->fault)
{
ONVIF_FREE(soap->fault->soap_env_value);
ONVIF_FREE(soap->fault->soap_env_subcode_1);
ONVIF_FREE(soap->fault->soap_env_subcode_2);
ONVIF_FREE(soap->fault->soap_env_reason);
}
else
{
soap->fault = ONVIF_MALLOC(sizeof(SOAP_ENV_FAULT));
}
if (NULL == soap->fault)
{
ONVIF_WARN(“ONVIF_MALLOC fault failed.”);
return ERROR;
}
memset(soap->fault, 0, sizeof(SOAP_ENV_FAULT));
soap->fault->soap_env_value = ONVIF_STRDUP(code);
if (NULL == soap->fault->soap_env_value)
{
ONVIF_WARN(“ONVIF_STRDUP soap_env_value failed.”);
return ERROR;
}
soap->fault->soap_env_subcode_1 = ONVIF_STRDUP(subcode1);
if (NULL == soap->fault->soap_env_subcode_1)
{
ONVIF_WARN(“ONVIF_STRDUP soap_env_subcode_1 failed.”);
return ERROR;
}
if (subcode2)
{
soap->fault->soap_env_subcode_2 = ONVIF_STRDUP(subcode2);
if (NULL == soap->fault->soap_env_subcode_2)
{
ONVIF_WARN(“ONVIF_STRDUP soap_env_subcode_2 failed.”);
return ERROR;
}
}
if (reason)
{
soap->fault->soap_env_reason = ONVIF_STRDUP(reason);
if (NULL == soap->fault->soap_env_reason)
{
ONVIF_WARN(“ONVIF_STRDUP soap_env_reason failed.”);
return ERROR;
}
}
return OK;
}
/******************************************************************************
函数名称: soap_generate_fault()
函数描述: 组装错误报文xml内容
输 入: soap – soap结构体地址
输 出: N/A
返 回 值: ERROR/OK
******************************************************************************/
LOCAL S32 soap_generate_fault(SOAP_CONTEXT *soap)
{
if (soap == NULL)
{
ONVIF_WARN(“soap == NULL.”);
return ERROR;
}
//soap_set_fault(soap);
if (soap->fault == NULL)
{
return ERROR;
}
if (soap->error < 200 && soap->error != SOAP_FAULT)
{
soap->has_header = FALSE;
}
return soap_generate_xml((p_out_fun)(soap_out_env_fault), soap, soap->fault);
}
/******************************************************************************
函数名称: soap_serve_request()
函数描述: soap请求处理函数入口
输 入: soap – soap结构体地址
输 出: N/A
返 回 值: ERROR/OK
******************************************************************************/
S32 soap_serve_request(SOAP_CONTEXT *soap)
{
U32 index = 0;
PASSTHROUGH_RET ret = 0;
if (soap == NULL || soap->tag[0] == ‘\0’)
{
return ERROR;
}
ret = onvif_serve_passthrough(soap);
if (PASSTHROUGH_ERROR == ret)
{
return ERROR;
}
else if (PASSTHROUGH_SOAP_FAULT == ret)
{
SOAP_IF_FAIL_RET(soap_generate_fault(soap));
}
else if (PASSTHROUGH_NOT_MATCH == ret)
{
for (index = 0; index < SOAP_TAG_NUM; index++)
{
if (NULL == g_soap_tag_handle[index].handle)
{
SOAP_IF_FAIL_RET(soap_fault(soap, “SOAP-ENV:Receiver”, “ter:ActionNotSupported”, NULL, NULL));
soap->error = SOAP_FAULT;
SOAP_IF_FAIL_RET(soap_generate_fault(soap));
break; } if (soap_match_tag(soap->tag, g_soap_tag_handle[index].tag)) { if (g_soap_tag_handle[index].handle(soap)) { if (soap->fault == NULL) { soap_fault(soap, "SOAP-ENV:Sender", "ter:InvalidArgVal", NULL, "error"); soap->error = SOAP_FAULT; } SOAP_IF_FAIL_RET(soap_generate_fault(soap)); } break; } } if (index >= SOAP_TAG_NUM) { SOAP_IF_FAIL_RET(soap_fault(soap, "SOAP-ENV:Receiver", "ter:ActionNotSupported", NULL, NULL)); soap->error = SOAP_FAULT; SOAP_IF_FAIL_RET(soap_generate_fault(soap)); }
}
/* UDP直接回复,HTTP在上一层回复 */
if (soap->use_udp == TRUE &&
soap->xml_buf.start != NULL &&
soap->xml_buf.start != soap->xml_buf.last)
{
return onvif_send_udp_packet(soap->sock, soap->in_ip, soap->sin_port,
soap->xml_buf.start, (soap->xml_buf.last - soap->xml_buf.start));
}
return OK;
}
LOCAL S32 soap_env_fault_handle(SOAP_CONTEXT *soap)
{
if (soap == NULL)
{
ONVIF_WARN(“soap == NULL.”);
return ERROR;
}
ONVIF_TRACE("SOAP-ENV:Fault handle."); /* do nothing and no response */ return OK;
}
/******************************************************************************
函数名称: soap_tag_handle_add()
函数描述: 注册soap请求处理函数
输 入: tag – 请求tag
handle -- 处理函数
输 出: N/A
返 回 值: ERROR/OK
******************************************************************************/
void soap_tag_handle_add(char *tag, void *handle)
{
U32 index = 0;
if ((NULL == tag) || (strlen(tag) >= 64) || (NULL == handle))
{
ONVIF_ERROR(“soap handle add error, invalid arg.”);
return;
}
while ((index < SOAP_TAG_NUM) &&
(NULL != g_soap_tag_handle[index].handle))
{
index++;
}
if (index >= SOAP_TAG_NUM)
{
ONVIF_ERROR(“soap handle add error, max support %d tags.”, SOAP_TAG_NUM);
return;
}
snprintf(g_soap_tag_handle[index].tag, sizeof(g_soap_tag_handle[index].tag), “%s”, tag);
g_soap_tag_handle[index].handle = handle;
return;
}
/******************************************************************************
函数名称: soap_tag_handle_init()
函数描述: 初始化soap请求处理函数
输 入: N/A
输 出: N/A
返 回 值: ERROR/OK
******************************************************************************/
void soap_tag_handle_init()
{
U32 index = 0;
for (index = 0; index < SOAP_TAG_NUM; index++)
{
memset(g_soap_tag_handle[index].tag, 0, sizeof(g_soap_tag_handle[index].tag));
g_soap_tag_handle[index].handle = NULL;
}
soap_tag_handle_add(“SOAP-ENV:Fault”, soap_env_fault_handle);
return;
}
/******************************************************************************
整体模块结构
初始化:调用soap_tag_handle_init初始化路由表。
创建上下文:new_soap创建一个新的SOAP上下文。
初始化上下文:soap_init初始化或重置上下文。
解析请求:由外部函数(如soap_parse_request)解析请求,填充上下文(如设置tag)。
处理请求:调用soap_serve_request,根据标签查找处理函数并执行。
错误处理:若处理出错,使用soap_fault设置错误信息,然后soap_generate_fault生成错误报文。
发送响应:如果是UDP,直接发送;如果是HTTP,由上层发送。
释放资源:调用free_soap释放上下文。
对外接口
soap_serve_request:请求处理入口。
soap_fault:业务函数用于报告错误。
soap_tag_handle_add:业务模块注册处理函数。
soap_tag_handle_init:模块初始化(系统启动时调用)。
//
Copyright © 2018-2018 TP-Link Systems Inc.
Filename: soap_parse.c
Version: 1.0
Description: soap 报文解析函数
Author: liyijieliyijie@tp-link.com.cn
Date: 2018-11-29
******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include “soap_global.h”
#include “soap_parse.h”
LOCAL const SOAP_CODE_MAP g_xml_entity_table[] =
{
{(S32)‘&’, “amp”},
{(S32)‘'’, “apos”},
{(S32)‘>’, “gt”},
{(S32)‘<’, “lt”},
{(S32)‘"’, “quot”}
};
/* abbr表示namespace的缩写,num表示该namespace在G_TP_NAMESPACE_LIST中的序号 */
struct recv_namespace_t
{
unsigned char num;
char abbr[MAX_NAMESPACE_ABBR_LEN];
};
struct recv_namespaces
{
unsigned char ns_count;
struct recv_namespace_t recv_namespace_list[MAX_TP_NAME_SPACE_COUNT];
};
LOCAL struct recv_namespaces g_recv_ns = {0};
LOCAL BOOL g_need_get_global_namespace = FALSE;
LOCAL BOOL g_need_get_tag_namespace = FALSE;
LOCAL int g_tag_namespace = -1;
/****************************************************************************
Function : soap_ipv4_ntop
Description: 将十进制形式的IPv4地址转换为字符串形式
Input : ip_str : IPv4地址字符串形式指针
ip_dec : IPv4地址十进制形式指针
str_len : IPv4地址缓存长度
Output : N/A
Return : 成功返回OK,出错返回ERROR
****************************************************************************/
STATUS soap_ipv4_ntop(u_int32 ip_dec, char *ip_str, u_int32 str_len)
{
struct in_addr in_addr;
if (!ip_str || str_len < 8)
{
return ERROR;
}
in_addr.s_addr = htonl(ip_dec);
if (inet_ntop(AF_INET, &in_addr, ip_str, str_len) == NULL)
{
return ERROR;
}
return OK;
}
/******************************************************************************
函数名称: soap_match_tag()
函数描述: 匹配soap tag
输 入: str – 需要比对的字符串
tag -- 输入的tag
输 出: N/A
返 回 值: TRUE/FALSE
******************************************************************************/
BOOL soap_match_tag(char *str, const char *tag)
{
char *ptr_str = NULL;
char *ptr_tag = NULL;
S32 i = 0;
if (str == NULL || tag == NULL)
{
return FALSE;
}
ptr_tag = strchr(tag, '😂;
ptr_str = strchr(str, '😂;
/* 当tag和str中都有’:'时,将两个字符串分成:前和:后,作两次比较 */
if (ptr_tag != NULL && ptr_str != NULL)
{
char *prev_str = str;
while (prev_str && *prev_str == '/') { prev_str++; } /*比较:前的部分*/ if (!prev_str || strncasecmp((const char *)prev_str, tag, ptr_tag - tag) != 0 || strncasecmp((const char *)prev_str, tag, ptr_str - prev_str) != 0) { return FALSE; } /*继续比较:后的部分*/ ptr_str = ptr_str + 1; ptr_tag = ptr_tag + 1;
}
/* 当tag和str中都没有’:‘时,完整比对两个字符串 */
else if (ptr_tag == NULL && ptr_str == NULL)
{
ptr_str = str;
ptr_tag = (char )tag;
}
/ 当tag和str中有一个字符串有’:‘时,该字符串跳过’:',然后再进行比对 */
else
{
ptr_tag = (ptr_tag == NULL) ? (char *)tag : ptr_tag + 1;
ptr_str = (ptr_str == NULL) ? str : ptr_str + 1;
}
while (ptr_str && *ptr_str == ‘/’)
{
ptr_str++;
}
if (!ptr_str || !ptr_tag)
{
return FALSE;
}
for (i = 0; i < strlen(ptr_tag); i++)
{
if (!ptr_str || *ptr_str == ‘\0’ || TOLOWER(*ptr_str) != TOLOWER(ptr_tag[i]))
{
return FALSE;
}
ptr_str++;
}
if (!ptr_str || *ptr_str != ‘\0’)
{
return FALSE;
}
return TRUE;
}
/******************************************************************************
函数名称: soap_get_char()
函数描述: 从需要解析的xml字串中从获取一个字符
输 入: str – xml字串地址
输 出: N/A
返 回 值: 获取的字符
******************************************************************************/
S32 soap_get_char(char **str)
{
S32 ch;
const char **ps;
if (str == NULL || *str == NULL)
{
return EOF;
}
ps = (const char **)str;
if ((ch = (*ps)[0]) != 0)
{
(*ps)++;
return ch;
}
return EOF;
}
/******************************************************************************
函数名称: soap_add_char()
函数描述: 将一个字符加入指定buf中
输 入: ch – 需要添加的字符
pch -- buf最后一个有效字符的地址
buf -- 指定buf
size -- 指定buf的大小
输 出: N/A
返 回 值: ERROR/OK
******************************************************************************/
S32 soap_add_char(S32 ch, char **pch, char *buf, S32 size)
{
if (pch == NULL || *pch == NULL || buf == NULL)
{
return ERROR;
}
if (*pch >= buf + size - 1)
{
return ERROR;
}
*(*pch)++ = ch & 0xff;
return OK;
}
/******************************************************************************
函数名称: soap_get_entity_value()
函数描述: 将xml字串中的转义字符串转换成实际字符
输 入: entity – 转义字符串
输 出: N/A
返 回 值: 获取的字符
******************************************************************************/
LOCAL S32 soap_get_entity_value(const char *entity)
{
U32 index = 0;
U32 size = sizeof(g_xml_entity_table) / sizeof(g_xml_entity_table[0]);
if (NULL == entity)
{
return -1;
}
for (index = 0; index < size; index++)
{
if (0 == strncmp(g_xml_entity_table[index].str, entity, strlen(g_xml_entity_table[index].str)))
{
return g_xml_entity_table[index].code;
}
}
return -1;
}
/******************************************************************************
函数名称: soap_get_entity()
函数描述: 获取xml字串中的转义字符串并转换成实际字符
输 入: str – xml字串地址
输 出: N/A
返 回 值: 获取的字符
******************************************************************************/
LOCAL S32 soap_get_entity(char **str)
{
S32 ch = 0;
char *entptr = NULL;
char entity[32] = {0};
if (str == NULL || *str == NULL)
{
return EOF;
}
entptr = entity;
while ((ch = soap_get_char(str)) != EOF)
{
if (ch > 126 || (!isalnum(ch) && ch != ‘#’))
{
break;
}
else if (entptr < entity + sizeof(entity) - 1)
{
*entptr++ = ch;
}
else
{
break;
}
}
*entptr = ‘\0’;
if (ch != ‘;’)
{
return EOF;
}
if (entity[0] == ‘#’)
{
if (entity[1] == ‘x’)
{
ch = strtol(entity + 2, NULL, 16);
}
else
{
ch = strtol(entity + 1, NULL, 10);
}
}
else
{
ch = soap_get_entity_value(entity);
}
return ch;
}
/******************************************************************************
函数名称: soap_get_tag()
函数描述: 获取xml字串中element tag
输 入: str_start – xml字串起始地址
xml_str_len -- xml字串长度
p -- 已经解析的xml字串地址
out_buf -- tag输出buf地址
out_buf_len -- tag输出buf大小
输 出: 获得的tag
返 回 值: 获得完整tag后的下一个字符
******************************************************************************/
S32 soap_get_tag(char *str_start, S32 xml_str_len,
char **p, char *out_buf, S32 out_buf_len)
{
S32 ch = 0;
char *pch = out_buf;
if (str_start == NULL ||
out_buf == NULL ||
*p < str_start ||
xml_str_len <= 0 ||
out_buf_len <= 0 ||
(*p - str_start) >= xml_str_len)
{
return EOF;
}
memset(out_buf, 0, out_buf_len);
while ((*p - str_start) < xml_str_len)
{
ch = soap_get_char(p);
if (ch == ‘<’)
{
pch = out_buf;
while ((*p - str_start) < xml_str_len)
{
ch = soap_get_char(p);
if (IS_WHITE_SPACE(ch) || ch == ‘>’ || (ch == ‘/’ && pch > out_buf))
{
break;
}
else if (ch == ‘&’)
{
if ((ch = soap_get_entity(p)) == EOF)
{
return EOF;
}
}
if(soap_add_char(ch, &pch, out_buf, out_buf_len)) { return EOF; } } pch[0] = '\0'; break; }
}
ONVIF_TRACE(“tag:%s”, out_buf);
return ch;
}
int soap_rearrange_tag(const char *src_tag, char *dest_tag)
{
char *temp_ptr = NULL;
int namespace_num = g_tag_namespace;
struct recv_namespaces *recv_ns = &g_recv_ns;
char tag_abbr[MAX_NAMESPACE_ABBR_LEN] = {0};
char temp_abbr[MAX_NAMESPACE_ABBR_LEN] = {0};
int i = 0;
if (!src_tag || !dest_tag) { ONVIF_ERROR("!src_tag || !dest_tag"); return ERROR; } if (namespace_num == -1 && recv_ns->ns_count == 0) { ONVIF_DEBUG("No need to rearrange tag."); return OK; } /* 获取tag内自带的abbr */ temp_ptr = strchr(src_tag, ':'); if (temp_ptr) { snprintf(tag_abbr, temp_ptr - src_tag + 1, "%s", src_tag); temp_ptr++; } else { temp_ptr = (char *)src_tag; } /* 获取abbr,首先使用tag后面指定的namespace */ if (namespace_num != -1) { if(namespace_num < 0 || namespace_num >= MAX_TP_NAME_SPACE_COUNT || G_TP_NAMESPACE_LIST[namespace_num].namespace[0] == 0 || G_TP_NAMESPACE_LIST[namespace_num].namespace_abbr[0] == 0) { ONVIF_ERROR("Get local namespace abbr fail, namespace_num=%d", namespace_num); return ERROR; } snprintf(temp_abbr, MAX_NAMESPACE_ABBR_LEN, "%s", G_TP_NAMESPACE_LIST[namespace_num].namespace_abbr); } /* 其次从g_recv_ns中获取 */ else if (tag_abbr[0] != 0) { for (i = 0; i < recv_ns->ns_count && i < MAX_TP_NAME_SPACE_COUNT; ++i) { if (strcmp(tag_abbr, recv_ns->recv_namespace_list[i].abbr) == 0 && recv_ns->recv_namespace_list[i].num < MAX_TP_NAME_SPACE_COUNT) { snprintf(temp_abbr, MAX_NAMESPACE_ABBR_LEN, "%s", G_TP_NAMESPACE_LIST[recv_ns->recv_namespace_list[i].num].namespace_abbr); //如果命名空间相同,取最新的,防重名 } } } /* 如果通过上面两种方式未获取到namespace,则直接退出,不重组tag */ if (0 == temp_abbr[0]) { return OK; } memset(dest_tag, 0, LEN_TAG); snprintf(dest_tag, LEN_TAG, "%s:%s", temp_abbr, temp_ptr); ONVIF_DEBUG("Tag changes, %s -> %s", src_tag, dest_tag); return OK;
}
/* 如果abbr为NULL,表示需要获取形如的
namespace,返回值为http://www.onvif.org/ver10/device/wsdl在G_TP_NAMESPACE_LIST中的下标值;
如果abbr不为空,表示需要获取形如<s:Envelope xmlns:s=“http://www.w3.org/2003/05/soap-envelope”>的
namespace,将这里定义的缩写s传到abbr中,并返回http://www.w3.org/2003/05/soap-envelope在
G_TP_NAMESPACE_LIST中的下标值;
如果没有匹配到namespace,或者tag里的namespace与缩写和已有的一致,则返回-1 */
int soap_get_namespace(const char *attr_name, const char *attr_value, char *abbr)
{
int i = -1;
if (!attr_name || !attr_value) { ONVIF_ERROR("!attr_name || !attr_value"); return -1; } /* 确认是否是namespace */ if (NULL == strstr(attr_name, "xmlns")) { ONVIF_ERROR("Not a namespace: %s", attr_name); return -1; } /* 获取abbr */ if (abbr) { memset(abbr, 0, MAX_NAMESPACE_ABBR_LEN); if (1 == sscanf(attr_name, "xmlns:%15s", abbr) && 0 < strlen(abbr)) { ONVIF_DEBUG("Get abbr=%s", abbr); } else { ONVIF_DEBUG("Get abbr fail, attr_name=%s", attr_name); abbr[0] = 0; } } /* 查找对应namespace的下标 */ for (i = 0; i < MAX_TP_NAME_SPACE_COUNT; ++i) { if (0 != G_TP_NAMESPACE_LIST[i].namespace[0] && 0 == strcmp(G_TP_NAMESPACE_LIST[i].namespace, attr_value)) { /* 如果获取的是local namespace,或者获取到的abbr与已有的不一致,那就直接返回 */ if (!abbr) { ONVIF_DEBUG("Find a local namespace-%s, ret-%d", attr_value, i); return i; } else if (0 != abbr[0]) { if (0 != strcmp(G_TP_NAMESPACE_LIST[i].namespace_abbr, abbr)) { ONVIF_DEBUG("Find a global namespace-%s(%s), ret-%d", attr_value, abbr, i); return i; } else { ONVIF_DEBUG("This global namespace(%s-%s) has already exist.", abbr, attr_value); return -1; } } else { ONVIF_DEBUG("Find a local namespace-%s, ret-%d", attr_value, i); return i; } } } ONVIF_DEBUG("Can not find this namespace:%s", attr_value); return -1;
}
/******************************************************************************
函数名称: soap_parse_element_attr()
函数描述: Parse an element for any attributes
输 入: str_start – xml字串起始地址
buf_len -- xml字串长度
p -- 已经解析的xml字串地址
输 出: 获得的tag
返 回 值: 解析完所有attr后的下一个字符
******************************************************************************/
S32 soap_parse_element_attr(char *str_start, S32 buf_len, char **p)
{
char attr_name[LEN_TAG] = {0};
char attr_value[LEN_INFO] = {0};
char *ptr = NULL;
S32 ch = 0;
S32 quote = 0;
BOOL need_get_tag_namespace = FALSE;
BOOL need_get_global_namespace = FALSE;
int temp_abbr_num = -1;
char temp_abbr[MAX_NAMESPACE_ABBR_LEN] = {0};
need_get_tag_namespace = g_need_get_tag_namespace;
g_need_get_tag_namespace = FALSE;
need_get_global_namespace = g_need_get_global_namespace;
g_need_get_global_namespace = FALSE;
if (str_start == NULL || p == NULL || *p == NULL)
{
return EOF;
}
while ((p - str_start) < buf_len)
{
ch = soap_get_char(p);
/ Skip leading whitespace */
if (IS_WHITE_SPACE(ch))
{
continue;
}
if (ch == '/' || ch == '?') { quote = soap_get_char(p); if (quote != '>') { return EOF; } (*p)--; break; } else if (ch == '<') { return EOF; } else if (ch == '>') { break; } attr_name[0] = ch; if (ch == '\"' || ch == '\'') /* Name is in quotes, so get a quoted string */ { quote = ch; ptr = attr_name; while ((*p - str_start) < buf_len) { ch = soap_get_char(p); if (ch == '&') { if ((ch = soap_get_entity(p)) == EOF) { return EOF; } } if(soap_add_char(ch, &ptr, attr_name, sizeof(attr_name))) { return EOF; } if (ch == quote) { break; } } } else { ptr = attr_name + 1; while ((*p - str_start) < buf_len) { ch = soap_get_char(p); if (IS_WHITE_SPACE(ch) || ch == '=' || ch == '/' || ch == '>' || ch == '?') { break; } if (ch == '&') { if ((ch = soap_get_entity(p)) == EOF) { return EOF; } } if(soap_add_char(ch, &ptr, attr_name, sizeof(attr_name))) { return EOF; } } } *ptr = '\0'; while ((*p - str_start) < buf_len && IS_WHITE_SPACE(ch)) { ch = soap_get_char(p); } if (ch != '=') { return EOF; } /* Read the attribute value */ while ((*p - str_start) < buf_len) { ch = soap_get_char(p); if (!IS_WHITE_SPACE(ch)) { break; } } if (ch == '\"' || ch == '\'') { quote = ch; ptr = attr_value; while ((*p - str_start) < buf_len) { ch = soap_get_char(p); if (ch == quote) { break; } if (ch == '&') { if ((ch = soap_get_entity(p)) == EOF) { return EOF; } } if(soap_add_char(ch, &ptr, attr_value, sizeof(attr_value))) { return EOF; } } } else { attr_value[0] = ch; ptr = attr_value + 1; while ((*p - str_start) < buf_len) { ch = soap_get_char(p); if (IS_WHITE_SPACE(ch) || ch == '=' || ch == '/' || ch == '>') { break; } if (ch == '&') { if ((ch = soap_get_entity(p)) == EOF) { return EOF; } } if(soap_add_char(ch, &ptr, attr_value, sizeof(attr_value))) { return EOF; } } } *ptr = '\0'; if (need_get_tag_namespace || need_get_global_namespace) { ONVIF_DEBUG("attr_name=%s, attr_value=%s", attr_name, attr_value); temp_abbr_num = soap_get_namespace(attr_name, attr_value, temp_abbr); ONVIF_DEBUG("temp_abbr_num=%d", temp_abbr_num); /* 通过temp_abbr[0]是否为0来区分是local还是global的abbr */ if (need_get_tag_namespace && temp_abbr_num > 0 && temp_abbr[0] == 0) { g_tag_namespace = temp_abbr_num; ONVIF_DEBUG("g_tag_namespace=%d", temp_abbr_num); } else if (need_get_global_namespace && temp_abbr_num != -1 && g_recv_ns.ns_count < MAX_TP_NAME_SPACE_COUNT && temp_abbr[0] != 0) { g_recv_ns.recv_namespace_list[g_recv_ns.ns_count].num = temp_abbr_num; snprintf(g_recv_ns.recv_namespace_list[g_recv_ns.ns_count].abbr, MAX_NAMESPACE_ABBR_LEN, "%s", temp_abbr); ONVIF_DEBUG("Recv global ns, ns_count=%d, num=%d, abbr=%s", g_recv_ns.ns_count, g_recv_ns.recv_namespace_list[g_recv_ns.ns_count].num, g_recv_ns.recv_namespace_list[g_recv_ns.ns_count].abbr); g_recv_ns.ns_count++; } } /* process attribute */ //if (soap_check_namespace(attr_value) == FALSE) //{ // ONVIF_WARN("soap_check_namespace failed, attr is %s:%s", attr_name, attr_value); // return EOF; //} if (ch == '/' || ch == '?') { quote = soap_get_char(p); if (quote != '>') { return EOF; } (*p)--; break; } else if (ch == '>') { break; }
}
return ch;
}
/******************************************************************************
函数名称: soap_parse_element_attr_out_len()
函数描述: Parse an element for any attributes
输 入: str_start – xml字串起始地址
buf_len -- xml字串长度
p -- 已经解析的xml字串地址 attr_num -- 想要从<>中获取的attr的个数 attr_in_name -- 二维数组,想要获取的attr的名字 name_str_len -- attr_in_name二维数组每个元素的长度 value_str_len -- attr_out_value二维数组每个元素的长度
输 出:
attr_out_value – 二维数组,存放attr_in_name对应的属性值
返 回 值:
解析完所有attr后的下一个字符
参数示例:
例如,想要取出<tt:SimpleItem Value=“60” Name=“Sensitivity”/>中,
attr “Value”、"Name"的值,则为本函数传入如下参数:
int attr_num = 2,
char attr_in_name[2][10] = {{“Value”}, {“Name”}};
char attr_out_buf[2][30] = {{0}, {0}};
int name_str_len = sizeof(attr_in_name[0]);
int value_str_len = sizeof(attr_out_buf[0]);
调用:
ch = soap_parse_element_attr_out_len(str_start, buf_len, p,
attr_num, (char *)attr_in_name, name_str_len, (char *)attr_out_buf, value_str_len);
******************************************************************************/
S32 soap_parse_element_attr_out_len(char *str_start, S32 buf_len, char p,
int attr_num, char attr_in_name, int name_str_len, char attr_out_value, int value_str_len)
{
char* attr_name = NULL;
char* attr_value = NULL;
char *ptr = NULL;
S32 ch = 0;
S32 quote = 0;
S32 i = 0;
char *pn = NULL;
char *pv = NULL;
if (str_start == NULL || p == NULL || *p == NULL || attr_num <= 0 || attr_in_name == NULL || name_str_len <= 0 || attr_out_value == NULL || value_str_len <= 0) { ONVIF_ERROR("param is error."); return EOF; } attr_name = SAFE_MALLOC(name_str_len); attr_value = SAFE_MALLOC(value_str_len); if (NULL == attr_name || NULL == attr_value) { ONVIF_ERROR("malloc fail"); goto error_end; } memset(attr_name, 0, name_str_len); memset(attr_value, 0, value_str_len); ONVIF_TRACE("before while"); while ((*p - str_start) < buf_len) { ch = soap_get_char(p); /* Skip leading whitespace */ if (IS_WHITE_SPACE(ch)) { continue; } if (ch == '/' || ch == '?') { quote = soap_get_char(p); if (quote != '>') { goto error_end; } (*p)--; break; } else if (ch == '<') { goto error_end; } else if (ch == '>') { break; } attr_name[0] = ch; if (ch == '\"' || ch == '\'') /* Name is in quotes, so get a quoted string */ { quote = ch; ptr = attr_name; while ((*p - str_start) < buf_len) { ch = soap_get_char(p); if (ch == '&') { if ((ch = soap_get_entity(p)) == EOF) { goto error_end; } } if(soap_add_char(ch, &ptr, attr_name, name_str_len)) { goto error_end; } if (ch == quote) { break; } } } else { ptr = attr_name + 1; while ((*p - str_start) < buf_len) { ch = soap_get_char(p); if (IS_WHITE_SPACE(ch) || ch == '=' || ch == '/' || ch == '>' || ch == '?') { break; } if (ch == '&') { if ((ch = soap_get_entity(p)) == EOF) { goto error_end; } } if(soap_add_char(ch, &ptr, attr_name, name_str_len)) { //goto error_end; } } } *ptr = '\0'; while ((*p - str_start) < buf_len && IS_WHITE_SPACE(ch)) { ch = soap_get_char(p); } if (ch != '=') { goto error_end; } /* Read the attribute value */ while ((*p - str_start) < buf_len) { ch = soap_get_char(p); if (!IS_WHITE_SPACE(ch)) { break; } } if (ch == '\"' || ch == '\'') { quote = ch; ptr = attr_value; while ((*p - str_start) < buf_len) { ch = soap_get_char(p); if (ch == quote) { break; } if (ch == '&') { if ((ch = soap_get_entity(p)) == EOF) { goto error_end; } } if(soap_add_char(ch, &ptr, attr_value, value_str_len)) { goto error_end; } } } else { attr_value[0] = ch; ptr = attr_value + 1; while ((*p - str_start) < buf_len) { ch = soap_get_char(p); if (IS_WHITE_SPACE(ch) || ch == '=' || ch == '/' || ch == '>') { break; } if (ch == '&') { if ((ch = soap_get_entity(p)) == EOF) { goto error_end; } } if(soap_add_char(ch, &ptr, attr_value, value_str_len)) { goto error_end; } } } *ptr = '\0'; ONVIF_TRACE("%s:%s", attr_name, attr_value); for (i = 0; i < attr_num; i++) { pn = attr_in_name + i * name_str_len; pv = attr_out_value + i * value_str_len; if (0 != *pv) { ONVIF_TRACE("%d has been set", i); continue; } ONVIF_TRACE("attr_name:\nwant:%s; get:%s", pn, attr_name); if (0 == strncmp(attr_name, pn, strlen(attr_name))) { strcpy(pv, attr_value); ONVIF_TRACE("%s:%s", pn, pv); memset(attr_name, 0, name_str_len); memset(attr_value, 0, value_str_len); break; } } /* process attribute */ //if (soap_check_namespace(attr_value) == FALSE) //{ // ONVIF_WARN("soap_check_namespace failed, attr is %s:%s", attr_name, attr_value); // return EOF; //} if (ch == '/' || ch == '?') { quote = soap_get_char(p); if (quote != '>') { goto error_end; } (*p)--; break; } else if (ch == '>') { break; } } ONVIF_FREE(attr_name); ONVIF_FREE(attr_value); return ch;
error_end:
ONVIF_FREE(attr_name);
ONVIF_FREE(attr_value);
return EOF;
}
/******************************************************************************
函数名称: soap_parse_element_value()
函数描述: 解析element内容
输 入: str_start – xml字串起始地址
xml_str_len -- xml字串长度
p -- 已经解析的xml字串地址
ch -- 当前需要解析的下一个字符
out_buf -- tag输出buf地址
out_buf_len -- tag输出buf大小
输 出: element内容
返 回 值: ERROR/OK
******************************************************************************/
S32 soap_parse_element_value(char *str_start, S32 buf_len, char **p,
S32 ch, char *out_buf, S32 out_buf_len)
{
S32 tmp_ch = ch;
char *pch = out_buf;
if (str_start == NULL || buf_len <= 0 || p == NULL || *p == NULL ||
out_buf == NULL || out_buf_len <=0)
{
return ERROR;
}
if (IS_WHITE_SPACE(tmp_ch))
{
tmp_ch = soap_parse_element_attr(str_start, buf_len, p); /* parse attribute */
if (tmp_ch == EOF)
{
ONVIF_WARN(“soap_parse_element_attr error.”);
return ERROR;
}
}
if (tmp_ch == ‘/’)
{
tmp_ch = soap_get_char(p);
if (tmp_ch != ‘>’)
{
ONVIF_WARN(“should be '>'(%d) but is %d.”, (S32)‘>’, tmp_ch);
return ERROR;
}
return OK;
}
else if (tmp_ch == ‘>’)
{
while ((*p - str_start) < buf_len)
{
tmp_ch = soap_get_char(p);
if (tmp_ch == ‘<’)
{
(*p)–;
break;
}
else if (tmp_ch == ‘&’)
{
if ((tmp_ch = soap_get_entity(p)) == EOF)
{
ONVIF_WARN(“soap_get_entity error.”);
return ERROR;
}
}
if(soap_add_char(tmp_ch, &pch, out_buf, out_buf_len)) { ONVIF_WARN("soap_add_char failed."); return ERROR; } } pch[0] = '\0';
}
else
{
ONVIF_WARN(“should be '>'(%d) but is %d.”, (S32)‘>’, tmp_ch);
return ERROR;
}
return OK;
}
/******************************************************************************
函数名称: soap_parse_header_element()
函数描述: 解析所有头部元素,并做相应处理
输 入: soap – soap结构体地址
tag -- 头部元素tag
str_start -- xml字串起始地址
buf_len -- xml字串长度
p -- 已经解析的xml字串地址
ch -- 当前需要解析的下一个字符
输 出: N/A
返 回 值: ERROR/OK
******************************************************************************/
LOCAL S32 soap_parse_header_element(SOAP_CONTEXT *soap, char *tag,
char *str_start, S32 buf_len, char **p, S32 ch)
{
char charbuf[LEN_INFO] = {0};
char tag_rearrange[LEN_TAG] = {0};
char *p1 = NULL;
if (soap == NULL || tag == NULL || str_start == NULL ||
buf_len <= 0 || p == NULL || *p == NULL)
{
return ERROR;
}
p1 = *p;
g_tag_namespace = -1;
g_need_get_global_namespace = TRUE;
g_need_get_tag_namespace = TRUE;
if (OK != soap_parse_element_value(str_start, buf_len, p, ch, charbuf, sizeof(charbuf)))
{
return ERROR;
}
ONVIF_TRACE(“%s: %s”, tag, charbuf);
if (charbuf[0] == ‘\0’)
{
return OK;
}
/* 根据命名空间跟换tag 如:
request中Envelope 有内容:xmlns:a=“http://www.w3.org/2005/08/addressing”
header中有: <a:MessageID>urn:uuid:7f52d7e1-63c4-4124-943c-c24d4825f15d</a:MessageID>
获取的tag为 a:MessageID
根据本地G_TP_NAMESPACE_LIST中的命名空间:{“wsa5”, “http://www.w3.org/2005/08/addressing”}
替换tag为 wsa5:MessageID
reponse中Envelope 有内容:xmlns:wsa5=“http://www.w3.org/2005/08/addressing”
header中有: wsa5:MessageIDurn:uuid:7f52d7e1-63c4-4124-943c-c24d4825f15d</wsa5:MessageID>
*/
soap_rearrange_tag(tag, tag_rearrange);
ONVIF_TRACE(“[%s]: %s”, tag_rearrange, charbuf);
if (TRUE == soap_match_tag(tag_rearrange, “wsa:MessageID”))
{
snprintf(soap->header.wsa_msg_id, sizeof(soap->header.wsa_msg_id), “%s”, charbuf);
}
else if(TRUE == soap_match_tag(tag_rearrange, “wsa:RelatesTo”))
{
if ((ch = soap_get_tag(str_start, buf_len, p, charbuf, sizeof(charbuf))) != EOF &&
TRUE == soap_match_tag(charbuf, “Relationship”) &&
OK == soap_parse_element_value(str_start, buf_len, p, ch, charbuf, sizeof(charbuf)))
{
snprintf(soap->header.wsa_relates_to, sizeof(soap->header.wsa_relates_to), “%s”, charbuf);
}
}
else if(TRUE == soap_match_tag(tag_rearrange, “wsa:From”))
{
if ((ch = soap_get_tag(str_start, buf_len, p, charbuf, sizeof(charbuf))) != EOF &&
TRUE == soap_match_tag(charbuf, “Address”) &&
OK == soap_parse_element_value(str_start, buf_len, p, ch, charbuf, sizeof(charbuf)))
{
snprintf(soap->header.wsa_from_addr, sizeof(soap->header.wsa_from_addr), “%s”, charbuf);
}
}
else if(TRUE == soap_match_tag(tag_rearrange, “wsa:ReplyTo”))
{
if ((ch = soap_get_tag(str_start, buf_len, p, charbuf, sizeof(charbuf))) != EOF &&
TRUE == soap_match_tag(charbuf, “Address”) &&
OK == soap_parse_element_value(str_start, buf_len, p, ch, charbuf, sizeof(charbuf)))
{
snprintf(soap->header.wsa_reply_to_addr, sizeof(soap->header.wsa_reply_to_addr), “%s”, charbuf);
}
}
else if(TRUE == soap_match_tag(tag_rearrange, “wsa:FaultTo”))
{
if ((ch = soap_get_tag(str_start, buf_len, p, charbuf, sizeof(charbuf))) != EOF &&
TRUE == soap_match_tag(charbuf, “Address”) &&
OK == soap_parse_element_value(str_start, buf_len, p, ch, charbuf, sizeof(charbuf)))
{
snprintf(soap->header.wsa_fault_to_addr, sizeof(soap->header.wsa_fault_to_addr), “%s”, charbuf);
}
}
else if(TRUE == soap_match_tag(tag_rearrange, “wsa:To”))
{
snprintf(soap->header.wsa_to, sizeof(soap->header.wsa_to), “%s”, charbuf);
}
else if(TRUE == soap_match_tag(tag_rearrange, “wsa:Action”))
{
snprintf(soap->header.wsa_action, sizeof(soap->header.wsa_action), “%s”, charbuf);
}
else if(TRUE == soap_match_tag(tag_rearrange, “wsdd:AppSequence”))
{
snprintf(soap->header.wsdd_app_sequence, sizeof(soap->header.wsdd_app_sequence), “%s”, charbuf);
}
else if (TRUE == soap_match_tag(tag_rearrange, “wsa5:MessageID”))
{
snprintf(soap->header.wsa5_msg_id, sizeof(soap->header.wsa5_msg_id), “%s”, charbuf);
}
else if(TRUE == soap_match_tag(tag_rearrange, “wsa5:RelatesTo”))
{
if ((ch = soap_get_tag(str_start, buf_len, p, charbuf, sizeof(charbuf))) != EOF &&
TRUE == soap_match_tag(charbuf, “RelatesToType”) &&
OK == soap_parse_element_value(str_start, buf_len, p, ch, charbuf, sizeof(charbuf)))
{
snprintf(soap->header.wsa5_relates_to, sizeof(soap->header.wsa5_relates_to), “%s”, charbuf);
}
}
else if(TRUE == soap_match_tag(tag_rearrange, “wsa5:From”))
{
if ((ch = soap_get_tag(str_start, buf_len, p, charbuf, sizeof(charbuf))) != EOF &&
TRUE == soap_match_tag(charbuf, “Address”) &&
OK == soap_parse_element_value(str_start, buf_len, p, ch, charbuf, sizeof(charbuf)))
{
snprintf(soap->header.wsa5_from_addr, sizeof(soap->header.wsa5_from_addr), “%s”, charbuf);
}
}
else if(TRUE == soap_match_tag(tag_rearrange, “wsa5:ReplyTo”))
{
if ((ch = soap_get_tag(str_start, buf_len, p, charbuf, sizeof(charbuf))) != EOF &&
TRUE == soap_match_tag(charbuf, “Address”) &&
OK == soap_parse_element_value(str_start, buf_len, p, ch, charbuf, sizeof(charbuf)))
{
snprintf(soap->header.wsa5_reply_to_addr, sizeof(soap->header.wsa5_reply_to_addr), “%s”, charbuf);
}
}
else if(TRUE == soap_match_tag(tag_rearrange, “wsa5:FaultTo”))
{
if ((ch = soap_get_tag(str_start, buf_len, p, charbuf, sizeof(charbuf))) != EOF &&
TRUE == soap_match_tag(charbuf, “Address”) &&
OK == soap_parse_element_value(str_start, buf_len, p, ch, charbuf, sizeof(charbuf)))
{
snprintf(soap->header.wsa5_fault_to_addr, sizeof(soap->header.wsa5_fault_to_addr), “%s”, charbuf);
}
}
else if(TRUE == soap_match_tag(tag_rearrange, “wsa5:To”))
{
snprintf(soap->header.wsa5_to, sizeof(soap->header.wsa5_to), “%s”, charbuf);
}
else if(TRUE == soap_match_tag(tag_rearrange, “wsa5:Action”))
{
snprintf(soap->header.wsa5_action, sizeof(soap->header.wsa5_action), “%s”, charbuf);
}
else if(TRUE == soap_match_tag(tag, “Username”))
{
snprintf(soap->header.username, sizeof(soap->header.username), “%s”, charbuf);
}
else if(TRUE == soap_match_tag(tag, “Password”))
{
soap_parse_element_attr_out_len(str_start, buf_len, &p1,
1, “Type”, LEN_IFNAME, (char *)soap->header.password_type, sizeof(soap->header.password_type));
snprintf(soap->header.password, sizeof(soap->header.password), "%s", charbuf);
}
else if(TRUE == soap_match_tag(tag, “Nonce”))
{
snprintf(soap->header.nonce, sizeof(soap->header.nonce), “%s”, charbuf);
}
else if(TRUE == soap_match_tag(tag, “Created”))
{
snprintf(soap->header.created, sizeof(soap->header.created), “%s”, charbuf);
}
/* 下面的内容是为了适配onvif device manager的异常tag { /
else if (TRUE == soap_match_tag(tag, “MessageID”))
{
if (‘\0’ == soap->header.wsa_msg_id[0])
{
snprintf(soap->header.wsa_msg_id, sizeof(soap->header.wsa_msg_id), “%s”, charbuf);
}
}
else if(TRUE == soap_match_tag(tag, “ReplyTo”))
{
if ((ch = soap_get_tag(str_start, buf_len, p, charbuf, sizeof(charbuf))) != EOF
&& TRUE == soap_match_tag(charbuf, “Address”)
&& OK == soap_parse_element_value(str_start, buf_len, p, ch, charbuf, sizeof(charbuf))
&& ‘\0’ == soap->header.wsa_reply_to_addr[0])
{
snprintf(soap->header.wsa_reply_to_addr, sizeof(soap->header.wsa_reply_to_addr), “%s”, charbuf);
}
}
else if(TRUE == soap_match_tag(tag, “To”))
{
if (‘\0’ == soap->header.wsa_to[0])
{
snprintf(soap->header.wsa_to, sizeof(soap->header.wsa_to), “%s”, charbuf);
}
}
else if(TRUE == soap_match_tag(tag, “Action”))
{
if (‘\0’ == soap->header.wsa_action[0])
{
snprintf(soap->header.wsa_action, sizeof(soap->header.wsa_action), “%s”, charbuf);
}
}
/ 适配onvif device manager的异常tag end} */
return OK;
}
/******************************************************************************
函数名称: soap_xml_parse()
函数描述: xml字串解析函数
输 入: soap – soap结构体地址
xml_str -- xml字串起始地址
buf_len -- xml字串长度
输 出: N/A
返 回 值: ERROR/OK
******************************************************************************/
S32 soap_xml_parse(SOAP_CONTEXT *soap, char **xml_str, S32 buf_len)
{
BOOL request_have_header = FALSE;
S32 ch = 0;
char charbuf[4 * LEN_INFO] = {0};
char *str_start = NULL;
char **p = xml_str;
if (soap == NULL || xml_str == NULL || *xml_str == NULL || buf_len <= 0)
{
ONVIF_WARN(“soap == NULL || xml_str == NULL || buf_len <= 0.”);
return ERROR;
}
str_start = *xml_str;
memset(&g_recv_ns, 0, sizeof(struct recv_namespaces));
/* onvif device manager发送的probe中不包含version行,导致设备探测失败;
当前也没有对version行进行处理,因此参考slp,不对version进行处理,先
去除这部分内容,从Envelope开始处理 */
// char pch = charbuf;
#if 0
/ parse version line */
while ((p - str_start) < buf_len)
{
ch = soap_get_char(p);
if (ch == ‘<’)
{
pch = charbuf;
ch = soap_get_char(p);
if (ch == ‘?’)
{
/ macth version line */
if(soap_add_char(ch, &pch, charbuf, sizeof(charbuf)))
{
goto error_parse;
}
while ((*p - str_start) < buf_len) { ch = soap_get_char(p); if (ch == '>' && pch > charbuf && pch[-1] == '?') { break; } else if (ch == '&') { if ((ch = soap_get_entity(p)) == EOF) { return EOF; } } if(soap_add_char(ch, &pch, charbuf, sizeof(charbuf))) { goto error_parse; } } if (ch != '>') { goto error_parse; } /* get version line, to do something */ pch[0] = '\0'; ONVIF_TRACE("version line: <%s>", charbuf); break; } else { continue; }
}
}
#endif
/* parse Envelope, request must have Envelope */
while ((*p - str_start) < buf_len)
{
if ((ch = soap_get_tag(str_start, buf_len, p, charbuf, sizeof(charbuf))) == EOF)
{
goto error_parse;
}
if (TRUE == soap_match_tag(charbuf, "Envelope")) { break; }
}
/* start parse Envelope attribute /
if (IS_WHITE_SPACE(ch))
{
g_need_get_global_namespace = TRUE;
ch = soap_parse_element_attr(str_start, buf_len, p); / parse attribute */
if (ch == EOF)
{
goto error_parse;
}
}
while ((*p - str_start) < buf_len)
{
if ((ch = soap_get_tag(str_start, buf_len, p, charbuf, sizeof(charbuf))) == EOF)
{
goto error_parse;
}
if (TRUE == soap_match_tag(charbuf, "Header") || TRUE == soap_match_tag(charbuf, "Body")) { break; }
}
soap->has_header = FALSE;
/* parse Header, request maybe have Header /
if (TRUE == soap_match_tag(charbuf, “Header”))
{
request_have_header = TRUE;
/ parse Header value /
/ start parse Envelope attribute /
if (IS_WHITE_SPACE(ch))
{
ch = soap_parse_element_attr(str_start, buf_len, p); / parse attribute */
if (ch == EOF)
{
goto error_parse;
}
}
if (ch == '/') { ch = soap_get_char(p); if (ch != '>') { goto error_parse; } goto parse_body; } soap->has_header = TRUE; while ((*p - str_start) < buf_len) { if ((ch = soap_get_tag(str_start, buf_len, p, charbuf, sizeof(charbuf))) == EOF) { goto error_parse; } if (charbuf[0] == '/') { if (TRUE == soap_match_tag(charbuf, "Header")) { /* end of Header */ ONVIF_TRACE("end of Header"); break; } else { continue; } } if (ERROR == soap_parse_header_element(soap, charbuf, str_start, buf_len, p, ch)) { goto error_parse; } }
}
else
{
request_have_header = FALSE;
}
parse_body:
/* parse Body, request must have Body */
if (request_have_header == TRUE)
{
while ((*p - str_start) < buf_len)
{
if ((ch = soap_get_tag(str_start, buf_len, p, charbuf, sizeof(charbuf))) == EOF)
{
goto error_parse;
}
if (TRUE == soap_match_tag(charbuf, "Body")) { break; } } } if (IS_WHITE_SPACE(ch)) { g_need_get_global_namespace = TRUE; ch = soap_parse_element_attr(str_start, buf_len, p); /* parse attribute */ if (ch == EOF) { goto error_parse; } } if (ch == '/') { ch = soap_get_char(p); if (ch != '>') { goto error_parse; } goto end_parse; } /* parse Body value */ if ((ch = soap_get_tag(str_start, buf_len, p, charbuf, sizeof(charbuf))) == EOF) { goto error_parse; } snprintf(soap->tag, sizeof(soap->tag), "%s", charbuf); ONVIF_TRACE("get soap->tag: %s", soap->tag); g_tag_namespace = -1; if (IS_WHITE_SPACE(ch)) { g_need_get_global_namespace = TRUE; g_need_get_tag_namespace = TRUE; ch = soap_parse_element_attr(str_start, buf_len, p); /* parse attribute */ if (ch == EOF) { goto error_parse; } } if (ch == '/') { ch = soap_get_char(p); if (ch != '>') { goto error_parse; } soap->request_begin = NULL; soap->request_end = NULL; } else if (ch == '>') { soap->request_begin = *p; while ((*p - str_start) < buf_len) { ch = soap_get_char(p); if (ch == '/' && 0 == strncmp(*p, soap->tag, strlen(soap->tag))) { while (**p != '<') { (*p)--; } soap->request_end = *p; break; } } } else { goto error_parse; } soap_rearrange_tag(charbuf, soap->tag);
end_parse:
return OK;
error_parse:
return ERROR;
}
——这个是soap.c和soap_parse.c文件,并注意Digest认证的验证函数直接写在onvif_srv.c就行,重新回答前面的Digest认证的实现的问题