TheRiver | blog

You have reached the world's edge, none but devils play past here

0%

gsoap添加header

Foreword

前端时间碰到个事,axis的相机onvif接入,告警订阅有些问题.折磨了好久,后来自己买了个2手的axis相机,试着改了下gsoap的代码,才搞定,记录下

Solution

这里有类似的问题:
ONVIF PullPointSubscriptionClient.PullMessages

I'm trying to get event messages from some ONVIF devices. My code is in C#.

On a (Axis camera) device on EventPortTypeClient.CreatePullPointSubscription returns:

Address.Value: http : / /192.168.8.48/onvif/services
ReferenceParameters.Any.First().OuterXml: <dom0:SubscriptionId xmlns:dom0="http : / /www.axis.com/2009/event">38</dom0:SubscriptionId>
So I add the "To" and "SubscriptionId" soap headers and can get event messages with PullPointSubscriptionClient.PullMessages("PT5M", 99, Any, out CurrentTime, out NotificationMessages)

<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
  <s:Header>
    <a:Action s:mustUnderstand="1">http://www.onvif.org/ver10/events/wsdl/PullPointSubscription/PullMessagesRequest</a:Action>
    <a:MessageID>urn:uuid:f243dbe4-b082-4a6c-aa65-8145468fcf3e</a:MessageID>
    <a:ReplyTo>
      <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
    </a:ReplyTo>
    <VsDebuggerCausalityData xmlns="http://schemas.microsoft.com/vstudio/diagnostics/servicemodelsink">uIDPo0zfnhoyh15KqPZwP/IS9H0AAAAAdCoo8EjbCUScx/bG/DGcdXp8kY6WrAJDp0TTtNAtj0EACQAA</VsDebuggerCausalityData>
    <Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
      <wsse:UsernameToken xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="SecurityToken-GWt5XP2ogUljZ/fzEJvnX0WhGpx3FV4i/dRnE539OFU=">
        <wsse:Username xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">root</wsse:Username>
        <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">pjwOOO0hOXtUZyJb6B6Lb0ctRIU=</wsse:Password>
        <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">DEE/P1c/P1E/eG9XTT87Pz8/</wsse:Nonce>
        <wsu:Created xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2015-03-02T19:06:54.269Z</wsu:Created>
      </wsse:UsernameToken>
    </Security>
    <a:To s:mustUnderstand="1">http://192.168.8.48/onvif/services</a:To>
    <SubscriptionId s:mustUnderstand="1" xmlns="http://www.axis.com/2009/event">38</SubscriptionId>
  </s:Header>
  <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <PullMessages xmlns="http://www.onvif.org/ver10/events/wsdl">
      <Timeout>PT5M</Timeout>
      <MessageLimit>99</MessageLimit>
    </PullMessages>
  </s:Body>
</s:Envelope>

onvif告警订阅的流程:

  • 订阅

    client –> subscribe –> server(ipc)

    server –> 200 ok –> client

  • 续订

    client –> renew –> server(ipc)

    server –> 200 ok –> client

  • 取消订阅

    client –> unsubscribe –> server(ipc)

    server –> 200 ok –> client

现在的问题是,axis的ipc在subscirbe的200 ok中携带了subscirbeid,他们用这个来区分订阅源的实例.并且要求client在renew和unsubscibe中携带这个subscribeid.这就比较麻烦了

200 ok携带的subscribeid:

现在需要在renew和unsubscribe的header中添加一个字段

参考gSoap: How to add info to SOAP Header using gSOAP

step 1

//soap->header中添加一个字段
struct SOAP_ENV__Header
{
    public:
     void *dummy; /* transient */
     char *username;
    ...
     char *subscribeid;
};

step 2

//在对应的renew和unsubscribe的gsoap函数下,添加
if (NULL != soap->header->subscribeid)
{
    soap_element_begin_out(soap, "SubscriptionId a:IsReferenceParameter=\"true\" xmlns=\"http://www.axis.com/2009/event\"", -1, "")
            || soap_string_out(soap, a->subscribe_id, 0)
            || soap_element_end_out(soap, "SubscriptionId")
}

step 3

//我省略了这步
//Add the namespace mapping to namespaces array in .nsmap file.
{"headerNS", "http://customeheader.test.com", NULL, NULL},        

step 4

//在对应的地方给subscirbeid赋值,即200 ok中返回的值,需要解析EndpointReference
struct soap soap; 
soap_init(&soap);
...
strcpy(soap->header->username, username);
strcpy(soap->header->password, passwd);
...
poSoap->header->subscribe_id = "EndpointReference"

Finally, like this:

ending

----------- ending -----------