/******************************************************************************
\* Copyright (c) 2018-2020 TP-Link Systems Inc.
*
\* 文件名称: onvif_common.h
\* 版 本: 1.0
\* 摘 要: ONVIF 通用函数及定义头文件
\* 作 者: liyijie<liyijie@tp-link.com.cn>
\* 创建时间: 2018-10-30
******************************************************************************/
\#ifndef __ONVIF_COMMON_H__
\#define __ONVIF_COMMON_H__
\#include <arpa/inet.h>
\#include "nsd_common.h"
\#include "../ipcd/api.h"
\#define ONVIF_DEBUG(fmt, ...) NSD_DEBUG(NSD_ONVIF, "[ONVIF]" fmt, ##__VA_ARGS__)
\#define ONVIF_WARN(fmt, ...) NSD_WARN(NSD_ONVIF, "[ONVIF]" fmt , ##__VA_ARGS__)
\#define ONVIF_ERROR(fmt, ...) NSD_ERROR(NSD_ONVIF, "[ONVIF]" fmt , ##__VA_ARGS__)
\#define ONVIF_INFO(fmt, ...) NSD_LOG(LOG_INFO, LOG_THIRDPARTY, "[ONVIF]" fmt, ##__VA_ARGS__)
\#ifdef __ONVIF_TRACE__
\#define ONVIF_TRACE(fmt, ...) ONVIF_DEBUG(fmt, ##__VA_ARGS__)
\#else
\#define ONVIF_TRACE(fmt, ...)
\#endif
\#define ONVIF_FREE SAFE_FREE
\#define ONVIF_MALLOC SAFE_MALLOC
\#define ONVIF_STRDUP(str) strdup((str))
\#define TOLOWER(c) (char)((c >= 'A' && c <= 'Z') ? (c | 0x20) : c)
\#define TOUPPER(c) (char)((c >= 'a' && c <= 'z') ? (c & ~0x20) : c)
\#define ONVIF_TTL 4
\#define ONVIF_MCAST_IP "239.255.255.250"
/* Params for Web Service */
\#define ONVIF_PORT_FOR_HTTP 80
\#define ONVIF_PORT_FOR_MAIN 2020
\#define ONVIF_PORT_FOR_DISCV 3702
\#define ONVIF_PORT_FOR_EVENT_BASE 1024
/* Prefix of UUID */
\#define UUID_PREFIX_FMAT "3fa1fe68-b915-4053-a3e1-"
\#define UUID_PREFIX_UFMAT "3fa1fe68b9154053a3e1"
/* msgq control message*/
\#define MSGQ_ON "on"
\#define MSGQ_OFF "off"
\#ifndef IFNAME_AP
\#define IFNAME_AP "wlan1"
\#endif
/* Length */
\#define LEN_IFNAME 8 /* length of interface name */
\#define LEN_MTU 8 /* length of MTU str */
\#define LEN_IP 16 /* length of IP */
\#define LEN_MAC 18 /* length of mac */
\#define LEN_XADDR 128 /* length of XAddr */
\#define LEN_STREAM_URI 256 /* length of STREAM URI */
\#define LEN_SOME_INFO 256 /* length of SOME_INFO */
\#define LEN_ANY 4096 /* length of __any */
\#define LEN_INFO 128 /* length of infomation */
\#define LEN_TOKEN 128 /* length of TOKEN */
\#define LEN_NAME 128 /* length of user name */
\#define LEN_TIME 22 /* lendth of time string */
\#define LEN_RECOVERY_STR 9
\#define LEN_SHA_PWD 15
\#define LEN_RES_OPTION_NAME 8
\#define LEN_UUID 37 /* length of UUID */
\#define LEN_TAG 64
\#define LEN_VALUE 32
\#define LEN_INT 16
\#define LEN_BOOL 8
\#define STREAM_TYPE_LEN 8
\#define ONVIF_MAX_FREE_NUM 80
\#define ONVIF_DISCV_BUF_LEN (4 * 1024) /* receive buffer length */
/* 当前NVMP平台的事件通知机制可以取消订阅者数量的限制,
\* 但为了防止恶意订阅消耗资源,按目前可支持接入的最大NVR数量限制订阅节点数量。*/
/* tev能力集中支持的最大节点数为10,创建节点是的节点数量限制应该同能力集一致,
\* RTSP最大流数位8,节点限制位10足够 */
\#define EVENT_NODE_LIMIT 10
\#define ONVIF_SOCKET_RECV_BUF_SIZE (32 * 1024)
\#define ONVIF_SOCKET_SEND_BUF_SIZE (32 * 1024)
\#define MAX_TP_NAME_SPACE_COUNT 48
\#define MAX_NAMESPACE_ABBR_LEN 16
\#define MAX_NAMESPACE_LEN 128
struct onvif_namespace
{
char namespace_abbr[MAX_NAMESPACE_ABBR_LEN];
char namespace[MAX_NAMESPACE_LEN];
};
typedef struct _ONVIF_BUF
{
char *start;
char *last;
char *end;
}ONVIF_BUF;
/* 判断有nvr接入需要进行的处理 */
void onvif_nvr_access_event();
BOOL onvif_get_dhcp_enable();
S32 onvif_get_ip_str(char *ip_str, U32 out_len);
S32 onvif_get_mac_str(char *mac_str, U32 out_len, BOOL need_separator);
U32 onvif_get_mtu();
U32 onvif_get_netmask();
S32 onvif_create_buf(ONVIF_BUF *buf, S32 size);
void onvif_free_buf(ONVIF_BUF *buf);
S32 onvif_buf_append_string(ONVIF_BUF *buf, const char *str, S32 len);
S32 onvif_str_append_chr(char *str, S32 buf_size, const char *fmt, ...);
S32 onvif_send_udp_packet(S32 sock, U32 dst_ip, U16 port, char *send_buf, S32 send_len);
S32 onvif_send_tcp_block(S32 sock, char *send_buf, S32 send_len);
size_t onvif_base64_encode_alloc (const char *in, size_t inlen, char **out);
BOOL onvif_base64_decode_alloc (const char *in, size_t inlen, char **out, size_t *outlen);
S32 onvif_get_netdevice_name(S32 ifindex, char *ifname, S32 len);
S32 onvif_get_discv_mode();
S32 onvif_set_discv_mode(S32 mode);
S32 onvif_set_sock_rcvbuf(S32 sock, S32 buf_size);
S32 onvif_set_sock_sndbuf(S32 sock, S32 buf_size);
void onvif_init_supported_event_topic();
void free_ptrs(void *ptrs[], S32 num);
S32 register_ptrs_to_free(void *ptr, void *ptrs[], S32 num);
void *malloc_and_register(U32 size, void *ptrs[], S32 num);
\#ifndef MALLOC_AND_REGISTER
\#define MALLOC_AND_REGISTER(struct, cnt, ptrs, ptr_cnt_max) \
(struct *)malloc_and_register(sizeof(struct) * (cnt), ptrs, ptr_cnt_max)
\#endif
\#endif /* __ONVIF_COMMON_H__ */
/******************************************************************************
\* Copyright (c) 2018-2018 TP-Link Systems Inc.
*
\* Filename: onvif_discv.c
\* Version: 1.0
\* Description: ONVIF 发现模块
\* Author: liyijie<liyijie@tp-link.com.cn>
\* Date: 2018-10-30
******************************************************************************/
\#include <stdio.h>
\#include <stdlib.h>
\#include <unistd.h>
\#include <string.h>
\#include <errno.h>
\#include <sys/types.h>
\#include <sys/socket.h>
\#include <netinet/tcp.h>
\#include <arpa/inet.h>
\#include "slp_model.h"
\#include "onvif_common.h"
\#include "onvif_discv.h"
\#include "soap_parse.h"
\#include "soap_wsdd.h"
LOCAL char g_onvif_discv_packet[ONVIF_DISCV_BUF_LEN + 1];
SOAP_CONTEXT *g_soap_for_discv = NULL;
S32 g_index_for_discv = -1;
LOCAL S32 onvif_recv_udp(SOAP_CONTEXT *soap, S32 sock, char *buf,
S32 buf_len, struct sockaddr_in *client)
{
S32 ret = 0;
struct msghdr mh;
struct iovec vector;
char cmbuf[100] = {0};
struct cmsghdr *cmsg = NULL;
struct in_pktinfo *pi = NULL;
if (soap == NULL || sock < 0 || buf == NULL || client == NULL)
{
return -1;
}
vector.iov_base = buf;
vector.iov_len = buf_len;
mh.msg_name = client;
mh.msg_namelen = sizeof(struct sockaddr_in);
mh.msg_iov = &vector;
mh.msg_iovlen = 1;
mh.msg_control = cmbuf;
mh.msg_controllen = sizeof(cmbuf);
mh.msg_flags = 0;
ret = recvmsg(sock, &mh, 0);
for (cmsg = CMSG_FIRSTHDR(&mh); cmsg != NULL; cmsg = CMSG_NXTHDR(&mh, cmsg))
{
if (cmsg->cmsg_level != IPPROTO_IP || cmsg->cmsg_type != IP_PKTINFO)
{
continue;
}
pi = (struct in_pktinfo *)CMSG_DATA(cmsg);
if (pi)
{
soap->ifindex = pi->ipi_ifindex;
}
else
{
soap->ifindex = -1;
}
break;
}
return ret;
}
/******************************************************************************
\* 函数名称: onvif_discover_handle()
\* 函数描述: onvif discover报文处理函数
\* 输 入: sock -- socket
\* 输 出: N/A
\* 返 回 值: ERROR/OK
******************************************************************************/
LOCAL S32 onvif_discover_handle(S32 sock)
{
S32 length = 0;
struct sockaddr_in client;
char *xml_buf = NULL;
char **xml_str = NULL;
char ip_str[LEN_IP] = {0};
if (sock < 0)
{
ONVIF_ERROR("Invalid listen socket.");
return ERROR;
}
soap_init(g_soap_for_discv);
g_soap_for_discv->use_udp = TRUE;
memset((void *)&client, 0, sizeof(client));
length = onvif_recv_udp(g_soap_for_discv, sock, g_onvif_discv_packet,
ONVIF_DISCV_BUF_LEN, &client);
if (length <= 0)
{
ONVIF_ERROR("recv onvif discover msg failed.");
return ERROR;
}
ONVIF_TRACE("Recv onvif discover msg.");
if (OK != onvif_get_ip_str(ip_str, LEN_IP))
{
ONVIF_WARN("onvif_get_ip_str failed.");
return ERROR;
}
/* 忽略本机发送的ONVIF包。 */
if (inet_addr(ip_str) == client.sin_addr.s_addr)
{
ONVIF_TRACE("Recv onvif packet from self.");
return OK;
}
g_soap_for_discv->in_ip = client.sin_addr.s_addr;
g_soap_for_discv->sin_port = client.sin_port;
g_onvif_discv_packet[length] = '\0';
xml_buf = g_onvif_discv_packet;
xml_str = (char **)&xml_buf;
if (OK != soap_xml_parse(g_soap_for_discv, xml_str, length))
{
ONVIF_TRACE("Soap_xml_parse error.");
return ERROR;
}
if (g_soap_for_discv->tag[0] == '\0')
{
ONVIF_TRACE("No request tag.");
return ERROR;
}
return soap_serve_request(g_soap_for_discv);
}
/******************************************************************************
\* 函数名称: onvif_discv_start()
\* 函数描述: onvif discover处理模块启动函数
\* 输 入: N/A
\* 输 出: N/A
\* 返 回 值: ERROR/OK
******************************************************************************/
S32 onvif_discv_start()
{
int on = 1;
ONVIF_INFO("Onvif discovery start");
g_soap_for_discv = new_soap();
if (g_soap_for_discv == NULL)
{
ONVIF_ERROR("Malloc g_soap_for_discv failed");
return ERROR;
}
g_soap_for_discv->sock = sock_create_udp(INADDR_ANY, ONVIF_PORT_FOR_DISCV);
if (g_soap_for_discv->sock < 0)
{
ONVIF_ERROR("Sock_create_udp failed");
free_soap(g_soap_for_discv);
g_soap_for_discv = NULL;
return ERROR;
}
if (sock_non_block(g_soap_for_discv->sock) < 0)
{
ONVIF_WARN("Sock_non_block fail with errno:%d", errno);
}
g_index_for_discv = inet_add_socket(g_soap_for_discv->sock,
(void*)onvif_discover_handle, NULL, NULL);
if (g_index_for_discv < 0)
{
ONVIF_ERROR("Inet_socket_add failed");
close(g_soap_for_discv->sock);
g_soap_for_discv->sock = -1;
free_soap(g_soap_for_discv);
g_soap_for_discv = NULL;
return ERROR;
}
if (0 > setsockopt(g_soap_for_discv->sock, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on)))
{
ONVIF_WARN("setsockopt IP_PKTINFO failed.");
}
if (0 > onvif_set_sock_rcvbuf(g_soap_for_discv->sock, ONVIF_SOCKET_RECV_BUF_SIZE))
{
ONVIF_WARN("setsockopt SO_RCVBUF failed.");
}
if (0 > onvif_set_sock_sndbuf(g_soap_for_discv->sock, ONVIF_SOCKET_SEND_BUF_SIZE))
{
ONVIF_WARN("setsockopt SO_SNDBUF failed.");
}
if (sock_mcast_ttl(g_soap_for_discv->sock, ONVIF_TTL) < 0)
{
ONVIF_WARN("setsockopt IP_MULTICAST_TTL fail with errno:%d", errno);
}
if (sock_mcast_group(g_soap_for_discv->sock, htonl(INADDR_ANY), inet_addr(ONVIF_MCAST_IP)) < 0)
{
ONVIF_WARN("setsockopt IP_ADD_MEMBERSHIP fail with errno:%d", errno);
}
if (sock_mcast_if(g_soap_for_discv->sock, htonl(INADDR_ANY)) < 0)
{
ONVIF_WARN("setsockopt IP_MULTICAST_IF fail with errno:%d", errno);
}
return OK;
}
/******************************************************************************
\* 函数名称: onvif_discv_stop()
\* 函数描述: onvif discover处理模块停止函数,释放数据
\* 输 入: N/A
\* 输 出: N/A
\* 返 回 值: ERROR/OK
******************************************************************************/
void onvif_discv_stop()
{
if (g_index_for_discv > 0)
{
inet_del_socket(g_index_for_discv);
g_index_for_discv = -1;
}
if (g_soap_for_discv->sock > 0)
{
close(g_soap_for_discv->sock);
}
free_soap(g_soap_for_discv);
g_soap_for_discv = NULL;
return;
}
/******************************************************************************
\* 函数名称: onvif_discv_remove_socket()
\* 函数描述: onvif discover处理模块固件升级时只移除socket,资源设备重启时回收
\* 输 入: N/A
\* 输 出: N/A
\* 返 回 值: ERROR/OK
******************************************************************************/
void onvif_discv_remove_socket()
{
if (g_index_for_discv > 0)
{
inet_del_socket(g_index_for_discv);
g_index_for_discv = -1;
}
if (g_soap_for_discv->sock > 0)
{
close(g_soap_for_discv->sock);
g_soap_for_discv->sock = -1;
}
return;
}
/******************************************************************************
\* 函数名称: onvif_hello()
\* 函数描述: 发送onvif Hello报文
\* 输 入: N/A
\* 输 出: N/A
\* 返 回 值: ERROR/OK
******************************************************************************/
S32 onvif_hello()
{
return soap_wsdd_hello(g_soap_for_discv);
}
/******************************************************************************
\* 函数名称: onvif_discv_handle_init()
\* 函数描述: 注册onvif discover模块需要的soap处理函数
\* 输 入: N/A
\* 输 出: N/A
\* 返 回 值: N/A
******************************************************************************/
void onvif_discv_handle_init()
{
soap_wsdd_handle_init();
}
/******************************************************************************
\* 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);
}——这部分是onvif模块剩下的部分代码,当前onvif模块仅支持http不支持https,需要提供onvif over tls支持,能够兼容切换非tls和tls client连接,端口选择443,请你分析下目前已有条件还有接下来需要做的所有修改,详细阐述并给出代码
最新发布