/* handler.cpp Multi-threaded C++ stand-alone event handler service Events are based on one-way SOAP messaging using HTTP keep-alive for persistent connections The 'synchronous' global flag illustrates SOAP one-way messaging, which requires an HTTP OK response with an empty body to be returned by the server. Compile: soapcpp2 -i event.h cc -o handler++ handler.cpp stdsoap2.cpp soapC.cpp soapEventService.cpp soapEventProxy.cpp Run: handler 18000 & Server will time out after 24hr of inactivity This code enables keep-alive support which can cause "broken pipes" when the client prematurely closes the connection while indicating it wants the connection to stay alive. Broken pipes (SIGPIPE) can be fixed using MSG_NOSIGNAL, SO_NOSIGPIPE, or with a signal handler, but this is not very portable (see code below) -------------------------------------------------------------------------------- gSOAP XML Web services tools Copyright (C) 2001-2008, Robert van Engelen, Genivia, Inc. All Rights Reserved. This software is released under one of the following two licenses: GPL or Genivia's license for commercial use. -------------------------------------------------------------------------------- GPL license. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Author contact information: engelen@genivia.com / engelen@acm.org -------------------------------------------------------------------------------- A commercial use license is available from Genivia, Inc., contact@genivia.com -------------------------------------------------------------------------------- */ #include "soapEventService.h" #include "soapEventProxy.h" #include "Event.nsmap" #include #ifdef _POSIX_THREADS #include // use Pthreads #endif #define BACKLOG (100) #define TIMEOUT (24*60*60) /* timeout after 24hrs of inactivity */ void *process_request(void*); int synchronous = 1; /* synchronous=0: asynchronous one-way messaging over HTTP (no HTTP response) */ /* synchronous=1: SOAP interoperable synchronous one-way messaging over HTTP */ int main(int argc, char **argv) { if (argc < 2) { fprintf(stderr, "Usage: handler \n"); exit(1); } int port = atoi(argv[1]); /* server with keep I/O alive and timeout settings */ EventService handler(SOAP_IO_KEEPALIVE, SOAP_IO_KEEPALIVE | SOAP_XML_INDENT); handler.accept_timeout = TIMEOUT; handler.bind_flags |= SO_REUSEADDR; /* don't use this in unsecured environments */ /* handler.socket_flags = MSG_NOSIGNAL; */ /* use this to disable SIGPIPE */ /* handler.bind_flags |= SO_NOSIGPIPE; */ /* or use this to disable SIGPIPE */ SOAP_SOCKET m = handler.bind(NULL, port, BACKLOG); if (!soap_valid_socket(m)) { handler.soap_print_fault(stderr); exit(1); } fprintf(stderr, "Socket connection successful %d\n", m); for (int i = 1; ; i++) { SOAP_SOCKET s = handler.accept(); if (!soap_valid_socket(s)) { if (handler.errnum) handler.soap_print_fault(stderr); else fprintf(stderr, "%s timed out\n", argv[0]); /* should really wait for threads to terminate, but 24hr timeout should be enough ... */ break; } fprintf(stderr, "Thread %d accepts socket %d connection from IP %d.%d.%d.%d\n", i, s, (int)(handler.ip>>24)&0xFF, (int)(handler.ip>>16)&0xFF, (int)(handler.ip>>8)&0xFF, (int)handler.ip&0xFF); EventService *thandler = handler.copy(); #ifdef _POSIX_THREADS pthread_t tid; pthread_create(&tid, NULL, (void*(*)(void*))process_request, (void*)thandler); #else process_request((void*)thandler); #endif } return 0; } void *process_request(void *thandler) { EventService *handler = (EventService *)thandler; #ifdef _POSIX_THREADS pthread_detach(pthread_self()); #endif handler->serve(); delete handler; return NULL; } int EventService::handle(enum ns__event event) { switch (event) { /* each event is just consumed without server response */ case EVENT_A: fprintf(stderr, "Server Received Event: A\n"); break; case EVENT_B: fprintf(stderr, "Server Received Event: B\n"); break; case EVENT_C: fprintf(stderr, "Server Received Event: C\n"); break; /* after receiving event Z, we echo events A to C back to the client */ case EVENT_Z: fprintf(stderr, "Server Received Event: Z\n"); { /* create a proxy with a copy of the server state */ EventProxy proxy(*this); /* send message over HTTP on current socket */ proxy.soap_endpoint = "http://"; /* these multiple sends assume that the client enabled keep-alive */ fprintf(stderr, "Server Sends Event: A\n"); proxy.send_handle(EVENT_A); fprintf(stderr, "Server Sends Event: B\n"); proxy.send_handle(EVENT_B); fprintf(stderr, "Server Sends Event: C\n"); proxy.send_handle(EVENT_C); } } if (event != EVENT_Z && synchronous) return send_handle_empty_response(SOAP_OK); return SOAP_OK; }