| 1 |
/******************************************************************************* |
|---|
| 2 |
* Copyright (C) 2004-2006 Intel Corp. All rights reserved. |
|---|
| 3 |
* |
|---|
| 4 |
* Redistribution and use in source and binary forms, with or without |
|---|
| 5 |
* modification, are permitted provided that the following conditions are met: |
|---|
| 6 |
* |
|---|
| 7 |
* - Redistributions of source code must retain the above copyright notice, |
|---|
| 8 |
* this list of conditions and the following disclaimer. |
|---|
| 9 |
* |
|---|
| 10 |
* - Redistributions in binary form must reproduce the above copyright notice, |
|---|
| 11 |
* this list of conditions and the following disclaimer in the documentation |
|---|
| 12 |
* and/or other materials provided with the distribution. |
|---|
| 13 |
* |
|---|
| 14 |
* - Neither the name of Intel Corp. nor the names of its |
|---|
| 15 |
* contributors may be used to endorse or promote products derived from this |
|---|
| 16 |
* software without specific prior written permission. |
|---|
| 17 |
* |
|---|
| 18 |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' |
|---|
| 19 |
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|---|
| 20 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|---|
| 21 |
* ARE DISCLAIMED. IN NO EVENT SHALL Intel Corp. OR THE CONTRIBUTORS |
|---|
| 22 |
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|---|
| 23 |
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|---|
| 24 |
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|---|
| 25 |
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
|---|
| 26 |
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|---|
| 27 |
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|---|
| 28 |
* POSSIBILITY OF SUCH DAMAGE. |
|---|
| 29 |
*******************************************************************************/ |
|---|
| 30 |
|
|---|
| 31 |
/** |
|---|
| 32 |
* @author Anas Nashif |
|---|
| 33 |
* @author Vadim Revyakin |
|---|
| 34 |
* @author Liang Hou |
|---|
| 35 |
*/ |
|---|
| 36 |
|
|---|
| 37 |
#define _GNU_SOURCE |
|---|
| 38 |
#ifdef HAVE_CONFIG_H |
|---|
| 39 |
#include "wsman_config.h" |
|---|
| 40 |
#endif |
|---|
| 41 |
|
|---|
| 42 |
#include <stdlib.h> |
|---|
| 43 |
#include <stdio.h> |
|---|
| 44 |
#include <ctype.h> |
|---|
| 45 |
#include <string.h> |
|---|
| 46 |
#include <sys/stat.h> |
|---|
| 47 |
|
|---|
| 48 |
#ifdef HAVE_UNISTD_H |
|---|
| 49 |
#include <unistd.h> |
|---|
| 50 |
#endif |
|---|
| 51 |
|
|---|
| 52 |
#ifndef WIN32 |
|---|
| 53 |
#include <dlfcn.h> |
|---|
| 54 |
#endif |
|---|
| 55 |
|
|---|
| 56 |
#include "u/libu.h" |
|---|
| 57 |
#include "wsman-xml-api.h" |
|---|
| 58 |
#include "wsman-soap.h" |
|---|
| 59 |
#include "wsman-soap-envelope.h" |
|---|
| 60 |
|
|---|
| 61 |
#include "wsman-xml.h" |
|---|
| 62 |
#include "wsman-xml-serializer.h" |
|---|
| 63 |
#include "wsman-dispatcher.h" |
|---|
| 64 |
|
|---|
| 65 |
#define OPENWSMAN |
|---|
| 66 |
#include "shttpd.h" |
|---|
| 67 |
|
|---|
| 68 |
#include "wsman-plugins.h" |
|---|
| 69 |
#include "wsmand-listener.h" |
|---|
| 70 |
#include "wsmand-daemon.h" |
|---|
| 71 |
#include "wsmand-auth.h" |
|---|
| 72 |
#include "wsman-server.h" |
|---|
| 73 |
#include "wsman-plugins.h" |
|---|
| 74 |
#ifdef ENABLE_EVENTING_SUPPORT |
|---|
| 75 |
#include "wsman-event-pool.h" |
|---|
| 76 |
#include "wsman-cimxmllistener-path.h" |
|---|
| 77 |
#include "wsman-cimindication-processor.h" |
|---|
| 78 |
#endif |
|---|
| 79 |
|
|---|
| 80 |
#define MULTITHREADED_SERVER |
|---|
| 81 |
|
|---|
| 82 |
#ifdef MULTITHREADED_SERVER |
|---|
| 83 |
#ifdef HAVE_PTHREAD_H |
|---|
| 84 |
#include <pthread.h> |
|---|
| 85 |
#endif |
|---|
| 86 |
#include <sys/socket.h> |
|---|
| 87 |
|
|---|
| 88 |
static pthread_mutex_t shttpd_mutex; |
|---|
| 89 |
static pthread_cond_t shttpd_cond; |
|---|
| 90 |
static list_t *request_list; |
|---|
| 91 |
static int num_threads = 0; |
|---|
| 92 |
static int min_threads = 2; |
|---|
| 93 |
static int idle_threads = 0; |
|---|
| 94 |
static int max_threads = 4; |
|---|
| 95 |
|
|---|
| 96 |
#endif |
|---|
| 97 |
|
|---|
| 98 |
|
|---|
| 99 |
int continue_working = 1; |
|---|
| 100 |
static int (*basic_auth_callback) (char *, char *) = NULL; |
|---|
| 101 |
|
|---|
| 102 |
|
|---|
| 103 |
static int |
|---|
| 104 |
digest_auth_callback(char *realm, char *method, struct digest *dig) |
|---|
| 105 |
{ |
|---|
| 106 |
WSmanAuthDigest wsdig; |
|---|
| 107 |
char *filename = wsmand_options_get_digest_password_file(); |
|---|
| 108 |
|
|---|
| 109 |
if (filename == NULL) { |
|---|
| 110 |
debug("Could not get digest password file name"); |
|---|
| 111 |
return 0; |
|---|
| 112 |
} |
|---|
| 113 |
wsdig.request_method = method; |
|---|
| 114 |
wsdig.username = dig->user; |
|---|
| 115 |
wsdig.realm = realm; |
|---|
| 116 |
wsdig.digest_uri = dig->uri; |
|---|
| 117 |
wsdig.nonce = dig->nonce; |
|---|
| 118 |
wsdig.cnonce = dig->cnonce; |
|---|
| 119 |
wsdig.qop = dig->qop; |
|---|
| 120 |
strncpy(wsdig.nonce_count, dig->nc, sizeof(wsdig.nonce_count)); |
|---|
| 121 |
wsdig.digest_response = dig->resp; |
|---|
| 122 |
|
|---|
| 123 |
return ws_authorize_digest(filename, &wsdig); |
|---|
| 124 |
} |
|---|
| 125 |
/* |
|---|
| 126 |
static char *shttp_reason_phrase(int status) |
|---|
| 127 |
{ |
|---|
| 128 |
if (status == WSMAN_STATUS_OK) { |
|---|
| 129 |
return "OK"; |
|---|
| 130 |
} |
|---|
| 131 |
return "Error"; |
|---|
| 132 |
} |
|---|
| 133 |
*/ |
|---|
| 134 |
|
|---|
| 135 |
typedef struct { |
|---|
| 136 |
char *response; |
|---|
| 137 |
int length; |
|---|
| 138 |
int ind; |
|---|
| 139 |
} ShttpMessage; |
|---|
| 140 |
|
|---|
| 141 |
|
|---|
| 142 |
|
|---|
| 143 |
static int server_callback(struct shttpd_arg_t *arg) |
|---|
| 144 |
{ |
|---|
| 145 |
const char *method; |
|---|
| 146 |
const char *content_type; |
|---|
| 147 |
// char *default_path; |
|---|
| 148 |
// const char *path; |
|---|
| 149 |
char *encoding = NULL; |
|---|
| 150 |
int status = WSMAN_STATUS_OK; |
|---|
| 151 |
char *fault_reason = NULL; |
|---|
| 152 |
|
|---|
| 153 |
ShttpMessage *shttp_msg = (ShttpMessage *) arg->state; |
|---|
| 154 |
int n = 0; |
|---|
| 155 |
int k; |
|---|
| 156 |
|
|---|
| 157 |
debug("Server callback started %s. len = %d, sent = %d", |
|---|
| 158 |
(shttp_msg == NULL) ? "initialy" : "continue", |
|---|
| 159 |
arg->buflen, (shttp_msg == NULL) ? 0 : shttp_msg->ind); |
|---|
| 160 |
if (shttp_msg != NULL) { |
|---|
| 161 |
// We already have the response, but server |
|---|
| 162 |
// output buffer is smaller then it. |
|---|
| 163 |
// Some part of resopnse have already sent. |
|---|
| 164 |
// Just continue to send it to server |
|---|
| 165 |
goto CONTINUE; |
|---|
| 166 |
} |
|---|
| 167 |
// Here we must handle the initial request |
|---|
| 168 |
WsmanMessage *wsman_msg = wsman_soap_message_new(); |
|---|
| 169 |
|
|---|
| 170 |
// Check HTTP headers |
|---|
| 171 |
|
|---|
| 172 |
method = shttpd_get_env(arg, "REQUEST_METHOD"); |
|---|
| 173 |
if (strncmp(method, "POST", 4)) { |
|---|
| 174 |
debug("Unsupported method %s", method); |
|---|
| 175 |
status = WSMAN_STATUS_METHOD_NOT_ALLOWED; |
|---|
| 176 |
fault_reason = "POST method supported only"; |
|---|
| 177 |
} |
|---|
| 178 |
|
|---|
| 179 |
|
|---|
| 180 |
content_type = shttpd_get_header(arg, "Content-Type"); |
|---|
| 181 |
if (content_type && strncmp(content_type, |
|---|
| 182 |
SOAP_CONTENT_TYPE, |
|---|
| 183 |
strlen(SOAP_CONTENT_TYPE)) != 0) { |
|---|
| 184 |
status = WSMAN_STATUS_UNSUPPORTED_MEDIA_TYPE; |
|---|
| 185 |
fault_reason = "Unsupported content type"; |
|---|
| 186 |
goto DONE; |
|---|
| 187 |
} |
|---|
| 188 |
if(content_type) { |
|---|
| 189 |
char *p = strstr(content_type, "charset"); |
|---|
| 190 |
if(p) { |
|---|
| 191 |
p += strlen("charset"); |
|---|
| 192 |
p++; |
|---|
| 193 |
wsman_msg->charset = u_strdup(p); |
|---|
| 194 |
encoding = u_strdup(p); |
|---|
| 195 |
} |
|---|
| 196 |
} |
|---|
| 197 |
SoapH soap = (SoapH) arg->user_data; |
|---|
| 198 |
wsman_msg->status.fault_code = WSMAN_RC_OK; |
|---|
| 199 |
wsman_msg->http_headers = shttpd_get_all_headers(arg); |
|---|
| 200 |
|
|---|
| 201 |
// Get request from http server |
|---|
| 202 |
size_t length = shttpd_get_post_query_len(arg); |
|---|
| 203 |
char *body = shttpd_get_post_query(arg); |
|---|
| 204 |
if (body == NULL) { |
|---|
| 205 |
status = WSMAN_STATUS_BAD_REQUEST; |
|---|
| 206 |
fault_reason = "No request body"; |
|---|
| 207 |
error("NULL request body. len = %d", length); |
|---|
| 208 |
} |
|---|
| 209 |
#if 0 |
|---|
| 210 |
if(strcmp(wsman_msg->charset, "UTF-8")) { |
|---|
| 211 |
iconv_t cd = iconv_open("UTF-8", wsman_msg->charset); |
|---|
| 212 |
if(cd == -1) { |
|---|
| 213 |
status = WSMAN_STATUS_INTERNAL_SERVER_ERROR; |
|---|
| 214 |
fault_reason = "Specified encoding unsupported"; |
|---|
| 215 |
goto DONE; |
|---|
| 216 |
} |
|---|
| 217 |
char *mbbuf = u_zalloc(length); |
|---|
| 218 |
size_t outbuf_len = length; |
|---|
| 219 |
size_t inbuf_len = length; |
|---|
| 220 |
char *inbuf = body; |
|---|
| 221 |
char *outbuf = mbbuf; |
|---|
| 222 |
size_t coverted = iconv(cd, &inbuf, &inbuf_len, &outbuf, &outbuf_len); |
|---|
| 223 |
if( coverted == -1) { |
|---|
| 224 |
status = WSMAN_STATUS_INTERNAL_SERVER_ERROR; |
|---|
| 225 |
fault_reason = "Cannot covert specified encoding"; |
|---|
| 226 |
goto DONE; |
|---|
| 227 |
} |
|---|
| 228 |
iconv_close(cd); |
|---|
| 229 |
// u_buf_construct(wsman_msg->request, mbbuf, length - outbuf_len, length - outbuf_len); |
|---|
| 230 |
debug("***coverted = %d***", length - outbuf_len); |
|---|
| 231 |
|
|---|
| 232 |
} |
|---|
| 233 |
#endif |
|---|
| 234 |
u_buf_construct(wsman_msg->request, body, length, length); |
|---|
| 235 |
debug("Posted request: %s, wsman_msg len = %d", u_buf_ptr(wsman_msg->request), |
|---|
| 236 |
u_buf_len(wsman_msg->request)); |
|---|
| 237 |
|
|---|
| 238 |
// some plugins can use credentials for its |
|---|
| 239 |
// own authentication |
|---|
| 240 |
shttpd_get_credentials(arg, &wsman_msg->auth_data.username, |
|---|
| 241 |
&wsman_msg->auth_data.password); |
|---|
| 242 |
|
|---|
| 243 |
|
|---|
| 244 |
// Call dispatcher. Real request handling |
|---|
| 245 |
if (status == WSMAN_STATUS_OK) { |
|---|
| 246 |
// dispatch if we didn't find out the error |
|---|
| 247 |
dispatch_inbound_call(soap, wsman_msg, NULL); |
|---|
| 248 |
status = wsman_msg->http_code; |
|---|
| 249 |
} |
|---|
| 250 |
|
|---|
| 251 |
|
|---|
| 252 |
if (wsman_msg->request) { |
|---|
| 253 |
// we don't need request any more |
|---|
| 254 |
// if(strcmp(wsman_msg->charset, "UTF-8") == 0) |
|---|
| 255 |
(void) u_buf_steal(wsman_msg->request); |
|---|
| 256 |
u_buf_free(wsman_msg->request); |
|---|
| 257 |
wsman_msg->request = NULL; |
|---|
| 258 |
} |
|---|
| 259 |
// here we start to handle the response |
|---|
| 260 |
|
|---|
| 261 |
shttp_msg = (ShttpMessage *) malloc(sizeof(ShttpMessage)); |
|---|
| 262 |
if (shttp_msg == NULL) { |
|---|
| 263 |
status = WSMAN_STATUS_INTERNAL_SERVER_ERROR; |
|---|
| 264 |
fault_reason = "No memory"; |
|---|
| 265 |
goto DONE; |
|---|
| 266 |
} |
|---|
| 267 |
|
|---|
| 268 |
|
|---|
| 269 |
shttp_msg->length = u_buf_len(wsman_msg->response); |
|---|
| 270 |
debug("message len = %d", shttp_msg->length); |
|---|
| 271 |
shttp_msg->response = u_buf_steal(wsman_msg->response); |
|---|
| 272 |
shttp_msg->ind = 0; |
|---|
| 273 |
DONE: |
|---|
| 274 |
wsman_soap_message_destroy(wsman_msg); |
|---|
| 275 |
/* u_free(wsman_msg->charset); |
|---|
| 276 |
if (wsman_msg->response) { |
|---|
| 277 |
u_buf_free(wsman_msg->response); |
|---|
| 278 |
wsman_msg->response = NULL; |
|---|
| 279 |
} |
|---|
| 280 |
// wsman_soap_message_destroy(wsman_msg); |
|---|
| 281 |
if (wsman_msg->http_headers) { |
|---|
| 282 |
hash_free(wsman_msg->http_headers); |
|---|
| 283 |
} |
|---|
| 284 |
u_free(wsman_msg); |
|---|
| 285 |
if (fault_reason == NULL) { |
|---|
| 286 |
fault_reason = shttp_reason_phrase(status); |
|---|
| 287 |
} |
|---|
| 288 |
*/ debug("Response (status) %d (%s)", status, fault_reason); |
|---|
| 289 |
|
|---|
| 290 |
// Here we begin to create the http response. |
|---|
| 291 |
// Create the headers at first. |
|---|
| 292 |
// We consider output buffer of server is large enough to hold all headers. |
|---|
| 293 |
|
|---|
| 294 |
n += snprintf(arg->buf + n, arg->buflen - n, "HTTP/1.1 %d %s\r\n", |
|---|
| 295 |
status, fault_reason); |
|---|
| 296 |
n += snprintf(arg->buf + n, arg->buflen - n, "Server: %s/%s\r\n", |
|---|
| 297 |
PACKAGE, VERSION); |
|---|
| 298 |
/* |
|---|
| 299 |
if (status != WSMAN_STATUS_OK) { |
|---|
| 300 |
n += snprintf(arg->buf + n, arg->buflen -n, "\r\n%d %s\r\n", |
|---|
| 301 |
status, fault_reason); |
|---|
| 302 |
arg->last = 1; |
|---|
| 303 |
u_free(shttp_msg); |
|---|
| 304 |
return n; |
|---|
| 305 |
} |
|---|
| 306 |
*/ |
|---|
| 307 |
if (!shttp_msg || shttp_msg->length == 0) { |
|---|
| 308 |
// can't send the body of response or nothing to send |
|---|
| 309 |
n += snprintf(arg->buf + n, arg->buflen - n, "\r\n"); |
|---|
| 310 |
arg->last = 1; |
|---|
| 311 |
u_free(shttp_msg); |
|---|
| 312 |
return n; |
|---|
| 313 |
} |
|---|
| 314 |
|
|---|
| 315 |
n += snprintf(arg->buf + n, arg->buflen - n, |
|---|
| 316 |
"Content-Type: application/soap+xml;charset=%s\r\n", encoding); |
|---|
| 317 |
n += snprintf(arg->buf + n, arg->buflen - n, |
|---|
| 318 |
"Content-Length: %d\r\n", shttp_msg->length); |
|---|
| 319 |
n += snprintf(arg->buf + n, arg->buflen - n, "\r\n"); |
|---|
| 320 |
u_free(encoding); |
|---|
| 321 |
// add response body to output buffer |
|---|
| 322 |
CONTINUE: |
|---|
| 323 |
k = arg->buflen - n; |
|---|
| 324 |
if (k <= shttp_msg->length - shttp_msg->ind) { |
|---|
| 325 |
// not enogh room for all message. transfer only part |
|---|
| 326 |
memcpy(arg->buf + n, shttp_msg->response + shttp_msg->ind, |
|---|
| 327 |
k); |
|---|
| 328 |
shttp_msg->ind += k; |
|---|
| 329 |
arg->state = shttp_msg; |
|---|
| 330 |
return n + k; |
|---|
| 331 |
} |
|---|
| 332 |
// Enough room for all response body |
|---|
| 333 |
memcpy(arg->buf + n, shttp_msg->response + shttp_msg->ind, |
|---|
| 334 |
shttp_msg->length - shttp_msg->ind); |
|---|
| 335 |
n += shttp_msg->length - shttp_msg->ind; |
|---|
| 336 |
if (n + 4 > arg->buflen) { |
|---|
| 337 |
// not enough room for empty lines at the end of the message |
|---|
| 338 |
arg->state = shttp_msg; |
|---|
| 339 |
shttp_msg->ind = shttp_msg->length; |
|---|
| 340 |
return n; |
|---|
| 341 |
} |
|---|
| 342 |
// here we can complete |
|---|
| 343 |
n += snprintf(arg->buf + n, arg->buflen - n, "\r\n\r\n"); |
|---|
| 344 |
debug("%s", arg->buf); |
|---|
| 345 |
u_free(shttp_msg->response); |
|---|
| 346 |
u_free(shttp_msg); |
|---|
| 347 |
|
|---|
| 348 |
arg->last = 1; |
|---|
| 349 |
arg->state = NULL; |
|---|
| 350 |
return n; |
|---|
| 351 |
} |
|---|
| 352 |
|
|---|
| 353 |
#ifdef ENABLE_EVENTING_SUPPORT |
|---|
| 354 |
|
|---|
| 355 |
static int cimxml_listener_callback(struct shttpd_arg_t *arg) |
|---|
| 356 |
{ |
|---|
| 357 |
debug("in cimxml_listener_callback"); |
|---|
| 358 |
const char *method; |
|---|
| 359 |
const char *content_type; |
|---|
| 360 |
int status = WSMAN_STATUS_OK; |
|---|
| 361 |
char *fault_reason = NULL; |
|---|
| 362 |
cimxml_context *cntx = NULL; |
|---|
| 363 |
ShttpMessage *shttp_msg = (ShttpMessage *) arg->state; |
|---|
| 364 |
int n = 0; |
|---|
| 365 |
int k; |
|---|
| 366 |
|
|---|
| 367 |
debug("CIM Indication Listener callback started %s. len = %d, sent = %d", |
|---|
| 368 |
(shttp_msg == NULL) ? "initialy" : "continue", |
|---|
| 369 |
arg->buflen, (shttp_msg == NULL) ? 0 : shttp_msg->ind); |
|---|
| 370 |
if (shttp_msg != NULL) { |
|---|
| 371 |
// We already have the response, but server |
|---|
| 372 |
// output buffer is smaller then it. |
|---|
| 373 |
// Some part of resopnse have already sent. |
|---|
| 374 |
// Just continue to send it to server |
|---|
| 375 |
goto CONTINUE; |
|---|
| 376 |
} |
|---|
| 377 |
// Here we must handle the initial request |
|---|
| 378 |
WsmanMessage *wsman_msg = wsman_soap_message_new(); |
|---|
| 379 |
|
|---|
| 380 |
// Check HTTP headers |
|---|
| 381 |
|
|---|
| 382 |
method = shttpd_get_env(arg, "REQUEST_METHOD"); |
|---|
| 383 |
if (strncmp(method, "POST", 4)) { |
|---|
| 384 |
debug("Unsupported method %s", method); |
|---|
| 385 |
status = WSMAN_STATUS_METHOD_NOT_ALLOWED; |
|---|
| 386 |
fault_reason = "POST method supported only"; |
|---|
| 387 |
} |
|---|
| 388 |
|
|---|
| 389 |
|
|---|
| 390 |
content_type = shttpd_get_header(arg, "Content-Type"); |
|---|
| 391 |
if (content_type && strncmp(content_type, |
|---|
| 392 |
CIMXML_CONTENT_TYPE, |
|---|
| 393 |
strlen(CIMXML_CONTENT_TYPE)) != 0) { |
|---|
| 394 |
status = WSMAN_STATUS_UNSUPPORTED_MEDIA_TYPE; |
|---|
| 395 |
fault_reason = "Unsupported content type"; |
|---|
| 396 |
goto DONE; |
|---|
| 397 |
} |
|---|
| 398 |
|
|---|
| 399 |
if(strncmp(shttpd_get_header(arg, "CIMExport"), "MethodRequest", strlen("MethodRequest")) || |
|---|
| 400 |
strncmp(shttpd_get_header(arg, "CIMExportMethod"), "ExportIndication", strlen("ExportIndication"))) { |
|---|
| 401 |
status = CIMXML_STATUS_UNSUPPORTED_OPERATION; |
|---|
| 402 |
fault_reason = "Unsupported operation"; |
|---|
| 403 |
goto DONE; |
|---|
| 404 |
} |
|---|
| 405 |
cntx = (cimxml_context *) arg->user_data; |
|---|
| 406 |
wsman_msg->status.fault_code = WSMAN_RC_OK; |
|---|
| 407 |
wsman_msg->http_headers = shttpd_get_all_headers(arg); |
|---|
| 408 |
|
|---|
| 409 |
// Get request from http server |
|---|
| 410 |
size_t length = shttpd_get_post_query_len(arg); |
|---|
| 411 |
char *body = shttpd_get_post_query(arg); |
|---|
| 412 |
if (body == NULL) { |
|---|
| 413 |
status = CIMXML_STATUS_REQUEST_NOT_WELL_FORMED; |
|---|
| 414 |
fault_reason = "No request body"; |
|---|
| 415 |
error("NULL request body. len = %d", length); |
|---|
| 416 |
} |
|---|
| 417 |
else { |
|---|
| 418 |
debug("Posted request: %s", body); |
|---|
| 419 |
} |
|---|
| 420 |
u_buf_construct(wsman_msg->request, body, length, length); |
|---|
| 421 |
|
|---|
| 422 |
// some plugins can use credentials for its |
|---|
| 423 |
// own authentication |
|---|
| 424 |
shttpd_get_credentials(arg, &wsman_msg->auth_data.username, |
|---|
| 425 |
&wsman_msg->auth_data.password); |
|---|
| 426 |
|
|---|
| 427 |
|
|---|
| 428 |
// Call dispatcher. Real request handling |
|---|
| 429 |
if (status == WSMAN_STATUS_OK) { |
|---|
| 430 |
CIM_Indication_call(cntx, wsman_msg, NULL); |
|---|
| 431 |
status = wsman_msg->http_code; |
|---|
| 432 |
} |
|---|
| 433 |
|
|---|
| 434 |
|
|---|
| 435 |
if (wsman_msg->request) { |
|---|
| 436 |
// we don't need request any more |
|---|
| 437 |
(void) u_buf_steal(wsman_msg->request); |
|---|
| 438 |
u_buf_free(wsman_msg->request); |
|---|
| 439 |
wsman_msg->request = NULL; |
|---|
| 440 |
} |
|---|
| 441 |
// here we start to handle the response |
|---|
| 442 |
|
|---|
| 443 |
shttp_msg = (ShttpMessage *) malloc(sizeof(ShttpMessage)); |
|---|
| 444 |
if (shttp_msg == NULL) { |
|---|
| 445 |
status = WSMAN_STATUS_INTERNAL_SERVER_ERROR; |
|---|
| 446 |
fault_reason = "No memory"; |
|---|
| 447 |
goto DONE; |
|---|
| 448 |
} |
|---|
| 449 |
|
|---|
| 450 |
|
|---|
| 451 |
shttp_msg->length = u_buf_len(wsman_msg->response); |
|---|
| 452 |
debug("message len = %d", shttp_msg->length); |
|---|
| 453 |
shttp_msg->response = u_buf_steal(wsman_msg->response); |
|---|
| 454 |
shttp_msg->ind = 0; |
|---|
| 455 |
|
|---|
| 456 |
DONE: |
|---|
| 457 |
wsman_soap_message_destroy(wsman_msg); |
|---|
| 458 |
if(cntx) { |
|---|
| 459 |
u_free(cntx->servicepath); |
|---|
| 460 |
u_free(cntx); |
|---|
| 461 |
} |
|---|
| 462 |
if (fault_reason == NULL) { |
|---|
| 463 |
fault_reason = shttp_reason_phrase(status); |
|---|
| 464 |
} |
|---|
| 465 |
debug("Response (status) %d (%s)", status, fault_reason); |
|---|
| 466 |
|
|---|
| 467 |
// Here we begin to create the http response. |
|---|
| 468 |
// Create the headers at first. |
|---|
| 469 |
// We consider output buffer of server is large enough to hold all headers. |
|---|
| 470 |
|
|---|
| 471 |
n += snprintf(arg->buf + n, arg->buflen - n, "HTTP/1.1 %d %s\r\n", |
|---|
| 472 |
status, fault_reason); |
|---|
| 473 |
n += snprintf(arg->buf + n, arg->buflen - n, "Server: %s/%s\r\n", |
|---|
| 474 |
PACKAGE, VERSION); |
|---|
| 475 |
if (status != WSMAN_STATUS_OK) { |
|---|
| 476 |
n += snprintf(arg->buf + n, arg->buflen -n, "\r\n%d %s\r\n", |
|---|
| 477 |
status, fault_reason); |
|---|
| 478 |
arg->last = 1; |
|---|
| 479 |
u_free(shttp_msg); |
|---|
| 480 |
return n; |
|---|
| 481 |
} |
|---|
| 482 |
if (!shttp_msg || shttp_msg->length == 0) { |
|---|
| 483 |
// can't send the body of response or nothing to send |
|---|
| 484 |
n += snprintf(arg->buf + n, arg->buflen - n, "\r\n"); |
|---|
| 485 |
arg->last = 1; |
|---|
| 486 |
u_free(shttp_msg); |
|---|
| 487 |
return n; |
|---|
| 488 |
} |
|---|
| 489 |
n += snprintf(arg->buf + n, arg->buflen - n, |
|---|
| 490 |
"Content-Type: application/xml; charset=\"utf-8\"\r\n"); |
|---|
| 491 |
n += snprintf(arg->buf + n, arg->buflen - n, |
|---|
| 492 |
"Content-Length: %d\r\n", shttp_msg->length); |
|---|
| 493 |
n += snprintf(arg->buf + n, arg->buflen - n, |
|---|
| 494 |
"CIMExport: MethodResponse\r\n"); |
|---|
| 495 |
n += snprintf(arg->buf + n, arg->buflen - n, "\r\n"); |
|---|
| 496 |
// add response body to output buffer |
|---|
| 497 |
CONTINUE: |
|---|
| 498 |
k = arg->buflen - n; |
|---|
| 499 |
if (k <= shttp_msg->length - shttp_msg->ind) { |
|---|
| 500 |
// not enogh room for all message. transfer only part |
|---|
| 501 |
memcpy(arg->buf + n, shttp_msg->response + shttp_msg->ind, |
|---|
| 502 |
k); |
|---|
| 503 |
shttp_msg->ind += k; |
|---|
| 504 |
arg->state = shttp_msg; |
|---|
| 505 |
return n + k; |
|---|
| 506 |
} |
|---|
| 507 |
// Enough room for all response body |
|---|
| 508 |
memcpy(arg->buf + n, shttp_msg->response + shttp_msg->ind, |
|---|
| 509 |
shttp_msg->length - shttp_msg->ind); |
|---|
| 510 |
n += shttp_msg->length - shttp_msg->ind; |
|---|
| 511 |
if (n + 4 > arg->buflen) { |
|---|
| 512 |
// not enough room for empty lines at the end of the message |
|---|
| 513 |
arg->state = shttp_msg; |
|---|
| 514 |
shttp_msg->ind = shttp_msg->length; |
|---|
| 515 |
return n; |
|---|
| 516 |
} |
|---|
| 517 |
// here we can complete |
|---|
| 518 |
n += snprintf(arg->buf + n, arg->buflen - n, "\r\n\r\n"); |
|---|
| 519 |
// debug("************\n%s\n***********", arg->buf); |
|---|
| 520 |
u_free(shttp_msg->response); |
|---|
| 521 |
u_free(shttp_msg); |
|---|
| 522 |
|
|---|
| 523 |
arg->last = 1; |
|---|
| 524 |
arg->state = NULL; |
|---|
| 525 |
return n; |
|---|
| 526 |
} |
|---|
| 527 |
#endif |
|---|
| 528 |
|
|---|
| 529 |
static void wsmand_start_notification_manager(WsContextH cntx, SubsRepositoryEntryH entry, int subsNum) |
|---|
| 530 |
{ |
|---|
| 531 |
WsmanMessage *wsman_msg = wsman_soap_message_new(); |
|---|
| 532 |
if(wsman_msg == NULL) return; |
|---|
| 533 |
unsigned char *strdoc = entry->strdoc; |
|---|
| 534 |
u_buf_construct(wsman_msg->request, strdoc, entry->len, entry->len); |
|---|
| 535 |
dispatch_inbound_call(cntx->soap, wsman_msg, NULL); |
|---|
| 536 |
wsman_soap_message_destroy(wsman_msg); |
|---|
| 537 |
if(list_count(cntx->soap->subscriptionMemList) > subsNum) { |
|---|
| 538 |
lnode_t *node = list_last(cntx->soap->subscriptionMemList); |
|---|
| 539 |
WsSubscribeInfo *subs = (WsSubscribeInfo *)node->list_data; |
|---|
| 540 |
//Delete new subscription file coz in fact we've got it |
|---|
| 541 |
// cntx->soap->subscriptionOpSet->delete_subscription(cntx->soap->uri_subsRepository, subs->subsId); |
|---|
| 542 |
//Update UUID in the memory |
|---|
| 543 |
strncpy(subs->subsId, entry->uuid+5, EUIDLEN); |
|---|
| 544 |
} |
|---|
| 545 |
} |
|---|
| 546 |
|
|---|
| 547 |
static int wsmand_clean_subsrepository(SoapH soap, SubsRepositoryEntryH entry) |
|---|
| 548 |
{ |
|---|
| 549 |
int retVal = 0; |
|---|
| 550 |
WsXmlDocH doc = ws_xml_read_memory( (char *)entry->strdoc, entry->len, "UTF-8", 0); |
|---|
| 551 |
|
|---|
| 552 |
if(doc) { |
|---|
| 553 |
WsXmlNodeH node = ws_xml_get_soap_body(doc); |
|---|
| 554 |
if(node) { |
|---|
| 555 |
node = ws_xml_get_child(node, 0, XML_NS_EVENTING, WSEVENT_SUBSCRIBE); |
|---|
| 556 |
node = ws_xml_get_child(node, 0, XML_NS_EVENTING, WSEVENT_EXPIRES); |
|---|
| 557 |
if(node == NULL) { //No specified expiration, delete it |
|---|
| 558 |
debug("subscription %s deleted from the repository", entry->uuid); |
|---|
| 559 |
soap->subscriptionOpSet->delete_subscription(soap->uri_subsRepository, entry->uuid+5); |
|---|
| 560 |
retVal = 1; |
|---|
| 561 |
} |
|---|
| 562 |
} |
|---|
| 563 |
ws_xml_destroy_doc(doc); |
|---|
| 564 |
} |
|---|
| 565 |
return retVal; |
|---|
| 566 |
} |
|---|
| 567 |
|
|---|
| 568 |
static void listener_shutdown_handler(void *p) |
|---|
| 569 |
{ |
|---|
| 570 |
int *a = (int *) p; |
|---|
| 571 |
debug("listener_shutdown_handler started"); |
|---|
| 572 |
*a = 0; |
|---|
| 573 |
} |
|---|
| 574 |
|
|---|
| 575 |
|
|---|
| 576 |
static struct shttpd_ctx *create_shttpd_context(SoapH soap) |
|---|
| 577 |
{ |
|---|
| 578 |
struct shttpd_ctx *ctx; |
|---|
| 579 |
if (wsmand_options_get_use_ssl()) { |
|---|
| 580 |
message("Using SSL"); |
|---|
| 581 |
ctx = shttpd_init(NULL, |
|---|
| 582 |
"ssl_certificate", |
|---|
| 583 |
wsmand_options_get_ssl_cert_file(), |
|---|
| 584 |
"ssl_priv_key", |
|---|
| 585 |
wsmand_options_get_ssl_key_file(), |
|---|
| 586 |
"auth_realm", AUTHENTICATION_REALM, |
|---|
| 587 |
"debug", |
|---|
| 588 |
wsmand_options_get_debug_level() > |
|---|
| 589 |
0 ? "1" : "0", NULL); |
|---|
| 590 |
} else { |
|---|
| 591 |
ctx = shttpd_init(NULL, |
|---|
| 592 |
"auth_realm", AUTHENTICATION_REALM, |
|---|
| 593 |
"debug", |
|---|
| 594 |
wsmand_options_get_debug_level() > |
|---|
| 595 |
0 ? "1" : "0", NULL); |
|---|
| 596 |
} |
|---|
| 597 |
if (ctx == NULL) { |
|---|
| 598 |
return NULL; |
|---|
| 599 |
} |
|---|
| 600 |
shttpd_register_url(ctx, wsmand_options_get_service_path(), |
|---|
| 601 |
server_callback, 0, (void *) soap); |
|---|
| 602 |
#ifdef ENABLE_EVENTING_SUPPORT |
|---|
| 603 |
list_t *listenerpath = get_cimxml_listener_path(); |
|---|
| 604 |
if(listenerpath) { |
|---|
| 605 |
lnode_t *node = list_first(listenerpath); |
|---|
| 606 |
while(node) { |
|---|
| 607 |
char *path = (char *)node->list_data; |
|---|
| 608 |
cimxml_context *cimcntx = u_malloc(sizeof(cimxml_context)); |
|---|
| 609 |
cimcntx->servicepath = u_strdup(path); |
|---|
| 610 |
cimcntx->soap = soap; |
|---|
| 611 |
shttpd_register_url(ctx, path, cimxml_listener_callback, |
|---|
| 612 |
0, (void *)cimcntx); |
|---|
| 613 |
debug("********registered service path: %s*********", path); |
|---|
| 614 |
node = list_next(listenerpath, node); |
|---|
| 615 |
} |
|---|
| 616 |
} |
|---|
| 617 |
#endif |
|---|
| 618 |
if (wsmand_options_get_digest_password_file()) { |
|---|
| 619 |
shttpd_register_dauth_callback(ctx, digest_auth_callback); |
|---|
| 620 |
debug("Using Digest Authorization"); |
|---|
| 621 |
} |
|---|
| 622 |
if (basic_auth_callback) { |
|---|
| 623 |
shttpd_register_bauth_callback(ctx, basic_auth_callback); |
|---|
| 624 |
debug("Using Basic Authorization %s", |
|---|
| 625 |
wsmand_option_get_basic_authenticator()? |
|---|
| 626 |
wsmand_option_get_basic_authenticator() : |
|---|
| 627 |
wsmand_default_basic_authenticator()); |
|---|
| 628 |
} |
|---|
| 629 |
|
|---|
| 630 |
return ctx; |
|---|
| 631 |
} |
|---|
| 632 |
|
|---|
| 633 |
#ifdef MULTITHREADED_SERVER |
|---|
| 634 |
|
|---|
| 635 |
static void handle_socket(int sock, SoapH soap) |
|---|
| 636 |
{ |
|---|
| 637 |
struct shttpd_ctx *ctx; |
|---|
| 638 |
|
|---|
| 639 |
debug("Thread %d handles sock %d", pthread_self(), sock); |
|---|
| 640 |
|
|---|
| 641 |
ctx = create_shttpd_context(soap); |
|---|
| 642 |
if (ctx == NULL) { |
|---|
| 643 |
(void) shutdown(sock, 2); |
|---|
| 644 |
close(sock); |
|---|
| 645 |
return; |
|---|
| 646 |
} |
|---|
| 647 |
shttpd_add(ctx, sock); |
|---|
| 648 |
while (shttpd_active(ctx) && continue_working) { |
|---|
| 649 |
shttpd_poll(ctx, 100); |
|---|
| 650 |
} |
|---|
| 651 |
shttpd_fini(ctx); |
|---|
| 652 |
debug("Thread %d processed sock %d", pthread_self(), sock); |
|---|
| 653 |
} |
|---|
| 654 |
|
|---|
| 655 |
|
|---|
| 656 |
static void *service_connection(void *arg) |
|---|
| 657 |
{ |
|---|
| 658 |
lnode_t *node; |
|---|
| 659 |
int sock; |
|---|
| 660 |
SoapH soap = (SoapH) arg; |
|---|
| 661 |
|
|---|
| 662 |
debug("shttpd thread %d started. num_threads = %d", |
|---|
| 663 |
pthread_self(), num_threads); |
|---|
| 664 |
pthread_mutex_lock(&shttpd_mutex); |
|---|
| 665 |
while (continue_working) { |
|---|
| 666 |
if (list_isempty(request_list)) { |
|---|
| 667 |
// no sockets to serve |
|---|
| 668 |
if (num_threads > min_threads) { |
|---|
| 669 |
debug("we have too many threads %d > %d" |
|---|
| 670 |
" Thread %d is being completed", |
|---|
| 671 |
num_threads, min_threads, |
|---|
| 672 |
pthread_self()); |
|---|
| 673 |
break; |
|---|
| 674 |
} else { |
|---|
| 675 |
idle_threads++; |
|---|
| 676 |
debug("Thread %d goes to idle state", |
|---|
| 677 |
pthread_self()); |
|---|
| 678 |
(void) pthread_cond_wait(&shttpd_cond, |
|---|
| 679 |
&shttpd_mutex); |
|---|
| 680 |
idle_threads--; |
|---|
| 681 |
continue; |
|---|
| 682 |
} |
|---|
| 683 |
} |
|---|
| 684 |
node = list_del_first(request_list); |
|---|
| 685 |
sock = (int) ((char *) lnode_get(node) - (char *) NULL); |
|---|
| 686 |
pthread_mutex_unlock(&shttpd_mutex); |
|---|
| 687 |
lnode_destroy(node); |
|---|
| 688 |
handle_socket(sock, soap); |
|---|
| 689 |
pthread_mutex_lock(&shttpd_mutex); |
|---|
| 690 |
} |
|---|
| 691 |
num_threads--; |
|---|
| 692 |
debug("shttpd thread %d completed. num_threads = %d", |
|---|
| 693 |
pthread_self(), num_threads); |
|---|
| 694 |
if (num_threads == 0 && continue_working == 0) { |
|---|
| 695 |
debug("last thread completed"); |
|---|
| 696 |
pthread_cond_broadcast(&shttpd_cond); |
|---|
| 697 |
} |
|---|
| 698 |
pthread_mutex_unlock(&shttpd_mutex); |
|---|
| 699 |
return NULL; |
|---|
| 700 |
} |
|---|
| 701 |
|
|---|
| 702 |
#endif |
|---|
| 703 |
|
|---|
| 704 |
|
|---|
| 705 |
static int initialize_basic_authenticator(void) |
|---|
| 706 |
{ |
|---|
| 707 |
char *auth; |
|---|
| 708 |
char *arg; |
|---|
| 709 |
void *hnd; |
|---|
| 710 |
int (*init) (char *); |
|---|
| 711 |
char *name; |
|---|
| 712 |
int should_return = 0; |
|---|
| 713 |
int res = 0; |
|---|
| 714 |
|
|---|
| 715 |
if (wsmand_options_get_basic_password_file() != NULL) { |
|---|
| 716 |
if ((wsmand_option_get_basic_authenticator() && |
|---|
| 717 |
(strcmp(wsmand_default_basic_authenticator(), |
|---|
| 718 |
wsmand_option_get_basic_authenticator()))) || |
|---|
| 719 |
wsmand_option_get_basic_authenticator_arg()) { |
|---|
| 720 |
fprintf(stderr, |
|---|
| 721 |
"basic authentication is ambigious in config file\n"); |
|---|
| 722 |
return 1; |
|---|
| 723 |
} |
|---|
| 724 |
auth = wsmand_default_basic_authenticator(); |
|---|
| 725 |
arg = wsmand_options_get_basic_password_file(); |
|---|
| 726 |
} else { |
|---|
| 727 |
auth = wsmand_option_get_basic_authenticator(); |
|---|
| 728 |
arg = wsmand_option_get_basic_authenticator_arg(); |
|---|
| 729 |
} |
|---|
| 730 |
|
|---|
| 731 |
if (auth == NULL) { |
|---|
| 732 |
// No basic authenticationame |
|---|
| 733 |
return 0; |
|---|
| 734 |
} |
|---|
| 735 |
|
|---|
| 736 |
if (auth[0] == '/') { |
|---|
| 737 |
name = auth; |
|---|
| 738 |
} else { |
|---|
| 739 |
name = u_strdup_printf("%s/%s", PACKAGE_AUTH_DIR, auth); |
|---|
| 740 |
should_return = 1; |
|---|
| 741 |
} |
|---|
| 742 |
|
|---|
| 743 |
hnd = dlopen(name, RTLD_LAZY | RTLD_GLOBAL); |
|---|
| 744 |
if (hnd == NULL) { |
|---|
| 745 |
fprintf(stderr, "Could not dlopen %s\n", name); |
|---|
| 746 |
res = 1; |
|---|
| 747 |
goto DONE; |
|---|
| 748 |
} |
|---|
| 749 |
basic_auth_callback = dlsym(hnd, "authorize"); |
|---|
| 750 |
if (basic_auth_callback == NULL) { |
|---|
| 751 |
fprintf(stderr, "Could not resolve authorize() in %s\n", |
|---|
| 752 |
name); |
|---|
| 753 |
res = 1; |
|---|
| 754 |
goto DONE; |
|---|
| 755 |
} |
|---|
| 756 |
|
|---|
| 757 |
init = dlsym(hnd, "initialize"); |
|---|
| 758 |
if (init != NULL) { |
|---|
| 759 |
res = init(arg); |
|---|
| 760 |
} |
|---|
| 761 |
DONE: |
|---|
| 762 |
if (should_return) { |
|---|
| 763 |
u_free(name); |
|---|
| 764 |
} |
|---|
| 765 |
return res; |
|---|
| 766 |
} |
|---|
| 767 |
|
|---|
| 768 |
|
|---|
| 769 |
WsManListenerH *wsmand_start_server(dictionary * ini) |
|---|
| 770 |
{ |
|---|
| 771 |
WsManListenerH *listener = wsman_dispatch_list_new(); |
|---|
| 772 |
listener->config = ini; |
|---|
| 773 |
WsContextH cntx = wsman_init_plugins(listener); |
|---|
| 774 |
#ifdef ENABLE_EVENTING_SUPPORT |
|---|
| 775 |
SubsRepositoryOpSetH ops = wsman_init_subscription_repository(cntx, wsmand_options_get_subscription_repository_uri()); |
|---|
| 776 |
list_t *subs_list = list_create(-1); |
|---|
| 777 |
debug("subscription_repository_uri = %s", wsmand_options_get_subscription_repository_uri()); |
|---|
| 778 |
if(ops->load_subscription(wsmand_options_get_subscription_repository_uri(), subs_list) == 0) { |
|---|
| 779 |
lnode_t *node = list_first(subs_list); |
|---|
| 780 |
while(node) { |
|---|
| 781 |
SubsRepositoryEntryH entry = (SubsRepositoryEntryH)node->list_data; |
|---|
| 782 |
if(wsmand_clean_subsrepository(cntx->soap, entry) == 0) { |
|---|
| 783 |
debug("load subscription %s", entry->uuid); |
|---|
| 784 |
wsmand_start_notification_manager(cntx, entry, list_count(cntx->soap->subscriptionMemList)); |
|---|
| 785 |
} |
|---|
| 786 |
u_free(entry->uuid); |
|---|
| 787 |
u_free(entry); |
|---|
| 788 |
list_delete(subs_list, node); |
|---|
| 789 |
lnode_destroy(node); |
|---|
| 790 |
node = list_first(subs_list); |
|---|
| 791 |
} |
|---|
| 792 |
} |
|---|
| 793 |
list_destroy(subs_list); |
|---|
| 794 |
wsman_init_event_pool(cntx, NULL); |
|---|
| 795 |
#endif |
|---|
| 796 |
#ifdef MULTITHREADED_SERVER |
|---|
| 797 |
int r; |
|---|
| 798 |
int sock; |
|---|
| 799 |
lnode_t *node; |
|---|
| 800 |
pthread_t thr_id; |
|---|
| 801 |
pthread_t notificationManager_id; |
|---|
| 802 |
pthread_attr_t pattrs; |
|---|
| 803 |
struct timespec timespec; |
|---|
| 804 |
#else |
|---|
| 805 |
struct shttpd_ctx *ctx; |
|---|
| 806 |
|
|---|
| 807 |
#endif |
|---|
| 808 |
|
|---|
| 809 |
if (cntx == NULL) { |
|---|
| 810 |
return listener; |
|---|
| 811 |
} |
|---|
| 812 |
#ifndef HAVE_SSL |
|---|
| 813 |
if (wsmand_options_get_use_ssl()) { |
|---|
| 814 |
error("Server configured without SSL support"); |
|---|
| 815 |
return listener; |
|---|
| 816 |
} |
|---|
| 817 |
#endif |
|---|
| 818 |
SoapH soap = ws_context_get_runtime(cntx); |
|---|
| 819 |
ws_set_context_enumIdleTimeout(cntx, |
|---|
| 820 |
wsmand_options_get_enumIdleTimeout |
|---|
| 821 |
()); |
|---|
| 822 |
if (initialize_basic_authenticator()) { |
|---|
| 823 |
return listener; |
|---|
| 824 |
} |
|---|
| 825 |
|
|---|
| 826 |
int lsn; |
|---|
| 827 |
int port; |
|---|
| 828 |
|
|---|
| 829 |
|
|---|
| 830 |
if (wsmand_options_get_use_ssl()) { |
|---|
| 831 |
message("Using SSL"); |
|---|
| 832 |
if (wsmand_options_get_ssl_cert_file() && |
|---|
| 833 |
wsmand_options_get_ssl_key_file() && |
|---|
| 834 |
(wsmand_options_get_server_ssl_port() > 0)) { |
|---|
| 835 |
port = wsmand_options_get_server_ssl_port(); |
|---|
| 836 |
} else { |
|---|
| 837 |
error("Not enough data to use SSL port"); |
|---|
| 838 |
return listener; |
|---|
| 839 |
} |
|---|
| 840 |
} else { |
|---|
| 841 |
port = wsmand_options_get_server_port(); |
|---|
| 842 |
} |
|---|
| 843 |
|
|---|
| 844 |
message(" Working on port %d", port); |
|---|
| 845 |
if (wsmand_options_get_digest_password_file()) { |
|---|
| 846 |
message("Using Digest Authorization"); |
|---|
| 847 |
} |
|---|
| 848 |
if (basic_auth_callback) { |
|---|
| 849 |
message("Using Basic Authorization %s", |
|---|
| 850 |
wsmand_option_get_basic_authenticator()? |
|---|
| 851 |
wsmand_option_get_basic_authenticator() : |
|---|
| 852 |
wsmand_default_basic_authenticator()); |
|---|
| 853 |
} |
|---|
| 854 |
|
|---|
| 855 |
if ((wsmand_options_get_digest_password_file() == NULL) && |
|---|
| 856 |
(basic_auth_callback == NULL)) { |
|---|
| 857 |
error("Server does not work without authentication"); |
|---|
| 858 |
return listener; |
|---|
| 859 |
} |
|---|
| 860 |
|
|---|
| 861 |
wsmand_shutdown_add_handler(listener_shutdown_handler, |
|---|
| 862 |
&continue_working); |
|---|
| 863 |
|
|---|
| 864 |
lsn = shttpd_open_port(port); |
|---|
| 865 |
|
|---|
| 866 |
#ifdef MULTITHREADED_SERVER |
|---|
| 867 |
if ((r = pthread_cond_init(&shttpd_cond, NULL)) != 0) { |
|---|
| 868 |
debug("pthread_cond_init failed = %d", r); |
|---|
| 869 |
return listener; |
|---|
| 870 |
} |
|---|
| 871 |
if ((r = pthread_mutex_init(&shttpd_mutex, NULL)) != 0) { |
|---|
| 872 |
debug("pthread_mutex_init failed = %d", r); |
|---|
| 873 |
return listener; |
|---|
| 874 |
} |
|---|
| 875 |
|
|---|
| 876 |
if ((r = pthread_attr_init(&pattrs)) != 0) { |
|---|
| 877 |
debug("pthread_attr_init failed = %d", r); |
|---|
| 878 |
return listener; |
|---|
| 879 |
} |
|---|
| 880 |
|
|---|
| 881 |
if ((r = pthread_attr_setdetachstate(&pattrs, |
|---|
| 882 |
PTHREAD_CREATE_DETACHED)) != 0) { |
|---|
| 883 |
debug("pthread_attr_setdetachstate = %d", r); |
|---|
| 884 |
return listener; |
|---|
| 885 |
} |
|---|
| 886 |
|
|---|
| 887 |
request_list = list_create(LISTCOUNT_T_MAX); |
|---|
| 888 |
|
|---|
| 889 |
min_threads = wsmand_options_get_min_threads(); |
|---|
| 890 |
max_threads = wsmand_options_get_max_threads(); |
|---|
| 891 |
|
|---|
| 892 |
pthread_create(&thr_id, &pattrs, |
|---|
| 893 |
wsman_server_auxiliary_loop_thread, cntx); |
|---|
| 894 |
#ifdef ENABLE_EVENTING_SUPPORT |
|---|
| 895 |
pthread_create(¬ificationManager_id, &pattrs, wsman_notification_manager, cntx); |
|---|
| 896 |
#endif |
|---|
| 897 |
while (continue_working) { |
|---|
| 898 |
if ((sock = shttpd_accept(lsn, 1000)) == -1) { |
|---|
| 899 |
continue; |
|---|
| 900 |
} |
|---|
| 901 |
debug("Sock %d accepted", sock); |
|---|
| 902 |
node = lnode_create((void *) ((char *) NULL + sock)); |
|---|
| 903 |
if (node == NULL) { |
|---|
| 904 |
debug("lnode_create == NULL"); |
|---|
| 905 |
(void) shutdown(sock, 2); |
|---|
| 906 |
close(sock); |
|---|
| 907 |
continue; |
|---|
| 908 |
} |
|---|
| 909 |
|
|---|
| 910 |
pthread_mutex_lock(&shttpd_mutex); |
|---|
| 911 |
|
|---|
| 912 |
list_append(request_list, node); |
|---|
| 913 |
if (idle_threads > 0) { |
|---|
| 914 |
// we have idle thread waiting for a request |
|---|
| 915 |
debug("using idle thread. idle_threads = %d", |
|---|
| 916 |
idle_threads); |
|---|
| 917 |
pthread_cond_signal(&shttpd_cond); |
|---|
| 918 |
pthread_mutex_unlock(&shttpd_mutex); |
|---|
| 919 |
continue; |
|---|
| 920 |
} |
|---|
| 921 |
if (num_threads >= max_threads) { |
|---|
| 922 |
// we have enough threads to serve requests |
|---|
| 923 |
debug("Using existing thread. %d > %d", |
|---|
| 924 |
num_threads, max_threads); |
|---|
| 925 |
pthread_mutex_unlock(&shttpd_mutex); |
|---|
| 926 |
continue; |
|---|
| 927 |
} |
|---|
| 928 |
debug("Creating new thread. Old num_threads = %d", |
|---|
| 929 |
num_threads); |
|---|
| 930 |
r = pthread_create(&thr_id, &pattrs, service_connection, |
|---|
| 931 |
soap); |
|---|
| 932 |
if (r == 0) { |
|---|
| 933 |
num_threads++; |
|---|
| 934 |
debug("Thread %d created", thr_id); |
|---|
| 935 |
pthread_mutex_unlock(&shttpd_mutex); |
|---|
| 936 |
continue; |
|---|
| 937 |
} |
|---|
| 938 |
debug("pthread_create failed = %d. num_threads = %d", |
|---|
| 939 |
r, num_threads); |
|---|
| 940 |
if (num_threads > 0) { |
|---|
| 941 |
// we have threads to serve request |
|---|
| 942 |
debug |
|---|
| 943 |
("we have threads to serve request. num_threads = %d", |
|---|
| 944 |
num_threads); |
|---|
| 945 |
pthread_mutex_unlock(&shttpd_mutex); |
|---|
| 946 |
continue; |
|---|
| 947 |
} |
|---|
| 948 |
|
|---|
| 949 |
// So we couldn't create even one thread. Serve the request here |
|---|
| 950 |
debug("Serve on main thread"); |
|---|
| 951 |
node = list_delete(request_list, node); |
|---|
| 952 |
if (node) { |
|---|
| 953 |
lnode_destroy(node); |
|---|
| 954 |
} else { |
|---|
| 955 |
error("Coundn't find node in a list"); |
|---|
| 956 |
} |
|---|
| 957 |
|
|---|
| 958 |
pthread_mutex_unlock(&shttpd_mutex); |
|---|
| 959 |
|
|---|
| 960 |
handle_socket(sock, soap); |
|---|
| 961 |
} |
|---|
| 962 |
|
|---|
| 963 |
pthread_mutex_lock(&shttpd_mutex); |
|---|
| 964 |
while (num_threads > 0) { |
|---|
| 965 |
pthread_cond_broadcast(&shttpd_cond); |
|---|
| 966 |
timespec.tv_sec = 1; |
|---|
| 967 |
timespec.tv_nsec = 0; |
|---|
| 968 |
pthread_cond_timedwait(&shttpd_cond, &shttpd_mutex, |
|---|
| 969 |
×pec); |
|---|
| 970 |
} |
|---|
| 971 |
pthread_mutex_unlock(&shttpd_mutex); |
|---|
| 972 |
|
|---|
| 973 |
#else |
|---|
| 974 |
ctx = create_shttpd_context(soap); |
|---|
| 975 |
if (ctx == NULL) { |
|---|
| 976 |
error("Could not create shttpd context"); |
|---|
| 977 |
return listener; |
|---|
| 978 |
} |
|---|
| 979 |
shttpd_listen(ctx, lsn); |
|---|
| 980 |
while (continue_working) { |
|---|
| 981 |
shttpd_poll(ctx, 1000); |
|---|
| 982 |
} |
|---|
| 983 |
shttpd_fini(ctx); |
|---|
| 984 |
|
|---|
| 985 |
#endif |
|---|
| 986 |
debug("shttpd_poll loop canceled"); |
|---|
| 987 |
|
|---|
| 988 |
return listener; |
|---|
| 989 |
} |
|---|