5
Example stand-alone gSOAP Web server based on the gSOAP HTTP GET plugin.
6
This is a small but fully functional (embedded) Web server for serving
7
static and dynamic pages and SOAP/XML responses.
9
--------------------------------------------------------------------------------
10
gSOAP XML Web services tools
11
Copyright (C) 2001-2004, Robert van Engelen, Genivia, Inc. All Rights Reserved.
12
This software is released under one of the following two licenses:
13
GPL or Genivia's license for commercial use.
14
--------------------------------------------------------------------------------
17
This program is free software; you can redistribute it and/or modify it under
18
the terms of the GNU General Public License as published by the Free Software
19
Foundation; either version 2 of the License, or (at your option) any later
22
This program is distributed in the hope that it will be useful, but WITHOUT ANY
23
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
24
PARTICULAR PURPOSE. See the GNU General Public License for more details.
26
You should have received a copy of the GNU General Public License along with
27
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
28
Place, Suite 330, Boston, MA 02111-1307 USA
30
Author contact information:
31
engelen@genivia.com / engelen@acm.org
32
--------------------------------------------------------------------------------
33
A commercial use license is available from Genivia, Inc., contact@genivia.com
34
--------------------------------------------------------------------------------
36
The Web server handles HTTP GET requests to serve pages and HTTP POST
37
reguests to handle SOAP/XML messages. This example only implements
38
a simple calculator XML Web service for demonstration purposes (the
39
service responds with SOAP/XML).
41
This application requires Zlib and Pthreads (you can replace Pthreads
42
with another thread library, but you need to study the OpenSSL thread
43
changes in the OpenSSL documentation).
45
On Unix/Linux, please enable SIGPIPE handling, see main function below.
46
SIGPIPE handling will avoid your server from termination when sockets
47
are disconnected by clients before the transaction was completed
50
Compile without OpenSSL:
51
soapcpp2 -c -n -popt opt.h
52
soapcpp2 -c webserver.h
53
Customize your COOKIE_DOMAIN in this file
54
gcc -DWITH_COOKIES -DWITH_ZLIB -o webserver webserver.c options.c plugin/httpget.c plugin/httpform.c plugin/logging.c stdsoap2.c soapC.c soapClient.c soapServer.c -lpthread -lz
57
soapcpp2 -c -n -popt opt.h
58
soapcpp2 -c webserver.h
59
Customize your COOKIE_DOMAIN in this file
60
gcc -DWITH_OPENSSL -DWITH_COOKIES -DWITH_ZLIB -o webserver webserver.c options.c plugin/httpget.c plugin/httpform.c plugin/logging.c stdsoap2.c soapC.c soapClient.c soapServer.c -lpthread -lz -lssl -lcrypto
63
Compile the web server as explained above
64
Start the web server on an even numbered port (e.g. 8080):
66
Start a web browser and open a (localhost) location:
68
and type userid 'admin' and passwd 'guest' to gain access
70
http://127.0.0.1:8080/calc.html
71
then enter an expression
73
http://127.0.0.1:8080/test.html
74
http://127.0.0.1:8081/webserver.wsdl
77
Create the SSL certificate
78
Compile the web server with OpenSSL as explained above
79
Start the web server on an odd numbered port (e.g. 8081)
81
Actually, you can start two servers, one on 8080 and a secure one on
83
Start a web browser and open a (localhost) location:
84
https://127.0.0.1:8081
85
and type userid 'admin' and passwd 'guest' to gain access
87
https://127.0.0.1:8081/calc.html
88
and enter an expression
90
https://127.0.0.1:8081/test.html
91
https://127.0.0.1:8081/webserver.wsdl
94
Serves SOAP/XML calculation requests
97
-z enables compression
100
-i enables non-threaded iterative server
101
-v enables verbose mode
102
-o<num> pool of <num> threads (cannot be used with option -i)
103
Note: interactive chunking/keep-alive settings cannot be
104
changed, unless the number of threads is interactively
105
changed to restart the pool
106
Note: <num>=0 specifies unlimited threads
107
-t<num> sets I/O timeout value (seconds)
108
-s<num> sets server timeout value (seconds)
109
-d<host> sets cookie domain
110
-p<path> sets cookie path
111
-l[none inbound outbound both]
114
Requires options.h and options.c for command line option parsing and
115
for parsing interactive Web page options settings. The
116
default_options[] array defines application options, short-hands,
117
selection lists, and default values. See options.h for more details.
121
#include "webserver.nsmap"
124
#include "httpform.h"
127
/* #include "httpda.h" */ /* enable HTTP Digest Authentication */
128
#include <signal.h> /* defines SIGPIPE */
130
#define BACKLOG (100)
132
#define AUTH_REALM "gSOAP Web Server Admin"
133
#define AUTH_USERID "admin" /* user ID to access admin pages */
134
#define AUTH_PASSWD "guest" /* user pw to access admin pages */
136
/******************************************************************************\
138
* Thread pool and request queue
140
\******************************************************************************/
142
#define MAX_THR (100)
143
#define MAX_QUEUE (1000)
145
static int poolsize = 0;
147
static int queue[MAX_QUEUE];
148
static int head = 0, tail = 0;
150
static MUTEX_TYPE queue_cs;
151
static COND_TYPE queue_cv;
153
/******************************************************************************\
157
\******************************************************************************/
159
static const struct option default_options[] =
160
{ { "z.compress", NULL, },
161
{ "c.chunking", NULL, },
162
{ "k.keepalive", NULL, },
163
{ "i.iterative", NULL, },
164
{ "v.verbose", NULL, },
165
{ "o.pool", "threads", 6, "none"},
166
{ "t.ioTimeout", "seconds", 6, "5"},
167
{ "s.serverTimeout", "seconds", 6, "3600"},
168
{ "d.cookieDomain", "host", 20, "localhost"},
169
{ "p.cookiePath", "path", 20, "/"},
170
{ "l.logging", "none inbound outbound both", },
171
{ "", "port", }, /* rest of command line args */
172
{ NULL }, /* must be NULL terminated */
175
/* The numbering of these defines must correspond to the option sequence */
187
#define OPTION_port 11
189
/******************************************************************************\
193
\******************************************************************************/
195
static struct option *options = NULL;
197
static int secure = 0; /* =0: no SSL, =1: support SSL */
199
static const char *minutes[60] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
200
static const char *hours[24] = {"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23"};
202
/******************************************************************************\
206
\******************************************************************************/
208
void server_loop(struct soap*);
209
void *process_request(void*); /* multi-threaded request handler */
210
void *process_queue(void*); /* multi-threaded request handler for pool */
211
int enqueue(SOAP_SOCKET);
212
SOAP_SOCKET dequeue();
213
int http_get_handler(struct soap*); /* HTTP get handler */
214
int http_form_handler(struct soap*); /* HTTP form handler */
215
int check_authentication(struct soap*); /* HTTP authentication check */
216
int copy_file(struct soap*, const char*, const char*); /* copy file as HTTP response */
217
int calcget(struct soap*);
218
int calcpost(struct soap*);
219
int info(struct soap*);
220
int html_hbar(struct soap*, const char*, size_t, size_t, unsigned long);
221
int html_hist(struct soap*, const char*, size_t, size_t, size_t, const char**, size_t*, size_t);
222
void sigpipe_handle(int); /* SIGPIPE handler: Unix/Linux only */
224
/******************************************************************************\
228
\******************************************************************************/
230
int CRYPTO_thread_setup();
231
void CRYPTO_thread_cleanup();
233
/******************************************************************************\
237
\******************************************************************************/
239
int main(int argc, char **argv)
247
options = copy_options(default_options); /* must copy, so option values can be modified */
248
if (parse_options(argc, argv, options))
251
if (options[OPTION_port].value)
252
port = atol(options[OPTION_port].value);
255
fprintf(stderr, "Starting Web server on port %d\n", port);
256
/* if the port is an odd number, the Web server uses HTTPS only */
260
fprintf(stderr, "[Note: use https://localhost:%d/test.html to test the server from browser]\n", port);
262
fprintf(stderr, "[Note: use http://localhost:%d/test.html to test the server from browser]\n", port);
263
fprintf(stderr, "[Note: you should enable Linux/Unix SIGPIPE handlers to avoid broken pipe]\n");
265
soap_init2(&soap, SOAP_IO_KEEPALIVE, SOAP_IO_DEFAULT);
268
if (CRYPTO_thread_setup())
270
fprintf(stderr, "Cannot setup thread mutex\n");
273
/* SSL (to enable: compile all sources with -DWITH_OPENSSL) */
274
if (secure && soap_ssl_server_context(&soap,
276
"server.pem", /* keyfile: see SSL docs on how to obtain this file */
277
"password", /* password to read the key file */
280
"dh512.pem", /* DH file, if NULL use RSA */
281
NULL, /* if randfile!=NULL: use a file with random data to seed randomness */
282
"webserver" /* server identification for SSL session cache (must be a unique name) */
285
soap_print_fault(&soap, stderr);
289
/* Register HTTP GET plugin */
290
if (soap_register_plugin_arg(&soap, http_get, (void*)http_get_handler))
291
soap_print_fault(&soap, stderr);
292
/* Register HTTP POST plugin */
293
if (soap_register_plugin_arg(&soap, http_form, (void*)http_form_handler))
294
soap_print_fault(&soap, stderr);
295
/* Register logging plugin */
296
if (soap_register_plugin(&soap, logging))
297
soap_print_fault(&soap, stderr);
299
/* Register HTTP Digest Authentication plugin */
300
if (soap_register_plugin(&soap, http_da))
301
soap_print_fault(&soap, stderr);
303
/* Unix SIGPIPE, this is OS dependent (win does not need this) */
304
/* soap.accept_flags = SO_NOSIGPIPE; */ /* some systems like this */
305
/* soap.socket_flags = MSG_NOSIGNAL; */ /* others need this */
306
/* signal(SIGPIPE, sigpipe_handle); */ /* and some older Unix systems may require a sigpipe handler */
307
master = soap_bind(&soap, NULL, port, BACKLOG);
308
if (!soap_valid_socket(master))
310
soap_print_fault(&soap, stderr);
313
fprintf(stderr, "Port bind successful: master socket = %d\n", master);
314
MUTEX_SETUP(queue_cs);
315
COND_SETUP(queue_cv);
317
MUTEX_CLEANUP(queue_cs);
318
COND_CLEANUP(queue_cv);
319
free_options(options);
323
CRYPTO_thread_cleanup();
329
void server_loop(struct soap *soap)
331
struct soap *soap_thr[MAX_THR];
332
THREAD_TYPE tid, tids[MAX_THR];
334
struct logging_data *logdata;
336
logdata = (struct logging_data*)soap_lookup_plugin(soap, logging_id); /* need to access plugin's data */
338
for (req = 1; ; req++)
343
soap->cookie_domain = options[OPTION_d].value;
344
soap->cookie_path = options[OPTION_p].value;
345
soap_set_cookie(soap, "visit", "true", NULL, NULL);
346
soap_set_cookie_expire(soap, "visit", 600, NULL, NULL);
348
if (options[OPTION_c].selected)
349
soap_set_omode(soap, SOAP_IO_CHUNK); /* use chunked HTTP content (fast) */
350
if (options[OPTION_k].selected)
351
soap_set_omode(soap, SOAP_IO_KEEPALIVE);
352
if (options[OPTION_t].value)
353
soap->send_timeout = soap->recv_timeout = atol(options[OPTION_t].value);
354
if (options[OPTION_s].value)
355
soap->accept_timeout = atol(options[OPTION_s].value);
356
if (options[OPTION_l].selected == 1 || options[OPTION_l].selected == 3)
357
logdata->inbound = stdout;
359
logdata->inbound = NULL;
360
if (options[OPTION_l].selected == 2 || options[OPTION_l].selected == 3)
361
logdata->outbound = stdout;
363
logdata->outbound = NULL;
365
newpoolsize = atol(options[OPTION_o].value);
369
else if (newpoolsize > MAX_THR)
370
newpoolsize = MAX_THR;
372
if (poolsize > newpoolsize)
376
for (job = 0; job < poolsize; job++)
378
while (enqueue(SOAP_INVALID_SOCKET) == SOAP_EOM)
382
for (job = 0; job < poolsize; job++)
384
fprintf(stderr, "Waiting for thread %d to terminate...\n", job);
385
THREAD_JOIN(tids[job]);
386
fprintf(stderr, "Thread %d has stopped\n", job);
387
soap_done(soap_thr[job]);
394
if (poolsize < newpoolsize)
398
for (job = poolsize; job < newpoolsize; job++)
400
soap_thr[job] = soap_copy(soap);
404
soap_thr[job]->user = (void*)job;
406
fprintf(stderr, "Starting thread %d\n", job);
407
THREAD_CREATE(&tids[job], (void*(*)(void*))process_queue, (void*)soap_thr[job]);
413
sock = soap_accept(soap);
414
if (!soap_valid_socket(sock))
418
soap_print_fault(soap, stderr);
419
fprintf(stderr, "Retry...\n");
422
fprintf(stderr, "gSOAP Web server timed out\n");
426
if (options[OPTION_v].selected)
427
fprintf(stderr, "Request #%d accepted on socket %d connected from IP %d.%d.%d.%d\n", req, sock, (int)(soap->ip>>24)&0xFF, (int)(soap->ip>>16)&0xFF, (int)(soap->ip>>8)&0xFF, (int)soap->ip&0xFF);
431
while (enqueue(sock) == SOAP_EOM)
436
struct soap *tsoap = NULL;
438
if (!options[OPTION_i].selected)
439
tsoap = soap_copy(soap);
444
if (secure && soap_ssl_accept(tsoap))
446
soap_print_fault(tsoap, stderr);
447
fprintf(stderr, "SSL request failed, continue with next call...\n");
454
tsoap->user = (void*)req;
455
THREAD_CREATE(&tid, (void*(*)(void*))process_request, (void*)tsoap);
460
if (secure && soap_ssl_accept(soap))
462
soap_print_fault(soap, stderr);
463
fprintf(stderr, "SSL request failed, continue with next call...\n");
468
if (soap_serve(soap))
470
fprintf(stderr, "Request #%d completed with failure %d\n", req, soap->error);
471
soap_print_fault(soap, stderr);
475
if (options[OPTION_v].selected)
476
fprintf(stderr, "Request #%d completed\n", req);
485
for (job = 0; job < poolsize; job++)
487
while (enqueue(SOAP_INVALID_SOCKET) == SOAP_EOM)
491
for (job = 0; job < poolsize; job++)
493
fprintf(stderr, "Waiting for thread %d to terminate... ", job);
494
THREAD_JOIN(tids[job]);
495
fprintf(stderr, "terminated\n");
496
soap_done(soap_thr[job]);
502
/******************************************************************************\
506
\******************************************************************************/
508
void *process_request(void *soap)
510
struct soap *tsoap = (struct soap*)soap;
512
THREAD_DETACH(THREAD_ID);
514
if (soap_serve(tsoap))
516
fprintf(stderr, "Thread %d completed with failure %d\n", (int)tsoap->user, tsoap->error);
517
soap_print_fault(tsoap, stderr);
519
else if (options[OPTION_v].selected)
520
fprintf(stderr, "Thread %d completed\n", (int)tsoap->user);
521
/* soap_destroy((struct soap*)soap); */ /* cleanup class instances (but this is a C app) */
530
/******************************************************************************\
532
* Thread pool (enabled with option -o<num>)
534
\******************************************************************************/
536
void *process_queue(void *soap)
538
struct soap *tsoap = (struct soap*)soap;
542
tsoap->socket = dequeue();
543
if (!soap_valid_socket(tsoap->socket))
544
{ if (options[OPTION_v].selected)
545
fprintf(stderr, "Thread %d terminating\n", (int)tsoap->user);
550
if (secure && soap_ssl_accept(tsoap))
552
soap_print_fault(tsoap, stderr);
553
fprintf(stderr, "SSL request failed, continue with next call...\n");
560
if (options[OPTION_v].selected)
561
fprintf(stderr, "Thread %d accepted a request\n", (int)tsoap->user);
562
if (soap_serve(tsoap))
564
fprintf(stderr, "Thread %d finished serving request with failure %d\n", (int)tsoap->user, tsoap->error);
565
soap_print_fault(tsoap, stderr);
567
else if (options[OPTION_v].selected)
568
fprintf(stderr, "Thread %d finished serving request\n", (int)tsoap->user);
577
int enqueue(SOAP_SOCKET sock)
579
int status = SOAP_OK;
583
if ((ret = MUTEX_LOCK(queue_cs)))
584
fprintf(stderr, "MUTEX_LOCK error %d\n", ret);
586
next = (tail + 1) % MAX_QUEUE;
589
/* don't block on full queue, return SOAP_EOM */
597
if (options[OPTION_v].selected)
598
fprintf(stderr, "enqueue(%d)\n", sock);
600
if ((ret = COND_SIGNAL(queue_cv)))
601
fprintf(stderr, "COND_SIGNAL error %d\n", ret);
604
if ((ret = MUTEX_UNLOCK(queue_cs)))
605
fprintf(stderr, "MUTEX_UNLOCK error %d\n", ret);
610
SOAP_SOCKET dequeue()
615
if ((ret = MUTEX_LOCK(queue_cs)))
616
fprintf(stderr, "MUTEX_LOCK error %d\n", ret);
619
if ((ret = COND_WAIT(queue_cv, queue_cs)))
620
fprintf(stderr, "COND_WAIT error %d\n", ret);
624
head = (head + 1) % MAX_QUEUE;
626
if (options[OPTION_v].selected)
627
fprintf(stderr, "dequeue(%d)\n", sock);
629
if ((ret = MUTEX_UNLOCK(queue_cs)))
630
fprintf(stderr, "MUTEX_UNLOCK error %d\n", ret);
635
/******************************************************************************\
637
* SOAP/XML handling: calculator example
639
\******************************************************************************/
641
int ns__add(struct soap *soap, double a, double b, double *c)
647
int ns__sub(struct soap *soap, double a, double b, double *c)
653
int ns__mul(struct soap *soap, double a, double b, double *c)
659
int ns__div(struct soap *soap, double a, double b, double *c)
665
/******************************************************************************\
667
* Server dummy methods to avoid link errors
669
\******************************************************************************/
671
int ns__addResponse_(struct soap *soap, double a)
673
return SOAP_NO_METHOD; /* we don't use this: we use soap_send_ns__addResponse instead */
676
int ns__subResponse_(struct soap *soap, double a)
678
return SOAP_NO_METHOD; /* we don't use this: we use soap_send_ns__subResponse instead */
681
int ns__mulResponse_(struct soap *soap, double a)
683
return SOAP_NO_METHOD; /* we don't use this: we use soap_send_ns__mulResponse instead */
686
int ns__divResponse_(struct soap *soap, double a)
688
return SOAP_NO_METHOD; /* we don't use this: we use soap_send_ns__divResponse instead */
691
/******************************************************************************\
693
* HTTP GET handler for plugin
695
\******************************************************************************/
697
int http_get_handler(struct soap *soap)
699
/* gSOAP >=2.5 soap_response() will do this automatically for us, when sending SOAP_HTML or SOAP_FILE:
700
if ((soap->omode & SOAP_IO) != SOAP_IO_CHUNK)
701
soap_set_omode(soap, SOAP_IO_STORE); */ /* if not chunking we MUST buffer entire content when returning HTML pages to determine content length */
703
if (options[OPTION_z].selected && soap->zlib_out == SOAP_ZLIB_GZIP) /* client accepts gzip */
704
{ soap_set_omode(soap, SOAP_ENC_ZLIB); /* so we can compress content (gzip) */
705
soap->z_level = 9; /* best compression */
708
soap_clr_omode(soap, SOAP_ENC_ZLIB); /* so we can compress content (gzip) */
710
/* Use soap->path (from request URL) to determine request: */
711
if (options[OPTION_v].selected)
712
fprintf(stderr, "HTTP GET Request: %s\n", soap->endpoint);
713
/* Note: soap->path always starts with '/' */
714
if (strchr(soap->path + 1, '/') || strchr(soap->path + 1, '\\')) /* we don't like snooping in dirs */
715
return 403; /* HTTP forbidden */
716
if (!soap_tag_cmp(soap->path, "*.html"))
717
return copy_file(soap, soap->path + 1, "text/html");
718
if (!soap_tag_cmp(soap->path, "*.xml")
719
|| !soap_tag_cmp(soap->path, "*.xsd")
720
|| !soap_tag_cmp(soap->path, "*.wsdl"))
721
return copy_file(soap, soap->path + 1, "text/xml");
722
if (!soap_tag_cmp(soap->path, "*.jpg"))
723
return copy_file(soap, soap->path + 1, "image/jpeg");
724
if (!soap_tag_cmp(soap->path, "*.gif"))
725
return copy_file(soap, soap->path + 1, "image/gif");
726
if (!soap_tag_cmp(soap->path, "*.png"))
727
return copy_file(soap, soap->path + 1, "image/png");
728
if (!soap_tag_cmp(soap->path, "*.ico"))
729
return copy_file(soap, soap->path + 1, "image/ico");
730
if (!strncmp(soap->path, "/calc?", 6))
731
return calcget(soap);
732
if (!strncmp(soap->path, "/genivia", 8))
733
{ strcpy(soap->endpoint, "http://genivia.com"); /* redirect */
734
strcat(soap->endpoint, soap->path + 8);
735
return 307; /* Temporary Redirect */
737
/* Check requestor's authentication: */
738
if (check_authentication(soap))
739
return 401; /* HTTP not authorized */
740
/* Return Web server status */
741
if (soap->path[1] == '\0' || soap->path[1] == '?')
743
return 404; /* HTTP not found */
746
int check_authentication(struct soap *soap)
747
{ if (soap->userid && soap->passwd)
748
{ if (!strcmp(soap->userid, AUTH_USERID) && !strcmp(soap->passwd, AUTH_PASSWD))
752
else if (soap->authrealm && soap->userid)
753
{ if (!strcmp(soap->authrealm, AUTH_REALM) && !strcmp(soap->userid, AUTH_USERID))
754
if (!http_da_verify_get(soap, AUTH_PASSWD))
758
soap->authrealm = AUTH_REALM;
762
/******************************************************************************\
764
* HTTP POST application/x-www-form-urlencoded handler for plugin
766
\******************************************************************************/
768
int http_form_handler(struct soap *soap)
771
if (options[OPTION_z].selected && soap->zlib_out == SOAP_ZLIB_GZIP) /* client accepts gzip */
772
soap_set_omode(soap, SOAP_ENC_ZLIB); /* so we can compress content (gzip) */
773
soap->z_level = 9; /* best compression */
775
/* Use soap->path (from request URL) to determine request: */
776
if (options[OPTION_v].selected)
777
fprintf(stderr, "HTTP POST Request: %s\n", soap->endpoint);
778
/* Note: soap->path always starts with '/' */
779
if (!strcmp(soap->path, "/calc"))
780
return calcpost(soap);
781
return 404; /* HTTP not found */
784
/******************************************************************************\
788
\******************************************************************************/
790
int copy_file(struct soap *soap, const char *name, const char *type)
793
fd = fopen(name, "rb"); /* open file to copy */
795
return 404; /* return HTTP not found */
796
soap->http_content = type;
797
if (soap_response(soap, SOAP_FILE)) /* OK HTTP response header */
798
{ soap_end_send(soap);
803
{ r = fread(soap->tmpbuf, 1, sizeof(soap->tmpbuf), fd);
806
if (soap_send_raw(soap, soap->tmpbuf, r))
807
{ soap_end_send(soap);
813
return soap_end_send(soap);
816
/******************************************************************************\
818
* Example dynamic HTTP GET application/x-www-form-urlencoded calculator
820
\******************************************************************************/
822
int calcget(struct soap *soap)
823
{ int o = 0, a = 0, b = 0, val;
825
char *s = query(soap); /* get argument string from URL ?query string */
827
{ char *key = query_key(soap, &s); /* decode next query string key */
828
char *val = query_val(soap, &s); /* decode next query string value (if any) */
830
{ if (!strcmp(key, "o"))
832
else if (!strcmp(key, "a"))
833
a = strtol(val, NULL, 10);
834
else if (!strcmp(key, "b"))
835
b = strtol(val, NULL, 10);
852
return soap_sender_fault(soap, "Unknown operation", NULL);
854
soap_response(soap, SOAP_HTML);
855
sprintf(buf, "<html>value=%d</html>", val);
856
soap_send(soap, buf);
861
/******************************************************************************\
863
* Example dynamic HTTP POST application/x-www-form-urlencoded calculator
865
\******************************************************************************/
867
int calcpost(struct soap *soap)
868
{ int o = 0, a = 0, b = 0, val;
870
char *s = form(soap); /* get form data from body */
872
{ char *key = query_key(soap, &s); /* decode next key */
873
char *val = query_val(soap, &s); /* decode next value (if any) */
875
{ if (!strcmp(key, "o"))
877
else if (!strcmp(key, "a"))
878
a = strtol(val, NULL, 10);
879
else if (!strcmp(key, "b"))
880
b = strtol(val, NULL, 10);
897
return soap_sender_fault(soap, "Unknown operation", NULL);
899
soap_response(soap, SOAP_HTML);
900
sprintf(buf, "<html>value=%d</html>", val);
901
soap_send(soap, buf);
906
/******************************************************************************\
908
* Example dynamic HTTP POST multipart/form-data form-based calculator
910
\******************************************************************************/
912
int f__form1(struct soap *soap)
913
{ int o = 0, a = 0, b = 0, val;
915
struct soap_multipart *content;
916
for (content = soap->mime.list; content; content = content->next)
917
{ if (content->id && content->ptr)
918
{ /* may have to check content->encoding to convert data when necessary! */
919
if (!strcmp(content->id, "o"))
921
else if (!strcmp(content->id, "a"))
922
a = strtol(content->ptr, NULL, 10);
923
else if (!strcmp(content->id, "b"))
924
b = strtol(content->ptr, NULL, 10);
941
return soap_sender_fault(soap, "Unknown operation", NULL);
943
soap_response(soap, SOAP_HTML);
944
sprintf(buf, "<html>value=%d</html>", val);
945
soap_send(soap, buf);
950
int f__form2(struct soap *soap, struct f__formResponse *response)
951
{ int o = 0, a = 0, b = 0;
952
struct soap_multipart *content;
953
for (content = soap->mime.list; content; content = content->next)
954
{ if (content->id && content->ptr)
955
{ /* may have to check content->encoding to convert data when necessary! */
956
if (!strcmp(content->id, "o"))
958
else if (!strcmp(content->id, "a"))
959
a = strtol(content->ptr, NULL, 10);
960
else if (!strcmp(content->id, "b"))
961
b = strtol(content->ptr, NULL, 10);
966
response->result = a + b;
969
response->result = a - b;
972
response->result = a * b;
975
response->result = a / b;
978
return soap_sender_fault(soap, "Unknown operation", NULL);
983
/******************************************************************************\
985
* Dynamic Web server info page
987
\******************************************************************************/
989
int info(struct soap *soap)
990
{ struct http_get_data *getdata;
991
struct logging_data *logdata;
992
const char *t0, *t1, *t2, *t3, *t4, *t5, *t6, *t7;
993
char buf[2048]; /* buffer large enough to hold HTML content */
994
struct soap_plugin *p;
995
time_t now = time(NULL), elapsed = now - start;
996
query_options(soap, options);
997
if (soap->omode & SOAP_IO_KEEPALIVE)
998
t0 = "<td align='center' bgcolor='green'>YES</td>";
1000
t0 = "<td align='center' bgcolor='red'>NO</td>";
1002
t1 = "<td align='center' bgcolor='green'>YES</td>";
1003
/* soap_env_cookie_value() returns value of a cookie received (from client) */
1004
if (soap_env_cookie_value(soap, "visit", NULL, NULL))
1005
t2 = "<td align='center' bgcolor='green'>PASS</td>";
1007
t2 = "<td align='center' bgcolor='yellow'>WAIT</td>";
1009
t1 = "<td align='center' bgcolor='red'>NO</td>";
1010
t2 = "<td align='center' bgcolor='blue'>N/A</td>";
1013
{ t3 = "<td align='center' bgcolor='green'>YES</td>";
1014
if (soap->imode & SOAP_ENC_SSL)
1015
t4 = "<td align='center' bgcolor='green'>PASS</td>";
1017
t4 = "<td align='center' bgcolor='red'><blink>FAIL</blink></td>";
1020
{ t3 = "<td align='center' bgcolor='red'>NO</td>";
1021
t4 = "<td align='center' bgcolor='blue'>N/A</td>";
1024
if (options[OPTION_z].selected)
1025
{ t5 = "<td align='center' bgcolor='green'>YES</td>";
1026
if (soap->omode & SOAP_ENC_ZLIB)
1027
t6 = "<td align='center' bgcolor='green'>PASS</td>";
1029
t6 = "<td align='center' bgcolor='yellow'>WAIT</td>";
1032
{ t5 = "<td align='center' bgcolor='red'>NO</td>";
1033
t6 = "<td align='center' bgcolor='blue'>N/A</td>";
1036
t5 = "<td align='center' bgcolor='red'>NO</td>";
1037
t6 = "<td align='center' bgcolor='blue'>N/A</td>";
1039
if (options[OPTION_c].selected || (soap->omode & SOAP_IO) == SOAP_IO_CHUNK)
1040
t7 = "<td align='center' bgcolor='green'>YES</td>";
1042
t7 = "<td align='center' bgcolor='red'>NO</td>";
1043
if (soap_response(soap, SOAP_HTML))
1048
<meta name='Author' content='Robert A. van Engelen'>\
1049
<meta name='Generator' content='gSOAP'>\
1050
<meta http-equiv='Refresh' content='60'>\
1051
<style type='text/css' media='screen'><!-- table { background-color: #666 } td { color: white; font-size: 10px; line-height: 10px; font-family: Arial, Helvetica, Geneva, Swiss, SunSans-Regular } --></style>\
1052
<title>gSOAP Web Server Administration</title>\
1054
<body bgcolor='#FFFFFF'>\
1055
<h1>gSOAP Web Server Administration</h1>\
1056
<p>Server endpoint=%s client agent IP=%d.%d.%d.%d\
1057
<h2>Registered Plugins</h2>\
1058
", soap->endpoint, (int)(soap->ip>>24)&0xFF, (int)(soap->ip>>16)&0xFF, (int)(soap->ip>>8)&0xFF, (int)soap->ip&0xFF);
1059
if (soap_send(soap, buf))
1061
for (p = soap->plugins; p; p = p->next)
1062
{ sprintf(buf, "%s<br>", p->id);
1063
if (soap_send(soap, buf))
1066
if (soap_send(soap, "<h2>Elapsed Time</h2>"))
1068
if (elapsed >= 86400)
1069
html_hbar(soap, "Days:", 100, elapsed/86400, 0x000000);
1070
if (elapsed >= 3600)
1071
html_hbar(soap, "Hours:", 100, elapsed/3600%24, 0x000000);
1072
html_hbar(soap, "Minutes:", 100, elapsed/60%60, 0x000000);
1073
soap_send(soap, "<h2>Control Panel</h2>");
1074
if (html_form_options(soap, options))
1077
<h2>Function Tests</h2>\
1078
<table border='0' cellspacing='0' cellpadding='0' bgcolor='#666666' nosave>\
1079
<tr height='10'><td height='10' background='bl.gif'></td><td height='10'><i>Function</i></td><td align='center' height='10'><i>Result</i></td><td height='10' background='obls.gif'></td></tr>\
1080
<tr><td background='bl.gif'></td><td>HTTP operational</td><td align='center' bgcolor='green'>YES</td><td width='10' background='ls.gif'></td></tr>\
1081
<tr><td background='bl.gif'></td><td>HTTP keep alive enabled</td>%s<td width='10' background='ls.gif'></td></tr>\
1082
<tr><td background='bl.gif'></td><td>HTTP cookies enabled</td>%s<td width='10' background='ls.gif'></td></tr>\
1083
<tr><td background='bl.gif'></td><td>HTTP cookies test</td>%s<td width='10' background='ls.gif'></td></tr>\
1084
<tr><td background='bl.gif'></td><td>HTTPS (OpenSSL) enabled</td>%s<td width='10' background='ls.gif'></td></tr>\
1085
<tr><td background='bl.gif'></td><td>HTTPS (OpenSSL) test</td>%s<td width='10' background='ls.gif'></td></tr>\
1086
<tr><td background='bl.gif'></td><td>HTTP compression enabled</td>%s<td width='10' background='ls.gif'></td></tr>\
1087
<tr><td background='bl.gif'></td><td>HTTP compression test</td>%s<td width='10' background='ls.gif'></td></tr>\
1088
<tr><td background='bl.gif'></td><td>HTTP chunking enabled</td>%s<td width='10' background='ls.gif'></td></tr>\
1089
<tr height='10'><td width='10' height='10' background=otrs.gif></td><td height='10' background='ts.gif'></td><td height='10' background='ts.gif'></td><td width='10' height='10' background='otls.gif'></td></tr>\
1090
</table>", t0, t1, t2, t3, t4, t5, t6, t7);
1091
if (soap_send(soap, buf))
1093
getdata = (struct http_get_data*)soap_lookup_plugin(soap, http_get_id);
1094
logdata = (struct logging_data*)soap_lookup_plugin(soap, logging_id);
1095
soap_send(soap, "<h2>Usage Statistics</h2>");
1097
{ html_hbar(soap, "HTTP GET", 120, getdata->stat_get, 0x0000FF);
1098
html_hbar(soap, "HTTP POST", 120, getdata->stat_post, 0x00FF00);
1099
html_hbar(soap, "HTTP FAIL", 120, getdata->stat_fail, 0xFF0000);
1102
{ html_hbar(soap, "SENT(kB)", 120, logdata->stat_sent/1024, 0x00FFFF);
1103
html_hbar(soap, "RECV(kB)", 120, logdata->stat_recv/1024, 0x00FFFF);
1105
{ html_hbar(soap, "SENT(kB/s)", 120, logdata->stat_sent/elapsed/1024, 0x00FFFF);
1106
html_hbar(soap, "RECV(kB/s)", 120, logdata->stat_recv/elapsed/1024, 0x00FFFF);
1114
#ifdef HAVE_LOCALTIME_R
1115
localtime_r(&now, &T);
1117
T = *localtime(&now);
1119
soap_send(soap, "<h2>Requests by the Minute</h2>");
1120
html_hist(soap, "Minute", 12, 0, 60, minutes, getdata->min, T.tm_min);
1121
soap_send(soap, "<h2>Requests by the Hour</h2>");
1122
html_hist(soap, "Hour", 30, 0, 24, hours, getdata->hour, T.tm_hour);
1123
soap_send(soap, "<h2>Requests by Day of the Year</h2>");
1124
html_hist(soap, "Day", 2, 0, 365, NULL, getdata->day, T.tm_yday);
1127
<p>This page will automatically reload every minute to refresh the statistics.\
1128
<br><br><br><img src='favicon.gif' align='absmiddle'>Powered by gSOAP\
1131
return soap_end_send(soap);
1134
static size_t html_scaled(char *buf, size_t len)
1135
{ if (len > 1000000)
1136
{ sprintf(buf, "%.2f·10<sup>6</sup>", (float)len/1000000.0);
1137
return len / 1000000;
1140
{ sprintf(buf, "%.2f·10<sup>3</sup>", (float)len/1000.0);
1143
sprintf(buf, "%lu", (unsigned long)len);
1147
int html_hbar(struct soap *soap, const char *title, size_t pix, size_t len, unsigned long color)
1148
{ char buf[2048]; /* buffer large enough to hold HTML content */
1150
len = html_scaled(lab, len);
1152
<table border='0' cellspacing='0' cellpadding='0' height='30'>\
1154
<td width='10' height='10' background='bl.gif'></td>\
1155
<td rowspan='2' bgcolor='#666666' width='%lu' height='20'>%s %s</td>\
1156
<td bgcolor='#%.6lx' width='%lu' height='10'></td>\
1157
<td width='10' height='10' background='obls.gif'></td>\
1160
<td width='10' height='10' background='bl.gif'></td>\
1161
<td height='10' background='ruler.gif'></td>\
1162
<td width='10' height='10' background='ls.gif'></td>\
1165
<td width='10' height='10' background='otrs.gif'></td>\
1166
<td colspan='2' height='10' background='ts.gif'></td>\
1167
<td width='10' height='10' background='otls.gif'></td>\
1169
</table>", (unsigned long)pix, title ? title : "", lab, color, (unsigned long)len * 2);
1170
return soap_send(soap, buf);
1173
int html_hist(struct soap *soap, const char *title, size_t barwidth, size_t height, size_t num, const char **key, size_t *val, size_t highlight)
1174
{ char buf[2048]; /* buffer large enough to hold HTML content */
1179
for (i = 0; i < num; i++)
1187
else if (height > 256)
1190
scale = (float)height / (float)max;
1191
html_scaled(lab, max);
1194
<table bgcolor='#FFFFFF' border='0' cellspacing='0' cellpadding='0' height='%lu' align='center'>\
1196
<td width='10' height='10' background='btl.gif'></td><td colspan='%lu' height='10' background='bt.gif'></td><td width='10' height='10' background='btr.gif'></td><td width='10' height='10' background='obls.gif'></td>\
1198
<tr height='%lu' align='center' valign='bottom'>\
1199
<td width='10' height='%lu' background='bl.gif'></td>\
1200
<td bgcolor='#666666' valign='top'>%s</td>", title ? title : "", (unsigned long)height + 50, (unsigned long)num + 1, (unsigned long)height, (unsigned long)height, lab);
1201
if (soap_send(soap, buf))
1203
for (i = 0; i < num; i++)
1204
{ unsigned long bar = (scale * val[i] + 0.5);
1207
<td bgcolor='#FFFFFF'><a onmouseover=\"window.status='%lu';return true\" onmouseout=\"window.status='';return true\" href='#%s'><img src='top.gif' alt='' width='%lu' height='1' align='bottom' border='0'><br><img src='bar.gif' alt='' width='%lu' height='%lu' align='bottom' border='0'></a></td>", (unsigned long)i, title ? title : "", (unsigned long)barwidth, (unsigned long)barwidth, bar - 1);
1210
<td bgcolor='#FFFFFF'><img src='bar.gif' alt='' width='%lu' height='0' align='bottom' border='0'></td>", (unsigned long)barwidth);
1211
if (soap_send(soap, buf))
1215
<td width='10' height='%lu' background='br.gif'></td>\
1216
<td width='10' height='%lu' background='ls.gif'></td>\
1218
<tr bgcolor='#666666' height='20' align='center'>\
1219
<td width='10' height='20' background='bl.gif'></td>\
1220
<td bgcolor='#666666'>%s</td>", (unsigned long)height, (unsigned long)height, title ? title : "");
1221
if (soap_send(soap, buf))
1223
for (i = 0; i < num; i++)
1224
{ sprintf(buf, "<td%s>%s</td>", (i == highlight) ? " bgcolor='#777777'" : "", key ? key[i] : "<img src='bar.gif'>");
1225
if (soap_send(soap, buf))
1228
if (soap_send(soap, "\
1229
<td width='10' height='20' background='br.gif'></td>\
1230
<td width='10' height='20' background='ls.gif'></td>"))
1235
<td width='10' height='10' background='bbl.gif'></td><td colspan='%lu' height='10' background='bb.gif'></td><td width='10' height='10' background='bbr.gif'></td><td width='10' height='10' background='ls.gif'></td>\
1238
<td width='10' height='10' background='otrs.gif'></td>\
1239
<td colspan='%lu' height='10' background='ts.gif'></td>\
1240
<td width='10' height='10' background='otls.gif'></td>\
1242
</table>", (unsigned long)num + 1, (unsigned long)num + 2);
1243
return soap_send(soap, buf);
1246
/******************************************************************************\
1250
\******************************************************************************/
1254
struct CRYPTO_dynlock_value
1258
static MUTEX_TYPE *mutex_buf;
1260
static struct CRYPTO_dynlock_value *dyn_create_function(const char *file, int line)
1261
{ struct CRYPTO_dynlock_value *value;
1262
value = (struct CRYPTO_dynlock_value*)malloc(sizeof(struct CRYPTO_dynlock_value));
1264
MUTEX_SETUP(value->mutex);
1268
static void dyn_lock_function(int mode, struct CRYPTO_dynlock_value *l, const char *file, int line)
1269
{ if (mode & CRYPTO_LOCK)
1270
MUTEX_LOCK(l->mutex);
1272
MUTEX_UNLOCK(l->mutex);
1275
static void dyn_destroy_function(struct CRYPTO_dynlock_value *l, const char *file, int line)
1276
{ MUTEX_CLEANUP(l->mutex);
1280
void locking_function(int mode, int n, const char *file, int line)
1281
{ if (mode & CRYPTO_LOCK)
1282
MUTEX_LOCK(mutex_buf[n]);
1284
MUTEX_UNLOCK(mutex_buf[n]);
1287
unsigned long id_function()
1288
{ return (unsigned long)THREAD_ID;
1291
int CRYPTO_thread_setup()
1293
mutex_buf = (MUTEX_TYPE*)malloc(CRYPTO_num_locks() * sizeof(MUTEX_TYPE));
1296
for (i = 0; i < CRYPTO_num_locks(); i++)
1297
MUTEX_SETUP(mutex_buf[i]);
1298
CRYPTO_set_id_callback(id_function);
1299
CRYPTO_set_locking_callback(locking_function);
1300
CRYPTO_set_dynlock_create_callback(dyn_create_function);
1301
CRYPTO_set_dynlock_lock_callback(dyn_lock_function);
1302
CRYPTO_set_dynlock_destroy_callback(dyn_destroy_function);
1306
void CRYPTO_thread_cleanup()
1310
CRYPTO_set_id_callback(NULL);
1311
CRYPTO_set_locking_callback(NULL);
1312
CRYPTO_set_dynlock_create_callback(NULL);
1313
CRYPTO_set_dynlock_lock_callback(NULL);
1314
CRYPTO_set_dynlock_destroy_callback(NULL);
1315
for (i = 0; i < CRYPTO_num_locks(); i++)
1316
MUTEX_CLEANUP(mutex_buf[i]);
1323
/******************************************************************************\
1327
\******************************************************************************/
1329
void sigpipe_handle(int x) { }