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

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

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