Annotation of embedaddon/php/sapi/cgi/fastcgi.c, revision 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>