
C++-style eventing client and event handler server.

Events are one-way SOAP messages using HTTP keep-alive for persistent
connections.

This example illustrates one-way message exchange patterns (MEP) between a
client and server, each with C and C++ implementations.

samples/event:
event.c         C-based client
handler.c       C-based multithreaded server (uses Pthreads)

samples/event++:
event.cpp       C++-based client
handler.cpp     C++-based server (uses Pthreads)

For HTTP communications events are not truly one-way, since HTTP Accept or OK
responses are expected to be returned to the client. Thus, this is a form of
synchronous communication with rendezvous.

The code also supports true one-way messaging, by setting the global flag
synchronous = 0. Note that all send operations may or may not block. Receive
operations always block.

All four files are built with the web service definitions given in the gSOAP
header file event.h. The event.h file is processed with soapcpp2 as follows:

Compilation in C:
    soapcpp2 -c event.h
    cc -o event event.c stdsoap2.c soapC.c soapClient.c
    cc -o handler handler.c stdsoap2.c soapC.c soapServer.c

Compilation in C++:
    soapcpp2 -i event.h
    cc -o event++ event.cpp stdsoap2.cpp soapC.cpp soapEventProxy.cpp
    cc -o handler++ handler.cpp stdsoap2.cpp soapC.cpp soapEventService.cpp soap
EventProxy.cpp

The C client-side uses:

  Initialization of the runtime engine:
    soap_init(struct soap*)
    soap_init2(struct soap*, soap_mode input_modes, soap_mode output_modes)
  Sending an event to the handler, this function is generated by soapcpp2:
    soap_send_ns__handle(struct soap*, const char *endpoint, const char *action,
                         enum ns__event event)
    Note: pass endpoint=NULL and action=NULL for defaults
  To accept an HTTP Accept or OK message (ack):
    soap_recv_empty_response(struct soap*)
  Receiving an event from the handler, this function is generated by soapcpp2:
    soap_recv_ns__handle(struct soap*, struct ns__handle*)
  Set and reset HTTP keep-alive connections (optional):
    soap_set_omode(soap, SOAP_IO_KEEPALIVE)
    soap_clr_omode(soap, SOAP_IO_KEEPALIVE)
  Close the socket (to end a keep-alive session)
    soap_closesocket(struct soap*)
  Print communication errors:
    soap_print_fault(struct soap*, FILE*)
  Allocate data, which stays alive until deallocated by soap_end()
    soap_malloc(struct soap*, size_t len)
  Delete deserialized data:
    soap_end(struct soap*)
  Finalize and detach the runtime engine:
    soap_done(struct soap*)

The multi-threaded C server-side uses:

  Initialization of the runtime engine:
    soap_init(struct soap*)
    soap_init2(struct soap*, soap_mode input_modes, soap_mode output_modes)
  Binding the port:
    soap_bind(struct soap*, const char *host, int port, int backlog)
  Accepting a request:
    soap_accept(struct soap*);
  Invoking the service dispatcher, this function is generated by soapcpp2:
    soap_serve(struct soap*)
  Print communication errors:
    soap_print_fault(struct soap*, FILE*)
  Allocate data, which stays alive until deallocated by soap_end()
    soap_malloc(struct soap*, size_t len)
  Delete deserialized data:
    soap_end(struct soap*)
  Send back sender-related fault:
    soap_sender_fault(struct soap*, const char *string, const char *detailXML)
  Send back receiver-related fault:
    soap_receiver_fault(struct soap*, const char *string, const char *detailXML)
  Make a copy of the current runtime engine:
    soap_copy(struct soap*)
  Finalize and detach the runtime engine:
    soap_done(struct soap*)
  Finalize, detach, and delete the runtime engine:
    soap_free(struct soap*)
  Service operation is not auto-generated (user-defined):
    ns__handle(struct soap*, enum ns__event *event);
  Sending an event to the client, this function is generated by soapcpp2:
    soap_send_ns__handle(struct soap*, const char *endpoint, const char *action,
                         enum ns__event event)
    where we use endpoint = "http://" to send message over current socket

The C++ client-side uses a proxy generated with soapcpp2 -i: class EventProxy

  Constructor
    EventProxy(soap_mode input_output_modes)
  The default endpoint can be changed:
    const char *EventProxxy::endpoint
  Invoke a call of xyz:
    EventProxy::xyz(double a, double b, double *result)
  Print communication errors:
    EventProxy::soap_stream_fault(std::ostream&)
  Error code (see list of error codes in documentation and stdsoap2.h):
    EventProxy::error
  Allocate data, deallocated by soap_end() or EventService destructor
    soap_malloc(EventService*, size_t len)
  Get new instance of class X, deallocated by soap_destroy() or EventService destructor
    soap_new_X(EventService*, -1)
  Get array of new instances of class X, deallocated by soap_destroy() or EventService destructor
    soap_new_X(EventService*, arraylen)
  Delete deserialized C++ class instances (also part of EventService destructor):
    soap_destroy(EventService*)
  Delete deserialized data (also part of EventService destructor):
    soap_end(EventService*)

The C++ server-side uses the server and proxy classes generated with soapcpp2
option -i. A proxy instance is needed for the one-way send operation.

  Create a serivce copy for new thread
    EventService::copy()
  Bind port
    EventService::bind(const char *host, int port, int backlog)
  Accept and set socket
    EventService::accept()
  Serve requests over current socket
    EventService::serve()
  Print communication errors:
    EventService::soap_stream_fault(std::ostream&)
  Error code (see list of error codes in documentation and stdsoap2.h):
    EventService::error
  Send back sender-related fault:
    EventService::soap_senderfault(const char *string, const char *detailXML)
  Send back sender-related fault with subcode (SOAP 1.2):
    EventService::soap_senderfault(const char *subcodeQName, const char *string, const char *detailXML)
  Send back receiver-related fault:
    EventService::soap_receiverfault(const char *string, const char *detailXML)
  Send back receiver-related fault with subcode (SOAP 1.2):
    EventService::soap_receiverfault(const char *subcodeQName, const char *string, const char *detailXML)
  Service operations are user-defined (not auto-generated):
    EventService::handle(enum ns__event *event)
  Allocate data, deallocated by soap_end() or EventService destructor
    soap_malloc(EventService*, size_t len)
  Get new instance of class X, deallocated by soap_destroy() or EventService destructor
    soap_new_X(EventService*, -1)
  Get array of new instances of class X, deallocated by soap_destroy() or EventService destructor
    soap_new_X(EventService*, arraylen)
  Delete deserialized C++ class instances (also part of EventService destructor):
    soap_destroy(EventService*)
  Delete deserialized data (also part of EventService destructor):
    soap_end(EventService*)

Note: all soap_xyz(struct soap*, ...) gSOAP API functions are also available
to the EventProxy and EventService classes by inheritance of the struct soap
runtime engine state object.
