| /* |
| |
| webserver.c |
| |
| Example stand-alone gSOAP Web server based on the gSOAP HTTP GET plugin. |
| This is a small but fully functional (embedded) Web server for serving |
| static and dynamic pages and SOAP/XML responses. |
| |
| -------------------------------------------------------------------------------- |
| gSOAP XML Web services tools |
| Copyright (C) 2001-2004, 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 |
| -------------------------------------------------------------------------------- |
| |
| The Web server handles HTTP GET requests to serve pages and HTTP POST |
| reguests to handle SOAP/XML messages. This example only implements |
| a simple calculator XML Web service for demonstration purposes (the |
| service responds with SOAP/XML). |
| |
| This application requires Zlib and Pthreads (you can replace Pthreads |
| with another thread library, but you need to study the OpenSSL thread |
| changes in the OpenSSL documentation). |
| |
| On Unix/Linux, please enable SIGPIPE handling, see main function below. |
| SIGPIPE handling will avoid your server from termination when sockets |
| are disconnected by clients before the transaction was completed |
| (aka broken pipe). |
| |
| Compile without OpenSSL: |
| soapcpp2 -c -n -popt opt.h |
| soapcpp2 -c webserver.h |
| Customize your COOKIE_DOMAIN in this file |
| 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 |
| |
| Compile with OpenSSL: |
| soapcpp2 -c -n -popt opt.h |
| soapcpp2 -c webserver.h |
| Customize your COOKIE_DOMAIN in this file |
| 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 |
| |
| Use (HTTP GET): |
| Compile the web server as explained above |
| Start the web server on an even numbered port (e.g. 8080): |
| > webserver 8080 & |
| Start a web browser and open a (localhost) location: |
| http://127.0.0.1:8080 |
| and type userid 'admin' and passwd 'guest' to gain access |
| Open the location: |
| http://127.0.0.1:8080/calc.html |
| then enter an expression |
| Open the locations: |
| http://127.0.0.1:8080/test.html |
| http://127.0.0.1:8081/webserver.wsdl |
| |
| Use (HTTPS GET): |
| Create the SSL certificate |
| Compile the web server with OpenSSL as explained above |
| Start the web server on an odd numbered port (e.g. 8081) |
| > webserver 8081 & |
| Actually, you can start two servers, one on 8080 and a secure one on |
| 8081 |
| Start a web browser and open a (localhost) location: |
| https://127.0.0.1:8081 |
| and type userid 'admin' and passwd 'guest' to gain access |
| Open the location: |
| https://127.0.0.1:8081/calc.html |
| and enter an expression |
| Open the locations: |
| https://127.0.0.1:8081/test.html |
| https://127.0.0.1:8081/webserver.wsdl |
| |
| Use (HTTP POST): |
| Serves SOAP/XML calculation requests |
| |
| Command-line options: |
| -z enables compression |
| -c enables chunking |
| -k enables keep-alive |
| -i enables non-threaded iterative server |
| -v enables verbose mode |
| -o<num> pool of <num> threads (cannot be used with option -i) |
| Note: interactive chunking/keep-alive settings cannot be |
| changed, unless the number of threads is interactively |
| changed to restart the pool |
| Note: <num>=0 specifies unlimited threads |
| -t<num> sets I/O timeout value (seconds) |
| -s<num> sets server timeout value (seconds) |
| -d<host> sets cookie domain |
| -p<path> sets cookie path |
| -l[none inbound outbound both] |
| enables logging |
| |
| Requires options.h and options.c for command line option parsing and |
| for parsing interactive Web page options settings. The |
| default_options[] array defines application options, short-hands, |
| selection lists, and default values. See options.h for more details. |
| */ |
| |
| #include "soapH.h" |
| #include "webserver.nsmap" |
| #include "options.h" |
| #include "httpget.h" |
| #include "httpform.h" |
| #include "logging.h" |
| #include "threads.h" |
| /* #include "httpda.h" */ /* enable HTTP Digest Authentication */ |
| #include <signal.h> /* defines SIGPIPE */ |
| |
| #define BACKLOG (100) |
| |
| #define AUTH_REALM "gSOAP Web Server Admin" |
| #define AUTH_USERID "admin" /* user ID to access admin pages */ |
| #define AUTH_PASSWD "guest" /* user pw to access admin pages */ |
| |
| /******************************************************************************\ |
| * |
| * Thread pool and request queue |
| * |
| \******************************************************************************/ |
| |
| #define MAX_THR (100) |
| #define MAX_QUEUE (1000) |
| |
| static int poolsize = 0; |
| |
| static int queue[MAX_QUEUE]; |
| static int head = 0, tail = 0; |
| |
| static MUTEX_TYPE queue_cs; |
| static COND_TYPE queue_cv; |
| |
| /******************************************************************************\ |
| * |
| * Program options |
| * |
| \******************************************************************************/ |
| |
| static const struct option default_options[] = |
| { { "z.compress", NULL, }, |
| { "c.chunking", NULL, }, |
| { "k.keepalive", NULL, }, |
| { "i.iterative", NULL, }, |
| { "v.verbose", NULL, }, |
| { "o.pool", "threads", 6, "none"}, |
| { "t.ioTimeout", "seconds", 6, "120"}, |
| { "s.serverTimeout", "seconds", 6, "3600"}, |
| { "d.cookieDomain", "host", 20, "localhost:8080"}, |
| { "p.cookiePath", "path", 20, "/"}, |
| { "l.logging", "none inbound outbound both", }, |
| { "", "port", }, /* rest of command line args */ |
| { NULL }, /* must be NULL terminated */ |
| }; |
| |
| /* The numbering of these defines must correspond to the option sequence */ |
| #define OPTION_z 0 |
| #define OPTION_c 1 |
| #define OPTION_k 2 |
| #define OPTION_i 3 |
| #define OPTION_v 4 |
| #define OPTION_o 5 |
| #define OPTION_t 6 |
| #define OPTION_s 7 |
| #define OPTION_d 8 |
| #define OPTION_p 9 |
| #define OPTION_l 10 |
| #define OPTION_port 11 |
| |
| /******************************************************************************\ |
| * |
| * Static |
| * |
| \******************************************************************************/ |
| |
| static struct option *options = NULL; |
| static time_t start; |
| static int secure = 0; /* =0: no SSL, =1: support SSL */ |
| |
| 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" }; |
| 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"}; |
| |
| /******************************************************************************\ |
| * |
| * Forward decls |
| * |
| \******************************************************************************/ |
| |
| void server_loop(struct soap*); |
| void *process_request(void*); /* multi-threaded request handler */ |
| void *process_queue(void*); /* multi-threaded request handler for pool */ |
| int enqueue(SOAP_SOCKET); |
| SOAP_SOCKET dequeue(); |
| int http_get_handler(struct soap*); /* HTTP get handler */ |
| int http_form_handler(struct soap*); /* HTTP form handler */ |
| int check_authentication(struct soap*); /* HTTP authentication check */ |
| int copy_file(struct soap*, const char*, const char*); /* copy file as HTTP response */ |
| int calcget(struct soap*); |
| int calcpost(struct soap*); |
| int info(struct soap*); |
| int html_hbar(struct soap*, const char*, size_t, size_t, unsigned long); |
| int html_hist(struct soap*, const char*, size_t, size_t, size_t, const char**, size_t*, size_t); |
| void sigpipe_handle(int); /* SIGPIPE handler: Unix/Linux only */ |
| |
| /******************************************************************************\ |
| * |
| * OpenSSL |
| * |
| \******************************************************************************/ |
| |
| int CRYPTO_thread_setup(); |
| void CRYPTO_thread_cleanup(); |
| |
| /******************************************************************************\ |
| * |
| * Main |
| * |
| \******************************************************************************/ |
| |
| int main(int argc, char **argv) |
| { |
| struct soap soap; |
| SOAP_SOCKET master; |
| int port = 0; |
| |
| start = time(NULL); |
| |
| options = copy_options(default_options); /* must copy, so option values can be modified */ |
| if (parse_options(argc, argv, options)) |
| exit(0); |
| |
| if (options[OPTION_port].value) |
| port = atol(options[OPTION_port].value); |
| if (!port) |
| port = 8080; |
| fprintf(stderr, "Starting Web server on port %d\n", port); |
| if (port != 8080) |
| fprintf(stderr, "[Note: use port 8080 to test server from browser with test.html and calc.html]\n"); |
| fprintf(stderr, "[Note: you must enable Linux/Unix SIGPIPE handler to avoid broken pipe]\n"); |
| |
| soap_init2(&soap, SOAP_IO_KEEPALIVE, SOAP_IO_DEFAULT); |
| |
| /* SSL init (to enable: compile all sources with -DWITH_OPENSSL) */ |
| soap_ssl_init(); |
| #ifdef WITH_OPENSSL |
| if (CRYPTO_thread_setup()) |
| { |
| fprintf(stderr, "Cannot setup thread mutex\n"); |
| exit(1); |
| } |
| /* if the port is an odd number, the Web server uses HTTPS only */ |
| if (port % 2) |
| secure = 1; |
| if (secure && soap_ssl_server_context(&soap, |
| SOAP_SSL_DEFAULT, |
| "server.pem", /* keyfile: see SSL docs on how to obtain this file */ |
| "password", /* password to read the key file */ |
| NULL, /* cacert */ |
| NULL, /* capath */ |
| "dh512.pem", /* DH file, if NULL use RSA */ |
| NULL, /* if randfile!=NULL: use a file with random data to seed randomness */ |
| "webserver" /* server identification for SSL session cache (must be a unique name) */ |
| )) |
| { |
| soap_print_fault(&soap, stderr); |
| exit(1); |
| } |
| #endif |
| /* Register HTTP GET plugin */ |
| if (soap_register_plugin_arg(&soap, http_get, (void*)http_get_handler)) |
| soap_print_fault(&soap, stderr); |
| /* Register HTTP POST plugin */ |
| if (soap_register_plugin_arg(&soap, http_form, (void*)http_form_handler)) |
| soap_print_fault(&soap, stderr); |
| /* Register logging plugin */ |
| if (soap_register_plugin(&soap, logging)) |
| soap_print_fault(&soap, stderr); |
| #ifdef HTTPDA_H |
| /* Register HTTP Digest Authentication plugin */ |
| if (soap_register_plugin(&soap, http_da)) |
| soap_print_fault(&soap, stderr); |
| #endif |
| /* Unix SIGPIPE, this is OS dependent (win does not need this) */ |
| /* soap.accept_flags = SO_NOSIGPIPE; */ /* some systems like this */ |
| /* soap.socket_flags = MSG_NOSIGNAL; */ /* others need this */ |
| /* signal(SIGPIPE, sigpipe_handle); */ /* and some older Unix systems may require a sigpipe handler */ |
| master = soap_bind(&soap, NULL, port, BACKLOG); |
| if (!soap_valid_socket(master)) |
| { |
| soap_print_fault(&soap, stderr); |
| exit(1); |
| } |
| fprintf(stderr, "Port bind successful: master socket = %d\n", master); |
| MUTEX_SETUP(queue_cs); |
| COND_SETUP(queue_cv); |
| server_loop(&soap); |
| MUTEX_CLEANUP(queue_cs); |
| COND_CLEANUP(queue_cv); |
| #ifdef WITH_OPENSSL |
| CRYPTO_thread_cleanup(); |
| #endif |
| free_options(options); |
| soap_end(&soap); |
| soap_done(&soap); |
| THREAD_EXIT; |
| return 0; |
| } |
| |
| void server_loop(struct soap *soap) |
| { |
| struct soap *soap_thr[MAX_THR]; |
| THREAD_TYPE tid, tids[MAX_THR]; |
| int req; |
| struct logging_data *logdata; |
| |
| logdata = (struct logging_data*)soap_lookup_plugin(soap, logging_id); /* need to access plugin's data */ |
| |
| for (req = 1; ; req++) |
| { |
| SOAP_SOCKET sock; |
| int newpoolsize; |
| |
| soap->cookie_domain = options[OPTION_d].value; |
| soap->cookie_path = options[OPTION_p].value; |
| soap_set_cookie(soap, "visit", "true", NULL, NULL); |
| soap_set_cookie_expire(soap, "visit", 600, NULL, NULL); |
| |
| if (options[OPTION_c].selected) |
| soap_set_omode(soap, SOAP_IO_CHUNK); /* use chunked HTTP content (fast) */ |
| if (options[OPTION_k].selected) |
| soap_set_omode(soap, SOAP_IO_KEEPALIVE); |
| if (options[OPTION_t].value) |
| soap->send_timeout = soap->recv_timeout = atol(options[OPTION_t].value); |
| if (options[OPTION_s].value) |
| soap->accept_timeout = atol(options[OPTION_s].value); |
| if (options[OPTION_l].selected == 1 || options[OPTION_l].selected == 3) |
| logdata->inbound = stdout; |
| else |
| logdata->inbound = NULL; |
| if (options[OPTION_l].selected == 2 || options[OPTION_l].selected == 3) |
| logdata->outbound = stdout; |
| else |
| logdata->outbound = NULL; |
| |
| newpoolsize = atol(options[OPTION_o].value); |
| |
| if (newpoolsize < 0) |
| newpoolsize = 0; |
| else if (newpoolsize > MAX_THR) |
| newpoolsize = MAX_THR; |
| |
| if (poolsize > newpoolsize) |
| { |
| int job; |
| |
| for (job = 0; job < poolsize; job++) |
| { |
| while (enqueue(SOAP_INVALID_SOCKET) == SOAP_EOM) |
| sleep(1); |
| } |
| |
| for (job = 0; job < poolsize; job++) |
| { |
| fprintf(stderr, "Waiting for thread %d to terminate...\n", job); |
| THREAD_JOIN(tids[job]); |
| fprintf(stderr, "Thread %d has stopped\n", job); |
| soap_done(soap_thr[job]); |
| free(soap_thr[job]); |
| } |
| |
| poolsize = 0; |
| } |
| |
| if (poolsize < newpoolsize) |
| { |
| int job; |
| |
| for (job = poolsize; job < newpoolsize; job++) |
| { |
| soap_thr[job] = soap_copy(soap); |
| if (!soap_thr[job]) |
| break; |
| |
| soap_thr[job]->user = (void*)job; |
| |
| fprintf(stderr, "Starting thread %d\n", job); |
| THREAD_CREATE(&tids[job], (void*(*)(void*))process_queue, (void*)soap_thr[job]); |
| } |
| |
| poolsize = job; |
| } |
| |
| sock = soap_accept(soap); |
| if (!soap_valid_socket(sock)) |
| { |
| if (soap->errnum) |
| { |
| soap_print_fault(soap, stderr); |
| fprintf(stderr, "Retry...\n"); |
| continue; |
| } |
| fprintf(stderr, "gSOAP Web server timed out\n"); |
| break; |
| } |
| |
| if (options[OPTION_v].selected) |
| 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); |
| |
| if (poolsize > 0) |
| { |
| while (enqueue(sock) == SOAP_EOM) |
| sleep(1); |
| } |
| else |
| { |
| struct soap *tsoap = NULL; |
| |
| if (!options[OPTION_i].selected) |
| tsoap = soap_copy(soap); |
| |
| if (tsoap) |
| { |
| #ifdef WITH_OPENSSL |
| if (secure && soap_ssl_accept(tsoap)) |
| { |
| soap_print_fault(tsoap, stderr); |
| fprintf(stderr, "SSL request failed, continue with next call...\n"); |
| soap_end(tsoap); |
| soap_done(tsoap); |
| free(tsoap); |
| continue; |
| } |
| #endif |
| tsoap->user = (void*)req; |
| THREAD_CREATE(&tid, (void*(*)(void*))process_request, (void*)tsoap); |
| } |
| else |
| { |
| #ifdef WITH_OPENSSL |
| if (secure && soap_ssl_accept(soap)) |
| { |
| soap_print_fault(soap, stderr); |
| fprintf(stderr, "SSL request failed, continue with next call...\n"); |
| soap_end(soap); |
| continue; |
| } |
| #endif |
| if (soap_serve(soap)) |
| { |
| fprintf(stderr, "Request #%d completed with failure %d\n", req, soap->error); |
| soap_print_fault(soap, stderr); |
| } |
| |
| soap_end(soap); |
| if (options[OPTION_v].selected) |
| fprintf(stderr, "Request #%d completed\n", req); |
| } |
| } |
| } |
| |
| if (poolsize > 0) |
| { |
| int job; |
| |
| for (job = 0; job < poolsize; job++) |
| { |
| while (enqueue(SOAP_INVALID_SOCKET) == SOAP_EOM) |
| sleep(1); |
| } |
| |
| for (job = 0; job < poolsize; job++) |
| { |
| fprintf(stderr, "Waiting for thread %d to terminate... ", job); |
| THREAD_JOIN(tids[job]); |
| fprintf(stderr, "terminated\n"); |
| soap_done(soap_thr[job]); |
| free(soap_thr[job]); |
| } |
| } |
| } |
| |
| /******************************************************************************\ |
| * |
| * Process dispatcher |
| * |
| \******************************************************************************/ |
| |
| void *process_request(void *soap) |
| { |
| struct soap *tsoap = (struct soap*)soap; |
| |
| THREAD_DETACH(THREAD_ID); |
| |
| if (soap_serve(tsoap)) |
| { |
| fprintf(stderr, "Thread %d completed with failure %d\n", (int)tsoap->user, tsoap->error); |
| soap_print_fault(tsoap, stderr); |
| } |
| else if (options[OPTION_v].selected) |
| fprintf(stderr, "Thread %d completed\n", (int)tsoap->user); |
| /* soap_destroy((struct soap*)soap); */ /* cleanup class instances (but this is a C app) */ |
| |
| soap_end(tsoap); |
| soap_done(tsoap); |
| free(soap); |
| |
| return NULL; |
| } |
| |
| /******************************************************************************\ |
| * |
| * Thread pool (enabled with option -o<num>) |
| * |
| \******************************************************************************/ |
| |
| void *process_queue(void *soap) |
| { |
| struct soap *tsoap = (struct soap*)soap; |
| |
| for (;;) |
| { |
| tsoap->socket = dequeue(); |
| if (!soap_valid_socket(tsoap->socket)) |
| { if (options[OPTION_v].selected) |
| fprintf(stderr, "Thread %d terminating\n", (int)tsoap->user); |
| break; |
| } |
| |
| #ifdef WITH_OPENSSL |
| if (secure && soap_ssl_accept(tsoap)) |
| { |
| soap_print_fault(tsoap, stderr); |
| fprintf(stderr, "SSL request failed, continue with next call...\n"); |
| soap_end(tsoap); |
| soap_done(tsoap); |
| continue; |
| } |
| #endif |
| |
| if (options[OPTION_v].selected) |
| fprintf(stderr, "Thread %d accepted a request\n", (int)tsoap->user); |
| if (soap_serve(tsoap)) |
| { |
| fprintf(stderr, "Thread %d finished serving request with failure %d\n", (int)tsoap->user, tsoap->error); |
| soap_print_fault(tsoap, stderr); |
| } |
| else if (options[OPTION_v].selected) |
| fprintf(stderr, "Thread %d finished serving request\n", (int)tsoap->user); |
| |
| soap_destroy(tsoap); |
| soap_end(tsoap); |
| } |
| |
| return NULL; |
| } |
| |
| int enqueue(SOAP_SOCKET sock) |
| { |
| int status = SOAP_OK; |
| int next; |
| int ret; |
| |
| if ((ret = MUTEX_LOCK(queue_cs))) |
| fprintf(stderr, "MUTEX_LOCK error %d\n", ret); |
| |
| next = (tail + 1) % MAX_QUEUE; |
| if (head == next) |
| { |
| /* don't block on full queue, return SOAP_EOM */ |
| status = SOAP_EOM; |
| } |
| else |
| { |
| queue[tail] = sock; |
| tail = next; |
| |
| if (options[OPTION_v].selected) |
| fprintf(stderr, "enqueue(%d)\n", sock); |
| |
| if ((ret = COND_SIGNAL(queue_cv))) |
| fprintf(stderr, "COND_SIGNAL error %d\n", ret); |
| } |
| |
| if ((ret = MUTEX_UNLOCK(queue_cs))) |
| fprintf(stderr, "MUTEX_UNLOCK error %d\n", ret); |
| |
| return status; |
| } |
| |
| SOAP_SOCKET dequeue() |
| { |
| SOAP_SOCKET sock; |
| int ret; |
| |
| if ((ret = MUTEX_LOCK(queue_cs))) |
| fprintf(stderr, "MUTEX_LOCK error %d\n", ret); |
| |
| while (head == tail) |
| if ((ret = COND_WAIT(queue_cv, queue_cs))) |
| fprintf(stderr, "COND_WAIT error %d\n", ret); |
| |
| sock = queue[head]; |
| |
| head = (head + 1) % MAX_QUEUE; |
| |
| if (options[OPTION_v].selected) |
| fprintf(stderr, "dequeue(%d)\n", sock); |
| |
| if ((ret = MUTEX_UNLOCK(queue_cs))) |
| fprintf(stderr, "MUTEX_UNLOCK error %d\n", ret); |
| |
| return sock; |
| } |
| |
| /******************************************************************************\ |
| * |
| * SOAP/XML handling: calculator example |
| * |
| \******************************************************************************/ |
| |
| int ns__add(struct soap *soap, double a, double b, double *c) |
| { |
| *c = a + b; |
| return SOAP_OK; |
| } |
| |
| int ns__sub(struct soap *soap, double a, double b, double *c) |
| { |
| *c = a - b; |
| return SOAP_OK; |
| } |
| |
| int ns__mul(struct soap *soap, double a, double b, double *c) |
| { |
| *c = a * b; |
| return SOAP_OK; |
| } |
| |
| int ns__div(struct soap *soap, double a, double b, double *c) |
| { |
| *c = a / b; |
| return SOAP_OK; |
| } |
| |
| /******************************************************************************\ |
| * |
| * Server dummy methods to avoid link errors |
| * |
| \******************************************************************************/ |
| |
| int ns__addResponse_(struct soap *soap, double a) |
| { |
| return SOAP_NO_METHOD; /* we don't use this: we use soap_send_ns__addResponse instead */ |
| } |
| |
| int ns__subResponse_(struct soap *soap, double a) |
| { |
| return SOAP_NO_METHOD; /* we don't use this: we use soap_send_ns__subResponse instead */ |
| } |
| |
| int ns__mulResponse_(struct soap *soap, double a) |
| { |
| return SOAP_NO_METHOD; /* we don't use this: we use soap_send_ns__mulResponse instead */ |
| } |
| |
| int ns__divResponse_(struct soap *soap, double a) |
| { |
| return SOAP_NO_METHOD; /* we don't use this: we use soap_send_ns__divResponse instead */ |
| } |
| |
| /******************************************************************************\ |
| * |
| * HTTP GET handler for plugin |
| * |
| \******************************************************************************/ |
| |
| int http_get_handler(struct soap *soap) |
| { |
| /* gSOAP >=2.5 soap_response() will do this automatically for us, when sending SOAP_HTML or SOAP_FILE: |
| if ((soap->omode & SOAP_IO) != SOAP_IO_CHUNK) |
| soap_set_omode(soap, SOAP_IO_STORE); */ /* if not chunking we MUST buffer entire content when returning HTML pages to determine content length */ |
| #ifdef WITH_ZLIB |
| if (options[OPTION_z].selected && soap->zlib_out == SOAP_ZLIB_GZIP) /* client accepts gzip */ |
| soap_set_omode(soap, SOAP_ENC_ZLIB); /* so we can compress content (gzip) */ |
| soap->z_level = 9; /* best compression */ |
| #endif |
| /* Use soap->path (from request URL) to determine request: */ |
| if (options[OPTION_v].selected) |
| fprintf(stderr, "HTTP GET Request: %s\n", soap->endpoint); |
| /* Note: soap->path always starts with '/' */ |
| if (strchr(soap->path + 1, '/') || strchr(soap->path + 1, '\\')) /* we don't like snooping in dirs */ |
| return 403; /* HTTP forbidden */ |
| if (!soap_tag_cmp(soap->path, "*.html")) |
| return copy_file(soap, soap->path + 1, "text/html"); |
| if (!soap_tag_cmp(soap->path, "*.xml") |
| || !soap_tag_cmp(soap->path, "*.xsd") |
| || !soap_tag_cmp(soap->path, "*.wsdl")) |
| return copy_file(soap, soap->path + 1, "text/xml"); |
| if (!soap_tag_cmp(soap->path, "*.jpg")) |
| return copy_file(soap, soap->path + 1, "image/jpeg"); |
| if (!soap_tag_cmp(soap->path, "*.gif")) |
| return copy_file(soap, soap->path + 1, "image/gif"); |
| if (!soap_tag_cmp(soap->path, "*.png")) |
| return copy_file(soap, soap->path + 1, "image/png"); |
| if (!soap_tag_cmp(soap->path, "*.ico")) |
| return copy_file(soap, soap->path + 1, "image/ico"); |
| if (!strncmp(soap->path, "/calc?", 6)) |
| return calcget(soap); |
| if (!strncmp(soap->path, "/genivia", 8)) |
| { strcpy(soap->endpoint, "http://genivia.com"); /* redirect */ |
| strcat(soap->endpoint, soap->path + 8); |
| return 307; /* Temporary Redirect */ |
| } |
| /* Check requestor's authentication: */ |
| if (check_authentication(soap)) |
| return 401; /* HTTP not authorized */ |
| /* Return Web server status */ |
| if (soap->path[1] == '\0' || soap->path[1] == '?') |
| return info(soap); |
| return 404; /* HTTP not found */ |
| } |
| |
| int check_authentication(struct soap *soap) |
| { if (soap->userid && soap->passwd) |
| { if (!strcmp(soap->userid, AUTH_USERID) && !strcmp(soap->passwd, AUTH_PASSWD)) |
| return SOAP_OK; |
| } |
| #ifdef HTTPDA_H |
| else if (soap->authrealm && soap->userid) |
| { if (!strcmp(soap->authrealm, AUTH_REALM) && !strcmp(soap->userid, AUTH_USERID)) |
| if (!http_da_verify_get(soap, AUTH_PASSWD)) |
| return SOAP_OK; |
| } |
| #endif |
| soap->authrealm = AUTH_REALM; |
| return 401; |
| } |
| |
| /******************************************************************************\ |
| * |
| * HTTP POST application/x-www-form-urlencoded handler for plugin |
| * |
| \******************************************************************************/ |
| |
| int http_form_handler(struct soap *soap) |
| { |
| #ifdef WITH_ZLIB |
| if (options[OPTION_z].selected && soap->zlib_out == SOAP_ZLIB_GZIP) /* client accepts gzip */ |
| soap_set_omode(soap, SOAP_ENC_ZLIB); /* so we can compress content (gzip) */ |
| soap->z_level = 9; /* best compression */ |
| #endif |
| /* Use soap->path (from request URL) to determine request: */ |
| if (options[OPTION_v].selected) |
| fprintf(stderr, "HTTP POST Request: %s\n", soap->endpoint); |
| /* Note: soap->path always starts with '/' */ |
| if (!strcmp(soap->path, "/calc")) |
| return calcpost(soap); |
| return 404; /* HTTP not found */ |
| } |
| |
| /******************************************************************************\ |
| * |
| * Copy static page |
| * |
| \******************************************************************************/ |
| |
| int copy_file(struct soap *soap, const char *name, const char *type) |
| { FILE *fd; |
| size_t r; |
| fd = fopen(name, "rb"); /* open file to copy */ |
| if (!fd) |
| return 404; /* return HTTP not found */ |
| soap->http_content = type; |
| if (soap_response(soap, SOAP_FILE)) /* OK HTTP response header */ |
| { soap_end_send(soap); |
| fclose(fd); |
| return soap->error; |
| } |
| for (;;) |
| { r = fread(soap->tmpbuf, 1, sizeof(soap->tmpbuf), fd); |
| if (!r) |
| break; |
| if (soap_send_raw(soap, soap->tmpbuf, r)) |
| { soap_end_send(soap); |
| fclose(fd); |
| return soap->error; |
| } |
| } |
| fclose(fd); |
| return soap_end_send(soap); |
| } |
| |
| /******************************************************************************\ |
| * |
| * Example dynamic HTTP GET application/x-www-form-urlencoded calculator |
| * |
| \******************************************************************************/ |
| |
| int calcget(struct soap *soap) |
| { int o = 0, a = 0, b = 0, val; |
| char buf[256]; |
| char *s = query(soap); /* get argument string from URL ?query string */ |
| while (s) |
| { char *key = query_key(soap, &s); /* decode next query string key */ |
| char *val = query_val(soap, &s); /* decode next query string value (if any) */ |
| if (key && val) |
| { if (!strcmp(key, "o")) |
| o = val[0]; |
| else if (!strcmp(key, "a")) |
| a = strtol(val, NULL, 10); |
| else if (!strcmp(key, "b")) |
| b = strtol(val, NULL, 10); |
| } |
| } |
| switch (o) |
| { case 'a': |
| val = a + b; |
| break; |
| case 's': |
| val = a - b; |
| break; |
| case 'm': |
| val = a * b; |
| break; |
| case 'd': |
| val = a / b; |
| break; |
| default: |
| return soap_sender_fault(soap, "Unknown operation", NULL); |
| } |
| soap_response(soap, SOAP_HTML); |
| sprintf(buf, "<html>value=%d</html>", val); |
| soap_send(soap, buf); |
| soap_end_send(soap); |
| return SOAP_OK; |
| } |
| |
| /******************************************************************************\ |
| * |
| * Example dynamic HTTP POST application/x-www-form-urlencoded calculator |
| * |
| \******************************************************************************/ |
| |
| int calcpost(struct soap *soap) |
| { int o = 0, a = 0, b = 0, val; |
| char buf[256]; |
| char *s = form(soap); /* get form data from body */ |
| while (s) |
| { char *key = query_key(soap, &s); /* decode next key */ |
| char *val = query_val(soap, &s); /* decode next value (if any) */ |
| if (key && val) |
| { if (!strcmp(key, "o")) |
| o = val[0]; |
| else if (!strcmp(key, "a")) |
| a = strtol(val, NULL, 10); |
| else if (!strcmp(key, "b")) |
| b = strtol(val, NULL, 10); |
| } |
| } |
| switch (o) |
| { case 'a': |
| val = a + b; |
| break; |
| case 's': |
| val = a - b; |
| break; |
| case 'm': |
| val = a * b; |
| break; |
| case 'd': |
| val = a / b; |
| break; |
| default: |
| return soap_sender_fault(soap, "Unknown operation", NULL); |
| } |
| soap_response(soap, SOAP_HTML); |
| sprintf(buf, "<html>value=%d</html>", val); |
| soap_send(soap, buf); |
| soap_end_send(soap); |
| return SOAP_OK; |
| } |
| |
| /******************************************************************************\ |
| * |
| * Example dynamic HTTP POST multipart/form-data form-based calculator |
| * |
| \******************************************************************************/ |
| |
| int f__form1(struct soap *soap) |
| { int o = 0, a = 0, b = 0, val; |
| char buf[256]; |
| struct soap_multipart *content; |
| for (content = soap->mime.list; content; content = content->next) |
| { if (content->id && content->ptr) |
| { /* may have to check content->encoding to convert data when necessary! */ |
| if (!strcmp(content->id, "o")) |
| o = content->ptr[0]; |
| else if (!strcmp(content->id, "a")) |
| a = strtol(content->ptr, NULL, 10); |
| else if (!strcmp(content->id, "b")) |
| b = strtol(content->ptr, NULL, 10); |
| } |
| } |
| switch (o) |
| { case 'a': |
| val = a + b; |
| break; |
| case 's': |
| val = a - b; |
| break; |
| case 'm': |
| val = a * b; |
| break; |
| case 'd': |
| val = a / b; |
| break; |
| default: |
| return soap_sender_fault(soap, "Unknown operation", NULL); |
| } |
| soap_response(soap, SOAP_HTML); |
| sprintf(buf, "<html>value=%d</html>", val); |
| soap_send(soap, buf); |
| soap_end_send(soap); |
| return SOAP_OK; |
| return SOAP_OK; |
| } |
| |
| int f__form2(struct soap *soap, struct f__formResponse *response) |
| { int o = 0, a = 0, b = 0; |
| struct soap_multipart *content; |
| for (content = soap->mime.list; content; content = content->next) |
| { if (content->id && content->ptr) |
| { /* may have to check content->encoding to convert data when necessary! */ |
| if (!strcmp(content->id, "o")) |
| o = content->ptr[0]; |
| else if (!strcmp(content->id, "a")) |
| a = strtol(content->ptr, NULL, 10); |
| else if (!strcmp(content->id, "b")) |
| b = strtol(content->ptr, NULL, 10); |
| } |
| } |
| switch (o) |
| { case 'a': |
| response->result = a + b; |
| break; |
| case 's': |
| response->result = a - b; |
| break; |
| case 'm': |
| response->result = a * b; |
| break; |
| case 'd': |
| response->result = a / b; |
| break; |
| default: |
| return soap_sender_fault(soap, "Unknown operation", NULL); |
| } |
| return SOAP_OK; |
| } |
| |
| /******************************************************************************\ |
| * |
| * Dynamic Web server info page |
| * |
| \******************************************************************************/ |
| |
| int info(struct soap *soap) |
| { struct http_get_data *getdata; |
| struct logging_data *logdata; |
| const char *t0, *t1, *t2, *t3, *t4, *t5, *t6, *t7; |
| char buf[2048]; /* buffer large enough to hold HTML content */ |
| struct soap_plugin *p; |
| time_t now = time(NULL), elapsed = now - start; |
| query_options(soap, options); |
| if (soap->omode & SOAP_IO_KEEPALIVE) |
| t0 = "<td align='center' bgcolor='green'>YES</td>"; |
| else |
| t0 = "<td align='center' bgcolor='red'>NO</td>"; |
| #ifdef WITH_COOKIES |
| t1 = "<td align='center' bgcolor='green'>YES</td>"; |
| /* soap_env_cookie_value() returns value of a cookie received (from client) */ |
| if (soap_env_cookie_value(soap, "visit", NULL, NULL)) |
| t2 = "<td align='center' bgcolor='green'>PASS</td>"; |
| else |
| t2 = "<td align='center' bgcolor='yellow'>WAIT</td>"; |
| #else |
| t1 = "<td align='center' bgcolor='red'>NO</td>"; |
| t2 = "<td align='center' bgcolor='blue'>N/A</td>"; |
| #endif |
| if (secure) |
| { t3 = "<td align='center' bgcolor='green'>YES</td>"; |
| if (soap->imode & SOAP_ENC_SSL) |
| t4 = "<td align='center' bgcolor='green'>PASS</td>"; |
| else |
| t4 = "<td align='center' bgcolor='red'><blink>FAIL</blink></td>"; |
| } |
| else |
| { t3 = "<td align='center' bgcolor='red'>NO</td>"; |
| t4 = "<td align='center' bgcolor='blue'>N/A</td>"; |
| } |
| #ifdef WITH_ZLIB |
| if (options[OPTION_z].selected) |
| { t5 = "<td align='center' bgcolor='green'>YES</td>"; |
| if (soap->omode & SOAP_ENC_ZLIB) |
| t6 = "<td align='center' bgcolor='green'>PASS</td>"; |
| else |
| t6 = "<td align='center' bgcolor='yellow'>WAIT</td>"; |
| } |
| else |
| { t5 = "<td align='center' bgcolor='red'>NO</td>"; |
| t6 = "<td align='center' bgcolor='blue'>N/A</td>"; |
| } |
| #else |
| t5 = "<td align='center' bgcolor='red'>NO</td>"; |
| t6 = "<td align='center' bgcolor='blue'>N/A</td>"; |
| #endif |
| if (options[OPTION_c].selected || (soap->omode & SOAP_IO) == SOAP_IO_CHUNK) |
| t7 = "<td align='center' bgcolor='green'>YES</td>"; |
| else |
| t7 = "<td align='center' bgcolor='red'>NO</td>"; |
| if (soap_response(soap, SOAP_HTML)) |
| return soap->error; |
| sprintf(buf, "\ |
| <html>\ |
| <head>\ |
| <meta name='Author' content='Robert A. van Engelen'>\ |
| <meta name='Generator' content='gSOAP'>\ |
| <meta http-equiv='Refresh' content='60'>\ |
| <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>\ |
| <title>gSOAP Web Server Administration</title>\ |
| </head>\ |
| <body bgcolor='#FFFFFF'>\ |
| <h1>gSOAP Web Server Administration</h1>\ |
| <p>Server endpoint=%s client agent IP=%d.%d.%d.%d\ |
| <h2>Registered Plugins</h2>\ |
| ", soap->endpoint, (int)(soap->ip>>24)&0xFF, (int)(soap->ip>>16)&0xFF, (int)(soap->ip>>8)&0xFF, (int)soap->ip&0xFF); |
| if (soap_send(soap, buf)) |
| return soap->error; |
| for (p = soap->plugins; p; p = p->next) |
| { sprintf(buf, "%s<br>", p->id); |
| if (soap_send(soap, buf)) |
| return soap->error; |
| } |
| if (soap_send(soap, "<h2>Elapsed Time</h2>")) |
| return soap->error; |
| if (elapsed >= 86400) |
| html_hbar(soap, "Days:", 100, elapsed/86400, 0x000000); |
| if (elapsed >= 3600) |
| html_hbar(soap, "Hours:", 100, elapsed/3600%24, 0x000000); |
| html_hbar(soap, "Minutes:", 100, elapsed/60%60, 0x000000); |
| soap_send(soap, "<h2>Control Panel</h2>"); |
| if (html_form_options(soap, options)) |
| return soap->error; |
| sprintf(buf, "\ |
| <h2>Function Tests</h2>\ |
| <table border='0' cellspacing='0' cellpadding='0' bgcolor='#666666' nosave>\ |
| <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>\ |
| <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>\ |
| <tr><td background='bl.gif'></td><td>HTTP keep alive enabled</td>%s<td width='10' background='ls.gif'></td></tr>\ |
| <tr><td background='bl.gif'></td><td>HTTP cookies enabled</td>%s<td width='10' background='ls.gif'></td></tr>\ |
| <tr><td background='bl.gif'></td><td>HTTP cookies test</td>%s<td width='10' background='ls.gif'></td></tr>\ |
| <tr><td background='bl.gif'></td><td>HTTPS (OpenSSL) enabled</td>%s<td width='10' background='ls.gif'></td></tr>\ |
| <tr><td background='bl.gif'></td><td>HTTPS (OpenSSL) test</td>%s<td width='10' background='ls.gif'></td></tr>\ |
| <tr><td background='bl.gif'></td><td>HTTP compression enabled</td>%s<td width='10' background='ls.gif'></td></tr>\ |
| <tr><td background='bl.gif'></td><td>HTTP compression test</td>%s<td width='10' background='ls.gif'></td></tr>\ |
| <tr><td background='bl.gif'></td><td>HTTP chunking enabled</td>%s<td width='10' background='ls.gif'></td></tr>\ |
| <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>\ |
| </table>", t0, t1, t2, t3, t4, t5, t6, t7); |
| if (soap_send(soap, buf)) |
| return soap->error; |
| getdata = (struct http_get_data*)soap_lookup_plugin(soap, http_get_id); |
| logdata = (struct logging_data*)soap_lookup_plugin(soap, logging_id); |
| soap_send(soap, "<h2>Usage Statistics</h2>"); |
| if (getdata) |
| { html_hbar(soap, "HTTP GET", 120, getdata->stat_get, 0x0000FF); |
| html_hbar(soap, "HTTP POST", 120, getdata->stat_post, 0x00FF00); |
| html_hbar(soap, "HTTP FAIL", 120, getdata->stat_fail, 0xFF0000); |
| } |
| if (logdata) |
| { html_hbar(soap, "SENT(kB)", 120, logdata->stat_sent/1024, 0x00FFFF); |
| html_hbar(soap, "RECV(kB)", 120, logdata->stat_recv/1024, 0x00FFFF); |
| if (elapsed > 0) |
| { html_hbar(soap, "SENT(kB/s)", 120, logdata->stat_sent/elapsed/1024, 0x00FFFF); |
| html_hbar(soap, "RECV(kB/s)", 120, logdata->stat_recv/elapsed/1024, 0x00FFFF); |
| } |
| } |
| if (getdata) |
| { struct tm T; |
| T.tm_min = 99; |
| T.tm_hour = 99; |
| T.tm_yday = 999; |
| #ifdef HAVE_LOCALTIME_R |
| localtime_r(&now, &T); |
| #else |
| T = *localtime(&now); |
| #endif |
| soap_send(soap, "<h2>Requests by the Minute</h2>"); |
| html_hist(soap, "Minute", 12, 0, 60, minutes, getdata->min, T.tm_min); |
| soap_send(soap, "<h2>Requests by the Hour</h2>"); |
| html_hist(soap, "Hour", 30, 0, 24, hours, getdata->hour, T.tm_hour); |
| soap_send(soap, "<h2>Requests by Day of the Year</h2>"); |
| html_hist(soap, "Day", 2, 0, 365, NULL, getdata->day, T.tm_yday); |
| } |
| soap_send(soap, "\ |
| <p>This page will automatically reload every minute to refresh the statistics.\ |
| <br><br><br><img src='favicon.gif' align='absmiddle'>Powered by gSOAP\ |
| </body>\ |
| </HTML>"); |
| return soap_end_send(soap); |
| } |
| |
| static size_t html_scaled(char *buf, size_t len) |
| { if (len > 1000000) |
| { sprintf(buf, "%.2f·10<sup>6</sup>", (float)len/1000000.0); |
| return len / 1000000; |
| } |
| if (len > 1000) |
| { sprintf(buf, "%.2f·10<sup>3</sup>", (float)len/1000.0); |
| return len / 1000; |
| } |
| sprintf(buf, "%lu", (unsigned long)len); |
| return len; |
| } |
| |
| int html_hbar(struct soap *soap, const char *title, size_t pix, size_t len, unsigned long color) |
| { char buf[2048]; /* buffer large enough to hold HTML content */ |
| char lab[32]; |
| len = html_scaled(lab, len); |
| sprintf(buf, "\ |
| <table border='0' cellspacing='0' cellpadding='0' height='30'>\ |
| <tr height='10'>\ |
| <td width='10' height='10' background='bl.gif'></td>\ |
| <td rowspan='2' bgcolor='#666666' width='%lu' height='20'>%s %s</td>\ |
| <td bgcolor='#%.6lx' width='%lu' height='10'></td>\ |
| <td width='10' height='10' background='obls.gif'></td>\ |
| </tr>\ |
| <tr height='10'>\ |
| <td width='10' height='10' background='bl.gif'></td>\ |
| <td height='10' background='ruler.gif'></td>\ |
| <td width='10' height='10' background='ls.gif'></td>\ |
| </tr>\ |
| <tr height='10'>\ |
| <td width='10' height='10' background='otrs.gif'></td>\ |
| <td colspan='2' height='10' background='ts.gif'></td>\ |
| <td width='10' height='10' background='otls.gif'></td>\ |
| </tr>\ |
| </table>", (unsigned long)pix, title ? title : "", lab, color, (unsigned long)len * 2); |
| return soap_send(soap, buf); |
| } |
| |
| 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) |
| { char buf[2048]; /* buffer large enough to hold HTML content */ |
| char lab[32]; |
| size_t i, max; |
| float scale; |
| max = 0; |
| for (i = 0; i < num; i++) |
| { if (val[i] > max) |
| max = val[i]; |
| } |
| if (height < 20) |
| { height = max; |
| if (height < 20) |
| height = 20; |
| else if (height > 256) |
| height = 256; |
| } |
| scale = (float)height / (float)max; |
| html_scaled(lab, max); |
| sprintf(buf, "\ |
| <a name='%s'></a>\ |
| <table bgcolor='#FFFFFF' border='0' cellspacing='0' cellpadding='0' height='%lu' align='center'>\ |
| <tr height='10'>\ |
| <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>\ |
| </tr>\ |
| <tr height='%lu' align='center' valign='bottom'>\ |
| <td width='10' height='%lu' background='bl.gif'></td>\ |
| <td bgcolor='#666666' valign='top'>%s</td>", title ? title : "", (unsigned long)height + 50, (unsigned long)num + 1, (unsigned long)height, (unsigned long)height, lab); |
| if (soap_send(soap, buf)) |
| return soap->error; |
| for (i = 0; i < num; i++) |
| { unsigned long bar = (scale * val[i] + 0.5); |
| if (bar >= 1) |
| sprintf(buf, "\ |
| <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); |
| else |
| sprintf(buf, "\ |
| <td bgcolor='#FFFFFF'><img src='bar.gif' alt='' width='%lu' height='0' align='bottom' border='0'></td>", (unsigned long)barwidth); |
| if (soap_send(soap, buf)) |
| return soap->error; |
| } |
| sprintf(buf, "\ |
| <td width='10' height='%lu' background='br.gif'></td>\ |
| <td width='10' height='%lu' background='ls.gif'></td>\ |
| </tr>\ |
| <tr bgcolor='#666666' height='20' align='center'>\ |
| <td width='10' height='20' background='bl.gif'></td>\ |
| <td bgcolor='#666666'>%s</td>", (unsigned long)height, (unsigned long)height, title ? title : ""); |
| if (soap_send(soap, buf)) |
| return soap->error; |
| for (i = 0; i < num; i++) |
| { sprintf(buf, "<td%s>%s</td>", (i == highlight) ? " bgcolor='#777777'" : "", key ? key[i] : "<img src='bar.gif'>"); |
| if (soap_send(soap, buf)) |
| return soap->error; |
| } |
| if (soap_send(soap, "\ |
| <td width='10' height='20' background='br.gif'></td>\ |
| <td width='10' height='20' background='ls.gif'></td>")) |
| return soap->error; |
| sprintf(buf, "\ |
| </tr>\ |
| <tr height='10'>\ |
| <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>\ |
| </tr>\ |
| <tr height='10'>\ |
| <td width='10' height='10' background='otrs.gif'></td>\ |
| <td colspan='%lu' height='10' background='ts.gif'></td>\ |
| <td width='10' height='10' background='otls.gif'></td>\ |
| </tr>\ |
| </table>", (unsigned long)num + 1, (unsigned long)num + 2); |
| return soap_send(soap, buf); |
| } |
| |
| /******************************************************************************\ |
| * |
| * OpenSSL |
| * |
| \******************************************************************************/ |
| |
| #ifdef WITH_OPENSSL |
| |
| struct CRYPTO_dynlock_value |
| { MUTEX_TYPE mutex; |
| }; |
| |
| static MUTEX_TYPE *mutex_buf; |
| |
| static struct CRYPTO_dynlock_value *dyn_create_function(const char *file, int line) |
| { struct CRYPTO_dynlock_value *value; |
| value = (struct CRYPTO_dynlock_value*)malloc(sizeof(struct CRYPTO_dynlock_value)); |
| if (value) |
| MUTEX_SETUP(value->mutex); |
| return value; |
| } |
| |
| static void dyn_lock_function(int mode, struct CRYPTO_dynlock_value *l, const char *file, int line) |
| { if (mode & CRYPTO_LOCK) |
| MUTEX_LOCK(l->mutex); |
| else |
| MUTEX_UNLOCK(l->mutex); |
| } |
| |
| static void dyn_destroy_function(struct CRYPTO_dynlock_value *l, const char *file, int line) |
| { MUTEX_CLEANUP(l->mutex); |
| free(l); |
| } |
| |
| void locking_function(int mode, int n, const char *file, int line) |
| { if (mode & CRYPTO_LOCK) |
| MUTEX_LOCK(mutex_buf[n]); |
| else |
| MUTEX_UNLOCK(mutex_buf[n]); |
| } |
| |
| unsigned long id_function() |
| { return (unsigned long)THREAD_ID; |
| } |
| |
| int CRYPTO_thread_setup() |
| { int i; |
| mutex_buf = (MUTEX_TYPE*)malloc(CRYPTO_num_locks() * sizeof(MUTEX_TYPE)); |
| if (!mutex_buf) |
| return SOAP_EOM; |
| for (i = 0; i < CRYPTO_num_locks(); i++) |
| MUTEX_SETUP(mutex_buf[i]); |
| CRYPTO_set_id_callback(id_function); |
| CRYPTO_set_locking_callback(locking_function); |
| CRYPTO_set_dynlock_create_callback(dyn_create_function); |
| CRYPTO_set_dynlock_lock_callback(dyn_lock_function); |
| CRYPTO_set_dynlock_destroy_callback(dyn_destroy_function); |
| return SOAP_OK; |
| } |
| |
| void CRYPTO_thread_cleanup() |
| { int i; |
| if (!mutex_buf) |
| return; |
| CRYPTO_set_id_callback(NULL); |
| CRYPTO_set_locking_callback(NULL); |
| CRYPTO_set_dynlock_create_callback(NULL); |
| CRYPTO_set_dynlock_lock_callback(NULL); |
| CRYPTO_set_dynlock_destroy_callback(NULL); |
| for (i = 0; i < CRYPTO_num_locks(); i++) |
| MUTEX_CLEANUP(mutex_buf[i]); |
| free(mutex_buf); |
| mutex_buf = NULL; |
| } |
| |
| #endif |
| |
| /******************************************************************************\ |
| * |
| * SIGPIPE |
| * |
| \******************************************************************************/ |
| |
| void sigpipe_handle(int x) { } |