WS-Discovery using gSoap
gsoap에서 만들어 놓은 import/wsdd10.h를 바로 써도 되지만 원리를 좀 더 알기 위함이다.
gsoap-2.8.6 버젼으로 진행한다.
2012년 6월 21일 신C
-
헤더파일 만들기
plug-in과 연동하기 위해 gsoap에서 수정한 사항을 생성된 wsa5.h에 적용
1) WS-Addressing 헤더 만들기
- wsdl2h -cgye -o wsa5.h -t WS-typemap.dat http://www.w3.org/2005/08/addressing/ws-addr.xsd
- Removed xsd__boolean declaration
- Added the following directive to import WS-Addressing namespace:
//gsoap wsa5 schema import: http://www.w3.org/2005/08/addressing
This ensures that the WS-Addressing schemas are not copied into the
generated WSDL by soapcpp2 but are referenced with schema import in the
generated WSDL.
- Added //gsoap wsa5 schema namespace2: http://schemas.xmlsoap.org/ws/2004/08/addressing
- Added #define SOAP_WSA_2005
- Added SOAP_ENV__Header struct
- wsa5__Action 에서 "wsa5__"제거
2) WS-Discovery 헤더 만들기
-
wsdl2h -cyex -o wsdiscovery.h -t WS-typemap.dat http://docs.oasis-open.org/ws-dd/discovery/1.1/os/wsdd-discovery-1.1-wsdl-os.wsdl http://docs.oasis-open.org/ws-dd/discovery/1.1/os/wsdd-discovery-1.1-schema-os.xsd
- Removed //gsoapopt
- Changed //gsoap wssd schema namespace directive to import directive
- Added #import "wsdx.h" at the end of these definitions
- wsdd__Types, wsdd__Scopes, wsdd_XAddrs, wsdd__MetadataVersion 에서 "wsdd__" 제거- Changed //gsoap wssd schema namespace directive to import directive
- Added #import "wsdx.h" at the end of these definitions
- wsdd__QNameListType* -> wsdd__QNameListType로 수정
wsdd-discovery-1.1-wsdl-os.wsdl 에는 Binding element가 정의 되지 않았다. 메소드가 WS-Addressing을 이용하므로 독립성을 주기 위한 것 같다.
- wsdl에 biding이 없으므로, 헤더에 서비스 메소드 정의가 생성되지 않는다(#import wsdx.h 없을시)
- 스키마를 인자로 주지 않으면 생성되는 헤더에 자동으로 #import 지시어가 붙는다.
2. 스텁코드 만들기
- soapcpp2 -cx wsdiscovery.h
3. 이벤트 핸들러를 wsdiscovery.c에 정의한다.
soap-2.8/gsoap/doc/wsdd/html/wsdd_0.html#wsdd_2 을 참고한다.
wsdd_event_Hello()
wsdd_event_Bye()
wsdd_event_Probe()
wsdd_event_ProbeMatches()
wsdd_event_Resolve()
wsdd_event_ResolveMatches()
4. 링크하기
soapC.c soapClient.c : stub code, soapServer.c에서 정의한 서버측 함수는 wsddapi.c에 새로 정의 한 것으로 쓰므로 필요없다.
wsddapi.c wsaapi.c (thread.h wsddapi.h wsaapi.h) : gsoap plug-in
wsdiscovery.c : user defined event handlers
1) wsddapi.c 에서 UDP multicast packet을 못 받는다.
- 원인 : 기본 설정이 TCP socket 으로 listen 한다.
- 해결방법: UDP 멀티캐스팅 되도록 소켓에 옵션을 준다.
- gsoap user guide 18.7 SOAP-over-UDP Multicast Receiving Server 참조
- src/gsoap/samples/udp/udpserver.c 참조
2) 윈도우용 디커버리 응용프로그램 SiONVIFManager, Milestion Xprotect 에서 device scan 했을 때,
"Method 'd:Probe' not implemented: method name or namespace not recognized" 가 나온다.
- 원 인 : 네임스페이스가 다르다. 클라이언트 http://schemas.xmlsoap.org/ws/2005/04/discovery 그리고 서버는 "http://docs.oasis-open.org/ws-dd/ns/discovery/2009/01"
- 해결방법 : wsdiscovery.h에 //gsoap wsdd schema namespace2: http://schemas.xmlsoap.org/ws/2005/04/discovery 를 추가하여 namespace table을 변경한다.
-참 고 : gsoap-2.8/gsoap/doc/soapdoc2.html
//gsoap namespace-prefix schema namespace2: namespace-URI-pattern
If the first namespace does not match the inbound parsed XML, then the second will be tried. This pattern may contain '*' multichar wildcards and '-' single chard wildcards. This allows two or more namespace versions to be handled by the same namespace prefix.
3) soap_wsdd_ProbeMatches(..) 을 실행하면 -1이 리턴된다.
- 원 인 : endpoint 파라미터 형식이 틀렸다.
- 해결방법: Probe event 에서 클라이언트 접속정보를 저장한 뒤 "soap.udp:// addresss:port" 형식으로 endpoint를 준다.
- 참고1: gsoap-2.8/gsoap/doc/wsdd/html/wsdd_0.html
In ad-hoc mode, ProbeMatches or ResolveMatches responses are NOT sent automatically. In ad-hoc mode the responses can be returned by adding code to the event handler or from anywhere in the main program, for example after soap_wsdd_listen. When responses are to be returned from the event handler or from the main program, you should invoke soap_wsdd_ProbeMatches and soap_wsdd_ResolveMatches to explicitly send unicast messages with the match(es) back to the clients. The WS-Addressing ReplyTo address can be used as the return address (when not anonymous), or by using the peer's host information that is accessible in the soap->peer and soap->peerlen members.
참고2: gsoap-2.8/gsoap/doc/soapdoc2.html (18 SOAP-over-UDP)
Client-side messages with SOAP-over-UDP endpoint URLs (soap.udp://...) will be automatically transmitted as datagrams. Server-side applications should set the SOAP_IO_UDP mode flag to accept UDP requests, e.g. using soap_init1 or soap_set_mode.The maximum message length for datagram packets is restricted by the buffer size SOAP_BUFLEN, which is 65536 by default, unless compiled with WITH_LEAN to support small-scale embedded systems. For UDP transport SOAP_BUFLEN must not exceed the maximum UDP packet size 65536 (the size of datagram messages is constrained by the UDP packet size 216=65536 as per UDP standard). You can use gzip compression to reduce the message size, but note that compressed SOAP-over-UDP is a gSOAP-specific feature because it is not part of the SOAP-over-UDP specification. The SOAP-over-UDP specification relies on WS-Addressing. The wsa.h file in the import directory defines the WS-Addressing elements for client and server applications.
4) soap_wsdd_ProbeMatches() 전송뒤 Client에서 Device service request가 없다.
- 원 인 : ONVIF Core Specification ver2.2 (2 Normative references)에서 Discovery는 "http://schemas.xmlsoap.org/ws/2005/04/discovery 으로 되어있다.
결국 Probe에서 Namespace가 맞지 않는 것도 당연하다.
- 해결 방법 : 라이브러리를 "http://schemas.xmlsoap.org/ws/2005/04/discovery" 로 구현해야 한다.
5. Soap-2.8.6 plug-in 을 http://schemas.xmlsoap.org/ws/2005/04/discovery 버젼으로 수정하기
(1) WS-typemap.dat에서 프리픽스 바인딩을 수정한다. wsddapi.c 에서 네임스페이스가 wsdd 프리픽스가 있기 때문이다.
-
wsdd11 = <http://docs.oasis-open.org/ws-dd/ns/discovery/2009/01>
wsdd = <http://schemas.xmlsoap.org/ws/2005/04/discovery>
(2) WS-addressing을 2004년 버젼으로 헤더 만들기
-
wsdl2h -cgye -o wsa.h -t WS-typemap.dat http://schemas.xmlsoap.org/ws/2004/08/addressing
- //gsoapopt 제거
- //gsoap wsa schema namespace:--- 에서 //gsoap wsa schema import:--으로 수정
- 구조체 추가
struct SOAP_ENV__Header
{
_wsa__MessageID wsa__MessageID 0;
_wsa__RelatesTo *wsa__RelatesTo 0;
_wsa__From *wsa__From 0;
mustUnderstand _wsa__ReplyTo *wsa__ReplyTo 0;
mustUnderstand _wsa__FaultTo *wsa__FaultTo 0;
mustUnderstand _wsa__To wsa__To 0;
mustUnderstand _wsa__Action wsa__Action 0;
};
- //gsoap wsa schema namespace:--- 에서 //gsoap wsa schema import:--으로 수정
- 구조체 추가
struct SOAP_ENV__Header
{
_wsa__MessageID wsa__MessageID 0;
_wsa__RelatesTo *wsa__RelatesTo 0;
_wsa__From *wsa__From 0;
mustUnderstand _wsa__ReplyTo *wsa__ReplyTo 0;
mustUnderstand _wsa__FaultTo *wsa__FaultTo 0;
mustUnderstand _wsa__To wsa__To 0;
mustUnderstand _wsa__Action wsa__Action 0;
};
(3) WS-typemap.dat에서 2004/08/addressing의 프리픽스가 wsa로 되어 있다. wsaapi.c에서 2004년버젼일 경우 wsa__ 함수로 구현되어 있으므로
wsdx.h의 프리픽스를 wsa로 수정한다.
wsa5__xxx -> wsa__xxx
(4) WS-Discovery을 2005년 버젼으로 헤더 만들기
-
wsdl2h -cyex -o wsdiscovery.h -t WS-typemap.dat http://schemas.xmlsoap.org/ws/2005/04/discovery/ws-discovery.wsdl http://schemas.xmlsoap.org/ws/2005/04/discovery/ws-discovery.xsd
- Removed //gsoapopt
- Changed //gsoap wssd schema namespace directive to import directive
- Added #import "wsdx.h" at the end of these definitions
- wsdd__Types, wsdd__Scopes, wsdd_XAddrs, wsdd__MetadataVersion 에서 "wsdd__" 제거- Changed //gsoap wssd schema namespace directive to import directive
- Added #import "wsdx.h" at the end of these definitions
- wsdd__QNameListType* -> wsdd__QNameListType로 수정
(5) 스텁코드 만들기
-
soapcpp2 -cx wsdiscovery.h
(6) wsddapi.c 수정하기
- soap_wsdd_Probe(...): struct wsdd__ResolveMatchesType res -> struct __wsdd__ProbeMatches res
- soap_wsdd_Resolve(...): struct wsdd__ResolveMatchesType res -> struct __wsdd__ResolveMatches res
- const char *Action = "http://docs.oasis-open.org/ws-dd/ns/discovery/2009/01/ProbeMatches"
-> const char *Action = "http://schemas.xmlsoap.org/ws/2005/04/discovery/ProbeMatches";
- const char *Action = "http://docs.oasis-open.org/ws-dd/ns/discovery/2009/01/ResolveMatches";
-> const char *Action = "http://schemas.xmlsoap.org/ws/2005/04/discovery/ResolveMatches";
- const char *Action = "http://docs.oasis-open.org/ws-dd/ns/discovery/2009/01/Hello";
-> "http://schemas.xmlsoap.org/ws/2005/04/discovery/Hello";
- const char *Action = "http://docs.oasis-open.org/ws-dd/ns/discovery/2009/01/Bye";
->"http://schemas.xmlsoap.org/ws/2005/04/discovery/Bye";
- To = "urn:docs-oasis-open-org:ws-dd:ns:discovery:2009:01";
-> "urn://schemas.xmlsoap.org:ws:2005:04:discovery";
- match.wsa5__* -> match.wsa__*
(7) 동작 확인(Probe/ProbeMatch)
- Milestone Xprotect (http://www.milestonesys.com/freetrialdownloads/) : 장치인식확인됨.
- schille ONVIF Device Manager (http://www.server001.net/PUBLIC/) : 장치인식확인됨.
(8) 디스커버리 클라이언트 - 서버 테스트용
1) Probe/Types 에 들어갈 데이터의 namespace를 wsdd.namap에 추가
- {"dn", "http://www.onvif.org/ver10/network/wsdl", NULL, NULL}
- {"dn", "http://www.onvif.org/ver10/network/wsdl", NULL, NULL}
2) 서버에서 만들어진 스텁코드와 event handler를 구현한 wsdiscovery_clnt.c , x86에서 컴파일 및 링크.
- soapC.c wsddapi.c wsaapi.c stdsoap2.c wsdiscovery_clnt.c soapClient.c soapServer.c
3) Trouble shoting
문제: Client에서 3702로 바인딩 되지 않은 소켓으로 전송하니까 임의로 지정된 포트가 지정되어, 서버에서 소스포트로 응답하면 클라이트는
3702포트로 수신 대기중이므로 데이터를 받지 못함.
해결 : 요청(probe/resolve)을 보낸 소켓을 응답까지 받고 세션을 끝내야한다.
mode=SOAP_WSDD_MANAGED;
3702포트로 수신 대기중이므로 데이터를 받지 못함.
해결 : 요청(probe/resolve)을 보낸 소켓을 응답까지 받고 세션을 끝내야한다.
mode=SOAP_WSDD_MANAGED;
문제 :Test Client 에서 보낸 Probe/Resolve에 내가 구현한 서버만 응답하고, Axis IP Camera에서 응답을 안한다.
원인: WSA <faultcode>를 보니 아래와 같아 확인해 보니 Action에 오타가 있었음.
<faultcode>wsa:InvalidMessageINformationHeader</faultcode>
<faul string> A message information header is not valid and the message cannot be processed</faul string>
<detail>wsa:Action</detail>
해결:스키마 어드레스 오타 수정 wsddapi.c에서
const char *Action = "http://schemas.xmlsoap.org/ws/2005/04/discovery/*"
원인: WSA <faultcode>를 보니 아래와 같아 확인해 보니 Action에 오타가 있었음.
<faultcode>wsa:InvalidMessageINformationHeader</faultcode>
<faul string> A message information header is not valid and the message cannot be processed</faul string>
<detail>wsa:Action</detail>
해결:스키마 어드레스 오타 수정 wsddapi.c에서
const char *Action = "http://schemas.xmlsoap.org/ws/2005/04/discovery/*"
문제: Probe/Resolve 요청시 응답이 없으면 무한정 기다린다.
원인: 타임아웃 설정 안했음.
해결: 타임아웃 설정 Probe/Resolve , soap context 초기화 후 설정.
wsdiscovery_clnt.c 에서 soap->accept_timeout = soap->recv_timeout = soap->send_timeout = 1;
원인: 타임아웃 설정 안했음.
해결: 타임아웃 설정 Probe/Resolve , soap context 초기화 후 설정.
wsdiscovery_clnt.c 에서 soap->accept_timeout = soap->recv_timeout = soap->send_timeout = 1;
문제: Probe 요청 후 ProbeMatch가 여러개 들어오면 하나만 받는다.
원인: soap_wsdd_Probe(..) in wsddapi.c 가 하나의 ProbeMatch만 받게 되어있다.
해결: soap_recv___wsdd__ProbeMatches(soap, &res) 를 타임 아웃될때 까지 루프를 돌아 받는다.
원인: soap_wsdd_Probe(..) in wsddapi.c 가 하나의 ProbeMatch만 받게 되어있다.
해결: soap_recv___wsdd__ProbeMatches(soap, &res) 를 타임 아웃될때 까지 루프를 돌아 받는다.
안녕하세요?
답글삭제혹시 gSOAP에 포함된 wsdd10.h 를 이용해서
WS-Discovery를 구현해보셨나요?
간단한 절차좀 알려주세요~ @.@
미안합니다. 너무 오래 지났네요 ^^;; 제 기억이 맞을지 확실하지 않지만..
답글삭제(5) 스텁코드 만들기: soapcpp2 -cx (wsdiscovery.h -> wsdd10.h)으로 하시면 될것 같아요.