/******************************************************************************
* Copyright (c) 2018-2018 TP-Link Systems Inc.
*
* Filename: soap_wsdd.c
* Version: 1.0
* Description: soap 处理函数头文件
* Author: liyijie<liyijie@tp-link.com.cn>
* Date: 2018-10-30
******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include "soap_global.h"
#include "soap_parse.h"
#include "soap_pack.h"
#include "soap_wsdd.h"
/******************************************************************************
* 函数名称: soap_check_scope()
* 函数描述: 检查输入的scope是否在设备保存的scope列表内
* 输 入: scopes -- 输入的scope字串
* 输 出: N/A
* 返 回 值: TRUE/FALSE
******************************************************************************/
LOCAL S32 soap_check_scope(char *scopes)
{
int i = 0;
S32 flag = -1;
S32 len = 0;
char *s = NULL;
char *e = NULL;
char *t = NULL;
SOAP_NODE *node = NULL;
if (scopes == NULL)
{
return 0;
}
if (strnlen(scopes, 1) == 0)
{
return 0;
}
for (t = scopes; t && strnlen(t, 1); t++)
{
e = (char *)strchr(t, ' ');
if (e != NULL)
{
len = e - t;
}
else
{
len = strlen(scopes) - (t - scopes);
}
if (len <= 0)
{
break;
}
for (i = 0; i < FIX_SCOPE_NUM; i++)
{
s = G_TP_FIXED_SCOPE[i];
if ( 0 == strncmp(s, t, len)
&& ('/' == *(s + len) || '\0' == *(s + len)) )
{
flag = 0;
break;
}
}
if (0 == flag)
{
break;
}
for (node = g_scope_list; node; node = node->next)
{
s = (char*)node->data;
if (0 == strncmp(s, t, len) && ('/' == *(s + len) || '\0' == *(s + len)))
{
flag = 0;
break;
}
}
if ( 0 == flag )
{
break;
}
if (NULL != e)
{
t = strchr(e, ' ');
}
else
{
t = NULL;
}
if (!t)
{
break;
}
}
return flag;
}
LOCAL S32 soap_out_scopes_item(ONVIF_BUF *xml_buf)
{
SOAP_NODE *node = NULL;
char scope_string[FIX_SCOPE_NUM * LEN_INFO + FIX_SCOPE_NUM] = {0};
if (xml_buf == NULL)
{
ONVIF_WARN("xml_buf == NULL.");
return ERROR;
}
/* wsdd:Scopes begin */
SOAP_IF_FAIL_RET(soap_element_begin_out(xml_buf, "wsdd:Scopes", NULL));
snprintf(scope_string, sizeof(scope_string), "%s %s %s %s %s",
G_TP_FIXED_SCOPE[0], G_TP_FIXED_SCOPE[1], G_TP_FIXED_SCOPE[2], G_TP_FIXED_SCOPE[3], G_TP_FIXED_SCOPE[4]);
SOAP_IF_FAIL_RET(onvif_buf_append_string(xml_buf, scope_string, strlen(scope_string)));
for (node = g_scope_list; node; node = node->next)
{
if (node->data != NULL)
{
SOAP_IF_FAIL_RET(onvif_buf_append_string(xml_buf, " ", 1));
SOAP_IF_FAIL_RET(onvif_buf_append_string(xml_buf, (char *)node->data, strlen((char *)node->data)));
}
}
/* wsdd:Scopes end */
SOAP_IF_FAIL_RET(soap_element_end_out(xml_buf, "wsdd:Scopes"));
return OK;
}
/******************************************************************************
* 函数名称: soap_out_wsdd_hello_type()
* 函数描述: 组装wsdd:Hello element内容
* 输 入: xml_buf -- 存放输出xml字串的内存地址
* data -- 为空
* 输 出: N/A
* 返 回 值: ERROR/OK
******************************************************************************/
LOCAL S32 soap_out_wsdd_hello_type(ONVIF_BUF *xml_buf, void *data)
{
S32 len = 0;
char tmp_str[LEN_INFO] = {0};
char ip_str[LEN_IP] = {0};
char mac_str[LEN_MAC] = {0};
if (xml_buf == NULL)
{
ONVIF_WARN("xml_buf == NULL.");
return ERROR;
}
SOAP_IF_FAIL_RET(onvif_get_ip_str(ip_str, LEN_IP));
SOAP_IF_FAIL_RET(onvif_get_mac_str(mac_str, LEN_MAC, FALSE));
/* wsdd:Hello begin */
SOAP_IF_FAIL_RET(soap_element_begin_out(xml_buf, "wsdd:Hello", NULL));
/* wsa:EndpointReference */
len = snprintf(tmp_str, sizeof(tmp_str), "uuid:%s%s", UUID_PREFIX_FMAT, mac_str);
if (len < 0 || len >= sizeof(tmp_str))
{
return ERROR;
}
SOAP_IF_FAIL_RET(soap_out_wsa_endpoint_reference(xml_buf, "wsa:EndpointReference", tmp_str));
/* wsdd:Types */
SOAP_IF_FAIL_RET(soap_element(xml_buf, "wsdd:Types", G_TYPES_VAL_STR, NULL));
/* wsdd:Scopes */
SOAP_IF_FAIL_RET(soap_out_scopes_item(xml_buf));
/* wsdd:XAddrs */
len = snprintf(tmp_str, sizeof(tmp_str), "http://%s:%d/onvif/device_service",
ip_str, ONVIF_PORT_FOR_MAIN);
if (len < 0 || len >= sizeof(tmp_str))
{
return ERROR;
}
SOAP_IF_FAIL_RET(soap_element(xml_buf, "wsdd:XAddrs", tmp_str, NULL));
/* wsdd:MetadataVersion */
SOAP_IF_FAIL_RET(soap_element(xml_buf, "wsdd:MetadataVersion", "1", NULL));
SOAP_IF_FAIL_RET(soap_element_end_out(xml_buf, "wsdd:Hello"));
return OK;
}
/******************************************************************************
* 函数名称: soap_out_wsdd_probe_match_type()
* 函数描述: 组装wsdd:ProbeMatch element内容
* 输 入: xml_buf -- 存放输出xml字串的内存地址
* 输 出: N/A
* 返 回 值: ERROR/OK
******************************************************************************/
LOCAL S32 soap_out_wsdd_probe_match_type(ONVIF_BUF *xml_buf)
{
S32 len = 0;
char tmp_str[LEN_INFO] = {0};
char ip_str[LEN_IP] = {0};
char mac_str[LEN_MAC] = {0};
if (xml_buf == NULL)
{
ONVIF_WARN("xml_buf == NULL.");
return ERROR;
}
SOAP_IF_FAIL_RET(onvif_get_ip_str(ip_str, LEN_IP));
SOAP_IF_FAIL_RET(onvif_get_mac_str(mac_str, LEN_MAC, FALSE));
/* wsdd:ProbeMatch begin */
SOAP_IF_FAIL_RET(soap_element_begin_out(xml_buf, "wsdd:ProbeMatch", NULL));
/* wsa:EndpointReference */
len = snprintf(tmp_str, sizeof(tmp_str), "uuid:%s%s", UUID_PREFIX_FMAT, mac_str);
if (len < 0 || len >= sizeof(tmp_str))
{
return ERROR;
}
SOAP_IF_FAIL_RET(soap_out_wsa_endpoint_reference(xml_buf, "wsa:EndpointReference", tmp_str));
/* wsdd:Types */
SOAP_IF_FAIL_RET(soap_element(xml_buf, "wsdd:Types", G_TYPES_VAL_STR, NULL));
/* wsdd:Scopes */
SOAP_IF_FAIL_RET(soap_out_scopes_item(xml_buf));
/* wsdd:XAddrs */
len = snprintf(tmp_str, sizeof(tmp_str), "http://%s:%d/onvif/device_service",
ip_str, ONVIF_PORT_FOR_MAIN);
if (len < 0 || len >= sizeof(tmp_str))
{
return ERROR;
}
SOAP_IF_FAIL_RET(soap_element(xml_buf, "wsdd:XAddrs", tmp_str, NULL));
/* wsdd:MetadataVersion */
SOAP_IF_FAIL_RET(soap_element(xml_buf, "wsdd:MetadataVersion", "1", NULL));
/* wsdd:ProbeMatch end */
SOAP_IF_FAIL_RET(soap_element_end_out(xml_buf, "wsdd:ProbeMatch"));
return OK;
}
/******************************************************************************
* 函数名称: soap_out_wsdd_probe_matches()
* 函数描述: 组装wsdd:ProbeMatches element内容
* 输 入: xml_buf -- 存放输出xml字串的内存地址
* data -- 为空
* 输 出: N/A
* 返 回 值: ERROR/OK
******************************************************************************/
LOCAL S32 soap_out_wsdd_probe_matches(ONVIF_BUF *xml_buf, void *data)
{
if (xml_buf == NULL)
{
ONVIF_WARN("xml_buf == NULL.");
return ERROR;
}
/* wsdd:ProbeMatches begin */
SOAP_IF_FAIL_RET(soap_element_begin_out(xml_buf, "wsdd:ProbeMatches", NULL));
/* wsdd:ProbeMatch */
SOAP_IF_FAIL_RET(soap_out_wsdd_probe_match_type(xml_buf));
/* wsdd:ProbeMatches end */
SOAP_IF_FAIL_RET(soap_element_end_out(xml_buf, "wsdd:ProbeMatches"));
return OK;
}
/*********************************************************************************
* Soap wsdd req parse
*********************************************************************************/
/******************************************************************************
* 函数名称: soap_wsdd_probe_req_parse()
* 函数描述: 解析发现报文的具体内容
* 输 入: soap -- soap结构体
* req_buf -- 请求内容
* buf_len -- 请求内容长度
* 输 出: N/A
* 返 回 值: ERROR/OK
******************************************************************************/
LOCAL S32 soap_wsdd_probe_req_parse(SOAP_CONTEXT *soap, char **req_buf, S32 buf_len)
{
S32 ch = 0;
char charbuf[LEN_INFO] = {0};
char *str_start = NULL;
char **p = req_buf;
if (soap == NULL)
{
ONVIF_TRACE("soap == NULL.");
return ERROR;
}
if (req_buf == NULL || *req_buf == NULL || buf_len <= 0)
{
ONVIF_TRACE("no request context to parse.");
return OK;
}
str_start = *req_buf;
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] == '/')
{
continue;
}
if (TRUE == soap_match_tag(charbuf, "Types"))
{
if (OK != soap_parse_element_value(str_start, buf_len, p, ch,
soap->types, sizeof(soap->types)))
{
goto error_parse;
}
ONVIF_TRACE("Types: %s", soap->types);
}
if (TRUE == soap_match_tag(charbuf, "Scopes"))
{
if (OK != soap_parse_element_value(str_start, buf_len, p, ch,
soap->scopes_item, sizeof(soap->scopes_item)))
{
goto error_parse;
}
ONVIF_TRACE("Scopes: %s", soap->scopes_item);
}
if (TRUE == soap_match_tag(charbuf, "MatchBy"))
{
if (OK != soap_parse_element_value(str_start, buf_len, p, ch,
soap->scopes_matchby, sizeof(soap->scopes_matchby)))
{
goto error_parse;
}
ONVIF_TRACE("MatchBy: %s", soap->scopes_matchby);
}
}
return OK;
error_parse:
return ERROR;
}
/******************************************************************************
* 函数名称: soap_wsdd_hello()
* 函数描述: 发送onvif Hello报文
* 输 入: soap -- soap结构体
* 输 出: N/A
* 返 回 值: ERROR/OK
******************************************************************************/
S32 soap_wsdd_hello(SOAP_CONTEXT *soap)
{
if (soap == NULL)
{
ONVIF_TRACE("soap == NULL.");
return ERROR;
}
SOAP_IF_FAIL_RET(soap_generate_xml((p_out_fun)(soap_out_wsdd_hello_type), soap, NULL));
return onvif_send_udp_packet(soap->sock, inet_addr(ONVIF_MCAST_IP), htons(ONVIF_PORT_FOR_DISCV),
soap->xml_buf.start, (soap->xml_buf.last - soap->xml_buf.start));
}
/******************************************************************************
* 函数名称: soap_wsdd_probe_handle()
* 函数描述: 发现请求的处理函数
* 输 入: soap -- soap结构体
* 输 出: N/A
* 返 回 值: ERROR/OK
******************************************************************************/
LOCAL S32 soap_wsdd_probe_handle(SOAP_CONTEXT *soap)
{
S32 request_len = 0;
BOOL match = FALSE;
char *xml_buf = NULL;
char **xml_str = NULL;
char ifname[LEN_IFNAME] = {0};
S32 scopes_matchby_flag = 0;
if (soap == NULL)
{
ONVIF_WARN("soap == NULL.");
return ERROR;
}
if (onvif_get_discv_mode() == DIS_MODE_NO)
{
ONVIF_DEBUG("discover mode is non-discoverable.");
return OK;
}
if (soap->request_begin != NULL && soap->request_end != NULL)
{
request_len = soap->request_end - soap->request_begin;
if (request_len < 0)
{
ONVIF_WARN("request_len < 0.");
return ERROR;
}
xml_buf = soap->request_begin;
xml_str = (char **)&xml_buf;
if (strstr(xml_buf, "<d:Scopes MatchBy=\"http://schemas.xmlsoap.org/ws/2005/04/discovery/rfc3986\"></d:Scopes>") != NULL)
{
scopes_matchby_flag = 1;
}
}
else
{
ONVIF_ERROR("soap request content is NULL.");
return ERROR;
}
if (OK != soap_wsdd_probe_req_parse(soap, xml_str, request_len))
{
return ERROR;
}
if (soap->types[0] != '\0')
{
if(0 == strcmp("tds:Device", soap->types) ||
0 == strcmp("tdn:NetworkVideoTransmitter", soap->types) ||
0 == strcmp("dn:NetworkVideoTransmitter", soap->types))
{
match = TRUE;
}
else if(0 == strcmp("dn:NetworkVideoRecorder", soap->types) ||
0 == strcmp("tdn:NetworkVideoRecorder", soap->types))
{
return OK;
}
}
else
{
match = TRUE;
}
if (match)
{
if (onvif_get_netdevice_name(soap->ifindex, ifname, LEN_IFNAME) == 0 &&
strncmp(ifname, IFNAME_AP, LEN_IFNAME) != 0)
{
/* 通知IPCD进行probe IP的跟随修改 */
NSD_SEND(NSD_PROBE_IP, (U8*)(&soap->in_ip), sizeof(soap->in_ip));
}
}
if (soap->scopes_item[0] != '\0')
{
if (soap->scopes_matchby[0] != '\0')
{
if (soap->has_header)
{
snprintf(soap->header.wsa_action, sizeof(soap->header.wsa_action),
"http://schemas.xmlsoap.org/ws/2005/04/discovery/fault");
snprintf(soap->header.wsa_to, sizeof(soap->header.wsa_to),
"http://schemas.xmlsoap.org/ws/2005/04/addressing/role/anonymous");
}
soap_fault(soap, "SOAP-ENV:Sender", "wsdd:MatchingRuleNotSupported",
NULL, "the matching rule specified is not supported");
soap->error = SOAP_FAULT;
return ERROR;
}
if (0 != soap_check_scope(soap->scopes_item))
{
return ERROR;
}
}
if (scopes_matchby_flag == 1)
{
if (soap->has_header)
{
snprintf(soap->header.wsa_action, sizeof(soap->header.wsa_action),
"http://schemas.xmlsoap.org/ws/2005/04/discovery/fault");
snprintf(soap->header.wsa_to, sizeof(soap->header.wsa_to),
"http://schemas.xmlsoap.org/ws/2005/04/addressing/role/anonymous");
}
soap_fault(soap, "SOAP-ENV:Sender", "wsdd:MatchingRuleNotSupported",
NULL, "the matching rule specified is not supported");
soap->error = SOAP_FAULT;
return ERROR;
}
//SOAP_IF_FAIL_RET(soap_generate_xml((p_out_fun)(soap_out_wsdd_probe_matches), soap, NULL));
//return onvif_send_udp_packet(soap->sock, soap->in_ip, htons(ONVIF_PORT_FOR_DISCV),
// soap->xml_buf.start, (soap->xml_buf.last - soap->xml_buf.start));
if (soap->header.wsa_relates_to[0] == '\0')
{
snprintf(soap->header.wsa_relates_to, sizeof(soap->header.wsa_relates_to),
"%s", soap->header.wsa_msg_id);
}
if (soap->header.wsa_action[0] != '\0')
{
onvif_str_append_chr(soap->header.wsa_action, sizeof(soap->header.wsa_action), "Matches");
}
return soap_generate_xml((p_out_fun)(soap_out_wsdd_probe_matches), soap, NULL);
}
/*********************************************************************************
* Soap wsdd Handles init
*********************************************************************************/
void soap_wsdd_handle_init()
{
soap_tag_handle_add("Probe", soap_wsdd_probe_handle);
}
——这个能不能详解一下,尤其是要讲清楚每个函数的功能及输入输出,整个模块的结构/功能以及对外接口