root/sapi/cgi/fastcgi.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. fcgi_hash_init
  2. fcgi_hash_destroy
  3. fcgi_hash_clean
  4. fcgi_hash_strndup
  5. fcgi_hash_set
  6. fcgi_hash_del
  7. fcgi_hash_get
  8. fcgi_hash_apply
  9. fcgi_shutdown_thread
  10. fcgi_signal_handler
  11. fcgi_setup_signals
  12. fcgi_in_shutdown
  13. fcgi_terminate
  14. fcgi_init
  15. fcgi_is_fastcgi
  16. fcgi_shutdown
  17. prepare_named_pipe_acl
  18. is_port_number
  19. fcgi_listen
  20. fcgi_init_request
  21. fcgi_destroy_request
  22. safe_write
  23. safe_read
  24. fcgi_make_header
  25. fcgi_get_params
  26. fcgi_read_request
  27. fcgi_read
  28. fcgi_close
  29. fcgi_accept_request
  30. open_packet
  31. close_packet
  32. fcgi_flush
  33. fcgi_write
  34. fcgi_finish_request
  35. fcgi_getenv
  36. fcgi_quick_getenv
  37. fcgi_putenv
  38. fcgi_quick_putenv
  39. fcgi_loadenv
  40. fcgi_impersonate
  41. fcgi_set_mgmt_var
  42. fcgi_free_mgmt_var_cb

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 5                                                        |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1997-2016 The PHP Group                                |
   6    +----------------------------------------------------------------------+
   7    | This source file is subject to version 3.01 of the PHP license,      |
   8    | that is bundled with this package in the file LICENSE, and is        |
   9    | available through the world-wide-web at the following url:           |
  10    | http://www.php.net/license/3_01.txt                                  |
  11    | If you did not receive a copy of the PHP license and are unable to   |
  12    | obtain it through the world-wide-web, please send a note to          |
  13    | license@php.net so we can mail you a copy immediately.               |
  14    +----------------------------------------------------------------------+
  15    | Authors: Dmitry Stogov <dmitry@zend.com>                             |
  16    +----------------------------------------------------------------------+
  17 */
  18 
  19 /* $Id$ */
  20 
  21 #include "php.h"
  22 #include "fastcgi.h"
  23 
  24 #include <string.h>
  25 #include <stdlib.h>
  26 #include <stdio.h>
  27 #include <stdarg.h>
  28 #include <errno.h>
  29 
  30 #ifndef MAXFQDNLEN
  31 #define MAXFQDNLEN 255
  32 #endif
  33 
  34 #ifdef _WIN32
  35 
  36 #include <windows.h>
  37 
  38         typedef unsigned int in_addr_t;
  39 
  40         struct sockaddr_un {
  41                 short   sun_family;
  42                 char    sun_path[MAXPATHLEN];
  43         };
  44 
  45         static HANDLE fcgi_accept_mutex = INVALID_HANDLE_VALUE;
  46         static int is_impersonate = 0;
  47 
  48 #define FCGI_LOCK(fd) \
  49         if (fcgi_accept_mutex != INVALID_HANDLE_VALUE) { \
  50                 DWORD ret; \
  51                 while ((ret = WaitForSingleObject(fcgi_accept_mutex, 1000)) == WAIT_TIMEOUT) { \
  52                         if (in_shutdown) return -1; \
  53                 } \
  54                 if (ret == WAIT_FAILED) { \
  55                         fprintf(stderr, "WaitForSingleObject() failed\n"); \
  56                         return -1; \
  57                 } \
  58         }
  59 
  60 #define FCGI_UNLOCK(fd) \
  61         if (fcgi_accept_mutex != INVALID_HANDLE_VALUE) { \
  62                 ReleaseMutex(fcgi_accept_mutex); \
  63         }
  64 
  65 #else
  66 
  67 # include <sys/types.h>
  68 # include <sys/stat.h>
  69 # include <unistd.h>
  70 # include <fcntl.h>
  71 # include <sys/socket.h>
  72 # include <sys/un.h>
  73 # include <netinet/in.h>
  74 # include <netinet/tcp.h>
  75 # include <arpa/inet.h>
  76 # include <netdb.h>
  77 # include <signal.h>
  78 
  79 # define closesocket(s) close(s)
  80 
  81 # if defined(HAVE_SYS_POLL_H) && defined(HAVE_POLL)
  82 #  include <sys/poll.h>
  83 # endif
  84 # if defined(HAVE_SYS_SELECT_H)
  85 #  include <sys/select.h>
  86 # endif
  87 
  88 #ifndef INADDR_NONE
  89 #define INADDR_NONE ((unsigned long) -1)
  90 #endif
  91 
  92 # ifndef HAVE_SOCKLEN_T
  93         typedef unsigned int socklen_t;
  94 # endif
  95 
  96 # ifdef USE_LOCKING
  97 #  define FCGI_LOCK(fd)                                                         \
  98         do {                                                                                    \
  99                 struct flock lock;                                                      \
 100                 lock.l_type = F_WRLCK;                                          \
 101                 lock.l_start = 0;                                                       \
 102                 lock.l_whence = SEEK_SET;                                       \
 103                 lock.l_len = 0;                                                         \
 104                 if (fcntl(fd, F_SETLKW, &lock) != -1) {         \
 105                         break;                                                                  \
 106                 } else if (errno != EINTR || in_shutdown) {     \
 107                         return -1;                                                              \
 108                 }                                                                                       \
 109         } while (1)
 110 
 111 #  define FCGI_UNLOCK(fd)                                                       \
 112         do {                                                                                    \
 113                 int orig_errno = errno;                                         \
 114                 while (1) {                                                                     \
 115                         struct flock lock;                                              \
 116                         lock.l_type = F_UNLCK;                                  \
 117                         lock.l_start = 0;                                               \
 118                         lock.l_whence = SEEK_SET;                               \
 119                         lock.l_len = 0;                                                 \
 120                         if (fcntl(fd, F_SETLK, &lock) != -1) {  \
 121                                 break;                                                          \
 122                         } else if (errno != EINTR) {                    \
 123                                 return -1;                                                      \
 124                         }                                                                               \
 125                 }                                                                                       \
 126                 errno = orig_errno;                                                     \
 127         } while (0)
 128 # else
 129 #  define FCGI_LOCK(fd)
 130 #  define FCGI_UNLOCK(fd)
 131 # endif
 132 
 133 #endif
 134 
 135 typedef union _sa_t {
 136         struct sockaddr     sa;
 137         struct sockaddr_un  sa_unix;
 138         struct sockaddr_in  sa_inet;
 139 } sa_t;
 140 
 141 static HashTable fcgi_mgmt_vars;
 142 
 143 static int is_initialized = 0;
 144 static int is_fastcgi = 0;
 145 static int in_shutdown = 0;
 146 static in_addr_t *allowed_clients = NULL;
 147 
 148 /* hash table */
 149 
 150 #define FCGI_HASH_TABLE_SIZE 128
 151 #define FCGI_HASH_TABLE_MASK (FCGI_HASH_TABLE_SIZE - 1)
 152 #define FCGI_HASH_SEG_SIZE   4096
 153 
 154 typedef struct _fcgi_hash_bucket {
 155         unsigned int              hash_value;
 156         unsigned int              var_len;
 157         char                     *var;
 158         unsigned int              val_len;
 159         char                     *val;
 160         struct _fcgi_hash_bucket *next;
 161         struct _fcgi_hash_bucket *list_next;
 162 } fcgi_hash_bucket;
 163 
 164 typedef struct _fcgi_hash_buckets {
 165         unsigned int               idx;
 166         struct _fcgi_hash_buckets *next;
 167         struct _fcgi_hash_bucket   data[FCGI_HASH_TABLE_SIZE];
 168 } fcgi_hash_buckets;
 169 
 170 typedef struct _fcgi_data_seg {
 171         char                  *pos;
 172         char                  *end;
 173         struct _fcgi_data_seg *next;
 174         char                   data[1];
 175 } fcgi_data_seg;
 176 
 177 typedef struct _fcgi_hash {
 178         fcgi_hash_bucket  *hash_table[FCGI_HASH_TABLE_SIZE];
 179         fcgi_hash_bucket  *list;
 180         fcgi_hash_buckets *buckets;
 181         fcgi_data_seg     *data;
 182 } fcgi_hash;
 183 
 184 static void fcgi_hash_init(fcgi_hash *h)
 185 {
 186         memset(h->hash_table, 0, sizeof(h->hash_table));
 187         h->list = NULL;
 188         h->buckets = (fcgi_hash_buckets*)malloc(sizeof(fcgi_hash_buckets));
 189         h->buckets->idx = 0;
 190         h->buckets->next = NULL;
 191         h->data = (fcgi_data_seg*)malloc(sizeof(fcgi_data_seg) - 1 + FCGI_HASH_SEG_SIZE);
 192         h->data->pos = h->data->data;
 193         h->data->end = h->data->pos + FCGI_HASH_SEG_SIZE;
 194         h->data->next = NULL;
 195 }
 196 
 197 static void fcgi_hash_destroy(fcgi_hash *h)
 198 {
 199         fcgi_hash_buckets *b;
 200         fcgi_data_seg *p;
 201 
 202         b = h->buckets;
 203         while (b) {
 204                 fcgi_hash_buckets *q = b;
 205                 b = b->next;
 206                 free(q);
 207         }
 208         p = h->data;
 209         while (p) {
 210                 fcgi_data_seg *q = p;
 211                 p = p->next;
 212                 free(q);
 213         }
 214 }
 215 
 216 static void fcgi_hash_clean(fcgi_hash *h)
 217 {
 218         memset(h->hash_table, 0, sizeof(h->hash_table));
 219         h->list = NULL;
 220         /* delete all bucket blocks except the first one */
 221         while (h->buckets->next) {
 222                 fcgi_hash_buckets *q = h->buckets;
 223 
 224                 h->buckets = h->buckets->next;
 225                 free(q);
 226         }
 227         h->buckets->idx = 0;
 228         /* delete all data segments except the first one */
 229         while (h->data->next) {
 230                 fcgi_data_seg *q = h->data;
 231 
 232                 h->data = h->data->next;
 233                 free(q);
 234         }
 235         h->data->pos = h->data->data;
 236 }
 237 
 238 static inline char* fcgi_hash_strndup(fcgi_hash *h, char *str, unsigned int str_len)
 239 {
 240         char *ret;
 241 
 242         if (UNEXPECTED(h->data->pos + str_len + 1 >= h->data->end)) {
 243                 unsigned int seg_size = (str_len + 1 > FCGI_HASH_SEG_SIZE) ? str_len + 1 : FCGI_HASH_SEG_SIZE;
 244                 fcgi_data_seg *p = (fcgi_data_seg*)malloc(sizeof(fcgi_data_seg) - 1 + seg_size);
 245 
 246                 p->pos = p->data;
 247                 p->end = p->pos + seg_size;
 248                 p->next = h->data;
 249                 h->data = p;
 250         }
 251         ret = h->data->pos; 
 252         memcpy(ret, str, str_len);
 253         ret[str_len] = 0;
 254         h->data->pos += str_len + 1;
 255         return ret;
 256 }
 257 
 258 static char* fcgi_hash_set(fcgi_hash *h, unsigned int hash_value, char *var, unsigned int var_len, char *val, unsigned int val_len)
 259 {
 260         unsigned int      idx = hash_value & FCGI_HASH_TABLE_MASK;
 261         fcgi_hash_bucket *p = h->hash_table[idx];
 262 
 263         while (UNEXPECTED(p != NULL)) {
 264                 if (UNEXPECTED(p->hash_value == hash_value) &&
 265                     p->var_len == var_len &&
 266                     memcmp(p->var, var, var_len) == 0) {
 267 
 268                         p->val_len = val_len;
 269                         p->val = fcgi_hash_strndup(h, val, val_len);
 270                         return p->val;
 271                 }
 272                 p = p->next;
 273         }
 274 
 275         if (UNEXPECTED(h->buckets->idx >= FCGI_HASH_TABLE_SIZE)) {
 276                 fcgi_hash_buckets *b = (fcgi_hash_buckets*)malloc(sizeof(fcgi_hash_buckets));
 277                 b->idx = 0;
 278                 b->next = h->buckets;
 279                 h->buckets = b;
 280         }
 281         p = h->buckets->data + h->buckets->idx;
 282         h->buckets->idx++;
 283         p->next = h->hash_table[idx];
 284         h->hash_table[idx] = p;
 285         p->list_next = h->list;
 286         h->list = p;
 287         p->hash_value = hash_value;
 288         p->var_len = var_len;
 289         p->var = fcgi_hash_strndup(h, var, var_len);
 290         p->val_len = val_len;
 291         p->val = fcgi_hash_strndup(h, val, val_len);
 292         return p->val;
 293 }
 294 
 295 static void fcgi_hash_del(fcgi_hash *h, unsigned int hash_value, char *var, unsigned int var_len)
 296 {
 297         unsigned int      idx = hash_value & FCGI_HASH_TABLE_MASK;
 298         fcgi_hash_bucket **p = &h->hash_table[idx];
 299 
 300         while (*p != NULL) {
 301                 if ((*p)->hash_value == hash_value &&
 302                     (*p)->var_len == var_len &&
 303                     memcmp((*p)->var, var, var_len) == 0) {
 304 
 305                     (*p)->val = NULL; /* NULL value means deleted */
 306                     (*p)->val_len = 0;
 307                         *p = (*p)->next;
 308                     return;
 309                 }
 310                 p = &(*p)->next;
 311         }
 312 }
 313 
 314 static char *fcgi_hash_get(fcgi_hash *h, unsigned int hash_value, char *var, unsigned int var_len, unsigned int *val_len)
 315 {
 316         unsigned int      idx = hash_value & FCGI_HASH_TABLE_MASK;
 317         fcgi_hash_bucket *p = h->hash_table[idx];
 318 
 319         while (p != NULL) {
 320                 if (p->hash_value == hash_value &&
 321                     p->var_len == var_len &&
 322                     memcmp(p->var, var, var_len) == 0) {
 323                     *val_len = p->val_len;
 324                     return p->val;
 325                 }
 326                 p = p->next;
 327         }
 328         return NULL;
 329 }
 330 
 331 static void fcgi_hash_apply(fcgi_hash *h, fcgi_apply_func func, void *arg TSRMLS_DC)
 332 {
 333         fcgi_hash_bucket *p     = h->list;
 334 
 335         while (p) {
 336                 if (EXPECTED(p->val != NULL)) {
 337                         func(p->var, p->var_len, p->val, p->val_len, arg TSRMLS_CC);
 338                 }
 339                 p = p->list_next;
 340         }
 341 }
 342 
 343 struct _fcgi_request {
 344         int            listen_socket;
 345         int            tcp;
 346         int            fd;
 347         int            id;
 348         int            keep;
 349 #ifdef TCP_NODELAY
 350         int            nodelay;
 351 #endif
 352         int            closed;
 353 
 354         int            in_len;
 355         int            in_pad;
 356 
 357         fcgi_header   *out_hdr;
 358         unsigned char *out_pos;
 359         unsigned char  out_buf[1024*8];
 360         unsigned char  reserved[sizeof(fcgi_end_request_rec)];
 361 
 362         int            has_env;
 363         fcgi_hash      env;
 364 };
 365 
 366 #ifdef _WIN32
 367 
 368 static DWORD WINAPI fcgi_shutdown_thread(LPVOID arg)
 369 {
 370         HANDLE shutdown_event = (HANDLE) arg;
 371         WaitForSingleObject(shutdown_event, INFINITE);
 372         in_shutdown = 1;
 373         return 0;
 374 }
 375 
 376 #else
 377 
 378 static void fcgi_signal_handler(int signo)
 379 {
 380         if (signo == SIGUSR1 || signo == SIGTERM) {
 381                 in_shutdown = 1;
 382         }
 383 }
 384 
 385 static void fcgi_setup_signals(void)
 386 {
 387         struct sigaction new_sa, old_sa;
 388 
 389         sigemptyset(&new_sa.sa_mask);
 390         new_sa.sa_flags = 0;
 391         new_sa.sa_handler = fcgi_signal_handler;
 392         sigaction(SIGUSR1, &new_sa, NULL);
 393         sigaction(SIGTERM, &new_sa, NULL);
 394         sigaction(SIGPIPE, NULL, &old_sa);
 395         if (old_sa.sa_handler == SIG_DFL) {
 396                 sigaction(SIGPIPE, &new_sa, NULL);
 397         }
 398 }
 399 #endif
 400 
 401 int fcgi_in_shutdown(void)
 402 {
 403         return in_shutdown;
 404 }
 405 
 406 void fcgi_terminate(void)
 407 {
 408         in_shutdown = 1;
 409 }
 410 
 411 int fcgi_init(void)
 412 {
 413         if (!is_initialized) {
 414 #ifndef _WIN32
 415                 sa_t sa;
 416                 socklen_t len = sizeof(sa);
 417 #endif
 418                 zend_hash_init(&fcgi_mgmt_vars, 0, NULL, fcgi_free_mgmt_var_cb, 1);
 419                 fcgi_set_mgmt_var("FCGI_MPXS_CONNS", sizeof("FCGI_MPXS_CONNS")-1, "0", sizeof("0")-1);
 420 
 421                 is_initialized = 1;
 422 #ifdef _WIN32
 423 # if 0
 424                 /* TODO: Support for TCP sockets */
 425                 WSADATA wsaData;
 426 
 427                 if (WSAStartup(MAKEWORD(2,0), &wsaData)) {
 428                         fprintf(stderr, "Error starting Windows Sockets.  Error: %d", WSAGetLastError());
 429                         return 0;
 430                 }
 431 # endif
 432                 if ((GetStdHandle(STD_OUTPUT_HANDLE) == INVALID_HANDLE_VALUE) &&
 433                     (GetStdHandle(STD_ERROR_HANDLE)  == INVALID_HANDLE_VALUE) &&
 434                     (GetStdHandle(STD_INPUT_HANDLE)  != INVALID_HANDLE_VALUE)) {
 435                         char *str;
 436                         DWORD pipe_mode = PIPE_READMODE_BYTE | PIPE_WAIT;
 437                         HANDLE pipe = GetStdHandle(STD_INPUT_HANDLE);
 438 
 439                         SetNamedPipeHandleState(pipe, &pipe_mode, NULL, NULL);
 440 
 441                         str = getenv("_FCGI_SHUTDOWN_EVENT_");
 442                         if (str != NULL) {
 443                                 HANDLE shutdown_event = (HANDLE) atoi(str);
 444                                 if (!CreateThread(NULL, 0, fcgi_shutdown_thread,
 445                                                   shutdown_event, 0, NULL)) {
 446                                         return -1;
 447                                 }
 448                         }
 449                         str = getenv("_FCGI_MUTEX_");
 450                         if (str != NULL) {
 451                                 fcgi_accept_mutex = (HANDLE) atoi(str);
 452                         }
 453                         return is_fastcgi = 1;
 454                 } else {
 455                         return is_fastcgi = 0;
 456                 }
 457 #else
 458                 errno = 0;
 459                 if (getpeername(0, (struct sockaddr *)&sa, &len) != 0 && errno == ENOTCONN) {
 460                         fcgi_setup_signals();
 461                         return is_fastcgi = 1;
 462                 } else {
 463                         return is_fastcgi = 0;
 464                 }
 465 #endif
 466         }
 467         return is_fastcgi;
 468 }
 469 
 470 
 471 int fcgi_is_fastcgi(void)
 472 {
 473         if (!is_initialized) {
 474                 return fcgi_init();
 475         } else {
 476                 return is_fastcgi;
 477         }
 478 }
 479 
 480 void fcgi_shutdown(void)
 481 {
 482         if (is_initialized) {
 483                 zend_hash_destroy(&fcgi_mgmt_vars);
 484         }
 485         is_fastcgi = 0;
 486         if (allowed_clients) {
 487                 free(allowed_clients);
 488         }
 489 }
 490 
 491 #ifdef _WIN32
 492 /* Do some black magic with the NT security API.
 493  * We prepare a DACL (Discretionary Access Control List) so that
 494  * we, the creator, are allowed all access, while "Everyone Else"
 495  * is only allowed to read and write to the pipe.
 496  * This avoids security issues on shared hosts where a luser messes
 497  * with the lower-level pipe settings and screws up the FastCGI service.
 498  */
 499 static PACL prepare_named_pipe_acl(PSECURITY_DESCRIPTOR sd, LPSECURITY_ATTRIBUTES sa)
 500 {
 501         DWORD req_acl_size;
 502         char everyone_buf[32], owner_buf[32];
 503         PSID sid_everyone, sid_owner;
 504         SID_IDENTIFIER_AUTHORITY
 505                 siaWorld = SECURITY_WORLD_SID_AUTHORITY,
 506                 siaCreator = SECURITY_CREATOR_SID_AUTHORITY;
 507         PACL acl;
 508 
 509         sid_everyone = (PSID)&everyone_buf;
 510         sid_owner = (PSID)&owner_buf;
 511 
 512         req_acl_size = sizeof(ACL) +
 513                 (2 * ((sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)) + GetSidLengthRequired(1)));
 514 
 515         acl = malloc(req_acl_size);
 516 
 517         if (acl == NULL) {
 518                 return NULL;
 519         }
 520 
 521         if (!InitializeSid(sid_everyone, &siaWorld, 1)) {
 522                 goto out_fail;
 523         }
 524         *GetSidSubAuthority(sid_everyone, 0) = SECURITY_WORLD_RID;
 525 
 526         if (!InitializeSid(sid_owner, &siaCreator, 1)) {
 527                 goto out_fail;
 528         }
 529         *GetSidSubAuthority(sid_owner, 0) = SECURITY_CREATOR_OWNER_RID;
 530 
 531         if (!InitializeAcl(acl, req_acl_size, ACL_REVISION)) {
 532                 goto out_fail;
 533         }
 534 
 535         if (!AddAccessAllowedAce(acl, ACL_REVISION, FILE_GENERIC_READ | FILE_GENERIC_WRITE, sid_everyone)) {
 536                 goto out_fail;
 537         }
 538 
 539         if (!AddAccessAllowedAce(acl, ACL_REVISION, FILE_ALL_ACCESS, sid_owner)) {
 540                 goto out_fail;
 541         }
 542 
 543         if (!InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION)) {
 544                 goto out_fail;
 545         }
 546 
 547         if (!SetSecurityDescriptorDacl(sd, TRUE, acl, FALSE)) {
 548                 goto out_fail;
 549         }
 550 
 551         sa->lpSecurityDescriptor = sd;
 552 
 553         return acl;
 554 
 555 out_fail:
 556         free(acl);
 557         return NULL;
 558 }
 559 #endif
 560 
 561 static int is_port_number(const char *bindpath)
 562 {
 563         while (*bindpath) {
 564                 if (*bindpath < '0' || *bindpath > '9') {
 565                         return 0;
 566                 }
 567                 bindpath++;
 568         }
 569         return 1;
 570 }
 571 
 572 int fcgi_listen(const char *path, int backlog)
 573 {
 574         char     *s;
 575         int       tcp = 0;
 576         char      host[MAXPATHLEN];
 577         short     port = 0;
 578         int       listen_socket;
 579         sa_t      sa;
 580         socklen_t sock_len;
 581 #ifdef SO_REUSEADDR
 582 # ifdef _WIN32
 583         BOOL reuse = 1;
 584 # else
 585         int reuse = 1;
 586 # endif
 587 #endif
 588 
 589         if ((s = strchr(path, ':'))) {
 590                 port = atoi(s+1);
 591                 if (port != 0 && (s-path) < MAXPATHLEN) {
 592                         strncpy(host, path, s-path);
 593                         host[s-path] = '\0';
 594                         tcp = 1;
 595                 }
 596         } else if (is_port_number(path)) {
 597                 port = atoi(path);
 598                 if (port != 0) {
 599                         host[0] = '\0';
 600                         tcp = 1;
 601                 }
 602         }
 603 
 604         /* Prepare socket address */
 605         if (tcp) {
 606                 memset(&sa.sa_inet, 0, sizeof(sa.sa_inet));
 607                 sa.sa_inet.sin_family = AF_INET;
 608                 sa.sa_inet.sin_port = htons(port);
 609                 sock_len = sizeof(sa.sa_inet);
 610 
 611                 if (!*host || !strncmp(host, "*", sizeof("*")-1)) {
 612                         sa.sa_inet.sin_addr.s_addr = htonl(INADDR_ANY);
 613                 } else {
 614                         sa.sa_inet.sin_addr.s_addr = inet_addr(host);
 615                         if (sa.sa_inet.sin_addr.s_addr == INADDR_NONE) {
 616                                 struct hostent *hep;
 617 
 618                                 if(strlen(host) > MAXFQDNLEN) {
 619                                         hep = NULL;
 620                                 } else {
 621                                         hep = gethostbyname(host);
 622                                 }
 623                                 if (!hep || hep->h_addrtype != AF_INET || !hep->h_addr_list[0]) {
 624                                         fprintf(stderr, "Cannot resolve host name '%s'!\n", host);
 625                                         return -1;
 626                                 } else if (hep->h_addr_list[1]) {
 627                                         fprintf(stderr, "Host '%s' has multiple addresses. You must choose one explicitly!\n", host);
 628                                         return -1;
 629                                 }
 630                                 sa.sa_inet.sin_addr.s_addr = ((struct in_addr*)hep->h_addr_list[0])->s_addr;
 631                         }
 632                 }
 633         } else {
 634 #ifdef _WIN32
 635                 SECURITY_DESCRIPTOR  sd;
 636                 SECURITY_ATTRIBUTES  saw;
 637                 PACL                 acl;
 638                 HANDLE namedPipe;
 639 
 640                 memset(&sa, 0, sizeof(saw));
 641                 saw.nLength = sizeof(saw);
 642                 saw.bInheritHandle = FALSE;
 643                 acl = prepare_named_pipe_acl(&sd, &saw);
 644 
 645                 namedPipe = CreateNamedPipe(path,
 646                         PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
 647                         PIPE_TYPE_BYTE | PIPE_WAIT | PIPE_READMODE_BYTE,
 648                         PIPE_UNLIMITED_INSTANCES,
 649                         8192, 8192, 0, &saw);
 650                 if (namedPipe == INVALID_HANDLE_VALUE) {
 651                         return -1;
 652                 }
 653                 listen_socket = _open_osfhandle((long)namedPipe, 0);
 654                 if (!is_initialized) {
 655                         fcgi_init();
 656                 }
 657                 is_fastcgi = 1;
 658                 return listen_socket;
 659 
 660 #else
 661                 int path_len = strlen(path);
 662 
 663                 if (path_len >= sizeof(sa.sa_unix.sun_path)) {
 664                         fprintf(stderr, "Listening socket's path name is too long.\n");
 665                         return -1;
 666                 }
 667 
 668                 memset(&sa.sa_unix, 0, sizeof(sa.sa_unix));
 669                 sa.sa_unix.sun_family = AF_UNIX;
 670                 memcpy(sa.sa_unix.sun_path, path, path_len + 1);
 671                 sock_len = (size_t)(((struct sockaddr_un *)0)->sun_path)        + path_len;
 672 #ifdef HAVE_SOCKADDR_UN_SUN_LEN
 673                 sa.sa_unix.sun_len = sock_len;
 674 #endif
 675                 unlink(path);
 676 #endif
 677         }
 678 
 679         /* Create, bind socket and start listen on it */
 680         if ((listen_socket = socket(sa.sa.sa_family, SOCK_STREAM, 0)) < 0 ||
 681 #ifdef SO_REUSEADDR
 682             setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse)) < 0 ||
 683 #endif
 684             bind(listen_socket, (struct sockaddr *) &sa, sock_len) < 0 ||
 685             listen(listen_socket, backlog) < 0) {
 686 
 687                 fprintf(stderr, "Cannot bind/listen socket - [%d] %s.\n",errno, strerror(errno));
 688                 return -1;
 689         }
 690 
 691         if (!tcp) {
 692                 chmod(path, 0777);
 693         } else {
 694                 char *ip = getenv("FCGI_WEB_SERVER_ADDRS");
 695                 char *cur, *end;
 696                 int n;
 697 
 698                 if (ip) {
 699                         ip = strdup(ip);
 700                         cur = ip;
 701                         n = 0;
 702                         while (*cur) {
 703                                 if (*cur == ',') n++;
 704                                 cur++;
 705                         }
 706                         allowed_clients = malloc(sizeof(in_addr_t) * (n+2));
 707                         n = 0;
 708                         cur = ip;
 709                         while (cur) {
 710                                 end = strchr(cur, ',');
 711                                 if (end) {
 712                                         *end = 0;
 713                                         end++;
 714                                 }
 715                                 allowed_clients[n] = inet_addr(cur);
 716                                 if (allowed_clients[n] == INADDR_NONE) {
 717                                         fprintf(stderr, "Wrong IP address '%s' in FCGI_WEB_SERVER_ADDRS\n", cur);
 718                                 }
 719                                 n++;
 720                                 cur = end;
 721                         }
 722                         allowed_clients[n] = INADDR_NONE;
 723                         free(ip);
 724                 }
 725         }
 726 
 727         if (!is_initialized) {
 728                 fcgi_init();
 729         }
 730         is_fastcgi = 1;
 731 
 732 #ifdef _WIN32
 733         if (tcp) {
 734                 listen_socket = _open_osfhandle((long)listen_socket, 0);
 735         }
 736 #else
 737         fcgi_setup_signals();
 738 #endif
 739         return listen_socket;
 740 }
 741 
 742 fcgi_request *fcgi_init_request(int listen_socket)
 743 {
 744         fcgi_request *req = (fcgi_request*)calloc(1, sizeof(fcgi_request));
 745         req->listen_socket = listen_socket;
 746         req->fd = -1;
 747         req->id = -1;
 748 
 749         req->in_len = 0;
 750         req->in_pad = 0;
 751 
 752         req->out_hdr = NULL;
 753         req->out_pos = req->out_buf;
 754 
 755 #ifdef _WIN32
 756         req->tcp = !GetNamedPipeInfo((HANDLE)_get_osfhandle(req->listen_socket), NULL, NULL, NULL, NULL);
 757 #endif
 758 
 759 #ifdef TCP_NODELAY
 760         req->nodelay = 0;
 761 #endif
 762 
 763         fcgi_hash_init(&req->env);
 764 
 765         return req;
 766 }
 767 
 768 void fcgi_destroy_request(fcgi_request *req)
 769 {
 770         fcgi_hash_destroy(&req->env);
 771         free(req);
 772 }
 773 
 774 static inline ssize_t safe_write(fcgi_request *req, const void *buf, size_t count)
 775 {
 776         int    ret;
 777         size_t n = 0;
 778 
 779         do {
 780                 errno = 0;
 781 #ifdef _WIN32
 782                 if (!req->tcp) {
 783                         ret = write(req->fd, ((char*)buf)+n, count-n);
 784                 } else {
 785                         ret = send(req->fd, ((char*)buf)+n, count-n, 0);
 786                         if (ret <= 0) {
 787                                 errno = WSAGetLastError();
 788                         }
 789                 }
 790 #else
 791                 ret = write(req->fd, ((char*)buf)+n, count-n);
 792 #endif
 793                 if (ret > 0) {
 794                         n += ret;
 795                 } else if (ret <= 0 && errno != 0 && errno != EINTR) {
 796                         return ret;
 797                 }
 798         } while (n != count);
 799         return n;
 800 }
 801 
 802 static inline ssize_t safe_read(fcgi_request *req, const void *buf, size_t count)
 803 {
 804         int    ret;
 805         size_t n = 0;
 806 
 807         do {
 808                 errno = 0;
 809 #ifdef _WIN32
 810                 if (!req->tcp) {
 811                         ret = read(req->fd, ((char*)buf)+n, count-n);
 812                 } else {
 813                         ret = recv(req->fd, ((char*)buf)+n, count-n, 0);
 814                         if (ret <= 0) {
 815                                 errno = WSAGetLastError();
 816                         }
 817                 }
 818 #else
 819                 ret = read(req->fd, ((char*)buf)+n, count-n);
 820 #endif
 821                 if (ret > 0) {
 822                         n += ret;
 823                 } else if (ret == 0 && errno == 0) {
 824                         return n;
 825                 } else if (ret <= 0 && errno != 0 && errno != EINTR) {
 826                         return ret;
 827                 }
 828         } while (n != count);
 829         return n;
 830 }
 831 
 832 static inline int fcgi_make_header(fcgi_header *hdr, fcgi_request_type type, int req_id, int len)
 833 {
 834         int pad = ((len + 7) & ~7) - len;
 835 
 836         hdr->contentLengthB0 = (unsigned char)(len & 0xff);
 837         hdr->contentLengthB1 = (unsigned char)((len >> 8) & 0xff);
 838         hdr->paddingLength = (unsigned char)pad;
 839         hdr->requestIdB0 = (unsigned char)(req_id & 0xff);
 840         hdr->requestIdB1 = (unsigned char)((req_id >> 8) & 0xff);
 841         hdr->reserved = 0;
 842         hdr->type = type;
 843         hdr->version = FCGI_VERSION_1;
 844         if (pad) {
 845                 memset(((unsigned char*)hdr) + sizeof(fcgi_header) + len, 0, pad);
 846         }
 847         return pad;
 848 }
 849 
 850 static int fcgi_get_params(fcgi_request *req, unsigned char *p, unsigned char *end)
 851 {
 852         unsigned int name_len, val_len;
 853 
 854         while (p < end) {
 855                 name_len = *p++;
 856                 if (UNEXPECTED(name_len >= 128)) {
 857                         if (UNEXPECTED(p + 3 >= end)) return 0;
 858                         name_len = ((name_len & 0x7f) << 24);
 859                         name_len |= (*p++ << 16);
 860                         name_len |= (*p++ << 8);
 861                         name_len |= *p++;
 862                 }
 863                 if (UNEXPECTED(p >= end)) return 0;
 864                 val_len = *p++;
 865                 if (UNEXPECTED(val_len >= 128)) {
 866                         if (UNEXPECTED(p + 3 >= end)) return 0;
 867                         val_len = ((val_len & 0x7f) << 24);
 868                         val_len |= (*p++ << 16);
 869                         val_len |= (*p++ << 8);
 870                         val_len |= *p++;
 871                 }
 872                 if (UNEXPECTED(name_len + val_len > (unsigned int) (end - p))) {
 873                         /* Malformated request */
 874                         return 0;
 875                 }
 876                 fcgi_hash_set(&req->env, FCGI_HASH_FUNC(p, name_len), (char*)p, name_len, (char*)p + name_len, val_len);
 877                 p += name_len + val_len;
 878         }
 879         return 1;
 880 }
 881 
 882 static int fcgi_read_request(fcgi_request *req)
 883 {
 884         fcgi_header hdr;
 885         int len, padding;
 886         unsigned char buf[FCGI_MAX_LENGTH+8];
 887 
 888         req->keep = 0;
 889         req->closed = 0;
 890         req->in_len = 0;
 891         req->out_hdr = NULL;
 892         req->out_pos = req->out_buf;
 893         req->has_env = 1;
 894 
 895         if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
 896             hdr.version < FCGI_VERSION_1) {
 897                 return 0;
 898         }
 899 
 900         len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
 901         padding = hdr.paddingLength;
 902 
 903         while (hdr.type == FCGI_STDIN && len == 0) {
 904                 if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
 905                     hdr.version < FCGI_VERSION_1) {
 906                         return 0;
 907                 }
 908 
 909                 len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
 910                 padding = hdr.paddingLength;
 911         }
 912 
 913         if (len + padding > FCGI_MAX_LENGTH) {
 914                 return 0;
 915         }
 916 
 917         req->id = (hdr.requestIdB1 << 8) + hdr.requestIdB0;
 918 
 919         if (hdr.type == FCGI_BEGIN_REQUEST && len == sizeof(fcgi_begin_request)) {
 920                 if (safe_read(req, buf, len+padding) != len+padding) {
 921                         return 0;
 922                 }
 923 
 924                 req->keep = (((fcgi_begin_request*)buf)->flags & FCGI_KEEP_CONN);
 925 #ifdef TCP_NODELAY
 926                 if (req->keep && req->tcp && !req->nodelay) {
 927 # ifdef _WIN32
 928                         BOOL on = 1;
 929 # else
 930                         int on = 1;
 931 # endif
 932 
 933                         setsockopt(req->fd, IPPROTO_TCP, TCP_NODELAY, (char*)&on, sizeof(on));
 934                         req->nodelay = 1;
 935                 }
 936 #endif
 937                 switch ((((fcgi_begin_request*)buf)->roleB1 << 8) + ((fcgi_begin_request*)buf)->roleB0) {
 938                         case FCGI_RESPONDER:
 939                                 fcgi_hash_set(&req->env, FCGI_HASH_FUNC("FCGI_ROLE", sizeof("FCGI_ROLE")-1), "FCGI_ROLE", sizeof("FCGI_ROLE")-1, "RESPONDER", sizeof("RESPONDER")-1);
 940                                 break;
 941                         case FCGI_AUTHORIZER:
 942                                 fcgi_hash_set(&req->env, FCGI_HASH_FUNC("FCGI_ROLE", sizeof("FCGI_ROLE")-1), "FCGI_ROLE", sizeof("FCGI_ROLE")-1, "AUTHORIZER", sizeof("AUTHORIZER")-1);
 943                                 break;
 944                         case FCGI_FILTER:
 945                                 fcgi_hash_set(&req->env, FCGI_HASH_FUNC("FCGI_ROLE", sizeof("FCGI_ROLE")-1), "FCGI_ROLE", sizeof("FCGI_ROLE")-1, "FILTER", sizeof("FILTER")-1);
 946                                 break;
 947                         default:
 948                                 return 0;
 949                 }
 950 
 951                 if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
 952                     hdr.version < FCGI_VERSION_1) {
 953                         return 0;
 954                 }
 955 
 956                 len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
 957                 padding = hdr.paddingLength;
 958 
 959                 while (hdr.type == FCGI_PARAMS && len > 0) {
 960                         if (len + padding > FCGI_MAX_LENGTH) {
 961                                 return 0;
 962                         }
 963 
 964                         if (safe_read(req, buf, len+padding) != len+padding) {
 965                                 req->keep = 0;
 966                                 return 0;
 967                         }
 968 
 969                         if (!fcgi_get_params(req, buf, buf+len)) {
 970                                 req->keep = 0;
 971                                 return 0;
 972                         }
 973 
 974                         if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
 975                             hdr.version < FCGI_VERSION_1) {
 976                                 req->keep = 0;
 977                                 return 0;
 978                         }
 979                         len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
 980                         padding = hdr.paddingLength;
 981                 }
 982         } else if (hdr.type == FCGI_GET_VALUES) {
 983                 unsigned char *p = buf + sizeof(fcgi_header);
 984                 zval ** value;
 985                 unsigned int zlen;
 986                 fcgi_hash_bucket *q;
 987 
 988                 if (safe_read(req, buf, len+padding) != len+padding) {
 989                         req->keep = 0;
 990                         return 0;
 991                 }
 992 
 993                 if (!fcgi_get_params(req, buf, buf+len)) {
 994                         req->keep = 0;
 995                         return 0;
 996                 }
 997 
 998                 q = req->env.list;
 999                 while (q != NULL) {
1000                         if (zend_hash_find(&fcgi_mgmt_vars, q->var, q->var_len, (void**) &value) != SUCCESS) {
1001                                 q = q->list_next;
1002                                 continue;
1003                         }
1004                         zlen = Z_STRLEN_PP(value);
1005                         if ((p + 4 + 4 + q->var_len + zlen) >= (buf + sizeof(buf))) {
1006                                 break;
1007                         }
1008                         if (q->var_len < 0x80) {
1009                                 *p++ = q->var_len;
1010                         } else {
1011                                 *p++ = ((q->var_len >> 24) & 0xff) | 0x80;
1012                                 *p++ = (q->var_len >> 16) & 0xff;
1013                                 *p++ = (q->var_len >> 8) & 0xff;
1014                                 *p++ = q->var_len & 0xff;
1015                         }
1016                         if (zlen < 0x80) {
1017                                 *p++ = zlen;
1018                         } else {
1019                                 *p++ = ((zlen >> 24) & 0xff) | 0x80;
1020                                 *p++ = (zlen >> 16) & 0xff;
1021                                 *p++ = (zlen >> 8) & 0xff;
1022                                 *p++ = zlen & 0xff;
1023                         }
1024                         memcpy(p, q->var, q->var_len);
1025                         p += q->var_len;
1026                         memcpy(p, Z_STRVAL_PP(value), zlen);
1027                         p += zlen;
1028                         q = q->list_next;
1029                 }
1030                 len = p - buf - sizeof(fcgi_header);
1031                 len += fcgi_make_header((fcgi_header*)buf, FCGI_GET_VALUES_RESULT, 0, len);
1032                 if (safe_write(req, buf, sizeof(fcgi_header)+len) != (int)sizeof(fcgi_header)+len) {
1033                         req->keep = 0;
1034                         return 0;
1035                 }
1036                 return 0;
1037         } else {
1038                 return 0;
1039         }
1040 
1041         return 1;
1042 }
1043 
1044 int fcgi_read(fcgi_request *req, char *str, int len)
1045 {
1046         int ret, n, rest;
1047         fcgi_header hdr;
1048         unsigned char buf[255];
1049 
1050         n = 0;
1051         rest = len;
1052         while (rest > 0) {
1053                 if (req->in_len == 0) {
1054                         if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
1055                             hdr.version < FCGI_VERSION_1 ||
1056                             hdr.type != FCGI_STDIN) {
1057                                 req->keep = 0;
1058                                 return 0;
1059                         }
1060                         req->in_len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
1061                         req->in_pad = hdr.paddingLength;
1062                         if (req->in_len == 0) {
1063                                 return n;
1064                         }
1065                 }
1066 
1067                 if (req->in_len >= rest) {
1068                         ret = safe_read(req, str, rest);
1069                 } else {
1070                         ret = safe_read(req, str, req->in_len);
1071                 }
1072                 if (ret < 0) {
1073                         req->keep = 0;
1074                         return ret;
1075                 } else if (ret > 0) {
1076                         req->in_len -= ret;
1077                         rest -= ret;
1078                         n += ret;
1079                         str += ret;
1080                         if (req->in_len == 0) {
1081                                 if (req->in_pad) {
1082                                         if (safe_read(req, buf, req->in_pad) != req->in_pad) {
1083                                                 req->keep = 0;
1084                                                 return ret;
1085                                         }
1086                                 }
1087                         } else {
1088                                 return n;
1089                         }
1090                 } else {
1091                         return n;
1092                 }
1093         }
1094         return n;
1095 }
1096 
1097 static inline void fcgi_close(fcgi_request *req, int force, int destroy)
1098 {
1099         if (destroy && req->has_env) {
1100                 fcgi_hash_clean(&req->env);
1101                 req->has_env = 0;
1102         }
1103 
1104 #ifdef _WIN32
1105         if (is_impersonate && !req->tcp) {
1106                 RevertToSelf();
1107         }
1108 #endif
1109 
1110         if ((force || !req->keep) && req->fd >= 0) {
1111 #ifdef _WIN32
1112                 if (!req->tcp) {
1113                         HANDLE pipe = (HANDLE)_get_osfhandle(req->fd);
1114 
1115                         if (!force) {
1116                                 FlushFileBuffers(pipe);
1117                         }
1118                         DisconnectNamedPipe(pipe);
1119                 } else {
1120                         if (!force) {
1121                                 fcgi_header buf;
1122 
1123                                 shutdown(req->fd, 1);
1124                                 /* read the last FCGI_STDIN header (it may be omitted) */
1125                                 recv(req->fd, (char *)(&buf), sizeof(buf), 0);
1126                         }
1127                         closesocket(req->fd);
1128                 }
1129 #else
1130                 if (!force) {
1131                         fcgi_header buf;
1132 
1133                         shutdown(req->fd, 1);
1134                         /* read the last FCGI_STDIN header (it may be omitted) */
1135                         recv(req->fd, (char *)(&buf), sizeof(buf), 0);
1136                 }
1137                 close(req->fd);
1138 #endif
1139 #ifdef TCP_NODELAY
1140                 req->nodelay = 0;
1141 #endif
1142                 req->fd = -1;
1143         }
1144 }
1145 
1146 int fcgi_accept_request(fcgi_request *req)
1147 {
1148 #ifdef _WIN32
1149         HANDLE pipe;
1150         OVERLAPPED ov;
1151 #endif
1152 
1153         while (1) {
1154                 if (req->fd < 0) {
1155                         while (1) {
1156                                 if (in_shutdown) {
1157                                         return -1;
1158                                 }
1159 #ifdef _WIN32
1160                                 if (!req->tcp) {
1161                                         pipe = (HANDLE)_get_osfhandle(req->listen_socket);
1162                                         FCGI_LOCK(req->listen_socket);
1163                                         ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
1164                                         if (!ConnectNamedPipe(pipe, &ov)) {
1165                                                 errno = GetLastError();
1166                                                 if (errno == ERROR_IO_PENDING) {
1167                                                         while (WaitForSingleObject(ov.hEvent, 1000) == WAIT_TIMEOUT) {
1168                                                                 if (in_shutdown) {
1169                                                                         CloseHandle(ov.hEvent);
1170                                                                         FCGI_UNLOCK(req->listen_socket);
1171                                                                         return -1;
1172                                                                 }
1173                                                         }
1174                                                 } else if (errno != ERROR_PIPE_CONNECTED) {
1175                                                 }
1176                                         }
1177                                         CloseHandle(ov.hEvent);
1178                                         req->fd = req->listen_socket;
1179                                         FCGI_UNLOCK(req->listen_socket);
1180                                 } else {
1181                                         SOCKET listen_socket = (SOCKET)_get_osfhandle(req->listen_socket);
1182 #else
1183                                 {
1184                                         int listen_socket = req->listen_socket;
1185 #endif
1186                                         sa_t sa;
1187                                         socklen_t len = sizeof(sa);
1188 
1189                                         FCGI_LOCK(req->listen_socket);
1190                                         req->fd = accept(listen_socket, (struct sockaddr *)&sa, &len);
1191                                         FCGI_UNLOCK(req->listen_socket);
1192                                         if (req->fd >= 0) {
1193                                                 if (((struct sockaddr *)&sa)->sa_family == AF_INET) {
1194 #ifndef _WIN32
1195                                                         req->tcp = 1;
1196 #endif
1197                                                         if (allowed_clients) {
1198                                                                 int n = 0;
1199                                                                 int allowed = 0;
1200 
1201                                                                 while (allowed_clients[n] != INADDR_NONE) {
1202                                                                         if (allowed_clients[n] == sa.sa_inet.sin_addr.s_addr) {
1203                                                                                 allowed = 1;
1204                                                                                 break;
1205                                                                         }
1206                                                                         n++;
1207                                                                 }
1208                                                                 if (!allowed) {
1209                                                                         fprintf(stderr, "Connection from disallowed IP address '%s' is dropped.\n", inet_ntoa(sa.sa_inet.sin_addr));
1210                                                                         closesocket(req->fd);
1211                                                                         req->fd = -1;
1212                                                                         continue;
1213                                                                 }
1214                                                         }
1215 #ifndef _WIN32
1216                                                 } else {
1217                                                         req->tcp = 0;
1218 #endif
1219                                                 }
1220                                         }
1221                                 }
1222 
1223 #ifdef _WIN32
1224                                 if (req->fd < 0 && (in_shutdown || errno != EINTR)) {
1225 #else
1226                                 if (req->fd < 0 && (in_shutdown || (errno != EINTR && errno != ECONNABORTED))) {
1227 #endif
1228                                         return -1;
1229                                 }
1230 
1231 #ifdef _WIN32
1232                                 break;
1233 #else
1234                                 if (req->fd >= 0) {
1235 #if defined(HAVE_SYS_POLL_H) && defined(HAVE_POLL)
1236                                         struct pollfd fds;
1237                                         int ret;
1238 
1239                                         fds.fd = req->fd;
1240                                         fds.events = POLLIN;
1241                                         fds.revents = 0;
1242                                         do {
1243                                                 errno = 0;
1244                                                 ret = poll(&fds, 1, 5000);
1245                                         } while (ret < 0 && errno == EINTR);
1246                                         if (ret > 0 && (fds.revents & POLLIN)) {
1247                                                 break;
1248                                         }
1249                                         fcgi_close(req, 1, 0);
1250 #else
1251                                         if (req->fd < FD_SETSIZE) {
1252                                                 struct timeval tv = {5,0};
1253                                                 fd_set set;
1254                                                 int ret;
1255 
1256                                                 FD_ZERO(&set);
1257                                                 FD_SET(req->fd, &set);
1258                                                 do {
1259                                                         errno = 0;
1260                                                         ret = select(req->fd + 1, &set, NULL, NULL, &tv) >= 0;
1261                                                 } while (ret < 0 && errno == EINTR);
1262                                                 if (ret > 0 && FD_ISSET(req->fd, &set)) {
1263                                                         break;
1264                                                 }
1265                                                 fcgi_close(req, 1, 0);
1266                                         } else {
1267                                                 fprintf(stderr, "Too many open file descriptors. FD_SETSIZE limit exceeded.");
1268                                                 fcgi_close(req, 1, 0);
1269                                         }
1270 #endif
1271                                 }
1272 #endif
1273                         }
1274                 } else if (in_shutdown) {
1275                         return -1;
1276                 }
1277                 if (fcgi_read_request(req)) {
1278 #ifdef _WIN32
1279                         if (is_impersonate && !req->tcp) {
1280                                 pipe = (HANDLE)_get_osfhandle(req->fd);
1281                                 if (!ImpersonateNamedPipeClient(pipe)) {
1282                                         fcgi_close(req, 1, 1);
1283                                         continue;
1284                                 }
1285                         }
1286 #endif
1287                         return req->fd;
1288                 } else {
1289                         fcgi_close(req, 1, 1);
1290                 }
1291         }
1292 }
1293 
1294 static inline fcgi_header* open_packet(fcgi_request *req, fcgi_request_type type)
1295 {
1296         req->out_hdr = (fcgi_header*) req->out_pos;
1297         req->out_hdr->type = type;
1298         req->out_pos += sizeof(fcgi_header);
1299         return req->out_hdr;
1300 }
1301 
1302 static inline void close_packet(fcgi_request *req)
1303 {
1304         if (req->out_hdr) {
1305                 int len = req->out_pos - ((unsigned char*)req->out_hdr + sizeof(fcgi_header));
1306 
1307                 req->out_pos += fcgi_make_header(req->out_hdr, (fcgi_request_type)req->out_hdr->type, req->id, len);
1308                 req->out_hdr = NULL;
1309         }
1310 }
1311 
1312 int fcgi_flush(fcgi_request *req, int close)
1313 {
1314         int len;
1315 
1316         close_packet(req);
1317 
1318         len = req->out_pos - req->out_buf;
1319 
1320         if (close) {
1321                 fcgi_end_request_rec *rec = (fcgi_end_request_rec*)(req->out_pos);
1322 
1323                 fcgi_make_header(&rec->hdr, FCGI_END_REQUEST, req->id, sizeof(fcgi_end_request));
1324                 rec->body.appStatusB3 = 0;
1325                 rec->body.appStatusB2 = 0;
1326                 rec->body.appStatusB1 = 0;
1327                 rec->body.appStatusB0 = 0;
1328                 rec->body.protocolStatus = FCGI_REQUEST_COMPLETE;
1329                 len += sizeof(fcgi_end_request_rec);
1330         }
1331 
1332         if (safe_write(req, req->out_buf, len) != len) {
1333                 req->keep = 0;
1334                 req->out_pos = req->out_buf;
1335                 return 0;
1336         }
1337 
1338         req->out_pos = req->out_buf;
1339         return 1;
1340 }
1341 
1342 int fcgi_write(fcgi_request *req, fcgi_request_type type, const char *str, int len)
1343 {
1344         int limit, rest;
1345 
1346         if (len <= 0) {
1347                 return 0;
1348         }
1349 
1350         if (req->out_hdr && req->out_hdr->type != type) {
1351                 close_packet(req);
1352         }
1353 #if 0
1354         /* Unoptimized, but clear version */
1355         rest = len;
1356         while (rest > 0) {
1357                 limit = sizeof(req->out_buf) - (req->out_pos - req->out_buf);
1358 
1359                 if (!req->out_hdr) {
1360                         if (limit < sizeof(fcgi_header)) {
1361                                 if (!fcgi_flush(req, 0)) {
1362                                         return -1;
1363                                 }
1364                         }
1365                         open_packet(req, type);
1366                 }
1367                 limit = sizeof(req->out_buf) - (req->out_pos - req->out_buf);
1368                 if (rest < limit) {
1369                         memcpy(req->out_pos, str, rest);
1370                         req->out_pos += rest;
1371                         return len;
1372                 } else {
1373                         memcpy(req->out_pos, str, limit);
1374                         req->out_pos += limit;
1375                         rest -= limit;
1376                         str += limit;
1377                         if (!fcgi_flush(req, 0)) {
1378                                 return -1;
1379                         }
1380                 }
1381         }
1382 #else
1383         /* Optimized version */
1384         limit = sizeof(req->out_buf) - (req->out_pos - req->out_buf);
1385         if (!req->out_hdr) {
1386                 limit -= sizeof(fcgi_header);
1387                 if (limit < 0) limit = 0;
1388         }
1389 
1390         if (len < limit) {
1391                 if (!req->out_hdr) {
1392                         open_packet(req, type);
1393                 }
1394                 memcpy(req->out_pos, str, len);
1395                 req->out_pos += len;
1396         } else if (len - limit < sizeof(req->out_buf) - sizeof(fcgi_header)) {
1397                 if (!req->out_hdr) {
1398                         open_packet(req, type);
1399                 }
1400                 if (limit > 0) {
1401                         memcpy(req->out_pos, str, limit);
1402                         req->out_pos += limit;
1403                 }
1404                 if (!fcgi_flush(req, 0)) {
1405                         return -1;
1406                 }
1407                 if (len > limit) {
1408                         open_packet(req, type);
1409                         memcpy(req->out_pos, str + limit, len - limit);
1410                         req->out_pos += len - limit;
1411                 }
1412         } else {
1413                 int pos = 0;
1414                 int pad;
1415 
1416                 close_packet(req);
1417                 while ((len - pos) > 0xffff) {
1418                         open_packet(req, type);
1419                         fcgi_make_header(req->out_hdr, type, req->id, 0xfff8);
1420                         req->out_hdr = NULL;
1421                         if (!fcgi_flush(req, 0)) {
1422                                 return -1;
1423                         }
1424                         if (safe_write(req, str + pos, 0xfff8) != 0xfff8) {
1425                                 req->keep = 0;
1426                                 return -1;
1427                         }
1428                         pos += 0xfff8;
1429                 }
1430 
1431                 pad = (((len - pos) + 7) & ~7) - (len - pos);
1432                 rest = pad ? 8 - pad : 0;
1433 
1434                 open_packet(req, type);
1435                 fcgi_make_header(req->out_hdr, type, req->id, (len - pos) - rest);
1436                 req->out_hdr = NULL;
1437                 if (!fcgi_flush(req, 0)) {
1438                         return -1;
1439                 }
1440                 if (safe_write(req, str + pos, (len - pos) - rest) != (len - pos) - rest) {
1441                         req->keep = 0;
1442                         return -1;
1443                 }
1444                 if (pad) {
1445                         open_packet(req, type);
1446                         memcpy(req->out_pos, str + len - rest,  rest);
1447                         req->out_pos += rest;
1448                 }
1449         }
1450 #endif
1451         return len;
1452 }
1453 
1454 int fcgi_finish_request(fcgi_request *req, int force_close)
1455 {
1456         int ret = 1;
1457 
1458         if (req->fd >= 0) {
1459                 if (!req->closed) {
1460                         ret = fcgi_flush(req, 1);
1461                         req->closed = 1;
1462                 }
1463                 fcgi_close(req, force_close, 1);
1464         }
1465         return ret;
1466 }
1467 
1468 char* fcgi_getenv(fcgi_request *req, const char* var, int var_len)
1469 {
1470         unsigned int val_len;
1471 
1472         if (!req) return NULL;
1473 
1474         return fcgi_hash_get(&req->env, FCGI_HASH_FUNC(var, var_len), (char*)var, var_len, &val_len);
1475 }
1476 
1477 char* fcgi_quick_getenv(fcgi_request *req, const char* var, int var_len, unsigned int hash_value)
1478 {
1479         unsigned int val_len;
1480 
1481         return fcgi_hash_get(&req->env, hash_value, (char*)var, var_len, &val_len);
1482 }
1483 
1484 char* fcgi_putenv(fcgi_request *req, char* var, int var_len, char* val)
1485 {
1486         if (!req) return NULL;
1487         if (val == NULL) {
1488                 fcgi_hash_del(&req->env, FCGI_HASH_FUNC(var, var_len), var, var_len);
1489                 return NULL;
1490         } else {
1491                 return fcgi_hash_set(&req->env, FCGI_HASH_FUNC(var, var_len), var, var_len, val, strlen(val));
1492         }
1493 }
1494 
1495 char* fcgi_quick_putenv(fcgi_request *req, char* var, int var_len, unsigned int hash_value, char* val)
1496 {
1497         if (val == NULL) {
1498                 fcgi_hash_del(&req->env, hash_value, var, var_len);
1499                 return NULL;
1500         } else {
1501                 return fcgi_hash_set(&req->env, hash_value, var, var_len, val, strlen(val));
1502         }
1503 }
1504 
1505 void fcgi_loadenv(fcgi_request *req, fcgi_apply_func func, zval *array TSRMLS_DC)
1506 {
1507         fcgi_hash_apply(&req->env, func, array TSRMLS_CC);
1508 }
1509 
1510 #ifdef _WIN32
1511 void fcgi_impersonate(void)
1512 {
1513         char *os_name;
1514 
1515         os_name = getenv("OS");
1516         if (os_name && stricmp(os_name, "Windows_NT") == 0) {
1517                 is_impersonate = 1;
1518         }
1519 }
1520 #endif
1521 
1522 void fcgi_set_mgmt_var(const char * name, size_t name_len, const char * value, size_t value_len)
1523 {
1524         zval * zvalue;
1525         zvalue = pemalloc(sizeof(*zvalue), 1);
1526         Z_TYPE_P(zvalue) = IS_STRING;
1527         Z_STRVAL_P(zvalue) = pestrndup(value, value_len, 1);
1528         Z_STRLEN_P(zvalue) = value_len;
1529         zend_hash_add(&fcgi_mgmt_vars, name, name_len, &zvalue, sizeof(zvalue), NULL);
1530 }
1531 
1532 void fcgi_free_mgmt_var_cb(void * ptr)
1533 {
1534         zval ** var = (zval **)ptr;
1535         pefree(Z_STRVAL_PP(var), 1);
1536         pefree(*var, 1);
1537 }
1538 
1539 /*
1540  * Local variables:
1541  * tab-width: 4
1542  * c-basic-offset: 4
1543  * End:
1544  * vim600: sw=4 ts=4 fdm=marker
1545  * vim<600: sw=4 ts=4
1546  */

/* [<][>][^][v][top][bottom][index][help] */