歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> Linux技術

(一)onvif

剛開始研究,參考了網上的代碼,但是出現了錯誤!還有很多問題慢慢理解吧!記錄今天的發現。
gsoap版本:2.8.32最新版本
下載onvif的wsdl文件生成c文件。
感謝此博客的博主,http://gaohtao.blog.163.com/blog/#m=0&t=3&c=onvif
從頭說起:
1、下載gsoap,解壓後進入目錄:
./configure <> make
gsoap\src 以及\gsoap\wsdl下可見生成onvif架構的可執行文件!——soapcpp2和wsdl2h可執行文件
2、利用上面兩個可執行文件生成onvif代碼如下:
首先可以下載onvif的wsdl文件,下載方法:
http://www.onvif.org/onvif/ver20/util/operation
比如下載devicemgmt.wsdl,對准DeviceMgmt下的比如GetDeviceInformation鏈接右鍵鏈接另存為即可出現!保存就好了,其他的下載方法一樣!
DeviceMgmt
GetDeviceInformation 。。。
拷貝soapcpp2和wsdl2h到bin的linui386目錄下(自己建立,可以自己建立,具體位置也無所謂),如果該目錄有此文件就不必拷貝了,如果運行不了在拷貝!
使用wsdl2h生成對應h文件。注意拷貝wsdl目錄下的typemap.dat以及下載回來的remotediscovery.wsdl到的bin/linuxi386目錄下,只用remotediscovey.wsdl。後面在研究其他的把
./wsdl2h -o remotediscovery.h -c -s -t typemap.dat remotediscovery.wsdl

生成C文件
./soapcpp2 remotediscovery.h -x -I ../../import
3、從網上download代碼下來,具體代碼不列出來了,編譯後執行
sudo ./onvifserver
在ONVIF Device Test tool 按device discovery 按鈕沒有發現,輸入IP後,按probe後彈出如下錯誤框
—————————————————————————————
| |
| Unexpected error occurred:XML文檔(2,833)中有錯誤。 |
| |
—————————————————————————————
重新編譯gsoap後又出現如下bug
—————————————————————————————
| |
| Unexpected error occurred:XML文檔(2,909)中有錯誤。 |
| |
—————————————————————————————
解決方法:查找到sendto函數看看onvif回復的信息,使用GDB調試;
GDB小技巧:
通常在gdb調試時要打印出一些字符串的內容,通過
p str@str_len 打印字符串時,通常有長度的限制,我測試linux機器上默認為200個,但實際輸出的長度str_len可能大於該值。
結果不能夠完全輸出,而進行了省略,通過命令set print element 0就可以了。
使用wireshark解析,過濾方法:(ip.addr eq 10.104.15.230 and ip.addr eq 10.104.15.50) and (udp.port eq 3702 and udp.port eq 3702)
分析ONVIF Device Test tool發送的數據以及discoveryserver回復的數據對比!
ONVIF Device Test tool發送的數據,發兩次數據如下:
<?xml version="1.0" encoding="utf-8"?>
<Envelope 
	xmlns:tds="http://www.onvif.org/ver10/device/wsdl" 
	xmlns="http://www.w3.org/2003/05/soap-envelope">
	<Header>
		<wsa:MessageID xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">uuid:ac68cf08-25da-465c-97f1-ac6da5efc4d9</wsa:MessageID>
		<wsa:To xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">urn:schemas-xmlsoap-org:ws:2005:04:discovery</wsa:To>
		<wsa:Action xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe</wsa:Action>
	</Header>
	<Body>
		<Probe xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
			xmlns:xsd="http://www.w3.org/2001/XMLSchema"
			xmlns="http://schemas.xmlsoap.org/ws/2005/04/discovery">
			<Types>tds:Device</Types>
			<Scopes><Scopes />
		</Probe>
	</Body>
</Envelope>

<?xml version="1.0" encoding="utf-8"?>
<Envelope xmlns:dn="http://www.onvif.org/ver10/network/wsdl" xmlns="http://www.w3.org/2003/05/soap-envelope">
	<Header>
	<wsa:MessageID xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">uuid:b02cab32-f5bc-4bfa-b968-0f4b0a228208</wsa:MessageID>
	<wsa:To xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">urn:schemas-xmlsoap-org:ws:2005:04:discovery</wsa:To>
	<wsa:Action xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe</wsa:Action>
	</Header>

	<Body>
		<Probe 
			xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
			xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
			xmlns="http://schemas.xmlsoap.org/ws/2005/04/discovery">
			<Types>dn:NetworkVideoTransmitter</Types>
			<Scopes />
		</Probe>
	</Body>
</Envelope>

onvifserver回復的數據如下:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope 
xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" 
	xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
	xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" 
	xmlns:wsdd="http://schemas.xmlsoap.org/ws/2005/04/discovery" 
	xmlns:tdn="http://www.onvif.org/ver10/network/wsdl">
	<SOAP-ENV:Header>
		<wsa:MessageID>uuid:2419d68a-2dd2-21b2-a205-010101010101</wsa:MessageID>
		<wsa:RelatesTo>uuid:3a7c78e4-bacb-4ec8-a4ee-225e5e575a41</wsa:RelatesTo>
		<wsa:To SOAP-ENV:mustUnderstand="true">http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
		<wsa:Action SOAP-ENV:mustUnderstand="true">http://schemas.xmlsoap.org/ws/2005/04/discovery/ProbeMatches</wsa:Action>
	</SOAP-ENV:Header>
	
	<SOAP-ENV:Body>
		<wsdd:ProbeMatches>
			<SOAP-RPC:result xmlns:SOAP-RPC="http://www.w3.org/2003/05/soap-rpc">-sizeProbeMatch</SOAP-RPC:result>
			<wsdd:ProbeMatch xmlns:_0="http://www.onvif.org/ver10/device/wsdl">
				<wsa:EndpointReference>
					<wsa:Address>urn:uuid:2419d68a-2dd2-21b2-a205-010101010101</wsa:Address>
					<wsa:ReferenceProperties></wsa:ReferenceProperties>
					<wsa:ReferenceParameters></wsa:ReferenceParameters>
					<wsa:PortType>ttl</wsa:PortType>
				</wsa:EndpointReference>
				
				<wsdd:Types>_0:Device</wsdd:Types>
				<wsdd:Scopes>onvif://www.onvif.org/type/NetworkVideoTransmitter</wsdd:Scopes>
				<wsdd:XAddrs>http://010.104.15.230/onvif/device_service</wsdd:XAddrs>
				<wsdd:MetadataVersion>1</wsdd:MetadataVersion>
			</wsdd:ProbeMatch>
		</wsdd:ProbeMatches>
	</SOAP-ENV:Body>
</SOAP-ENV:Envelope

ONVIF Device Test tool提示的錯誤:
Unexpected error occurred:XML文檔(2,909)中有錯誤
是discoveryserver回復的XML文件有錯誤,偏移位置909,定位至909,為:
<SOAP-RPC:result xmlns:SOAP-RPC="http://www.w3.org/2003/05/soap-rpc">-sizeProbeMatch</SOAP-RPC:result>

這句有錯誤。查看代碼定位置-sizeProbeMatch字符串,調試具體代碼如下:
SOAP_FMAC3 int SOAP_FMAC4 soap_out_wsdd__ProbeMatchesType(struct soap *soap, const char *tag, int id, const struct wsdd__ProbeMatchesType *a, const char *type)
{
	(void)soap; (void)tag; (void)id; (void)a; (void)type; /* appease -Wall -Werror */
	if (soap_element_begin_out(soap, tag, soap_embedded_id(soap, id, a, SOAP_TYPE_wsdd__ProbeMatchesType), type))
		return soap->error;
	printf("function:%s,line:%d \n",__FUNCTION__,__LINE__);
	soap_element_result(soap, "-sizeProbeMatch");
	//
	if (a->ProbeMatch)
	{	int i;
		for (i = 0; i < (int)a->__sizeProbeMatch; i++)
			if (soap_out_wsdd__ProbeMatchType(soap, "wsdd:ProbeMatch", -1, a->ProbeMatch + i, ""))
				return soap->error;
	}
	return soap_element_end_out(soap, tag);
}

定位函數soap_element_result(soap, "-sizeProbeMatch");
屏蔽次函數即可,就不會發送<SOAP-RPC:result xmlns:SOAP-RPC="http://www.w3.org/2003/05/soap-rpc">-sizeProbeMatch</SOAP-RPC:result>這個了,一切正常!
點擊Onvif Device test tool的Discover Devices無法枚舉,原因如下:
分析:使用wireshark由於Discover Devices點擊會發送的是組播信息,使用GDB調試程序發現一直停在了recvfrom函數,對組播信息完全忽略。跟蹤發現soap_bind如下代碼:
if (soap_valid_socket(soap->master)){ 
    soap->fclosesocket(soap, soap->master);
    soap->master = SOAP_INVALID_SOCKET;
}
soap->fclosesocket(soap, soap->master);
//linux下調用close,也就是會把之前申請的關閉了,所以之前對socket加入組播信息也會沒有,如果要重新識別組播信息,就必須重新加入組播,
//所以在bind後面必要重新加入組播代碼如下:
struct ip_mreq mreq;
   mreq.imr_multiaddr.s_addr = inet_addr("239.255.255.250");
   mreq.imr_interface.s_addr = htonl(INADDR_ANY);

   if(setsockopt(server_udp,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq))==-1){
	   _DBG_ERROR("memberchip error\n");
   }
原主函數:
int main
{
	int server_udp;
	
	int retval=0;
	struct soap *soap_udp;
	int fault_flag = 0;
	server_udp = create_server_socket_udp();
	bind_server_udp1(server_udp);
	while(1){
		soap_udp=soap_new();
		//soap_init(soap_udp);
		soap_init1(soap_udp, SOAP_IO_UDP);
		soap_udp->master = server_udp;
		soap_udp->socket = server_udp;
		printf("skfd:%d \n",server_udp);
		soap_udp->errmode = 0;
		soap_udp->bind_flags = 1;
		if (!soap_valid_socket(soap_bind(soap_udp, NULL, UDP_PORT, 100)))
		{	 
			soap_print_fault(soap_udp, stderr);
		}
		printf("%d \n",soap_udp->master);
		PRINT_MSG("soap_serve starting..\n");
		retval = soap_serve(soap_udp); 
		if(retval && !(fault_flag))
		{
			fault_flag = 1;
		}
		else if(!retval)
		{
			fault_flag = 0;
		}
		soap_destroy(soap_udp);
		soap_end(soap_udp);
		soap_done(soap_udp);
		free(soap_udp);
	}
}

新的主函數:
int main
{
	int server_udp;
	
	int retval=0;
	struct soap *soap_udp;
	int fault_flag = 0;
	server_udp = create_server_socket_udp();
	bind_server_udp1(server_udp);
	while(1){
		soap_udp=soap_new();
		soap_init1(soap_udp, SOAP_IO_UDP);
		soap_udp->master = server_udp;
		soap_udp->socket = server_udp;
		soap_udp->errmode = 0;
		soap_udp->bind_flags = 1;
		if (!soap_valid_socket(soap_bind(soap_udp, NULL, UDP_PORT, 100)))
		{	 
			soap_print_fault(soap_udp, stderr);
		}
//重新加入組播	
#define 1
		struct ip_mreq mreq;
		mreq.imr_multiaddr.s_addr = inet_addr("239.255.255.250");
		mreq.imr_interface.s_addr = htonl(INADDR_ANY);
		if(setsockopt(server_udp,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq))==-1){
		   _DBG_ERROR("memberchip error\n");
		}
#endif
		PRINT_MSG("soap_serve starting..\n");
		retval = soap_serve(soap_udp); 
		if(retval && !(fault_flag))
		{
			fault_flag = 1;
		}
		else if(!retval)
		{
			fault_flag = 0;
		}
		soap_destroy(soap_udp);
		soap_end(soap_udp);
		soap_done(soap_udp);
		free(soap_udp);
	}
}
Copyright © Linux教程網 All Rights Reserved