Annotation of embedaddon/php/sapi/cgi/fastcgi.c, revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>