PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LTP GCOV extension - code coverage report
Current view: directory - var/php_gcov/PHP_5_3/sapi/cgi - fastcgi.c
Test: PHP Code Coverage
Date: 2009-11-21 Instrumented lines: 488
Code covered: 6.1 % Executed lines: 30
Legend: not executed executed

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

Generated by: LTP GCOV extension version 1.5

Generated at Sat, 21 Nov 2009 12:27:17 +0000 (3 days ago)

Copyright © 2005-2009 The PHP Group
All rights reserved.