annotate src/c/fastcgi.c @ 862:66dbf3953758

Fix memory leak in fastcgi environment management
author Adam Chlipala <adamc@hcoop.net>
date Sat, 27 Jun 2009 16:56:32 -0400
parents bd153951c794
children 305bc0a431de
rev   line source
adamc@859 1 #define _GNU_SOURCE
adamc@859 2
adamc@859 3 #include <stdio.h>
adamc@859 4 #include <string.h>
adamc@859 5 #include <stdlib.h>
adamc@859 6 #include <sys/types.h>
adamc@859 7 #include <sys/socket.h>
adamc@859 8 #include <netdb.h>
adamc@859 9 #include <netinet/in.h>
adamc@859 10 #include <unistd.h>
adamc@859 11 #include <signal.h>
adamc@859 12 #include <stdarg.h>
adamc@859 13
adamc@859 14 #include <pthread.h>
adamc@859 15
adamc@859 16 #include "urweb.h"
adamc@859 17 #include "request.h"
adamc@859 18 #include "queue.h"
adamc@859 19
adamc@859 20 #include "fastcgi.h"
adamc@859 21
adamc@859 22 typedef struct {
adamc@859 23 unsigned char version;
adamc@859 24 unsigned char type;
adamc@859 25 unsigned char requestIdB1;
adamc@859 26 unsigned char requestIdB0;
adamc@859 27 unsigned char contentLengthB1;
adamc@859 28 unsigned char contentLengthB0;
adamc@859 29 unsigned char paddingLength;
adamc@859 30 unsigned char reserved;
adamc@859 31 unsigned char contentData[65535];
adamc@859 32 } FCGI_Record;
adamc@859 33
adamc@859 34 typedef struct {
adamc@859 35 FCGI_Record r;
adamc@859 36 int sock;
adamc@859 37 } FCGI_Output;
adamc@859 38
adamc@859 39 typedef struct {
adamc@859 40 char buf[sizeof(FCGI_Record) + 255];
adamc@859 41 int available, used, sock;
adamc@859 42 } FCGI_Input;
adamc@859 43
adamc@859 44 static FCGI_Output *fastcgi_output() {
adamc@859 45 FCGI_Output *o = malloc(sizeof(FCGI_Output));
adamc@859 46
adamc@859 47 o->r.version = FCGI_VERSION_1;
adamc@859 48 o->r.paddingLength = 0;
adamc@859 49 o->r.reserved = 0;
adamc@859 50
adamc@859 51 return o;
adamc@859 52 }
adamc@859 53
adamc@859 54 static FCGI_Input *fastcgi_input() {
adamc@859 55 FCGI_Input *i = malloc(sizeof(FCGI_Input));
adamc@859 56
adamc@859 57 i->available = i->used = 0;
adamc@859 58
adamc@859 59 return i;
adamc@859 60 }
adamc@859 61
adamc@859 62 static void fastcgi_input_reset(FCGI_Input *i) {
adamc@859 63 i->available = i->used = 0;
adamc@859 64 }
adamc@859 65
adamc@859 66 static int fastcgi_send(FCGI_Output *o,
adamc@859 67 unsigned char type,
adamc@859 68 unsigned short contentLength) {
adamc@859 69 o->r.type = type;
adamc@860 70 o->r.requestIdB1 = o->r.requestIdB0 = 0;
adamc@859 71 o->r.contentLengthB1 = contentLength >> 8;
adamc@859 72 o->r.contentLengthB0 = contentLength & 255;
adamc@861 73 return uw_really_send(o->sock, &o->r, sizeof(o->r) - 65535 + contentLength);
adamc@859 74 }
adamc@859 75
adamc@859 76 #define LATEST(i) ((FCGI_Record *)(i->buf + i->used))
adamc@859 77
adamc@859 78 static FCGI_Record *fastcgi_recv(FCGI_Input *i) {
adamc@859 79 while (1) {
adamc@859 80 ssize_t n;
adamc@859 81
adamc@859 82 if (i->available >= i->used + sizeof(FCGI_Record) - 65535
adamc@859 83 && i->available >= i->used + sizeof(FCGI_Record) - 65535
adamc@860 84 + ((LATEST(i)->contentLengthB1 << 8) | LATEST(i)->contentLengthB0)
adamc@859 85 + LATEST(i)->paddingLength) {
adamc@859 86 FCGI_Record *r = LATEST(i);
adamc@859 87
adamc@859 88 i->used += sizeof(FCGI_Record) - 65535
adamc@860 89 + ((LATEST(i)->contentLengthB1 << 8) | LATEST(i)->contentLengthB0)
adamc@859 90 + LATEST(i)->paddingLength;
adamc@859 91
adamc@859 92 return r;
adamc@859 93 }
adamc@859 94
adamc@859 95 if (i->used > 0) {
adamc@859 96 memmove(i->buf, i->buf + i->used, i->available - i->used);
adamc@859 97 i->available -= i->used;
adamc@859 98 i->used = 0;
adamc@859 99 }
adamc@859 100
adamc@859 101 n = recv(i->sock, i->buf + i->available, sizeof(i->buf) - i->available, 0);
adamc@859 102
adamc@859 103 if (n <= 0)
adamc@859 104 return NULL;
adamc@859 105
adamc@859 106 i->available += n;
adamc@859 107 }
adamc@859 108 }
adamc@859 109
adamc@859 110 static void on_success(uw_context ctx) { }
adamc@859 111
adamc@859 112 static void on_failure(uw_context ctx) {
adamc@859 113 uw_write_header(ctx, "Status: 500 Internal Server Error\r\n");
adamc@859 114 }
adamc@859 115
adamc@860 116 static int write_stdout(void *data, char *buf, size_t len) {
adamc@860 117 FCGI_Output *o = (FCGI_Output *)data;
adamc@860 118 while (len > 0) {
adamc@860 119 size_t len2 = len;
adamc@860 120 if (len2 > 65535)
adamc@860 121 len2 = 65535;
adamc@860 122 memcpy(o->r.contentData, buf, len2);
adamc@860 123 if (fastcgi_send(o, FCGI_STDOUT, len2)) {
adamc@860 124 fprintf(stderr, "fastcgi_send() failed in write_stdout().\n");
adamc@860 125 return -1;
adamc@860 126 }
adamc@860 127 buf += len2;
adamc@860 128 len -= len2;
adamc@860 129 }
adamc@860 130
adamc@860 131 return 0;
adamc@860 132 }
adamc@860 133
adamc@859 134 static void write_stderr(FCGI_Output *o, const char *fmt, ...) {
adamc@859 135 int len;
adamc@859 136 va_list ap;
adamc@859 137 va_start(ap, fmt);
adamc@859 138
adamc@859 139 len = vsnprintf(o->r.contentData, 65535, fmt, ap);
adamc@859 140 if (len < 0)
adamc@860 141 fprintf(stderr, "vsnprintf() failed in write_stderr().\n");
adamc@860 142 else if (fastcgi_send(o, FCGI_STDERR, len))
adamc@860 143 fprintf(stderr, "fastcgi_send() failed in write_stderr().\n");
adamc@860 144 }
adamc@860 145
adamc@860 146 static void close_stream(FCGI_Output *o, unsigned char type) {
adamc@860 147 if (fastcgi_send(o, type, 0))
adamc@860 148 fprintf(stderr, "fastcgi_send() failed in close_stream().\n");
adamc@859 149 }
adamc@859 150
adamc@859 151 static void log_error(void *data, const char *fmt, ...) {
adamc@859 152 FCGI_Output *o = (FCGI_Output *)data;
adamc@859 153 va_list ap;
adamc@859 154 va_start(ap, fmt);
adamc@859 155
adamc@859 156 if (o) {
adamc@859 157 int len = vsnprintf(o->r.contentData, 65535, fmt, ap);
adamc@859 158 if (len < 0)
adamc@859 159 fprintf(stderr, "vsnprintf() failed in log_error().\n");
adamc@860 160 else if (fastcgi_send(o, FCGI_STDERR, len))
adamc@859 161 fprintf(stderr, "fastcgi_send() failed in log_error().\n");
adamc@859 162 } else
adamc@859 163 vfprintf(stderr, fmt, ap);
adamc@859 164 }
adamc@859 165
adamc@859 166 static void log_debug(void *data, const char *fmt, ...) {
adamc@859 167 }
adamc@859 168
adamc@860 169 typedef struct {
adamc@860 170 char *name, *value;
adamc@860 171 unsigned name_len, value_len;
adamc@860 172 } nvp;
adamc@860 173
adamc@860 174 static char *search_nvps(nvp *nvps, const char *h) {
adamc@862 175 for (; nvps->name[0]; ++nvps)
adamc@860 176 if (!strcmp(h, nvps->name))
adamc@860 177 return nvps->value;
adamc@860 178
adamc@860 179 return NULL;
adamc@860 180 }
adamc@860 181
adamc@860 182 typedef struct {
adamc@860 183 nvp *nvps;
adamc@860 184 char *uppercased;
adamc@860 185 int n_nvps, uppercased_len;
adamc@860 186 } headers;
adamc@860 187
adamc@860 188 static char *get_header(void *data, const char *h) {
adamc@860 189 headers *hs = (headers *)data;
adamc@860 190 size_t len = strlen(h);
adamc@860 191 char *s, *r;
adamc@860 192 const char *saved_h = h;
adamc@860 193
adamc@860 194 if (len > hs->uppercased_len) {
adamc@860 195 hs->uppercased_len = len;
adamc@860 196 hs->uppercased = realloc(hs->uppercased, len + 6);
adamc@860 197 }
adamc@860 198
adamc@860 199 strcpy(hs->uppercased, "HTTP_");
adamc@860 200 for (s = hs->uppercased+5; *h; ++h)
adamc@860 201 *s++ = *h == '-' ? '_' : toupper(*h);
adamc@860 202 *s = 0;
adamc@860 203
adamc@860 204 if (!strcasecmp(saved_h, "Content-length")
adamc@860 205 || !strcasecmp(saved_h, "Content-type"))
adamc@860 206 return search_nvps(hs->nvps, hs->uppercased + 5);
adamc@860 207 else
adamc@860 208 return search_nvps(hs->nvps, hs->uppercased);
adamc@860 209 }
adamc@860 210
adamc@861 211 static int read_funny_len(char **buf, int *len) {
adamc@861 212 if (*len <= 0)
adamc@861 213 return -1;
adamc@861 214
adamc@861 215 if ((*buf)[0] >> 7 == 0) {
adamc@861 216 int r = (*buf)[0];
adamc@861 217 ++*buf;
adamc@861 218 --*len;
adamc@861 219 return r;
adamc@861 220 }
adamc@861 221 else if (*len < 4)
adamc@861 222 return -1;
adamc@861 223 else {
adamc@861 224 int r = (((*buf)[3] & 0x7f) << 24) + ((*buf)[2] << 16) + ((*buf)[1] << 8) + (*buf)[0];
adamc@861 225 *buf += 4;
adamc@861 226 *len -= 4;
adamc@861 227 return r;
adamc@861 228 }
adamc@861 229 }
adamc@861 230
adamc@860 231 static int read_nvp(char *buf, int len, nvp *nv) {
adamc@860 232 int nameLength, valueLength;
adamc@860 233
adamc@860 234 if ((nameLength = read_funny_len(&buf, &len)) < 0)
adamc@860 235 return -1;
adamc@860 236 if ((valueLength = read_funny_len(&buf, &len)) < 0)
adamc@860 237 return -1;
adamc@860 238 if (len < nameLength + valueLength)
adamc@860 239 return -1;
adamc@860 240
adamc@862 241 if (nameLength+1 > nv->name_len) {
adamc@860 242 nv->name_len = nameLength+1;
adamc@862 243 nv->name = realloc(nv->name, nv->name_len);
adamc@860 244 }
adamc@862 245 if (valueLength+1 > nv->value_len) {
adamc@860 246 nv->value_len = valueLength+1;
adamc@862 247 nv->value = realloc(nv->value, nv->value_len);
adamc@860 248 }
adamc@860 249
adamc@860 250 memcpy(nv->name, buf, nameLength);
adamc@860 251 nv->name[nameLength] = 0;
adamc@860 252
adamc@860 253 memcpy(nv->value, buf + nameLength, valueLength);
adamc@860 254 nv->value[valueLength] = 0;
adamc@860 255
adamc@860 256 return 0;
adamc@860 257 }
adamc@860 258
adamc@859 259 static void *worker(void *data) {
adamc@859 260 int me = *(int *)data;
adamc@859 261 FCGI_Input *in = fastcgi_input();
adamc@859 262 FCGI_Output *out = fastcgi_output();
adamc@859 263 uw_context ctx = uw_request_new_context(out, log_error, log_debug);
adamc@859 264 uw_request_context rc = uw_new_request_context();
adamc@860 265 headers hs;
adamc@860 266 size_t body_size = 0;
adamc@860 267 char *body = malloc(0);
adamc@860 268 size_t path_size = 0;
adamc@860 269 char *path_buf = malloc(0);
adamc@861 270 int tries = 0;
adamc@860 271
adamc@860 272 hs.uppercased = malloc(0);
adamc@860 273 hs.uppercased_len = 0;
adamc@860 274 hs.nvps = malloc(sizeof(nvp));
adamc@860 275 hs.n_nvps = 1;
adamc@862 276 hs.nvps[0].name = malloc(1);
adamc@862 277 hs.nvps[0].name_len = 1;
adamc@862 278 hs.nvps[0].value = malloc(0);
adamc@862 279 hs.nvps[0].value_len = 0;
adamc@859 280
adamc@859 281 while (1) {
adamc@859 282 FCGI_Record *r;
adamc@860 283 size_t used_nvps = 0;
adamc@860 284 int body_len, body_read;
adamc@860 285 char *s;
adamc@860 286 char *method, *path, *path_info, *query_string;
adamc@859 287
adamc@859 288 in->sock = out->sock = uw_dequeue();
adamc@859 289
adamc@859 290 if (!(r = fastcgi_recv(in))) {
adamc@859 291 fprintf(stderr, "Error receiving initial message\n");
adamc@860 292 goto done;
adamc@859 293 }
adamc@861 294
adamc@859 295 if (r->type != FCGI_BEGIN_REQUEST) {
adamc@859 296 write_stderr(out, "First message is not BEGIN_REQUEST\n");
adamc@859 297 goto done;
adamc@859 298 } else if (((FCGI_BeginRequestBody *)&r->contentData)->roleB0 != FCGI_RESPONDER) {
adamc@859 299 write_stderr(out, "First message is not BEGIN_REQUEST\n");
adamc@859 300 goto done;
adamc@859 301 }
adamc@859 302
adamc@860 303 while (1) {
adamc@860 304 char *buf;
adamc@860 305
adamc@860 306 if (!(r = fastcgi_recv(in))) {
adamc@860 307 write_stderr(out, "Error receiving environment variables\n");
adamc@860 308 goto done;
adamc@860 309 }
adamc@860 310
adamc@860 311 if (r->type != FCGI_PARAMS) {
adamc@860 312 write_stderr(out, "Expected FCGI_PARAMS but got %d\n", r->type);
adamc@860 313 goto done;
adamc@860 314 }
adamc@860 315
adamc@860 316 if (r->contentLengthB1 == 0 && r->contentLengthB0 == 0)
adamc@860 317 break;
adamc@860 318
adamc@860 319 if (used_nvps == hs.n_nvps-1) {
adamc@860 320 ++hs.n_nvps;
adamc@860 321 hs.nvps = realloc(hs.nvps, hs.n_nvps * sizeof(nvp));
adamc@862 322 hs.nvps[hs.n_nvps-1].name = malloc(1);
adamc@862 323 hs.nvps[hs.n_nvps-1].value = malloc(0);
adamc@862 324 hs.nvps[hs.n_nvps-1].name_len = 1;
adamc@862 325 hs.nvps[hs.n_nvps-1].value_len = 0;
adamc@860 326 }
adamc@860 327
adamc@860 328 if (read_nvp(r->contentData, (r->contentLengthB1 << 8) | r->contentLengthB0, &hs.nvps[used_nvps]) < 0) {
adamc@860 329 write_stderr(out, "Error reading FCGI_PARAMS name-value pair\n");
adamc@860 330 goto done;
adamc@860 331 }
adamc@860 332
adamc@860 333 ++used_nvps;
adamc@859 334 }
adamc@860 335
adamc@862 336 hs.nvps[used_nvps].name[0] = 0;
adamc@860 337
adamc@860 338 if (s = get_header(&hs, "Content-Length")) {
adamc@860 339 body_len = atoi(s);
adamc@860 340 if (body_len < 0) {
adamc@860 341 write_stderr(out, "Invalid Content-Length\n");
adamc@860 342 goto done;
adamc@860 343 }
adamc@860 344 } else
adamc@860 345 body_len = 0;
adamc@860 346
adamc@861 347 if (body_len+1 > body_size) {
adamc@861 348 body_size = body_len+1;
adamc@860 349 body = realloc(body, body_size);
adamc@860 350 }
adamc@860 351
adamc@860 352 for (body_read = 0; body_read < body_len; ) {
adamc@860 353 char *buf;
adamc@860 354 int this_len;
adamc@860 355
adamc@860 356 if (!(r = fastcgi_recv(in))) {
adamc@860 357 write_stderr(out, "Error receiving STDIN\n");
adamc@860 358 goto done;
adamc@860 359 }
adamc@860 360
adamc@860 361 if (r->type != FCGI_STDIN) {
adamc@860 362 write_stderr(out, "Expected FCGI_STDIN but got %d\n", r->type);
adamc@860 363 goto done;
adamc@860 364 }
adamc@860 365
adamc@860 366 if (r->contentLengthB1 == 0 && r->contentLengthB0 == 0) {
adamc@860 367 write_stderr(out, "End of STDIN\n");
adamc@860 368 break;
adamc@860 369 }
adamc@860 370
adamc@860 371 this_len = (r->contentLengthB1 << 8) | r->contentLengthB0;
adamc@860 372
adamc@860 373 if (body_read + this_len > body_len) {
adamc@860 374 write_stderr(out, "Too much STDIN\n");
adamc@860 375 goto done;
adamc@860 376 }
adamc@860 377
adamc@860 378 memcpy(&body[body_read], r->contentData, this_len);
adamc@860 379 body_read += this_len;
adamc@860 380 }
adamc@860 381
adamc@861 382 body[body_read] = 0;
adamc@861 383
adamc@860 384 if (!(method = search_nvps(hs.nvps, "REQUEST_METHOD"))) {
adamc@860 385 write_stderr(out, "REQUEST_METHOD not set\n");
adamc@860 386 goto done;
adamc@860 387 }
adamc@860 388
adamc@860 389 if (!(path = search_nvps(hs.nvps, "SCRIPT_NAME"))) {
adamc@860 390 write_stderr(out, "SCRIPT_NAME not set\n");
adamc@860 391 goto done;
adamc@860 392 }
adamc@861 393
adamc@860 394 if (path_info = search_nvps(hs.nvps, "PATH_INFO")) {
adamc@860 395 int len1 = strlen(path), len2 = strlen(path_info);
adamc@860 396 int len = len1 + len2 + 1;
adamc@860 397
adamc@860 398 if (len > path_size) {
adamc@860 399 path_size = len;
adamc@860 400 path_buf = realloc(path_buf, path_size);
adamc@860 401 }
adamc@860 402
adamc@860 403 sprintf(path_buf, "%s%s", path, path_info);
adamc@860 404 path = path_buf;
adamc@860 405 }
adamc@860 406
adamc@860 407 if (!(query_string = search_nvps(hs.nvps, "QUERY_STRING")))
adamc@860 408 query_string = "";
adamc@860 409
adamc@860 410 uw_set_headers(ctx, get_header, &hs);
adamc@861 411
adamc@860 412 {
adamc@860 413 request_result rr;
adamc@860 414 FCGI_EndRequestBody *erb = (FCGI_EndRequestBody *)out->r.contentData;
adamc@860 415
adamc@860 416 rr = uw_request(rc, ctx, method, path, query_string, body, body_read,
adamc@860 417 on_success, on_failure,
adamc@860 418 out, log_error, log_debug,
adamc@860 419 in->sock);
adamc@860 420
adamc@860 421 if (rr == KEEP_OPEN)
adamc@860 422 goto done2;
adamc@860 423
adamc@860 424 uw_output(ctx, write_stdout, out);
adamc@860 425 close_stream(out, FCGI_STDOUT);
adamc@860 426 close_stream(out, FCGI_STDERR);
adamc@860 427
adamc@860 428 if (rr == SERVED)
adamc@860 429 erb->appStatusB3 = erb->appStatusB2 = erb->appStatusB1 = erb->appStatusB0 = 0;
adamc@860 430 else
adamc@860 431 erb->appStatusB3 = erb->appStatusB2 = erb->appStatusB1 = erb->appStatusB0 = 0xFF;
adamc@860 432
adamc@860 433 erb->protocolStatus = FCGI_REQUEST_COMPLETE;
adamc@860 434 fastcgi_send(out, FCGI_END_REQUEST, sizeof(FCGI_EndRequestBody));
adamc@860 435 }
adamc@859 436
adamc@859 437 done:
adamc@859 438 close(in->sock);
adamc@860 439 done2:
adamc@859 440 fastcgi_input_reset(in);
adamc@859 441 uw_reset(ctx);
adamc@859 442 }
adamc@859 443 }
adamc@859 444
adamc@859 445 static void help(char *cmd) {
adamc@859 446 printf("Usage: %s [-t <thread-count>]\n", cmd);
adamc@859 447 }
adamc@859 448
adamc@859 449 static void sigint(int signum) {
adamc@859 450 printf("Exiting....\n");
adamc@859 451 exit(0);
adamc@859 452 }
adamc@859 453
adamc@859 454 static loggers ls = {NULL, log_error, log_debug};
adamc@859 455
adamc@859 456 int main(int argc, char *argv[]) {
adamc@859 457 // The skeleton for this function comes from Beej's sockets tutorial.
adamc@859 458 struct sockaddr_in their_addr; // connector's address information
adamc@859 459 int sin_size, yes = 1;
adamc@859 460 int nthreads = 1, i, *names, opt;
adamc@859 461 char *fwsa = getenv("FCGI_WEB_SERVER_ADDRS"), *nthreads_s = getenv("URWEB_NUM_THREADS");
adamc@859 462
adamc@859 463 if (nthreads_s) {
adamc@859 464 nthreads = atoi(nthreads_s);
adamc@859 465 if (nthreads <= 0) {
adamc@859 466 fprintf(stderr, "Bad URWEB_NUM_THREADS value\n");
adamc@859 467 return 1;
adamc@859 468 }
adamc@859 469 }
adamc@859 470
adamc@859 471 signal(SIGINT, sigint);
adamc@859 472 signal(SIGPIPE, SIG_IGN);
adamc@859 473 signal(SIGUSR1, sigint);
adamc@859 474 signal(SIGTERM, sigint);
adamc@859 475
adamc@859 476 while ((opt = getopt(argc, argv, "ht:")) != -1) {
adamc@859 477 switch (opt) {
adamc@859 478 case '?':
adamc@859 479 fprintf(stderr, "Unknown command-line option");
adamc@859 480 help(argv[0]);
adamc@859 481 return 1;
adamc@859 482
adamc@859 483 case 'h':
adamc@859 484 help(argv[0]);
adamc@859 485 return 0;
adamc@859 486
adamc@859 487 case 't':
adamc@859 488 nthreads = atoi(optarg);
adamc@859 489 if (nthreads <= 0) {
adamc@859 490 fprintf(stderr, "Invalid thread count\n");
adamc@859 491 help(argv[0]);
adamc@859 492 return 1;
adamc@859 493 }
adamc@859 494 break;
adamc@859 495
adamc@859 496 default:
adamc@859 497 fprintf(stderr, "Unexpected getopt() behavior\n");
adamc@859 498 return 1;
adamc@859 499 }
adamc@859 500 }
adamc@859 501
adamc@860 502 uw_set_on_success("");
adamc@859 503 uw_request_init(NULL, log_error, log_debug);
adamc@859 504
adamc@859 505 names = calloc(nthreads, sizeof(int));
adamc@859 506
adamc@859 507 sin_size = sizeof their_addr;
adamc@859 508
adamc@859 509 {
adamc@859 510 pthread_t thread;
adamc@859 511 int name;
adamc@859 512
adamc@859 513 if (pthread_create(&thread, NULL, client_pruner, &ls)) {
adamc@859 514 fprintf(stderr, "Error creating pruner thread\n");
adamc@859 515 return 1;
adamc@859 516 }
adamc@859 517 }
adamc@859 518
adamc@859 519 for (i = 0; i < nthreads; ++i) {
adamc@859 520 pthread_t thread;
adamc@859 521 names[i] = i;
adamc@859 522 if (pthread_create(&thread, NULL, worker, &names[i])) {
adamc@859 523 fprintf(stderr, "Error creating worker thread #%d\n", i);
adamc@859 524 return 1;
adamc@859 525 }
adamc@859 526 }
adamc@859 527
adamc@859 528 while (1) {
adamc@859 529 int new_fd = accept(FCGI_LISTENSOCK_FILENO, (struct sockaddr *)&their_addr, &sin_size);
adamc@859 530
adamc@859 531 if (new_fd < 0) {
adamc@859 532 fprintf(stderr, "Socket accept failed\n");
adamc@859 533 return 1;
adamc@859 534 }
adamc@859 535
adamc@859 536 if (fwsa) {
adamc@859 537 char host[100], matched = 0;
adamc@859 538 char *ips, *sep;
adamc@859 539
adamc@859 540 if (getnameinfo((struct sockaddr *)&their_addr, sin_size, host, sizeof host, NULL, 0, NI_NUMERICHOST)) {
adamc@859 541 fprintf(stderr, "Remote IP determination failed\n");
adamc@859 542 return 1;
adamc@859 543 }
adamc@859 544
adamc@859 545 for (ips = fwsa; sep = strchr(ips, ','); ips = sep+1) {
adamc@859 546 if (!strncmp(ips, host, sep - ips)) {
adamc@859 547 matched = 1;
adamc@859 548 break;
adamc@859 549 }
adamc@859 550 }
adamc@859 551
adamc@859 552 if (!matched && strcmp(ips, host)) {
adamc@859 553 fprintf(stderr, "Remote address is not in FCGI_WEB_SERVER_ADDRS");
adamc@859 554 return 1;
adamc@859 555 }
adamc@859 556 }
adamc@859 557
adamc@859 558 uw_enqueue(new_fd);
adamc@859 559 }
adamc@859 560 }