blob: b0151f2f75ab2e98661d8ef8aecfc86fad952170 [file] [log] [blame]
SOAP-over-UDP
Conformance
-----------
The SOAP-over-UDP specification relies on WS-Addressing. The WS-Addressing.h
file defines the WS-Addressing elements for client and server applications.
The implementation conforms to the SOAP-over-UDP requirements:
* SOAP-over-UDP server endpoint URL format: soap.udp://host:port/path
* Support one-way message-exchange pattern (MEP) where a SOAP envelope is
carried in a user datagram.
* Support request-response message-exchange pattern (MEP) where SOAP envelopes
are carried in user datagrams.
* Support multicast transmission of SOAP envelopes carried in user datagrams.
* Support both SOAP 1.1 and SOAP 1.2 envelopes.
The SOAP-over-UDP specification can be found at:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnglobspec/html/soap-over-udp.asp
Features
--------
The following additional features are also available:
* Zlib/gzip message compression (compile -DWITH_GZIP).
* SOAP with DIME attachments over UDP.
* SOAP with MIME attachments (SwA) over UDP.
* Support for IPv6 (compile -DWITH_IPV6)
Message retransmission
----------------------
Retransmission is implemented using a retry and exponential back-off algorithm
as per SOAP-over-UDP retransmission requirements, see SOAP-over-UDP Appendix I.
Duplicate message detection
---------------------------
The user is responsible for implementing a duplicate message detection
algorithm, see SOAP-over-UDP Appendix II. An example algorithm is given in
udpserver.c
Usage
-----
Note: UDP support requires compilation with -DWITH_UDP
* Header file:
//gsoap wsa schema import: http://schemas.xmlsoap.org/ws/2004/08/addressing
#import "was.h"
struct SOAP_ENV__Header
{ mustUnderstand wsa__AttributedURI wsa__MessageID 0;
mustUnderstand struct wsa__Relationship *wsa__RelatesTo 0;
mustUnderstand struct wsa__EndpointReferenceType *wsa__From 0;
mustUnderstand struct wsa__EndpointReferenceType *wsa__ReplyTo 0;
mustUnderstand struct wsa__EndpointReferenceType *wsa__FaultTo 0;
mustUnderstand struct wsa__EndpointReferenceType *wsa__Recipient 0;
mustUnderstand wsa__AttributedURI wsa__To 0;
mustUnderstand wsa__AttributedURI wsa__Action 0;
};
... your declarations go here (request-response and one-way) ...
... for example:
int ns__echoString(char *str, char **res);
int ns__sendString(char *str, void);
int ns__sendStringResponse(char *res, void);
* Client-side one-way unicast/multicast:
struct soap soap;
struct SOAP_ENV__Header header;
soap_init(&soap);
if (multicast)
soap.connect_flags = SO_BROADCAST;
soap.send_timeout = 1; // 1s timeout
soap_default_SOAP_ENV__Header(&soap, &header);
soap.header = &header;
header.wsa__MessageID = "<message ID>";
header.wsa__To = "<server URL>";
header.wsa__Action = "<server action>";
if (soap_send_ns__echoString(&soap, "soap.udp://...", NULL, "hello world!"))
soap_print_fault(&soap, stderr);
soap_end(&soap); // cleanup
soap_destroy(&soap); // cleanup
soap_done(&soap); // close connection (should not use soap struct after this)
* Client-side request-response unicast:
struct soap soap;
struct SOAP_ENV__Header header;
struct wsa__EndpointReferenceType replyTo;
char *res;
soap_init(&soap);
soap.send_timeout = 1; // 1s timeout
soap.recv_timeout = 1; // 1s timeout
soap_default_SOAP_ENV__Header(&soap, &header);
soap.header = &header;
soap_default_wsa__EndpointReferenceType(&soap, &replyTo);
replyTo.Address = "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous";
header.wsa__MessageID = "<message ID>";
header.wsa__To = "<server URL>";
header.wsa__Action = "<server action>";
header.wsa__ReplyTo = &replyTo;
if (soap_call_ns__echoString(&soap, "soap.udp://...", NULL, "hello world!", &res))
{ if (soap.error == SOAP_EOF && soap.errnum == 0)
printf("Timeout: message probably already delivered\n");
else
soap_print_fault(&soap, stderr);
}
else
printf("UDP server response: %s\n", res);
soap_end(&soap); // cleanup
soap_destroy(&soap); // cleanup
soap_done(&soap); // close connection (should not use soap struct after this)
* Client-side request-response multicast:
struct soap soap;
struct SOAP_ENV__Header header;
struct wsa__EndpointReferenceType replyTo;
char *res;
soap_init(&soap);
soap.connect_flags = SO_BROADCAST;
soap.send_timeout = 1; // 1s timeout
soap.recv_timeout = 1; // 1s timeout
soap_default_SOAP_ENV__Header(&soap, &header);
soap.header = &header;
soap_default_wsa__EndpointReferenceType(&soap, &replyTo);
replyTo.Address = "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous";
header.wsa__MessageID = "<message ID>";
header.wsa__To = "<server URL>";
header.wsa__Action = "<server action>";
header.wsa__ReplyTo = &replyTo;
if (soap_send_ns__echoString(&soap, "soap.udp://...", NULL, "hello world!"))
soap_print_fault(&soap, stderr);
else
{ for (;;)
{ if (soap_recv_ns__sendStringResponse(&soap, &res))
break;
printf("Multicast response: %s\n", res);
}
if (soap.error == SOAP_EOF && soap.errnum == 0)
printf("Timeout: no more messages received\n");
else
soap_print_fault(&soap, stderr);
}
soap_end(&soap); // cleanup
soap_destroy(&soap); // cleanup
soap_done(&soap); // close connection (should not use soap struct after this)
* Server-side
struct soap soap;
soap_init1(&soap, SOAP_IO_UDP); // must set UDP flag
if (!soap_valid_socket(soap_bind(&soap, host, port, 100)))
{ soap_print_fault(&soap, stderr);
exit(1);
}
for (;;)
{ if (soap_serve(&soap))
soap_print_fault(&soap, stderr); // just report the problem
soap_destroy(&soap);
soap_end(&soap);
}
soap_done(&soap); // close connection
...
int ns__echoString(struct soap *soap, char *str, char **res)
{ if (!soap->header)
return soap_sender_fault(soap, "No SOAP header", NULL);
if (!soap->header->wsa__MessageID)
return soap_sender_fault(soap, "No WS-Addressing MessageID", NULL);
soap->header->wsa__RelatesTo = (struct wsa__Relationship*)soap_malloc(soap, sizeof(struct wsa__Relationship));
soap_default_wsa__Relationship(soap, soap->header->wsa__RelatesTo);
soap->header->wsa__RelatesTo->__item = soap->header->wsa__MessageID;
// must check for duplicate messages
if (check_received(soap->header->wsa__MessageID))
{ printf("Request message %s already received\n", soap->header->wsa__MessageID);
return SOAP_STOP; // don't return response
}
if (!soap->header->wsa__ReplyTo || !soap->header->wsa__ReplyTo->Address)
return soap_sender_fault(soap, "No WS-Addressing ReplyTo address", NULL);
soap->header->wsa__To = soap->header->wsa__ReplyTo->Address;
soap->header->wsa__MessageID = soap_strdup(soap, soap_int2s(soap,
id_count++)) ;
soap->header->wsa__Action = "http://genivia.com/udp/echoStringResponse";
*res = str;
return SOAP_OK;
}
...
int ns__sendString(struct soap *soap, char *str)
{ if (!soap->header)
return SOAP_STOP;
if (!soap->header->wsa__MessageID)
return SOAP_STOP;
// must check for duplicate messages
if (check_received(soap->header->wsa__MessageID))
return SOAP_STOP;
return SOAP_OK;
}
...
int ns__sendStringResponse(struct soap *soap, char *res)
{ return SOAP_NO_METHOD; } // we don't expect to serve this message
Built steps
-----------
Important: To build SOAP-over-UDP client and server applications, you MUST
compile all sources using the -DWITH_UDP compiler option.
A Makefile is included to build client and server applications.
To build the example client:
make udpclient
To build the example server:
make udpserver
To generate the wsa.h file:
wsdl2h -c -t ../../WS/WS-typemap.dat -o wsa.h http://schemas.xmlsoap.org/ws/2004/08/addressing
Then manually replace in WS-Addressing.h
//gsoapopt cw
with
//gsoapopt c
to ensure .wsdl and .xsd files are generated for your Web service
applications.
Example run
-----------
Start udpserver in a shell window (window 1):
$ ./udpserver
Execute udpclient in another shell window (window 2):
$ ./udpclient
Window 1 displays (server):
Accepting requests...
Request message id1 accepted
Response message 1 returned
Accepting requests...
One-way message id2 accepted and serviced
Accepting requests...
Window 2 displays (client):
UDP server response: hello world!
Re-execute the udpclient (window 2):
$ ./udpclient
Window 1 displays (server):
Request message id1 already received
SOAP FAULT: SOAP-ENV:Client
"Stopped: no response sent"
Accepting requests...
One-way message id2 already received
Accepting requests...
Window 2 displays (client):
Timeout: message probably already delivered