onvif学习笔记3:NTP命令实现的示例

来源:互联网 发布:2015网络歌曲排行榜 编辑:程序博客网 时间:2024/06/05 14:34

对于开始接触onvif的人,相信都会被其庞大的代码吓到。一般不建议上来就看代码,而是先去了解概念,然后去官网下载Spec来看。有一定概念后,再对照着wsdl命令描述、spec描述来阅读代码,这个时候就会比较清晰了。本文就按这个思路来讲解一下NTP的设置和获取命令。

1、SetNTP

首先看设置NTP命令SetNTP的描述,地址为:http://www.onvif.org/onvif/ver10/device/wsdl/devicemgmt.wsdl#op.SetNTP

如下图:


“Input”处定义了命令字段及解释。第一个字段为FromDHCP,如果为1,则表示NTP地址信息是从DHCP获取的。第二个字段为NTPManual,是手动设置NTP信息,其下又有类型Type(同时给出了枚举类型),还有IPv4或IPv6,等等。

再来看spec对SetNTP命令的描述,如下图:


对比上面两张图,可以看到,spec的字段不是太详细,但它给出了错误码Fault codes。有的错误码在代码里是需要设置的(下面的示例伪代码就使用到)。

伪代码示例如下:

SOAP_FMAC5 int SOAP_FMAC6 __tds__SetNTP(struct soap* soap, struct _tds__SetNTP *tds__SetNTP, struct _tds__SetNTPResponse *tds__SetNTPResponse){    onvif_debug(7, "--%s--\n", __func__);    // 不支持FromDHCP,所以返回错误    if (tds__SetNTP->FromDHCP == TRUE)    {        onvif_fault(soap,"ter:NotSupported", "ter:SetDHCPNotAllowed");        return SOAP_FAULT;    }    // 不支持IPv6Address,所以返回错误    if (tds__SetNTP->NTPManual->IPv6Address != NULL)    {        onvif_fault(soap,"ter:NotSupported", "ter:IPv6AddressNotAllowed");                return SOAP_FAULT;    }    // 只支持IPv4Address    if(tds__SetNTP->NTPManual->IPv4Address != NULL)    {        // 地址非法,返回错误        if(isValidIp4(tds__SetNTP->NTPManual->IPv4Address[0]) == 0)        {            onvif_fault(soap,"ter:InvalidArgVal", "ter:InvalidIPv4Address");            return SOAP_FAULT;        }        sa.sin_family = AF_INET;        inet_aton(tds__SetNTP->NTPManual->IPv4Address[0], &sa.sin_addr.s_addr);        s = getnameinfo(&sa, sizeof(sa), host, sizeof(host), service, sizeof(service), NI_NAMEREQD); //转换host        // 如果host非法,返回错误        if(isValidHostname(host) == 0)        {            onvif_fault(soap,"ter:InvalidArgVal", "ter:InvalidDnsName");            return SOAP_FAULT;        }        // 这里设置设备的NTP服务器地址...    }    return SOAP_OK;}
涉及到的结构体定义如下:

struct _tds__SetNTP{/// @brief Indicate if NTP address information is to be retrieved using DHCP./// Element FromDHCP of type xs:boolean.    enum xsd__boolean                    FromDHCP                       1;     ///< Required element./// @brief Manual NTP settings./// Size of array of struct tt__NetworkHost* is 0..unbounded   $int                                  __sizeNTPManual                0;/// Array struct tt__NetworkHost* of length 0..unbounded    struct tt__NetworkHost*              NTPManual                      0;};struct tt__NetworkHost{/// @brief Network host type: IPv4, IPv6 or DNS./// Element Type of type "http://www.onvif.org/ver10/schema":NetworkHostType.    enum tt__NetworkHostType             Type                           1;     ///< Required element./// @brief IPv4 address./// Element IPv4Address of type "http://www.onvif.org/ver10/schema":IPv4Address.    tt__IPv4Address                      IPv4Address                    0;     ///< Optional element./// @brief IPv6 address./// Element IPv6Address of type "http://www.onvif.org/ver10/schema":IPv6Address.    tt__IPv6Address                      IPv6Address                    0;     ///< Optional element./// @brief DNS name./// Element DNSname of type "http://www.onvif.org/ver10/schema":DNSName.    tt__DNSName                          DNSname                        0;     ///< Optional element./// Element Extension of type "http://www.onvif.org/ver10/schema":NetworkHostExtension.    struct tt__NetworkHostExtension*     Extension                      0;     ///< Optional element./// <anyAttribute namespace="##any">/// TODO: Schema extensibility is user-definable.///       Consult the protocol documentation to change or insert declarations.///       Use wsdl2h option -x to remove this attribute.///       Use wsdl2h option -d for xsd__anyAttribute DOM (soap_dom_attribute).   @_XML                                 __anyAttribute                ;     ///< A placeholder that has no effect: please see comment.};

小结:onvif的设置命令,基本套路的根据文档(建议同时看wsdl及spec)知道有哪些字段,然后结合实际情况填充(比如SetNTP,不支持的都返回错误码),在此过程可能要实现部分功能函数(如获取IP)。

2、GetNTP

onvif很多命令是成对出现的,有Set也有Get。这里介绍获取NTP命令GetNTP。按例上wsdl描述,地址为:http://www.onvif.org/onvif/ver10/device/wsdl/devicemgmt.wsdl#op.GetNTP。

如图:


比较详细地规定各个字段名字、含义,是否是可选的。一般地Get和Set命令字段都是一一对应的。再来看看spec的定义:


同样地,spec也是大概地描述字段,没有很详细。

接下来看看SetNTP命令的代码实现,如下:

SOAP_FMAC5 int SOAP_FMAC6 __tds__GetNTP(struct soap* soap, struct _tds__GetNTP *tds__GetNTP, struct _tds__GetNTPResponse *tds__GetNTPResponse){    char *ip_address = getIPAddress(); // 获取IP地址;    int dhcp_enable = getDhcpStatus(); // 获取dhcp使能标志    tds__GetNTPResponse->NTPInformation = (struct tt__NTPInformation*)soap_malloc(soap, sizeof(struct tt__NTPInformation));    tds__GetNTPResponse->NTPInformation->FromDHCP = dhcp_enable;    if(dhcp_enable == 1) // NTPFromDHCP    {        tds__GetNTPResponse->NTPInformation->__sizeNTPFromDHCP = 1;        // 开辟空间        tds__GetNTPResponse->NTPInformation->NTPFromDHCP = (struct tt__NetworkHost*)soap_malloc(soap, sizeof(struct tt__NetworkHost));        tds__GetNTPResponse->NTPInformation->NTPFromDHCP->Type = IPv4; // 枚举类型:enum { 'IPv4', 'IPv6', 'DNS' }        tds__GetNTPResponse->NTPInformation->NTPFromDHCP->IPv4Address = (char **)soap_malloc(soap, sizeof(char *));        tds__GetNTPResponse->NTPInformation->NTPFromDHCP->IPv4Address[0] = (char *)soap_malloc(soap, sizeof(char) * 128);        strcpy(tds__GetNTPResponse->NTPInformation->NTPFromDHCP->IPv4Address[0], ip_address);        tds__GetNTPResponse->NTPInformation->NTPFromDHCP->IPv6Address = NULL;        tds__GetNTPResponse->NTPInformation->NTPFromDHCP->DNSname = NULL;        tds__GetNTPResponse->NTPInformation->NTPFromDHCP->Extension = NULL;        tds__GetNTPResponse->NTPInformation->__sizeNTPManual = 0;        tds__GetNTPResponse->NTPInformation->NTPManual = NULL;    }    else // 手动    {        tds__GetNTPResponse->NTPInformation->__sizeNTPManual = 1; // 置为1        tds__GetNTPResponse->NTPInformation->NTPManual = ((struct tt__IPAddress *)soap_malloc(soap, sizeof(struct tt__IPAddress)));        tds__GetNTPResponse->NTPInformation->NTPManual->Type = IPv4;        tds__GetNTPResponse->NTPInformation->NTPManual->IPv4Address = (char **)soap_malloc(soap, sizeof(char *));        // 开辟存储IP地址空间        tds__GetNTPResponse->NTPInformation->NTPManual->IPv4Address[0] = (char *)soap_malloc(soap, sizeof(char) * 128);        strcpy(tds__GetNTPResponse->NTPInformation->NTPManual->IPv4Address[0], ip_address); // 赋值        // 下面这些没有,置为NULL        tds__GetNTPResponse->NTPInformation->NTPManual->IPv6Address = NULL;        tds__GetNTPResponse->NTPInformation->NTPManual->DNSname = NULL;        tds__GetNTPResponse->NTPInformation->NTPManual->Extension = NULL;        tds__GetNTPResponse->NTPInformation->__sizeNTPFromDHCP = 0;        tds__GetNTPResponse->NTPInformation->NTPFromDHCP = NULL;    }    return SOAP_OK;}
小结:onvif的获取命令,套路和设置命令类似。要注意的是字段空间的申请,很多字段使用指针,如果需要使用这些字段,就是开辟空间。如果不留意,可能就会出现段错误。

3、参考

参考:
onvif 设备管理:http://www.onvif.org/onvif/ver10/device/wsdl/devicemgmt.wsdl

onvif最新(2015年)的核心规范:http://www.onvif.org/specs/DocMap-2.6.html
onvif规范(含profile、web serivce描述、设备测试规范):http://www.onvif.org/Documents/Specifications.aspx

李迟 2015.12.14 夜

2 0