dmitry Wed Mar 28 15:39:23 2007 UTC
Modified files: (Branch: PHP_5_2)
/php-src NEWS
/php-src/sapi/cgi cgi_main.c fastcgi.c fastcgi.h
Log:
Improved FastCGI SAPI to support external pipe and socket servers on win32
http://cvs.php.net/viewvc.cgi/php-src/NEWS?r1=1.2027.2.547.2.615&r2=1.2027.2.547.2.616&diff_format=u
Index: php-src/NEWS
diff -u php-src/NEWS:1.2027.2.547.2.615 php-src/NEWS:1.2027.2.547.2.616
--- php-src/NEWS:1.2027.2.547.2.615 Wed Mar 28 10:08:31 2007
+++ php-src/NEWS Wed Mar 28 15:39:22 2007
@@ -9,6 +9,8 @@
- Upgraded SQLite 3 to version 3.3.13 (Ilia)
- Upgraded PCRE to version 7.0 (Nuno)
- Updated timezone database to version 2007.3. (Derick)
+- Improved FastCGI SAPI to support external pipe and socket servers on win32.
+ (Dmitry)
- Improved Zend Memory Manager
. guarantee of reasonable time for worst cases of best-fit free block
searching algorithm. (Dmitry)
@@ -58,6 +60,7 @@
- Fixed bug #40770 (Apache child exits when PHP memory limit reached). (Dmitry)
- Fixed bug #40764 (line thickness not respected for horizontal and vertical
lines). (Pierre)
+- Fixed bug #40758 (Test fcgi_is_fastcgi() is wrong on windows). (Dmitry)
- Fixed bug #40754 (added substr() & substr_replace() overflow checks). (Ilia)
- Fixed bug #40752 (parse_ini_file() segfaults when a scalar setting is
redeclared as an array). (Tony)
http://cvs.php.net/viewvc.cgi/php-src/sapi/cgi/cgi_main.c?r1=1.267.2.15.2.30&r2=1.267.2.15.2.31&diff_format=u
Index: php-src/sapi/cgi/cgi_main.c
diff -u php-src/sapi/cgi/cgi_main.c:1.267.2.15.2.30
php-src/sapi/cgi/cgi_main.c:1.267.2.15.2.31
--- php-src/sapi/cgi/cgi_main.c:1.267.2.15.2.30 Fri Mar 9 16:46:07 2007
+++ php-src/sapi/cgi/cgi_main.c Wed Mar 28 15:39:22 2007
@@ -21,7 +21,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: cgi_main.c,v 1.267.2.15.2.30 2007/03/09 16:46:07 dmitry Exp $ */
+/* $Id: cgi_main.c,v 1.267.2.15.2.31 2007/03/28 15:39:22 dmitry Exp $ */
#include "php.h"
#include "php_globals.h"
@@ -123,9 +123,7 @@
static const opt_struct OPTIONS[] = {
{'a', 0, "interactive"},
-#ifndef PHP_WIN32
{'b', 1, "bindpath"},
-#endif
{'C', 0, "no-chdir"},
{'c', 1, "php-ini"},
{'d', 1, "define"},
@@ -630,7 +628,7 @@
php_printf("Usage: %s [-q] [-h] [-s] [-v] [-i] [-f <file>]\n"
" %s <file> [args...]\n"
" -a Run interactively\n"
-#if PHP_FASTCGI && !defined(PHP_WIN32)
+#if PHP_FASTCGI
" -b <address:port>|<port> Bind Path for external
FASTCGI Server mode\n"
#endif
" -C Do not chdir to the script's
directory\n"
@@ -997,21 +995,6 @@
}
#endif
-#if PHP_FASTCGI
-#ifndef PHP_WIN32
-static int is_port_number(const char *bindpath)
-{
- while (*bindpath) {
- if (*bindpath < '0' || *bindpath > '9') {
- return 0;
- }
- bindpath++;
- }
- return 1;
-}
-#endif
-#endif
-
PHP_INI_BEGIN()
STD_PHP_INI_ENTRY("cgi.rfc2616_headers", "0", PHP_INI_ALL,
OnUpdateBool, rfc2616_headers, php_cgi_globals_struct, php_cgi_globals)
STD_PHP_INI_ENTRY("cgi.nph", "0", PHP_INI_ALL,
OnUpdateBool, nph, php_cgi_globals_struct, php_cgi_globals)
@@ -1133,9 +1116,7 @@
int max_requests = 500;
int requests = 0;
int fastcgi = fcgi_is_fastcgi();
-#ifndef PHP_WIN32
char *bindpath = NULL;
-#endif
int fcgi_fd = 0;
fcgi_request request;
#ifndef PHP_WIN32
@@ -1233,8 +1214,6 @@
}
break;
}
-#if PHP_FASTCGI
-#ifndef PHP_WIN32
/* if we're started on command line, check to see if
we are being started as an 'external' fastcgi
server by accepting a bindpath parameter. */
@@ -1243,8 +1222,6 @@
bindpath = strdup(php_optarg);
}
break;
-#endif
-#endif
}
}
@@ -1311,26 +1288,10 @@
#endif /* FORCE_CGI_REDIRECT */
#if PHP_FASTCGI
-#ifndef PHP_WIN32
/* for windows, socket listening is broken in the fastcgi library itself
so dissabling this feature on windows till time is available to fix
it */
if (bindpath) {
- /* Pass on the arg to the FastCGI library, with one exception.
- * If just a port is specified, then we prepend a ':' onto the
- * path (it's what the fastcgi library expects)
- */
- if (strchr(bindpath, ':') == NULL && is_port_number(bindpath)) {
- char *tmp;
-
- tmp = malloc(strlen(bindpath) + 2);
- tmp[0] = ':';
- memcpy(tmp + 1, bindpath, strlen(bindpath) + 1);
-
- fcgi_fd = fcgi_listen(tmp, 128);
- free(tmp);
- } else {
- fcgi_fd = fcgi_listen(bindpath, 128);
- }
+ fcgi_fd = fcgi_listen(bindpath, 128);
if (fcgi_fd < 0) {
fprintf(stderr, "Couldn't create FastCGI listen socket
on port %s\n", bindpath);
#ifdef ZTS
@@ -1340,7 +1301,7 @@
}
fastcgi = fcgi_is_fastcgi();
}
-#endif
+
if (fastcgi) {
/* How many times to run PHP scripts before dying */
if (getenv("PHP_FCGI_MAX_REQUESTS")) {
@@ -1828,11 +1789,9 @@
requests++;
if (max_requests && (requests == max_requests)) {
fcgi_finish_request(&request);
-#ifndef PHP_WIN32
if (bindpath) {
free(bindpath);
}
-#endif
break;
}
/* end of fastcgi loop */
http://cvs.php.net/viewvc.cgi/php-src/sapi/cgi/fastcgi.c?r1=1.4.2.13.2.22&r2=1.4.2.13.2.23&diff_format=u
Index: php-src/sapi/cgi/fastcgi.c
diff -u php-src/sapi/cgi/fastcgi.c:1.4.2.13.2.22
php-src/sapi/cgi/fastcgi.c:1.4.2.13.2.23
--- php-src/sapi/cgi/fastcgi.c:1.4.2.13.2.22 Mon Mar 12 07:39:01 2007
+++ php-src/sapi/cgi/fastcgi.c Wed Mar 28 15:39:22 2007
@@ -16,7 +16,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: fastcgi.c,v 1.4.2.13.2.22 2007/03/12 07:39:01 dmitry Exp $ */
+/* $Id: fastcgi.c,v 1.4.2.13.2.23 2007/03/28 15:39:22 dmitry Exp $ */
#include "php.h"
#include "fastcgi.h"
@@ -32,6 +32,7 @@
#include <windows.h>
typedef unsigned int size_t;
+ typedef unsigned int in_addr_t;
struct sockaddr_un {
short sun_family;
@@ -71,6 +72,8 @@
# include <netdb.h>
# include <signal.h>
+# define closesocket(s) close(s)
+
# if defined(HAVE_SYS_POLL_H) && defined(HAVE_POLL)
# include <sys/poll.h>
# endif
@@ -147,6 +150,7 @@
static int is_initialized = 0;
static int is_fastcgi = 0;
static int in_shutdown = 0;
+static in_addr_t *allowed_clients = NULL;
#ifdef _WIN32
@@ -160,8 +164,6 @@
#else
-static in_addr_t *allowed_clients = NULL;
-
static void fcgi_signal_handler(int signo)
{
if (signo == SIGUSR1 || signo == SIGTERM) {
@@ -254,12 +256,89 @@
}
}
+#ifdef _WIN32
+/* Do some black magic with the NT security API.
+ * We prepare a DACL (Discretionary Access Control List) so that
+ * we, the creator, are allowed all access, while "Everyone Else"
+ * is only allowed to read and write to the pipe.
+ * This avoids security issues on shared hosts where a luser messes
+ * with the lower-level pipe settings and screws up the FastCGI service.
+ */
+static PACL prepare_named_pipe_acl(PSECURITY_DESCRIPTOR sd,
LPSECURITY_ATTRIBUTES sa)
+{
+ DWORD req_acl_size;
+ char everyone_buf[32], owner_buf[32];
+ PSID sid_everyone, sid_owner;
+ SID_IDENTIFIER_AUTHORITY
+ siaWorld = SECURITY_WORLD_SID_AUTHORITY,
+ siaCreator = SECURITY_CREATOR_SID_AUTHORITY;
+ PACL acl;
+
+ sid_everyone = (PSID)&everyone_buf;
+ sid_owner = (PSID)&owner_buf;
+
+ req_acl_size = sizeof(ACL) +
+ (2 * ((sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)) +
GetSidLengthRequired(1)));
+
+ acl = malloc(req_acl_size);
+
+ if (acl == NULL) {
+ return NULL;
+ }
+
+ if (!InitializeSid(sid_everyone, &siaWorld, 1)) {
+ goto out_fail;
+ }
+ *GetSidSubAuthority(sid_everyone, 0) = SECURITY_WORLD_RID;
+
+ if (!InitializeSid(sid_owner, &siaCreator, 1)) {
+ goto out_fail;
+ }
+ *GetSidSubAuthority(sid_owner, 0) = SECURITY_CREATOR_OWNER_RID;
+
+ if (!InitializeAcl(acl, req_acl_size, ACL_REVISION)) {
+ goto out_fail;
+ }
+
+ if (!AddAccessAllowedAce(acl, ACL_REVISION, FILE_GENERIC_READ |
FILE_GENERIC_WRITE, sid_everyone)) {
+ goto out_fail;
+ }
+
+ if (!AddAccessAllowedAce(acl, ACL_REVISION, FILE_ALL_ACCESS, sid_owner)) {
+ goto out_fail;
+ }
+
+ if (!InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION)) {
+ goto out_fail;
+ }
+
+ if (!SetSecurityDescriptorDacl(sd, TRUE, acl, FALSE)) {
+ goto out_fail;
+ }
+
+ sa->lpSecurityDescriptor = sd;
+
+ return acl;
+
+out_fail:
+ free(acl);
+ return NULL;
+}
+#endif
+
+static int is_port_number(const char *bindpath)
+{
+ while (*bindpath) {
+ if (*bindpath < '0' || *bindpath > '9') {
+ return 0;
+ }
+ bindpath++;
+ }
+ return 1;
+}
+
int fcgi_listen(const char *path, int backlog)
{
-#ifdef _WIN32
- /* TODO: Support for manual binding on TCP sockets (php -b <port>) */
- return -1;
-#else
char *s;
int tcp = 0;
char host[MAXPATHLEN];
@@ -275,6 +354,12 @@
host[s-path] = '\0';
tcp = 1;
}
+ } else if (is_port_number(path)) {
+ port = atoi(path);
+ if (port != 0) {
+ host[0] = '\0';
+ tcp = 1;
+ }
}
/* Prepare socket address */
@@ -303,6 +388,33 @@
}
}
} else {
+#ifdef _WIN32
+ SECURITY_DESCRIPTOR sd;
+ SECURITY_ATTRIBUTES sa;
+ PACL acl;
+ HANDLE namedPipe;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.nLength = sizeof(sa);
+ sa.bInheritHandle = FALSE;
+ acl = prepare_named_pipe_acl(&sd, &sa);
+
+ namedPipe = CreateNamedPipe(path,
+ PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+ PIPE_TYPE_BYTE | PIPE_WAIT | PIPE_READMODE_BYTE,
+ PIPE_UNLIMITED_INSTANCES,
+ 8192, 8192, 0, &sa);
+ if (namedPipe == INVALID_HANDLE_VALUE) {
+ return -1;
+ }
+ listen_socket = _open_osfhandle((long)namedPipe, 0);
+ if (!is_initialized) {
+ fcgi_init();
+ }
+ is_fastcgi = 1;
+ return listen_socket;
+
+#else
int path_len = strlen(path);
if (path_len >= sizeof(sa.sa_unix.sun_path)) {
@@ -318,6 +430,7 @@
sa.sa_unix.sun_len = sock_len;
#endif
unlink(path);
+#endif
}
/* Create, bind socket and start listen on it */
@@ -369,8 +482,13 @@
fcgi_init();
}
is_fastcgi = 1;
- return listen_socket;
+
+#ifdef _WIN32
+ if (tcp) {
+ listen_socket = _open_osfhandle((long)listen_socket, 0);
+ }
#endif
+ return listen_socket;
}
void fcgi_init_request(fcgi_request *req, int listen_socket)
@@ -385,6 +503,10 @@
req->out_hdr = NULL;
req->out_pos = req->out_buf;
+
+#ifdef _WIN32
+ req->tcp =
!GetNamedPipeInfo((HANDLE)_get_osfhandle(req->listen_socket), NULL, NULL, NULL,
NULL);
+#endif
}
static inline ssize_t safe_write(fcgi_request *req, const void *buf, size_t
count)
@@ -394,7 +516,18 @@
do {
errno = 0;
+#ifdef _WIN32
+ if (!req->tcp) {
+ ret = write(req->fd, ((char*)buf)+n, count-n);
+ } else {
+ ret = send(req->fd, ((char*)buf)+n, count-n, 0);
+ if (ret <= 0) {
+ errno = WSAGetLastError();
+ }
+ }
+#else
ret = write(req->fd, ((char*)buf)+n, count-n);
+#endif
if (ret > 0) {
n += ret;
} else if (ret <= 0 && errno != 0 && errno != EINTR) {
@@ -411,7 +544,18 @@
do {
errno = 0;
+#ifdef _WIN32
+ if (!req->tcp) {
+ ret = read(req->fd, ((char*)buf)+n, count-n);
+ } else {
+ ret = recv(req->fd, ((char*)buf)+n, count-n, 0);
+ if (ret <= 0) {
+ errno = WSAGetLastError();
+ }
+ }
+#else
ret = read(req->fd, ((char*)buf)+n, count-n);
+#endif
if (ret > 0) {
n += ret;
} else if (ret == 0 && errno == 0) {
@@ -666,19 +810,29 @@
}
#ifdef _WIN32
- if (is_impersonate) {
+ if (is_impersonate && !req->tcp) {
RevertToSelf();
}
#endif
if ((force || !req->keep) && req->fd >= 0) {
#ifdef _WIN32
- HANDLE pipe = (HANDLE)_get_osfhandle(req->fd);
+ if (!req->tcp) {
+ HANDLE pipe = (HANDLE)_get_osfhandle(req->fd);
- if (!force) {
- FlushFileBuffers(pipe);
+ if (!force) {
+ FlushFileBuffers(pipe);
+ }
+ DisconnectNamedPipe(pipe);
+ } else {
+ if (!force) {
+ char buf[8];
+
+ shutdown(req->fd, 1);
+ while (recv(req->fd, buf, sizeof(buf), 0) > 0)
{}
+ }
+ closesocket(req->fd);
}
- DisconnectNamedPipe(pipe);
#else
if (!force) {
char buf[8];
@@ -707,33 +861,37 @@
return -1;
}
#ifdef _WIN32
- pipe =
(HANDLE)_get_osfhandle(req->listen_socket);
-
- FCGI_LOCK(req->listen_socket);
- ov.hEvent = CreateEvent(NULL, TRUE, FALSE,
NULL);
- if (!ConnectNamedPipe(pipe, &ov)) {
- errno = GetLastError();
- if (errno == ERROR_IO_PENDING) {
- while
(WaitForSingleObject(ov.hEvent, 1000) == WAIT_TIMEOUT) {
- if (in_shutdown) {
-
CloseHandle(ov.hEvent);
-
FCGI_UNLOCK(req->listen_socket);
- return -1;
+ if (!req->tcp) {
+ pipe =
(HANDLE)_get_osfhandle(req->listen_socket);
+ FCGI_LOCK(req->listen_socket);
+ ov.hEvent = CreateEvent(NULL, TRUE,
FALSE, NULL);
+ if (!ConnectNamedPipe(pipe, &ov)) {
+ errno = GetLastError();
+ if (errno == ERROR_IO_PENDING) {
+ while
(WaitForSingleObject(ov.hEvent, 1000) == WAIT_TIMEOUT) {
+ if
(in_shutdown) {
+
CloseHandle(ov.hEvent);
+
FCGI_UNLOCK(req->listen_socket);
+ return
-1;
+ }
}
+ } else if (errno !=
ERROR_PIPE_CONNECTED) {
}
- } else if (errno !=
ERROR_PIPE_CONNECTED) {
}
- }
- CloseHandle(ov.hEvent);
- req->fd = req->listen_socket;
- FCGI_UNLOCK(req->listen_socket);
+ CloseHandle(ov.hEvent);
+ req->fd = req->listen_socket;
+ FCGI_UNLOCK(req->listen_socket);
+ } else {
+ SOCKET listen_socket =
(SOCKET)_get_osfhandle(req->listen_socket);
#else
{
+ int listen_socket = req->listen_socket;
+#endif
sa_t sa;
socklen_t len = sizeof(sa);
FCGI_LOCK(req->listen_socket);
- req->fd = accept(req->listen_socket,
(struct sockaddr *)&sa, &len);
+ req->fd = accept(listen_socket, (struct
sockaddr *)&sa, &len);
FCGI_UNLOCK(req->listen_socket);
if (req->fd >= 0 && allowed_clients) {
int n = 0;
@@ -748,13 +906,12 @@
}
if (!allowed) {
fprintf(stderr,
"Connection from disallowed IP address '%s' is dropped.\n",
inet_ntoa(sa.sa_inet.sin_addr));
- close(req->fd);
+ closesocket(req->fd);
req->fd = -1;
continue;
}
}
}
-#endif
if (req->fd < 0 && (in_shutdown || errno !=
EINTR)) {
return -1;
@@ -808,7 +965,7 @@
}
if (fcgi_read_request(req)) {
#ifdef _WIN32
- if (is_impersonate) {
+ if (is_impersonate && !req->tcp) {
pipe = (HANDLE)_get_osfhandle(req->fd);
if (!ImpersonateNamedPipeClient(pipe)) {
fcgi_close(req, 1, 1);
http://cvs.php.net/viewvc.cgi/php-src/sapi/cgi/fastcgi.h?r1=1.2.2.4.2.3&r2=1.2.2.4.2.4&diff_format=u
Index: php-src/sapi/cgi/fastcgi.h
diff -u php-src/sapi/cgi/fastcgi.h:1.2.2.4.2.3
php-src/sapi/cgi/fastcgi.h:1.2.2.4.2.4
--- php-src/sapi/cgi/fastcgi.h:1.2.2.4.2.3 Thu Feb 15 12:33:16 2007
+++ php-src/sapi/cgi/fastcgi.h Wed Mar 28 15:39:22 2007
@@ -16,7 +16,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: fastcgi.h,v 1.2.2.4.2.3 2007/02/15 12:33:16 dmitry Exp $ */
+/* $Id: fastcgi.h,v 1.2.2.4.2.4 2007/03/28 15:39:22 dmitry Exp $ */
/* FastCGI protocol */
@@ -93,6 +93,9 @@
typedef struct _fcgi_request {
int listen_socket;
+#ifdef _WIN32
+ int tcp;
+#endif
int fd;
int id;
int keep;
--
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php