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: