Back to index

php5  5.3.10
fastcgi.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2009 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Authors: Dmitry Stogov <dmitry@zend.com>                             |
00016    +----------------------------------------------------------------------+
00017 */
00018 
00019 /* $Id: fastcgi.c 287777 2009-08-26 19:17:32Z pajoye $ */
00020 
00021 #include "php.h"
00022 #include "fastcgi.h"
00023 
00024 #include <string.h>
00025 #include <stdlib.h>
00026 #include <stdio.h>
00027 #include <stdarg.h>
00028 #include <errno.h>
00029 #include <limits.h>
00030 
00031 #include <php_config.h>
00032 #include "fpm.h"
00033 #include "fpm_request.h"
00034 #include "zlog.h"
00035 
00036 #ifdef _WIN32
00037 
00038 #include <windows.h>
00039 
00040        typedef unsigned int in_addr_t;
00041 
00042        struct sockaddr_un {
00043               short   sun_family;
00044               char    sun_path[MAXPATHLEN];
00045        };
00046 
00047        static HANDLE fcgi_accept_mutex = INVALID_HANDLE_VALUE;
00048        static int is_impersonate = 0;
00049 
00050 #define FCGI_LOCK(fd) \
00051        if (fcgi_accept_mutex != INVALID_HANDLE_VALUE) { \
00052               DWORD ret; \
00053               while ((ret = WaitForSingleObject(fcgi_accept_mutex, 1000)) == WAIT_TIMEOUT) { \
00054                      if (in_shutdown) return -1; \
00055               } \
00056               if (ret == WAIT_FAILED) { \
00057                      fprintf(stderr, "WaitForSingleObject() failed\n"); \
00058                      return -1; \
00059               } \
00060        }
00061 
00062 #define FCGI_UNLOCK(fd) \
00063        if (fcgi_accept_mutex != INVALID_HANDLE_VALUE) { \
00064               ReleaseMutex(fcgi_accept_mutex); \
00065        }
00066 
00067 #else
00068 
00069 # include <sys/types.h>
00070 # include <sys/stat.h>
00071 # include <unistd.h>
00072 # include <fcntl.h>
00073 # include <sys/socket.h>
00074 # include <sys/un.h>
00075 # include <netinet/in.h>
00076 # include <arpa/inet.h>
00077 # include <netdb.h>
00078 # include <signal.h>
00079 
00080 # define closesocket(s) close(s)
00081 
00082 # if defined(HAVE_SYS_POLL_H) && defined(HAVE_POLL)
00083 #  include <sys/poll.h>
00084 # endif
00085 # if defined(HAVE_SYS_SELECT_H)
00086 #  include <sys/select.h>
00087 # endif
00088 
00089 #ifndef INADDR_NONE
00090 #define INADDR_NONE ((unsigned long) -1)
00091 #endif
00092 
00093 # ifndef HAVE_SOCKLEN_T
00094        typedef unsigned int socklen_t;
00095 # endif
00096 
00097 # ifdef USE_LOCKING
00098 #  define FCGI_LOCK(fd)                                                      \
00099        do {                                                                         \
00100               struct flock lock;                                             \
00101               lock.l_type = F_WRLCK;                                         \
00102               lock.l_start = 0;                                              \
00103               lock.l_whence = SEEK_SET;                               \
00104               lock.l_len = 0;                                                       \
00105               if (fcntl(fd, F_SETLKW, &lock) != -1) {          \
00106                      break;                                                         \
00107               } else if (errno != EINTR || in_shutdown) {      \
00108                      return -1;                                                     \
00109               }                                                                            \
00110        } while (1)
00111 
00112 #  define FCGI_UNLOCK(fd)                                             \
00113        do {                                                                         \
00114               int orig_errno = errno;                                        \
00115               while (1) {                                                           \
00116                      struct flock lock;                                      \
00117                      lock.l_type = F_UNLCK;                                  \
00118                      lock.l_start = 0;                                       \
00119                      lock.l_whence = SEEK_SET;                        \
00120                      lock.l_len = 0;                                                \
00121                      if (fcntl(fd, F_SETLK, &lock) != -1) {    \
00122                             break;                                                  \
00123                      } else if (errno != EINTR) {                     \
00124                             return -1;                                              \
00125                      }                                                                     \
00126               }                                                                            \
00127               errno = orig_errno;                                            \
00128        } while (0)
00129 # else
00130 #  define FCGI_LOCK(fd)
00131 #  define FCGI_UNLOCK(fd)
00132 # endif
00133 
00134 #endif
00135 
00136 typedef union _sa_t {
00137        struct sockaddr     sa;
00138        struct sockaddr_un  sa_unix;
00139        struct sockaddr_in  sa_inet;
00140 } sa_t;
00141 
00142 static HashTable fcgi_mgmt_vars;
00143 
00144 static int is_initialized = 0;
00145 static int in_shutdown = 0;
00146 static in_addr_t *allowed_clients = NULL;
00147 
00148 static sa_t client_sa;
00149 
00150 #ifdef _WIN32
00151 
00152 static DWORD WINAPI fcgi_shutdown_thread(LPVOID arg)
00153 {
00154        HANDLE shutdown_event = (HANDLE) arg;
00155        WaitForSingleObject(shutdown_event, INFINITE);
00156        in_shutdown = 1;
00157        return 0;
00158 }
00159 
00160 #else
00161 
00162 static void fcgi_signal_handler(int signo)
00163 {
00164        if (signo == SIGUSR1 || signo == SIGTERM) {
00165               in_shutdown = 1;
00166        }
00167 }
00168 
00169 static void fcgi_setup_signals(void)
00170 {
00171        struct sigaction new_sa, old_sa;
00172 
00173        sigemptyset(&new_sa.sa_mask);
00174        new_sa.sa_flags = 0;
00175        new_sa.sa_handler = fcgi_signal_handler;
00176        sigaction(SIGUSR1, &new_sa, NULL);
00177        sigaction(SIGTERM, &new_sa, NULL);
00178        sigaction(SIGPIPE, NULL, &old_sa);
00179        if (old_sa.sa_handler == SIG_DFL) {
00180               sigaction(SIGPIPE, &new_sa, NULL);
00181        }
00182 }
00183 #endif
00184 
00185 int fcgi_init(void)
00186 {
00187        if (!is_initialized) {
00188               zend_hash_init(&fcgi_mgmt_vars, 0, NULL, fcgi_free_mgmt_var_cb, 1);
00189               fcgi_set_mgmt_var("FCGI_MPXS_CONNS", sizeof("FCGI_MPXS_CONNS") - 1, "0", sizeof("0")-1);
00190 
00191               is_initialized = 1;
00192 #ifdef _WIN32
00193 # if 0
00194               /* TODO: Support for TCP sockets */
00195               WSADATA wsaData;
00196 
00197               if (WSAStartup(MAKEWORD(2,0), &wsaData)) {
00198                      fprintf(stderr, "Error starting Windows Sockets.  Error: %d", WSAGetLastError());
00199                      return 0;
00200               }
00201 # endif
00202               {
00203                      char *str;
00204                      DWORD pipe_mode = PIPE_READMODE_BYTE | PIPE_WAIT;
00205                      HANDLE pipe = GetStdHandle(STD_INPUT_HANDLE);
00206 
00207                      SetNamedPipeHandleState(pipe, &pipe_mode, NULL, NULL);
00208 
00209                      str = getenv("_FCGI_SHUTDOWN_EVENT_");
00210                      if (str != NULL) {
00211                             HANDLE shutdown_event = (HANDLE) atoi(str);
00212                             if (!CreateThread(NULL, 0, fcgi_shutdown_thread,
00213                                               shutdown_event, 0, NULL)) {
00214                                    return -1;
00215                             }
00216                      }
00217                      str = getenv("_FCGI_MUTEX_");
00218                      if (str != NULL) {
00219                             fcgi_accept_mutex = (HANDLE) atoi(str);
00220                      }
00221                      return 1;
00222               }
00223 #else
00224               fcgi_setup_signals();
00225               return 1;
00226 #endif
00227        }
00228        return 1;
00229 }
00230 
00231 void fcgi_set_in_shutdown(int new_value)
00232 {
00233        in_shutdown = new_value;
00234 }
00235 
00236 void fcgi_shutdown(void)
00237 {
00238        if (is_initialized) {
00239               zend_hash_destroy(&fcgi_mgmt_vars);
00240        }
00241        if (allowed_clients) {
00242               free(allowed_clients);
00243        }
00244 }
00245 
00246 void fcgi_set_allowed_clients(char *ip)
00247 {
00248        char *cur, *end;
00249        int n;
00250 
00251        if (ip) {
00252               ip = strdup(ip);
00253               cur = ip;
00254               n = 0;
00255               while (*cur) {
00256                      if (*cur == ',') n++;
00257                      cur++;
00258               }
00259               if (allowed_clients) free(allowed_clients);
00260               allowed_clients = malloc(sizeof(in_addr_t) * (n+2));
00261               n = 0;
00262               cur = ip;
00263               while (cur) {
00264                      end = strchr(cur, ',');
00265                      if (end) {
00266                             *end = 0;
00267                             end++;
00268                      }
00269                      allowed_clients[n] = inet_addr(cur);
00270                      if (allowed_clients[n] == INADDR_NONE) {
00271                             zlog(ZLOG_ERROR, "Wrong IP address '%s' in listen.allowed_clients", cur);
00272                      }
00273                      n++;
00274                      cur = end;
00275               }
00276               allowed_clients[n] = INADDR_NONE;
00277               free(ip);
00278        }
00279 }
00280 
00281 void fcgi_init_request(fcgi_request *req, int listen_socket)
00282 {
00283        memset(req, 0, sizeof(fcgi_request));
00284        req->listen_socket = listen_socket;
00285        req->fd = -1;
00286        req->id = -1;
00287 
00288        req->in_len = 0;
00289        req->in_pad = 0;
00290 
00291        req->out_hdr = NULL;
00292        req->out_pos = req->out_buf;
00293 
00294 #ifdef _WIN32
00295        req->tcp = !GetNamedPipeInfo((HANDLE)_get_osfhandle(req->listen_socket), NULL, NULL, NULL, NULL);
00296 #endif
00297 }
00298 
00299 static inline ssize_t safe_write(fcgi_request *req, const void *buf, size_t count)
00300 {
00301        int    ret;
00302        size_t n = 0;
00303 
00304        do {
00305               errno = 0;
00306 #ifdef _WIN32
00307               if (!req->tcp) {
00308                      ret = write(req->fd, ((char*)buf)+n, count-n);
00309               } else {
00310                      ret = send(req->fd, ((char*)buf)+n, count-n, 0);
00311                      if (ret <= 0) {
00312                             errno = WSAGetLastError();
00313                      }
00314               }
00315 #else
00316               ret = write(req->fd, ((char*)buf)+n, count-n);
00317 #endif
00318               if (ret > 0) {
00319                      n += ret;
00320               } else if (ret <= 0 && errno != 0 && errno != EINTR) {
00321                      return ret;
00322               }
00323        } while (n != count);
00324        return n;
00325 }
00326 
00327 static inline ssize_t safe_read(fcgi_request *req, const void *buf, size_t count)
00328 {
00329        int    ret;
00330        size_t n = 0;
00331 
00332        do {
00333               errno = 0;
00334 #ifdef _WIN32
00335               if (!req->tcp) {
00336                      ret = read(req->fd, ((char*)buf)+n, count-n);
00337               } else {
00338                      ret = recv(req->fd, ((char*)buf)+n, count-n, 0);
00339                      if (ret <= 0) {
00340                             errno = WSAGetLastError();
00341                      }
00342               }
00343 #else
00344               ret = read(req->fd, ((char*)buf)+n, count-n);
00345 #endif
00346               if (ret > 0) {
00347                      n += ret;
00348               } else if (ret == 0 && errno == 0) {
00349                      return n;
00350               } else if (ret <= 0 && errno != 0 && errno != EINTR) {
00351                      return ret;
00352               }
00353        } while (n != count);
00354        return n;
00355 }
00356 
00357 static inline int fcgi_make_header(fcgi_header *hdr, fcgi_request_type type, int req_id, int len)
00358 {
00359        int pad = ((len + 7) & ~7) - len;
00360 
00361        hdr->contentLengthB0 = (unsigned char)(len & 0xff);
00362        hdr->contentLengthB1 = (unsigned char)((len >> 8) & 0xff);
00363        hdr->paddingLength = (unsigned char)pad;
00364        hdr->requestIdB0 = (unsigned char)(req_id & 0xff);
00365        hdr->requestIdB1 = (unsigned char)((req_id >> 8) & 0xff);
00366        hdr->reserved = 0;
00367        hdr->type = type;
00368        hdr->version = FCGI_VERSION_1;
00369        if (pad) {
00370               memset(((unsigned char*)hdr) + sizeof(fcgi_header) + len, 0, pad);
00371        }
00372        return pad;
00373 }
00374 
00375 static inline size_t fcgi_get_params_len( int *result, unsigned char *p, unsigned char *end)
00376 {
00377        size_t ret = 0;
00378 
00379        if (p < end) {
00380               *result = p[0];
00381               if (*result < 128) {
00382                      ret = 1;
00383               }
00384               else if (p + 3 < end) {
00385                      *result = ((*result & 0x7f) << 24);
00386                      *result |= (p[1] << 16);
00387                      *result |= (p[2] << 8);
00388                      *result |= p[3];
00389                      ret = 4;
00390               }
00391        }
00392        if (*result < 0) {
00393               ret = 0;
00394        }
00395        return ret;
00396 }
00397 
00398 static inline int fcgi_param_get_eff_len( unsigned char *p, unsigned char *end, uint *eff_len)
00399 {
00400        int ret = 1;
00401        int zero_found = 0;
00402         *eff_len = 0;
00403        for (; p != end; ++p) {
00404               if (*p == '\0') {
00405                      zero_found = 1;
00406               }
00407               else {
00408                      if (zero_found) {
00409                             ret = 0;
00410                             break;
00411                      }
00412                      if (*eff_len < ((uint)-1)) {
00413                             ++*eff_len;
00414                      }
00415                      else {
00416                             ret = 0;
00417                             break;
00418                      }
00419               }
00420        }
00421        return ret;
00422 }
00423 
00424 static int fcgi_get_params(fcgi_request *req, unsigned char *p, unsigned char *end)
00425 {
00426        char buf[128];
00427        char *tmp = buf;
00428        size_t buf_size = sizeof(buf);
00429        int name_len, val_len;
00430        uint eff_name_len, eff_val_len;
00431        char *s;
00432        int ret = 1;
00433        size_t bytes_consumed;
00434 
00435        while (p < end) {
00436               bytes_consumed = fcgi_get_params_len(&name_len, p, end);
00437               if (!bytes_consumed) {
00438                      /* Malformated request */
00439                      ret = 0;
00440                      break;
00441               }
00442               p += bytes_consumed;
00443               bytes_consumed = fcgi_get_params_len(&val_len, p, end);
00444               if (!bytes_consumed) {
00445                      /* Malformated request */
00446                      ret = 0;
00447                      break;
00448               }
00449               p += bytes_consumed;
00450               if (name_len > (INT_MAX - val_len) || /* would the addition overflow? */
00451                   name_len + val_len > end - p) {   /* would we exceed the buffer? */
00452                      /* Malformated request */
00453                      ret = 0;
00454                      break;
00455               }
00456               if (!fcgi_param_get_eff_len(p, p+name_len, &eff_name_len) ||
00457                   !fcgi_param_get_eff_len(p+name_len, p+name_len+val_len, &eff_val_len)) {
00458                      /* Malicious request */
00459                      ret = 0;
00460                      break;
00461               }
00462               if (eff_name_len >= buf_size-1) {
00463                      if (eff_name_len > ((uint)-1)-64) { 
00464                             ret = 0;
00465                             break;
00466                      }
00467                      buf_size = eff_name_len + 64;
00468                      tmp = (tmp == buf ? emalloc(buf_size): erealloc(tmp, buf_size));
00469                      if (tmp == NULL) {
00470                             ret = 0;
00471                             break;
00472                      }
00473               }
00474               memcpy(tmp, p, eff_name_len);
00475               tmp[eff_name_len] = 0;
00476               s = estrndup((char*)p + name_len, eff_val_len);
00477               if (s == NULL) {
00478                      ret = 0;
00479                      break;
00480               }
00481               zend_hash_update(req->env, tmp, eff_name_len+1, &s, sizeof(char*), NULL);
00482               p += name_len + val_len;
00483        }
00484        if (tmp != buf && tmp != NULL) {
00485               efree(tmp);
00486        }
00487        return ret;
00488 }
00489 
00490 static void fcgi_free_var(char **s)
00491 {
00492        efree(*s);
00493 }
00494 
00495 static int fcgi_read_request(fcgi_request *req)
00496 {
00497        fcgi_header hdr;
00498        int len, padding;
00499        unsigned char buf[FCGI_MAX_LENGTH+8];
00500 
00501        req->keep = 0;
00502        req->closed = 0;
00503        req->in_len = 0;
00504        req->out_hdr = NULL;
00505        req->out_pos = req->out_buf;
00506        ALLOC_HASHTABLE(req->env);
00507        zend_hash_init(req->env, 0, NULL, (void (*)(void *)) fcgi_free_var, 0);
00508 
00509        if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
00510            hdr.version < FCGI_VERSION_1) {
00511               return 0;
00512        }
00513 
00514        len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
00515        padding = hdr.paddingLength;
00516 
00517        while (hdr.type == FCGI_STDIN && len == 0) {
00518               if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
00519                   hdr.version < FCGI_VERSION_1) {
00520                      return 0;
00521               }
00522 
00523               len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
00524               padding = hdr.paddingLength;
00525        }
00526 
00527        if (len + padding > FCGI_MAX_LENGTH) {
00528               return 0;
00529        }
00530 
00531        req->id = (hdr.requestIdB1 << 8) + hdr.requestIdB0;
00532 
00533        if (hdr.type == FCGI_BEGIN_REQUEST && len == sizeof(fcgi_begin_request)) {
00534               char *val;
00535 
00536               if (safe_read(req, buf, len+padding) != len+padding) {
00537                      return 0;
00538               }
00539 
00540               req->keep = (((fcgi_begin_request*)buf)->flags & FCGI_KEEP_CONN);
00541               switch ((((fcgi_begin_request*)buf)->roleB1 << 8) + ((fcgi_begin_request*)buf)->roleB0) {
00542                      case FCGI_RESPONDER:
00543                             val = estrdup("RESPONDER");
00544                             zend_hash_update(req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), &val, sizeof(char*), NULL);
00545                             break;
00546                      case FCGI_AUTHORIZER:
00547                             val = estrdup("AUTHORIZER");
00548                             zend_hash_update(req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), &val, sizeof(char*), NULL);
00549                             break;
00550                      case FCGI_FILTER:
00551                             val = estrdup("FILTER");
00552                             zend_hash_update(req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), &val, sizeof(char*), NULL);
00553                             break;
00554                      default:
00555                             return 0;
00556               }
00557 
00558               if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
00559                   hdr.version < FCGI_VERSION_1) {
00560                      return 0;
00561               }
00562 
00563               len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
00564               padding = hdr.paddingLength;
00565 
00566               while (hdr.type == FCGI_PARAMS && len > 0) {
00567                      if (len + padding > FCGI_MAX_LENGTH) {
00568                             return 0;
00569                      }
00570 
00571                      if (safe_read(req, buf, len+padding) != len+padding) {
00572                             req->keep = 0;
00573                             return 0;
00574                      }
00575 
00576                      if (!fcgi_get_params(req, buf, buf+len)) {
00577                             req->keep = 0;
00578                             return 0;
00579                      }
00580 
00581                      if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
00582                          hdr.version < FCGI_VERSION_1) {
00583                             req->keep = 0;
00584                             return 0;
00585                      }
00586                      len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
00587                      padding = hdr.paddingLength;
00588               }
00589        } else if (hdr.type == FCGI_GET_VALUES) {
00590               unsigned char *p = buf + sizeof(fcgi_header);
00591               HashPosition pos;
00592               char * str_index;
00593               uint str_length;
00594               ulong num_index;
00595               int key_type;
00596               zval ** value;
00597 
00598               if (safe_read(req, buf, len+padding) != len+padding) {
00599                      req->keep = 0;
00600                      return 0;
00601               }
00602 
00603               if (!fcgi_get_params(req, buf, buf+len)) {
00604                      req->keep = 0;
00605                      return 0;
00606               }
00607 
00608               zend_hash_internal_pointer_reset_ex(req->env, &pos);
00609               while ((key_type = zend_hash_get_current_key_ex(req->env, &str_index, &str_length, &num_index, 0, &pos)) != HASH_KEY_NON_EXISTANT) {
00610                      int zlen;
00611                      zend_hash_move_forward_ex(req->env, &pos);
00612                      if (key_type != HASH_KEY_IS_STRING) {
00613                             continue;
00614                      }
00615                      if (zend_hash_find(&fcgi_mgmt_vars, str_index, str_length, (void**) &value) != SUCCESS) {
00616                             continue;
00617                      }
00618                      --str_length;
00619                      zlen = Z_STRLEN_PP(value);
00620                      if ((p + 4 + 4 + str_length + zlen) >= (buf + sizeof(buf))) {
00621                             break;
00622                      }
00623                      if (str_length < 0x80) {
00624                             *p++ = str_length;
00625                      } else {
00626                             *p++ = ((str_length >> 24) & 0xff) | 0x80;
00627                             *p++ = (str_length >> 16) & 0xff;
00628                             *p++ = (str_length >> 8) & 0xff;
00629                             *p++ = str_length & 0xff;
00630                      }
00631                      if (zlen < 0x80) {
00632                             *p++ = zlen;
00633                      } else {
00634                             *p++ = ((zlen >> 24) & 0xff) | 0x80;
00635                             *p++ = (zlen >> 16) & 0xff;
00636                             *p++ = (zlen >> 8) & 0xff;
00637                             *p++ = zlen & 0xff;
00638                      }
00639                      memcpy(p, str_index, str_length);
00640                      p += str_length;
00641                      memcpy(p, Z_STRVAL_PP(value), zlen);
00642                      p += zlen;
00643               }
00644               len = p - buf - sizeof(fcgi_header);
00645               len += fcgi_make_header((fcgi_header*)buf, FCGI_GET_VALUES_RESULT, 0, len);
00646               if (safe_write(req, buf, sizeof(fcgi_header)+len) != (int)sizeof(fcgi_header)+len) {
00647                      req->keep = 0;
00648                      return 0;
00649               }
00650               return 0;
00651        } else {
00652               return 0;
00653        }
00654 
00655        return 1;
00656 }
00657 
00658 int fcgi_read(fcgi_request *req, char *str, int len)
00659 {
00660        int ret, n, rest;
00661        fcgi_header hdr;
00662        unsigned char buf[255];
00663 
00664        n = 0;
00665        rest = len;
00666        while (rest > 0) {
00667               if (req->in_len == 0) {
00668                      if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
00669                          hdr.version < FCGI_VERSION_1 ||
00670                          hdr.type != FCGI_STDIN) {
00671                             req->keep = 0;
00672                             return 0;
00673                      }
00674                      req->in_len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
00675                      req->in_pad = hdr.paddingLength;
00676                      if (req->in_len == 0) {
00677                             return n;
00678                      }
00679               }
00680 
00681               if (req->in_len >= rest) {
00682                      ret = safe_read(req, str, rest);
00683               } else {
00684                      ret = safe_read(req, str, req->in_len);
00685               }
00686               if (ret < 0) {
00687                      req->keep = 0;
00688                      return ret;
00689               } else if (ret > 0) {
00690                      req->in_len -= ret;
00691                      rest -= ret;
00692                      n += ret;
00693                      str += ret;
00694                      if (req->in_len == 0) {
00695                             if (req->in_pad) {
00696                                    if (safe_read(req, buf, req->in_pad) != req->in_pad) {
00697                                           req->keep = 0;
00698                                           return ret;
00699                                    }
00700                             }
00701                      } else {
00702                             return n;
00703                      }
00704               } else {
00705                      return n;
00706               }
00707        }
00708        return n;
00709 }
00710 
00711 void fcgi_close(fcgi_request *req, int force, int destroy)
00712 {
00713        if (destroy && req->env) {
00714               zend_hash_destroy(req->env);
00715               FREE_HASHTABLE(req->env);
00716               req->env = NULL;
00717        }
00718 
00719 #ifdef _WIN32
00720        if (is_impersonate && !req->tcp) {
00721               RevertToSelf();
00722        }
00723 #endif
00724 
00725        if ((force || !req->keep) && req->fd >= 0) {
00726 #ifdef _WIN32
00727               if (!req->tcp) {
00728                      HANDLE pipe = (HANDLE)_get_osfhandle(req->fd);
00729 
00730                      if (!force) {
00731                             FlushFileBuffers(pipe);
00732                      }
00733                      DisconnectNamedPipe(pipe);
00734               } else {
00735                      if (!force) {
00736                             char buf[8];
00737 
00738                             shutdown(req->fd, 1);
00739                             while (recv(req->fd, buf, sizeof(buf), 0) > 0) {}
00740                      }
00741                      closesocket(req->fd);
00742               }
00743 #else
00744               if (!force) {
00745                      char buf[8];
00746 
00747                      shutdown(req->fd, 1);
00748                      while (recv(req->fd, buf, sizeof(buf), 0) > 0) {}
00749               }
00750               close(req->fd);
00751 #endif
00752               req->fd = -1;
00753               fpm_request_finished();
00754        }
00755 }
00756 
00757 int fcgi_accept_request(fcgi_request *req)
00758 {
00759 #ifdef _WIN32
00760        HANDLE pipe;
00761        OVERLAPPED ov;
00762 #endif
00763 
00764        while (1) {
00765               if (req->fd < 0) {
00766                      while (1) {
00767                             if (in_shutdown) {
00768                                    return -1;
00769                             }
00770 #ifdef _WIN32
00771                             if (!req->tcp) {
00772                                    pipe = (HANDLE)_get_osfhandle(req->listen_socket);
00773                                    FCGI_LOCK(req->listen_socket);
00774                                    ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
00775                                    if (!ConnectNamedPipe(pipe, &ov)) {
00776                                           errno = GetLastError();
00777                                           if (errno == ERROR_IO_PENDING) {
00778                                                  while (WaitForSingleObject(ov.hEvent, 1000) == WAIT_TIMEOUT) {
00779                                                         if (in_shutdown) {
00780                                                                CloseHandle(ov.hEvent);
00781                                                                FCGI_UNLOCK(req->listen_socket);
00782                                                                return -1;
00783                                                         }
00784                                                  }
00785                                           } else if (errno != ERROR_PIPE_CONNECTED) {
00786                                           }
00787                                    }
00788                                    CloseHandle(ov.hEvent);
00789                                    req->fd = req->listen_socket;
00790                                    FCGI_UNLOCK(req->listen_socket);
00791                             } else {
00792                                    SOCKET listen_socket = (SOCKET)_get_osfhandle(req->listen_socket);
00793 #else
00794                             {
00795                                    int listen_socket = req->listen_socket;
00796 #endif
00797                                    sa_t sa;
00798                                    socklen_t len = sizeof(sa);
00799 
00800                                    fpm_request_accepting();
00801 
00802                                    FCGI_LOCK(req->listen_socket);
00803                                    req->fd = accept(listen_socket, (struct sockaddr *)&sa, &len);
00804                                    FCGI_UNLOCK(req->listen_socket);
00805 
00806                                    client_sa = sa;
00807                                    if (sa.sa.sa_family == AF_INET && req->fd >= 0 && allowed_clients) {
00808                                           int n = 0;
00809                                           int allowed = 0;
00810 
00811                                           while (allowed_clients[n] != INADDR_NONE) {
00812                                                  if (allowed_clients[n] == sa.sa_inet.sin_addr.s_addr) {
00813                                                         allowed = 1;
00814                                                         break;
00815                                                  }
00816                                                  n++;
00817                                           }
00818                                           if (!allowed) {
00819                                                  zlog(ZLOG_ERROR, "Connection disallowed: IP address '%s' has been dropped.", inet_ntoa(sa.sa_inet.sin_addr));
00820                                                  closesocket(req->fd);
00821                                                  req->fd = -1;
00822                                                  continue;
00823                                           }
00824                                    }
00825                             }
00826 
00827 #ifdef _WIN32
00828                             if (req->fd < 0 && (in_shutdown || errno != EINTR)) {
00829 #else
00830                             if (req->fd < 0 && (in_shutdown || (errno != EINTR && errno != ECONNABORTED))) {
00831 #endif
00832                                    return -1;
00833                             }
00834 
00835 #ifdef _WIN32
00836                             break;
00837 #else
00838                             if (req->fd >= 0) {
00839 #if defined(HAVE_SYS_POLL_H) && defined(HAVE_POLL)
00840                                    struct pollfd fds;
00841                                    int ret;
00842 
00843                                    fpm_request_reading_headers();
00844 
00845                                    fds.fd = req->fd;
00846                                    fds.events = POLLIN;
00847                                    fds.revents = 0;
00848                                    do {
00849                                           errno = 0;
00850                                           ret = poll(&fds, 1, 5000);
00851                                    } while (ret < 0 && errno == EINTR);
00852                                    if (ret > 0 && (fds.revents & POLLIN)) {
00853                                           break;
00854                                    }
00855                                    fcgi_close(req, 1, 0);
00856 #else
00857                                    fpm_request_reading_headers();
00858 
00859                                    if (req->fd < FD_SETSIZE) {
00860                                           struct timeval tv = {5,0};
00861                                           fd_set set;
00862                                           int ret;
00863 
00864                                           FD_ZERO(&set);
00865                                           FD_SET(req->fd, &set);
00866                                           do {
00867                                                  errno = 0;
00868                                                  ret = select(req->fd + 1, &set, NULL, NULL, &tv) >= 0;
00869                                           } while (ret < 0 && errno == EINTR);
00870                                           if (ret > 0 && FD_ISSET(req->fd, &set)) {
00871                                                  break;
00872                                           }
00873                                           fcgi_close(req, 1, 0);
00874                                    } else {
00875                                           zlog(ZLOG_ERROR, "Too many open file descriptors. FD_SETSIZE limit exceeded.");
00876                                           fcgi_close(req, 1, 0);
00877                                    }
00878 #endif
00879                             }
00880 #endif
00881                      }
00882               } else if (in_shutdown) {
00883                      return -1;
00884               }
00885               if (fcgi_read_request(req)) {
00886 #ifdef _WIN32
00887                      if (is_impersonate && !req->tcp) {
00888                             pipe = (HANDLE)_get_osfhandle(req->fd);
00889                             if (!ImpersonateNamedPipeClient(pipe)) {
00890                                    fcgi_close(req, 1, 1);
00891                                    continue;
00892                             }
00893                      }
00894 #endif
00895                      return req->fd;
00896               } else {
00897                      fcgi_close(req, 1, 1);
00898               }
00899        }
00900 }
00901 
00902 static inline fcgi_header* open_packet(fcgi_request *req, fcgi_request_type type)
00903 {
00904        req->out_hdr = (fcgi_header*) req->out_pos;
00905        req->out_hdr->type = type;
00906        req->out_pos += sizeof(fcgi_header);
00907        return req->out_hdr;
00908 }
00909 
00910 static inline void close_packet(fcgi_request *req)
00911 {
00912        if (req->out_hdr) {
00913               int len = req->out_pos - ((unsigned char*)req->out_hdr + sizeof(fcgi_header));
00914 
00915               req->out_pos += fcgi_make_header(req->out_hdr, (fcgi_request_type)req->out_hdr->type, req->id, len);
00916               req->out_hdr = NULL;
00917        }
00918 }
00919 
00920 int fcgi_flush(fcgi_request *req, int close)
00921 {
00922        int len;
00923 
00924        close_packet(req);
00925 
00926        len = req->out_pos - req->out_buf;
00927 
00928        if (close) {
00929               fcgi_end_request_rec *rec = (fcgi_end_request_rec*)(req->out_pos);
00930 
00931               fcgi_make_header(&rec->hdr, FCGI_END_REQUEST, req->id, sizeof(fcgi_end_request));
00932               rec->body.appStatusB3 = 0;
00933               rec->body.appStatusB2 = 0;
00934               rec->body.appStatusB1 = 0;
00935               rec->body.appStatusB0 = 0;
00936               rec->body.protocolStatus = FCGI_REQUEST_COMPLETE;
00937               len += sizeof(fcgi_end_request_rec);
00938        }
00939 
00940        if (safe_write(req, req->out_buf, len) != len) {
00941               req->keep = 0;
00942               return 0;
00943        }
00944 
00945        req->out_pos = req->out_buf;
00946        return 1;
00947 }
00948 
00949 ssize_t fcgi_write(fcgi_request *req, fcgi_request_type type, const char *str, int len)
00950 {
00951        int limit, rest;
00952 
00953        if (len <= 0) {
00954               return 0;
00955        }
00956 
00957        if (req->out_hdr && req->out_hdr->type != type) {
00958               close_packet(req);
00959        }
00960 
00961        /* Optimized version */
00962        limit = sizeof(req->out_buf) - (req->out_pos - req->out_buf);
00963        if (!req->out_hdr) {
00964               limit -= sizeof(fcgi_header);
00965               if (limit < 0) limit = 0;
00966        }
00967 
00968        if (len < limit) {
00969               if (!req->out_hdr) {
00970                      open_packet(req, type);
00971               }
00972               memcpy(req->out_pos, str, len);
00973               req->out_pos += len;
00974        } else if (len - limit < sizeof(req->out_buf) - sizeof(fcgi_header)) {
00975               if (!req->out_hdr) {
00976                      open_packet(req, type);
00977               }
00978               if (limit > 0) {
00979                      memcpy(req->out_pos, str, limit);
00980                      req->out_pos += limit;
00981               }
00982               if (!fcgi_flush(req, 0)) {
00983                      return -1;
00984               }
00985               if (len > limit) {
00986                      open_packet(req, type);
00987                      memcpy(req->out_pos, str + limit, len - limit);
00988                      req->out_pos += len - limit;
00989               }
00990        } else {
00991               int pos = 0;
00992               int pad;
00993 
00994               close_packet(req);
00995               while ((len - pos) > 0xffff) {
00996                      open_packet(req, type);
00997                      fcgi_make_header(req->out_hdr, type, req->id, 0xfff8);
00998                      req->out_hdr = NULL;
00999                      if (!fcgi_flush(req, 0)) {
01000                             return -1;
01001                      }
01002                      if (safe_write(req, str + pos, 0xfff8) != 0xfff8) {
01003                             req->keep = 0;
01004                             return -1;
01005                      }
01006                      pos += 0xfff8;
01007               }             
01008               
01009               pad = (((len - pos) + 7) & ~7) - (len - pos);
01010               rest = pad ? 8 - pad : 0;
01011 
01012               open_packet(req, type);
01013               fcgi_make_header(req->out_hdr, type, req->id, (len - pos) - rest);
01014               req->out_hdr = NULL;
01015               if (!fcgi_flush(req, 0)) {
01016                      return -1;
01017               }
01018               if (safe_write(req, str + pos, (len - pos) - rest) != (len - pos) - rest) {
01019                      req->keep = 0;
01020                      return -1;
01021               }
01022               if (pad) {
01023                      open_packet(req, type);
01024                      memcpy(req->out_pos, str + len - rest,  rest);
01025                      req->out_pos += rest;
01026               }
01027        }
01028 
01029        return len;
01030 }
01031 
01032 int fcgi_finish_request(fcgi_request *req, int force_close)
01033 {
01034        int ret = 1;
01035 
01036        if (req->fd >= 0) {
01037               if (!req->closed) {
01038                      ret = fcgi_flush(req, 1);
01039                      req->closed = 1;
01040               }
01041               fcgi_close(req, force_close, 1);
01042        }
01043        return ret;
01044 }
01045 
01046 char* fcgi_getenv(fcgi_request *req, const char* var, int var_len)
01047 {
01048        char **val;
01049 
01050        if (!req) return NULL;
01051 
01052        if (zend_hash_find(req->env, (char*)var, var_len+1, (void**)&val) == SUCCESS) {
01053               return *val;
01054        }
01055        return NULL;
01056 }
01057 
01058 char* fcgi_putenv(fcgi_request *req, char* var, int var_len, char* val)
01059 {
01060        if (var && req) {
01061               if (val == NULL) {
01062                      zend_hash_del(req->env, var, var_len+1);
01063               } else {
01064                      char **ret;
01065 
01066                      val = estrdup(val);
01067                      if (zend_hash_update(req->env, var, var_len+1, &val, sizeof(char*), (void**)&ret) == SUCCESS) {
01068                             return *ret;
01069                      }
01070               }
01071        }
01072        return NULL;
01073 }
01074 
01075 void fcgi_set_mgmt_var(const char * name, size_t name_len, const char * value, size_t value_len)
01076 {
01077        zval * zvalue;
01078        zvalue = pemalloc(sizeof(*zvalue), 1);
01079        Z_TYPE_P(zvalue) = IS_STRING;
01080        Z_STRVAL_P(zvalue) = pestrndup(value, value_len, 1);
01081        Z_STRLEN_P(zvalue) = value_len;
01082        zend_hash_add(&fcgi_mgmt_vars, name, name_len + 1, &zvalue, sizeof(zvalue), NULL);
01083 }
01084 
01085 void fcgi_free_mgmt_var_cb(void * ptr)
01086 {
01087        zval ** var = (zval **)ptr;
01088        pefree(Z_STRVAL_PP(var), 1);
01089        pefree(*var, 1);
01090 }
01091 
01092 char *fcgi_get_last_client_ip() /* {{{ */
01093 {
01094        if (client_sa.sa.sa_family == AF_UNIX) {
01095               return NULL;
01096        }
01097        return inet_ntoa(client_sa.sa_inet.sin_addr);
01098 }
01099 /* }}} */
01100 /*
01101  * Local variables:
01102  * tab-width: 4
01103  * c-basic-offset: 4
01104  * End:
01105  * vim600: sw=4 ts=4 fdm=marker
01106  * vim<600: sw=4 ts=4
01107  */