File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / sapi / cgi / fastcgi.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 22 01:32:13 2013 UTC (10 years, 11 months ago) by misho
Branches: php, MAIN
CVS tags: v5_4_29p0, v5_4_20p0, v5_4_20, v5_4_17, HEAD
5.4.17

    1: /*
    2:    +----------------------------------------------------------------------+
    3:    | PHP Version 5                                                        |
    4:    +----------------------------------------------------------------------+
    5:    | Copyright (c) 1997-2013 The PHP Group                                |
    6:    +----------------------------------------------------------------------+
    7:    | This source file is subject to version 3.01 of the PHP license,      |
    8:    | that is bundled with this package in the file LICENSE, and is        |
    9:    | available through the world-wide-web at the following url:           |
   10:    | http://www.php.net/license/3_01.txt                                  |
   11:    | If you did not receive a copy of the PHP license and are unable to   |
   12:    | obtain it through the world-wide-web, please send a note to          |
   13:    | license@php.net so we can mail you a copy immediately.               |
   14:    +----------------------------------------------------------------------+
   15:    | Authors: Dmitry Stogov <dmitry@zend.com>                             |
   16:    +----------------------------------------------------------------------+
   17: */
   18: 
   19: /* $Id: fastcgi.c,v 1.1.1.3 2013/07/22 01:32:13 misho Exp $ */
   20: 
   21: #include "php.h"
   22: #include "fastcgi.h"
   23: 
   24: #include <string.h>
   25: #include <stdlib.h>
   26: #include <stdio.h>
   27: #include <stdarg.h>
   28: #include <errno.h>
   29: 
   30: #ifdef _WIN32
   31: 
   32: #include <windows.h>
   33: 
   34: 	typedef unsigned int in_addr_t;
   35: 
   36: 	struct sockaddr_un {
   37: 		short   sun_family;
   38: 		char    sun_path[MAXPATHLEN];
   39: 	};
   40: 
   41: 	static HANDLE fcgi_accept_mutex = INVALID_HANDLE_VALUE;
   42: 	static int is_impersonate = 0;
   43: 
   44: #define FCGI_LOCK(fd) \
   45: 	if (fcgi_accept_mutex != INVALID_HANDLE_VALUE) { \
   46: 		DWORD ret; \
   47: 		while ((ret = WaitForSingleObject(fcgi_accept_mutex, 1000)) == WAIT_TIMEOUT) { \
   48: 			if (in_shutdown) return -1; \
   49: 		} \
   50: 		if (ret == WAIT_FAILED) { \
   51: 			fprintf(stderr, "WaitForSingleObject() failed\n"); \
   52: 			return -1; \
   53: 		} \
   54: 	}
   55: 
   56: #define FCGI_UNLOCK(fd) \
   57: 	if (fcgi_accept_mutex != INVALID_HANDLE_VALUE) { \
   58: 		ReleaseMutex(fcgi_accept_mutex); \
   59: 	}
   60: 
   61: #else
   62: 
   63: # include <sys/types.h>
   64: # include <sys/stat.h>
   65: # include <unistd.h>
   66: # include <fcntl.h>
   67: # include <sys/socket.h>
   68: # include <sys/un.h>
   69: # include <netinet/in.h>
   70: # include <netinet/tcp.h>
   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: 
  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: 
  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: 
  402: void fcgi_terminate(void)
  403: {
  404: 	in_shutdown = 1;
  405: }
  406: 
  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;
  644: 		}
  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 {
  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++;
  706: 				}
  707: 				allowed_clients[n] = inet_addr(cur);
  708: 				if (allowed_clients[n] == INADDR_NONE) {
  709: 					fprintf(stderr, "Wrong IP address '%s' in FCGI_WEB_SERVER_ADDRS\n", cur);
  710: 				}
  711: 				n++;
  712: 				cur = end;
  713: 			}
  714: 			allowed_clients[n] = INADDR_NONE;
  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: 
  734: fcgi_request *fcgi_init_request(int listen_socket)
  735: {
  736: 	fcgi_request *req = (fcgi_request*)calloc(1, sizeof(fcgi_request));
  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
  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);
  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++;
  848: 		if (UNEXPECTED(name_len >= 128)) {
  849: 			if (UNEXPECTED(p + 3 >= end)) return 0;
  850: 			name_len = ((name_len & 0x7f) << 24);
  851: 			name_len |= (*p++ << 16);
  852: 			name_len |= (*p++ << 8);
  853: 			name_len |= *p++;
  854: 		}
  855: 		if (UNEXPECTED(p >= end)) return 0;
  856: 		val_len = *p++;
  857: 		if (UNEXPECTED(val_len >= 128)) {
  858: 			if (UNEXPECTED(p + 3 >= end)) return 0;
  859: 			val_len = ((val_len & 0x7f) << 24);
  860: 			val_len |= (*p++ << 16);
  861: 			val_len |= (*p++ << 8);
  862: 			val_len |= *p++;
  863: 		}
  864: 		if (UNEXPECTED(name_len + val_len > (unsigned int) (end - p))) {
  865: 			/* Malformated request */
  866: 			return 0;
  867: 		}
  868: 		fcgi_hash_set(&req->env, FCGI_HASH_FUNC(p, name_len), (char*)p, name_len, (char*)p + name_len, val_len);
  869: 		p += name_len + val_len;
  870: 	}
  871: 	return 1;
  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;
  885: 	req->has_env = 1;
  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);
  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
  929: 		switch ((((fcgi_begin_request*)buf)->roleB1 << 8) + ((fcgi_begin_request*)buf)->roleB0) {
  930: 			case FCGI_RESPONDER:
  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);
  932: 				break;
  933: 			case FCGI_AUTHORIZER:
  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);
  935: 				break;
  936: 			case FCGI_FILTER:
  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);
  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;
  977: 		unsigned int zlen;
  978: 		fcgi_hash_bucket *q;
  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: 
  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) {
  993: 				continue;
  994: 			}
  995: 			zlen = Z_STRLEN_PP(value);
  996: 			if ((p + 4 + 4 + q->var_len + zlen) >= (buf + sizeof(buf))) {
  997: 				break;
  998: 			}
  999: 			if (q->var_len < 0x80) {
 1000: 				*p++ = q->var_len;
 1001: 			} else {
 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;
 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: 			}
 1015: 			memcpy(p, q->var, q->var_len);
 1016: 			p += q->var_len;
 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: {
 1089: 	if (destroy && req->has_env) {
 1090: 		fcgi_hash_clean(&req->env);
 1091: 		req->has_env = 0;
 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) {
 1111: 				fcgi_header buf;
 1112: 
 1113: 				shutdown(req->fd, 1);
 1114: 				/* read the last FCGI_STDIN header (it may be omitted) */
 1115: 				recv(req->fd, &buf, sizeof(buf), 0);
 1116: 			}
 1117: 			closesocket(req->fd);
 1118: 		}
 1119: #else
 1120: 		if (!force) {
 1121: 			fcgi_header buf;
 1122: 
 1123: 			shutdown(req->fd, 1);
 1124: 			/* read the last FCGI_STDIN header (it may be omitted) */
 1125: 			recv(req->fd, &buf, sizeof(buf), 0);
 1126: 		}
 1127: 		close(req->fd);
 1128: #endif
 1129: #ifdef TCP_NODELAY
 1130: 		req->nodelay = 0;
 1131: #endif
 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);
 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;
 1203: 								}
 1204: 							}
 1205: #ifndef _WIN32
 1206: 						} else {
 1207: 							req->tcp = 0;
 1208: #endif
 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;
 1418: 		}
 1419: 
 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: {
 1459: 	unsigned int val_len;
 1460: 
 1461: 	if (!req) return NULL;
 1462: 
 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);
 1471: }
 1472: 
 1473: char* fcgi_putenv(fcgi_request *req, char* var, int var_len, char* val)
 1474: {
 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: }
 1483: 
 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));
 1491: 	}
 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);
 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;
 1518: 	zend_hash_add(&fcgi_mgmt_vars, name, name_len, &zvalue, sizeof(zvalue), NULL);
 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>