summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXinchen Hui <laruence@gmail.com>2015-05-23 10:31:50 +0800
committerXinchen Hui <laruence@gmail.com>2015-05-23 19:01:41 +0800
commit18cf4e0a8a574034f60f4d123407c173e57e54ec (patch)
tree08392346acfd0bc45d1a4449bcee0ebd44f101a3
parentfef18f4bea1980a59a9283c2197bd090aaf500cb (diff)
downloadphp-git-18cf4e0a8a574034f60f4d123407c173e57e54ec.tar.gz
Fixed fpm-side (tests passes)
-rw-r--r--main/fastcgi.c307
-rw-r--r--main/fastcgi.h92
-rw-r--r--sapi/cgi/cgi_main.c184
-rw-r--r--sapi/fpm/config.m43
-rw-r--r--sapi/fpm/fpm/fastcgi.c1340
-rw-r--r--sapi/fpm/fpm/fastcgi.h151
-rw-r--r--sapi/fpm/fpm/fpm_main.c95
-rw-r--r--sapi/fpm/fpm/zlog.c14
-rw-r--r--sapi/fpm/fpm/zlog.h4
9 files changed, 436 insertions, 1754 deletions
diff --git a/main/fastcgi.c b/main/fastcgi.c
index a1e48c4a84..8bc4d2784f 100644
--- a/main/fastcgi.c
+++ b/main/fastcgi.c
@@ -20,7 +20,6 @@
#include "php.h"
#include "php_network.h"
-#include "fastcgi.h"
#include <string.h>
#include <stdlib.h>
@@ -32,8 +31,6 @@
#define MAXFQDNLEN 255
#endif
-static fcgi_logger flog;
-
#ifdef _WIN32
#include <windows.h>
@@ -133,10 +130,16 @@ static int is_impersonate = 0;
#endif
+#include "fastcgi.h"
+
+/* maybe it's better to use weak name instead */
+static fcgi_logger logger;
+
typedef union _sa_t {
struct sockaddr sa;
struct sockaddr_un sa_unix;
struct sockaddr_in sa_inet;
+ struct sockaddr_in6 sa_inet6;
} sa_t;
static HashTable fcgi_mgmt_vars;
@@ -144,44 +147,10 @@ static HashTable fcgi_mgmt_vars;
static int is_initialized = 0;
static int is_fastcgi = 0;
static int in_shutdown = 0;
-static in_addr_t *allowed_clients = NULL;
+static sa_t *allowed_clients = NULL;
+static sa_t client_sa;
/* hash table */
-
-#define FCGI_HASH_TABLE_SIZE 128
-#define FCGI_HASH_TABLE_MASK (FCGI_HASH_TABLE_SIZE - 1)
-#define FCGI_HASH_SEG_SIZE 4096
-
-typedef struct _fcgi_hash_bucket {
- unsigned int hash_value;
- unsigned int var_len;
- char *var;
- unsigned int val_len;
- char *val;
- struct _fcgi_hash_bucket *next;
- struct _fcgi_hash_bucket *list_next;
-} fcgi_hash_bucket;
-
-typedef struct _fcgi_hash_buckets {
- unsigned int idx;
- struct _fcgi_hash_buckets *next;
- struct _fcgi_hash_bucket data[FCGI_HASH_TABLE_SIZE];
-} fcgi_hash_buckets;
-
-typedef struct _fcgi_data_seg {
- char *pos;
- char *end;
- struct _fcgi_data_seg *next;
- char data[1];
-} fcgi_data_seg;
-
-typedef struct _fcgi_hash {
- fcgi_hash_bucket *hash_table[FCGI_HASH_TABLE_SIZE];
- fcgi_hash_bucket *list;
- fcgi_hash_buckets *buckets;
- fcgi_data_seg *data;
-} fcgi_hash;
-
static void fcgi_hash_init(fcgi_hash *h)
{
memset(h->hash_table, 0, sizeof(h->hash_table));
@@ -341,29 +310,6 @@ static void fcgi_hash_apply(fcgi_hash *h, fcgi_apply_func func, void *arg)
}
}
-struct _fcgi_request {
- int listen_socket;
- int tcp;
- int fd;
- int id;
- int keep;
-#ifdef TCP_NODELAY
- int nodelay;
-#endif
- int closed;
-
- int in_len;
- int in_pad;
-
- fcgi_header *out_hdr;
- unsigned char *out_pos;
- unsigned char out_buf[1024*8];
- unsigned char reserved[sizeof(fcgi_end_request_rec)];
-
- int has_env;
- fcgi_hash env;
-};
-
#ifdef _WIN32
static DWORD WINAPI fcgi_shutdown_thread(LPVOID arg)
@@ -399,6 +345,11 @@ static void fcgi_setup_signals(void)
}
#endif
+void fcgi_set_in_shutdown(int new_value)
+{
+ in_shutdown = new_value;
+}
+
int fcgi_in_shutdown(void)
{
return in_shutdown;
@@ -409,8 +360,8 @@ void fcgi_terminate(void)
in_shutdown = 1;
}
-void fcgi_set_logger(fcgi_logger logger) {
- flog = logger;
+void fcgi_set_logger(fcgi_logger lg) {
+ logger = lg;
}
int fcgi_init(void)
@@ -632,10 +583,10 @@ int fcgi_listen(const char *path, int backlog)
hep = gethostbyname(host);
}
if (!hep || hep->h_addrtype != AF_INET || !hep->h_addr_list[0]) {
- flog(FCGI_ERROR, "Cannot resolve host name '%s'!\n", host);
+ logger(FCGI_ERROR, "Cannot resolve host name '%s'!\n", host);
return -1;
} else if (hep->h_addr_list[1]) {
- flog(FCGI_ERROR, "Host '%s' has multiple addresses. You must choose one explicitly!\n", host);
+ logger(FCGI_ERROR, "Host '%s' has multiple addresses. You must choose one explicitly!\n", host);
return -1;
}
sa.sa_inet.sin_addr.s_addr = ((struct in_addr*)hep->h_addr_list[0])->s_addr;
@@ -672,7 +623,7 @@ int fcgi_listen(const char *path, int backlog)
int path_len = strlen(path);
if (path_len >= sizeof(sa.sa_unix.sun_path)) {
- flog(FCGI_ERROR, "Listening socket's path name is too long.\n");
+ logger(FCGI_ERROR, "Listening socket's path name is too long.\n");
return -1;
}
@@ -695,7 +646,7 @@ int fcgi_listen(const char *path, int backlog)
bind(listen_socket, (struct sockaddr *) &sa, sock_len) < 0 ||
listen(listen_socket, backlog) < 0) {
- flog(FCGI_ERROR, "Cannot bind/listen socket - [%d] %s.\n",errno, strerror(errno));
+ logger(FCGI_ERROR, "Cannot bind/listen socket - [%d] %s.\n",errno, strerror(errno));
return -1;
}
@@ -714,7 +665,7 @@ int fcgi_listen(const char *path, int backlog)
if (*cur == ',') n++;
cur++;
}
- allowed_clients = malloc(sizeof(in_addr_t) * (n+2));
+ allowed_clients = malloc(sizeof(sa_t) * (n+2));
n = 0;
cur = ip;
while (cur) {
@@ -723,15 +674,25 @@ int fcgi_listen(const char *path, int backlog)
*end = 0;
end++;
}
- allowed_clients[n] = inet_addr(cur);
- if (allowed_clients[n] == INADDR_NONE) {
- flog(FCGI_ERROR, "Wrong IP address '%s' in FCGI_WEB_SERVER_ADDRS\n", cur);
+ if (inet_pton(AF_INET, cur, &allowed_clients[n].sa_inet.sin_addr)>0) {
+ allowed_clients[n].sa.sa_family = AF_INET;
+ n++;
+#ifdef HAVE_IPV6
+ } else if (inet_pton(AF_INET6, cur, &allowed_clients[n].sa_inet6.sin6_addr)>0) {
+ allowed_clients[n].sa.sa_family = AF_INET6;
+ n++;
+#endif
+ } else {
+ logger(FCGI_ERROR, "Wrong IP address '%s' in listen.allowed_clients", cur);
}
- n++;
cur = end;
}
- allowed_clients[n] = INADDR_NONE;
+ allowed_clients[n].sa.sa_family = 0;
free(ip);
+ if (!n) {
+ logger(FCGI_ERROR, "There are no allowed addresses");
+ /* don't clear allowed_clients as it will create an "open for all" security issue */
+ }
}
}
@@ -750,36 +711,79 @@ int fcgi_listen(const char *path, int backlog)
return listen_socket;
}
-fcgi_request *fcgi_init_request(int listen_socket)
+void fcgi_set_allowed_clients(char *ip)
+{
+ char *cur, *end;
+ int n;
+
+ if (ip) {
+ ip = strdup(ip);
+ cur = ip;
+ n = 0;
+ while (*cur) {
+ if (*cur == ',') n++;
+ cur++;
+ }
+ if (allowed_clients) free(allowed_clients);
+ allowed_clients = malloc(sizeof(sa_t) * (n+2));
+ n = 0;
+ cur = ip;
+ while (cur) {
+ end = strchr(cur, ',');
+ if (end) {
+ *end = 0;
+ end++;
+ }
+ if (inet_pton(AF_INET, cur, &allowed_clients[n].sa_inet.sin_addr)>0) {
+ allowed_clients[n].sa.sa_family = AF_INET;
+ n++;
+#ifdef HAVE_IPV6
+ } else if (inet_pton(AF_INET6, cur, &allowed_clients[n].sa_inet6.sin6_addr)>0) {
+ allowed_clients[n].sa.sa_family = AF_INET6;
+ n++;
+#endif
+ } else {
+ logger(FCGI_ERROR, "Wrong IP address '%s' in listen.allowed_clients", cur);
+ }
+ cur = end;
+ }
+ allowed_clients[n].sa.sa_family = 0;
+ free(ip);
+ if (!n) {
+ logger(FCGI_ERROR, "There are no allowed addresses");
+ /* don't clear allowed_clients as it will create an "open for all" security issue */
+ }
+ }
+}
+
+fcgi_request *fcgi_init_request(fcgi_request *req, int listen_socket)
{
- fcgi_request *req = (fcgi_request*)calloc(1, sizeof(fcgi_request));
+ memset(req, 0, sizeof(fcgi_request));
req->listen_socket = listen_socket;
req->fd = -1;
req->id = -1;
+ /*
req->in_len = 0;
req->in_pad = 0;
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
#ifdef TCP_NODELAY
req->nodelay = 0;
#endif
- fcgi_hash_init(&req->env);
+ req->env = NULL;
+ req->has_env = 0;
- return req;
-}
+ */
+ req->out_pos = req->out_buf;
-void fcgi_destroy_request(fcgi_request *req)
-{
- fcgi_hash_destroy(&req->env);
- free(req);
+#ifdef _WIN32
+ req->tcp = !GetNamedPipeInfo((HANDLE)_get_osfhandle(req->listen_socket), NULL, NULL, NULL, NULL);
+#endif
+
+ return req;
}
static inline ssize_t safe_write(fcgi_request *req, const void *buf, size_t count)
@@ -919,6 +923,7 @@ static int fcgi_read_request(fcgi_request *req)
req->in_len = 0;
req->out_hdr = NULL;
req->out_pos = req->out_buf;
+ fcgi_hash_init(&req->env);
req->has_env = 1;
if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
@@ -1058,7 +1063,7 @@ static int fcgi_read_request(fcgi_request *req)
}
len = (int)(p - buf - sizeof(fcgi_header));
len += fcgi_make_header((fcgi_header*)buf, FCGI_GET_VALUES_RESULT, 0, len);
- if (safe_write(req, buf, sizeof(fcgi_header)+len) != (int)sizeof(fcgi_header)+len) {
+ if (safe_write(req, buf, sizeof(fcgi_header) + len) != (ssize_t)sizeof(fcgi_header)+len) {
req->keep = 0;
return 0;
}
@@ -1123,10 +1128,11 @@ int fcgi_read(fcgi_request *req, char *str, int len)
return n;
}
-static inline void fcgi_close(fcgi_request *req, int force, int destroy)
+void fcgi_close(fcgi_request *req, int force, int destroy)
{
if (destroy && req->has_env) {
fcgi_hash_clean(&req->env);
+ fcgi_hash_destroy(&req->env);
req->has_env = 0;
}
@@ -1169,7 +1175,55 @@ static inline void fcgi_close(fcgi_request *req, int force, int destroy)
req->nodelay = 0;
#endif
req->fd = -1;
+
+ if (req->hook.on_close) {
+ req->hook.on_close();
+ }
+ }
+}
+
+int fcgi_is_closed(fcgi_request *req)
+{
+ return (req->fd < 0);
+}
+
+static int fcgi_is_allowed() {
+ int i;
+
+ if (client_sa.sa.sa_family == AF_UNIX) {
+ return 1;
+ }
+ if (!allowed_clients) {
+ return 1;
}
+ if (client_sa.sa.sa_family == AF_INET) {
+ for (i = 0; allowed_clients[i].sa.sa_family ; i++) {
+ if (allowed_clients[i].sa.sa_family == AF_INET
+ && !memcmp(&client_sa.sa_inet.sin_addr, &allowed_clients[i].sa_inet.sin_addr, 4)) {
+ return 1;
+ }
+ }
+ }
+#ifdef HAVE_IPV6
+ if (client_sa.sa.sa_family == AF_INET6) {
+ for (i = 0; allowed_clients[i].sa.sa_family ; i++) {
+ if (allowed_clients[i].sa.sa_family == AF_INET6
+ && !memcmp(&client_sa.sa_inet6.sin6_addr, &allowed_clients[i].sa_inet6.sin6_addr, 12)) {
+ return 1;
+ }
+#ifdef IN6_IS_ADDR_V4MAPPED
+ if (allowed_clients[i].sa.sa_family == AF_INET
+ && IN6_IS_ADDR_V4MAPPED(&client_sa.sa_inet6.sin6_addr)
+ && !memcmp(((char *)&client_sa.sa_inet6.sin6_addr)+12, &allowed_clients[i].sa_inet.sin_addr, 4)) {
+ return 1;
+ }
+#endif
+ }
+ }
+#endif
+
+ logger(FCGI_ERROR, "Connection disallowed: IP address '%s' has been dropped.", fcgi_get_last_client_ip());
+ return 0;
}
int fcgi_accept_request(fcgi_request *req)
@@ -1215,37 +1269,19 @@ int fcgi_accept_request(fcgi_request *req)
sa_t sa;
socklen_t len = sizeof(sa);
+ if (req->hook.on_accept) {
+ req->hook.on_accept();
+ }
+
FCGI_LOCK(req->listen_socket);
req->fd = accept(listen_socket, (struct sockaddr *)&sa, &len);
FCGI_UNLOCK(req->listen_socket);
- if (req->fd >= 0) {
- if (((struct sockaddr *)&sa)->sa_family == AF_INET) {
-#ifndef _WIN32
- req->tcp = 1;
-#endif
- if (allowed_clients) {
- int n = 0;
- int allowed = 0;
-
- while (allowed_clients[n] != INADDR_NONE) {
- if (allowed_clients[n] == sa.sa_inet.sin_addr.s_addr) {
- allowed = 1;
- break;
- }
- n++;
- }
- if (!allowed) {
- flog(FCGI_ERROR, "Connection from disallowed IP address '%s' is dropped.\n", inet_ntoa(sa.sa_inet.sin_addr));
- closesocket(req->fd);
- req->fd = -1;
- continue;
- }
- }
-#ifndef _WIN32
- } else {
- req->tcp = 0;
-#endif
- }
+
+ client_sa = sa;
+ if (req->fd >= 0 && !fcgi_is_allowed()) {
+ closesocket(req->fd);
+ req->fd = -1;
+ continue;
}
}
@@ -1265,6 +1301,10 @@ int fcgi_accept_request(fcgi_request *req)
struct pollfd fds;
int ret;
+ if (req->hook.on_read) {
+ req->hook.on_read();
+ }
+
fds.fd = req->fd;
fds.events = POLLIN;
fds.revents = 0;
@@ -1277,6 +1317,10 @@ int fcgi_accept_request(fcgi_request *req)
}
fcgi_close(req, 1, 0);
#else
+ if (req->hook.on_read) {
+ req->hook.on_read();
+ }
+
if (req->fd < FD_SETSIZE) {
struct timeval tv = {5,0};
fd_set set;
@@ -1293,7 +1337,7 @@ int fcgi_accept_request(fcgi_request *req)
}
fcgi_close(req, 1, 0);
} else {
- flog(FCGI_ERROR, "Too many open file descriptors. FD_SETSIZE limit exceeded.");
+ logger(FCGI_ERROR, "Too many open file descriptors. FD_SETSIZE limit exceeded.");
fcgi_close(req, 1, 0);
}
#endif
@@ -1560,6 +1604,31 @@ void fcgi_free_mgmt_var_cb(zval *zv)
pefree(Z_STR_P(zv), 1);
}
+const char *fcgi_get_last_client_ip()
+{
+ static char str[INET6_ADDRSTRLEN];
+
+ /* Ipv4 */
+ if (client_sa.sa.sa_family == AF_INET) {
+ return inet_ntop(client_sa.sa.sa_family, &client_sa.sa_inet.sin_addr, str, INET6_ADDRSTRLEN);
+ }
+#ifdef HAVE_IPV6
+#ifdef IN6_IS_ADDR_V4MAPPED
+ /* Ipv4-Mapped-Ipv6 */
+ if (client_sa.sa.sa_family == AF_INET6
+ && IN6_IS_ADDR_V4MAPPED(&client_sa.sa_inet6.sin6_addr)) {
+ return inet_ntop(AF_INET, ((char *)&client_sa.sa_inet6.sin6_addr)+12, str, INET6_ADDRSTRLEN);
+ }
+#endif
+ /* Ipv6 */
+ if (client_sa.sa.sa_family == AF_INET6) {
+ return inet_ntop(client_sa.sa.sa_family, &client_sa.sa_inet6.sin6_addr, str, INET6_ADDRSTRLEN);
+ }
+#endif
+ /* Unix socket */
+ return NULL;
+}
+
/*
* Local variables:
* tab-width: 4
diff --git a/main/fastcgi.h b/main/fastcgi.h
index b7fa210bfe..b8ff9ba123 100644
--- a/main/fastcgi.h
+++ b/main/fastcgi.h
@@ -49,11 +49,13 @@ typedef enum _fcgi_role {
FCGI_FILTER = 3
} fcgi_role;
-typedef enum _fcgi_code {
- FCGI_NOTICE,
- FCGI_WARNING,
- FCGI_ERROR,
-} fcgi_code;
+enum {
+ FCGI_DEBUG = 1,
+ FCGI_NOTICE = 2,
+ FCGI_WARNING = 3,
+ FCGI_ERROR = 4,
+ FCGI_ALERT = 5,
+};
typedef enum _fcgi_request_type {
FCGI_BEGIN_REQUEST = 1, /* [in] */
@@ -116,21 +118,91 @@ typedef struct _fcgi_end_request_rec {
typedef void (*fcgi_apply_func)(char *var, unsigned int var_len, char *val, unsigned int val_len, void *arg);
-typedef void (*fcgi_logger)(int type, const char *format, ...);
+typedef void (*fcgi_logger)(int type, const char *fmt, ...);
+
+#define FCGI_HASH_TABLE_SIZE 128
+#define FCGI_HASH_TABLE_MASK (FCGI_HASH_TABLE_SIZE - 1)
+#define FCGI_HASH_SEG_SIZE 4096
+
+typedef struct _fcgi_hash_bucket {
+ unsigned int hash_value;
+ unsigned int var_len;
+ char *var;
+ unsigned int val_len;
+ char *val;
+ struct _fcgi_hash_bucket *next;
+ struct _fcgi_hash_bucket *list_next;
+} fcgi_hash_bucket;
+
+typedef struct _fcgi_hash_buckets {
+ unsigned int idx;
+ struct _fcgi_hash_buckets *next;
+ struct _fcgi_hash_bucket data[FCGI_HASH_TABLE_SIZE];
+} fcgi_hash_buckets;
+
+typedef struct _fcgi_data_seg {
+ char *pos;
+ char *end;
+ struct _fcgi_data_seg *next;
+ char data[1];
+} fcgi_data_seg;
+
+typedef struct _fcgi_hash {
+ fcgi_hash_bucket *hash_table[FCGI_HASH_TABLE_SIZE];
+ fcgi_hash_bucket *list;
+ fcgi_hash_buckets *buckets;
+ fcgi_data_seg *data;
+} fcgi_hash;
+
+typedef struct _fcgi_request fcgi_request;
+typedef struct _fcgi_req_hook fcgi_req_hook;
+
+struct _fcgi_req_hook {
+ void(*on_accept)();
+ void(*on_read)();
+ void(*on_close)();
+};
+
+struct _fcgi_request {
+ int listen_socket;
+ int tcp;
+ int fd;
+ int id;
+ int keep;
+#ifdef TCP_NODELAY
+ int nodelay;
+#endif
+ int closed;
+
+ fcgi_req_hook hook;
+
+ int in_len;
+ int in_pad;
+
+ fcgi_header *out_hdr;
+ unsigned char *out_pos;
+ unsigned char out_buf[1024*8];
+ unsigned char reserved[sizeof(fcgi_end_request_rec)];
-typedef struct _fcgi_request fcgi_request;
+ int has_env;
+ fcgi_hash env;
+};
int fcgi_init(void);
void fcgi_shutdown(void);
int fcgi_is_fastcgi(void);
+int fcgi_is_closed(fcgi_request *req);
+void fcgi_close(fcgi_request *req, int force, int destroy);
int fcgi_in_shutdown(void);
void fcgi_terminate(void);
int fcgi_listen(const char *path, int backlog);
-fcgi_request* fcgi_init_request(int listen_socket);
-void fcgi_destroy_request(fcgi_request *req);
+fcgi_request* fcgi_init_request(fcgi_request *request, int listen_socket);
+void fcgi_set_allowed_clients(char *ip);
int fcgi_accept_request(fcgi_request *req);
int fcgi_finish_request(fcgi_request *req, int force_close);
-void fcgi_set_logger(fcgi_logger logger);
+void fcgi_set_logger(fcgi_logger lg);
+const char *fcgi_get_last_client_ip();
+void fcgi_set_in_shutdown(int new_value);
char* fcgi_getenv(fcgi_request *req, const char* var, int var_len);
char* fcgi_putenv(fcgi_request *req, char* var, int var_len, char* val);
diff --git a/sapi/cgi/cgi_main.c b/sapi/cgi/cgi_main.c
index a60b7c22a9..b89829f016 100644
--- a/sapi/cgi/cgi_main.c
+++ b/sapi/cgi/cgi_main.c
@@ -1034,12 +1034,12 @@ static int is_valid_path(const char *path)
/* }}} */
#define CGI_GETENV(name) \
- ((request) ? \
+ ((request->has_env) ? \
FCGI_GETENV(request, name) : \
getenv(name))
#define CGI_PUTENV(name, value) \
- ((request) ? \
+ ((request->has_env) ? \
FCGI_PUTENV(request, name, value) : \
_sapi_cgi_putenv(name, sizeof(name)-1, value))
@@ -1732,7 +1732,7 @@ int main(int argc, char *argv[])
int fastcgi;
char *bindpath = NULL;
int fcgi_fd = 0;
- fcgi_request *request = NULL;
+ fcgi_request request = {0};
int warmup_repeats = 0;
int repeats = 1;
int benchmark = 0;
@@ -1967,109 +1967,109 @@ consult the installation file that came with this distribution, or visit \n\
php_import_environment_variables = cgi_php_import_environment_variables;
/* library is already initialized, now init our request */
- request = fcgi_init_request(fcgi_fd);
+ fcgi_init_request(&request, fcgi_fd);
#ifndef PHP_WIN32
- /* Pre-fork, if required */
- if (getenv("PHP_FCGI_CHILDREN")) {
- char * children_str = getenv("PHP_FCGI_CHILDREN");
- children = atoi(children_str);
- if (children < 0) {
- fprintf(stderr, "PHP_FCGI_CHILDREN is not valid\n");
- return FAILURE;
+ /* Pre-fork, if required */
+ if (getenv("PHP_FCGI_CHILDREN")) {
+ char * children_str = getenv("PHP_FCGI_CHILDREN");
+ children = atoi(children_str);
+ if (children < 0) {
+ fprintf(stderr, "PHP_FCGI_CHILDREN is not valid\n");
+ return FAILURE;
+ }
+ fcgi_set_mgmt_var("FCGI_MAX_CONNS", sizeof("FCGI_MAX_CONNS")-1, children_str, strlen(children_str));
+ /* This is the number of concurrent requests, equals FCGI_MAX_CONNS */
+ fcgi_set_mgmt_var("FCGI_MAX_REQS", sizeof("FCGI_MAX_REQS")-1, children_str, strlen(children_str));
+ } else {
+ fcgi_set_mgmt_var("FCGI_MAX_CONNS", sizeof("FCGI_MAX_CONNS")-1, "1", sizeof("1")-1);
+ fcgi_set_mgmt_var("FCGI_MAX_REQS", sizeof("FCGI_MAX_REQS")-1, "1", sizeof("1")-1);
}
- fcgi_set_mgmt_var("FCGI_MAX_CONNS", sizeof("FCGI_MAX_CONNS")-1, children_str, strlen(children_str));
- /* This is the number of concurrent requests, equals FCGI_MAX_CONNS */
- fcgi_set_mgmt_var("FCGI_MAX_REQS", sizeof("FCGI_MAX_REQS")-1, children_str, strlen(children_str));
- } else {
- fcgi_set_mgmt_var("FCGI_MAX_CONNS", sizeof("FCGI_MAX_CONNS")-1, "1", sizeof("1")-1);
- fcgi_set_mgmt_var("FCGI_MAX_REQS", sizeof("FCGI_MAX_REQS")-1, "1", sizeof("1")-1);
- }
- if (children) {
- int running = 0;
- pid_t pid;
+ if (children) {
+ int running = 0;
+ pid_t pid;
- /* Create a process group for ourself & children */
- setsid();
- pgroup = getpgrp();
+ /* Create a process group for ourself & children */
+ setsid();
+ pgroup = getpgrp();
#ifdef DEBUG_FASTCGI
- fprintf(stderr, "Process group %d\n", pgroup);
+ fprintf(stderr, "Process group %d\n", pgroup);
#endif
- /* Set up handler to kill children upon exit */
- act.sa_flags = 0;
- act.sa_handler = fastcgi_cleanup;
- if (sigaction(SIGTERM, &act, &old_term) ||
- sigaction(SIGINT, &act, &old_int) ||
- sigaction(SIGQUIT, &act, &old_quit)
- ) {
- perror("Can't set signals");
- exit(1);
- }
+ /* Set up handler to kill children upon exit */
+ act.sa_flags = 0;
+ act.sa_handler = fastcgi_cleanup;
+ if (sigaction(SIGTERM, &act, &old_term) ||
+ sigaction(SIGINT, &act, &old_int) ||
+ sigaction(SIGQUIT, &act, &old_quit)
+ ) {
+ perror("Can't set signals");
+ exit(1);
+ }
- if (fcgi_in_shutdown()) {
- goto parent_out;
- }
+ if (fcgi_in_shutdown()) {
+ goto parent_out;
+ }
- while (parent) {
- do {
+ while (parent) {
+ do {
#ifdef DEBUG_FASTCGI
- fprintf(stderr, "Forking, %d running\n", running);
-#endif
- pid = fork();
- switch (pid) {
- case 0:
- /* One of the children.
- * Make sure we don't go round the
- * fork loop any more
- */
- parent = 0;
+ fprintf(stderr, "Forking, %d running\n", running);
+#endif
+ pid = fork();
+ switch (pid) {
+ case 0:
+ /* One of the children.
+ * Make sure we don't go round the
+ * fork loop any more
+ */
+ parent = 0;
- /* don't catch our signals */
- sigaction(SIGTERM, &old_term, 0);
- sigaction(SIGQUIT, &old_quit, 0);
- sigaction(SIGINT, &old_int, 0);
- break;
- case -1:
- perror("php (pre-forking)");
- exit(1);
- break;
- default:
- /* Fine */
- running++;
- break;
- }
- } while (parent && (running < children));
+ /* don't catch our signals */
+ sigaction(SIGTERM, &old_term, 0);
+ sigaction(SIGQUIT, &old_quit, 0);
+ sigaction(SIGINT, &old_int, 0);
+ break;
+ case -1:
+ perror("php (pre-forking)");
+ exit(1);
+ break;
+ default:
+ /* Fine */
+ running++;
+ break;
+ }
+ } while (parent && (running < children));
- if (parent) {
+ if (parent) {
#ifdef DEBUG_FASTCGI
- fprintf(stderr, "Wait for kids, pid %d\n", getpid());
+ fprintf(stderr, "Wait for kids, pid %d\n", getpid());
#endif
- parent_waiting = 1;
- while (1) {
- if (wait(&status) >= 0) {
- running--;
- break;
- } else if (exit_signal) {
- break;
+ parent_waiting = 1;
+ while (1) {
+ if (wait(&status) >= 0) {
+ running--;
+ break;
+ } else if (exit_signal) {
+ break;
+ }
}
- }
- if (exit_signal) {
+ if (exit_signal) {
#if 0
- while (running > 0) {
- while (wait(&status) < 0) {
+ while (running > 0) {
+ while (wait(&status) < 0) {
+ }
+ running--;
}
- running--;
- }
#endif
- goto parent_out;
+ goto parent_out;
+ }
}
}
+ } else {
+ parent = 0;
}
- } else {
- parent = 0;
- }
#endif /* WIN32 */
}
@@ -2096,9 +2096,6 @@ consult the installation file that came with this distribution, or visit \n\
break;
case 'h':
case '?':
- if (request) {
- fcgi_destroy_request(request);
- }
fcgi_shutdown();
no_headers = 1;
SG(headers_sent) = 1;
@@ -2120,9 +2117,9 @@ consult the installation file that came with this distribution, or visit \n\
fcgi_impersonate();
}
#endif
- while (!fastcgi || fcgi_accept_request(request) >= 0) {
- SG(server_context) = fastcgi ? (void *) request : (void *) 1;
- init_request_info(request);
+ while (!fastcgi || fcgi_accept_request(&request) >= 0) {
+ SG(server_context) = fastcgi ? (void *)&request : (void *) 1;
+ init_request_info(&request);
if (!cgi && !fastcgi) {
while ((c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2)) != -1) {
@@ -2307,7 +2304,7 @@ consult the installation file that came with this distribution, or visit \n\
* get path_translated */
if (php_request_startup() == FAILURE) {
if (fastcgi) {
- fcgi_finish_request(request, 1);
+ fcgi_finish_request(&request, 1);
}
SG(server_context) = NULL;
php_module_shutdown();
@@ -2518,7 +2515,7 @@ fastcgi_request_done:
/* only fastcgi will get here */
requests++;
if (max_requests && (requests == max_requests)) {
- fcgi_finish_request(request, 1);
+ fcgi_finish_request(&request, 1);
if (bindpath) {
free(bindpath);
}
@@ -2530,9 +2527,6 @@ fastcgi_request_done:
}
/* end of fastcgi loop */
}
- if (request) {
- fcgi_destroy_request(request);
- }
fcgi_shutdown();
if (cgi_sapi_module.php_ini_path_override) {
diff --git a/sapi/fpm/config.m4 b/sapi/fpm/config.m4
index b4a4f4fb33..563e96d073 100644
--- a/sapi/fpm/config.m4
+++ b/sapi/fpm/config.m4
@@ -678,8 +678,7 @@ if test "$PHP_FPM" != "no"; then
PHP_FPM_CFLAGS="-I$abs_srcdir/sapi/fpm"
- PHP_FPM_FILES="fpm/fastcgi.c \
- fpm/fpm.c \
+ PHP_FPM_FILES="fpm/fpm.c \
fpm/fpm_children.c \
fpm/fpm_cleanup.c \
fpm/fpm_clock.c \
diff --git a/sapi/fpm/fpm/fastcgi.c b/sapi/fpm/fpm/fastcgi.c
deleted file mode 100644
index 71eaa78cd4..0000000000
--- a/sapi/fpm/fpm/fastcgi.c
+++ /dev/null
@@ -1,1340 +0,0 @@
-/*
- +----------------------------------------------------------------------+
- | PHP Version 7 |
- +----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
- +----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Authors: Dmitry Stogov <dmitry@zend.com> |
- +----------------------------------------------------------------------+
-*/
-
-/* $Id: fastcgi.c 287777 2009-08-26 19:17:32Z pajoye $ */
-
-#include "php.h"
-#include "fastcgi.h"
-
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <errno.h>
-#include <limits.h>
-
-#include <php_config.h>
-#include "fpm.h"
-#include "fpm_request.h"
-#include "zlog.h"
-
-#ifdef _WIN32
-
-#include <windows.h>
-
- struct sockaddr_un {
- short sun_family;
- char sun_path[MAXPATHLEN];
- };
-
- static HANDLE fcgi_accept_mutex = INVALID_HANDLE_VALUE;
- static int is_impersonate = 0;
-
-#define FCGI_LOCK(fd) \
- if (fcgi_accept_mutex != INVALID_HANDLE_VALUE) { \
- DWORD ret; \
- while ((ret = WaitForSingleObject(fcgi_accept_mutex, 1000)) == WAIT_TIMEOUT) { \
- if (in_shutdown) return -1; \
- } \
- if (ret == WAIT_FAILED) { \
- fprintf(stderr, "WaitForSingleObject() failed\n"); \
- return -1; \
- } \
- }
-
-#define FCGI_UNLOCK(fd) \
- if (fcgi_accept_mutex != INVALID_HANDLE_VALUE) { \
- ReleaseMutex(fcgi_accept_mutex); \
- }
-
-#else
-
-# include <sys/types.h>
-# include <sys/stat.h>
-# include <unistd.h>
-# include <fcntl.h>
-# include <sys/socket.h>
-# include <sys/un.h>
-# include <netinet/in.h>
-# include <arpa/inet.h>
-# 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
-# if defined(HAVE_SYS_SELECT_H)
-# include <sys/select.h>
-# endif
-
-#ifndef INADDR_NONE
-#define INADDR_NONE ((unsigned long) -1)
-#endif
-
-# ifndef HAVE_SOCKLEN_T
- typedef unsigned int socklen_t;
-# endif
-
-# ifdef USE_LOCKING
-# define FCGI_LOCK(fd) \
- do { \
- struct flock lock; \
- lock.l_type = F_WRLCK; \
- lock.l_start = 0; \
- lock.l_whence = SEEK_SET; \
- lock.l_len = 0; \
- if (fcntl(fd, F_SETLKW, &lock) != -1) { \
- break; \
- } else if (errno != EINTR || in_shutdown) { \
- return -1; \
- } \
- } while (1)
-
-# define FCGI_UNLOCK(fd) \
- do { \
- int orig_errno = errno; \
- while (1) { \
- struct flock lock; \
- lock.l_type = F_UNLCK; \
- lock.l_start = 0; \
- lock.l_whence = SEEK_SET; \
- lock.l_len = 0; \
- if (fcntl(fd, F_SETLK, &lock) != -1) { \
- break; \
- } else if (errno != EINTR) { \
- return -1; \
- } \
- } \
- errno = orig_errno; \
- } while (0)
-# else
-# define FCGI_LOCK(fd)
-# define FCGI_UNLOCK(fd)
-# endif
-
-#endif
-
-typedef union _sa_t {
- struct sockaddr sa;
- struct sockaddr_un sa_unix;
- struct sockaddr_in sa_inet;
- struct sockaddr_in6 sa_inet6;
-} sa_t;
-
-static HashTable fcgi_mgmt_vars;
-
-static int is_initialized = 0;
-static int in_shutdown = 0;
-static sa_t *allowed_clients = NULL;
-
-static sa_t client_sa;
-
-/* hash table */
-
-#define FCGI_HASH_TABLE_SIZE 128
-#define FCGI_HASH_TABLE_MASK (FCGI_HASH_TABLE_SIZE - 1)
-#define FCGI_HASH_SEG_SIZE 4096
-
-typedef struct _fcgi_hash_bucket {
- unsigned int hash_value;
- unsigned int var_len;
- char *var;
- unsigned int val_len;
- char *val;
- struct _fcgi_hash_bucket *next;
- struct _fcgi_hash_bucket *list_next;
-} fcgi_hash_bucket;
-
-typedef struct _fcgi_hash_buckets {
- unsigned int idx;
- struct _fcgi_hash_buckets *next;
- struct _fcgi_hash_bucket data[FCGI_HASH_TABLE_SIZE];
-} fcgi_hash_buckets;
-
-typedef struct _fcgi_data_seg {
- char *pos;
- char *end;
- struct _fcgi_data_seg *next;
- char data[1];
-} fcgi_data_seg;
-
-typedef struct _fcgi_hash {
- fcgi_hash_bucket *hash_table[FCGI_HASH_TABLE_SIZE];
- fcgi_hash_bucket *list;
- fcgi_hash_buckets *buckets;
- fcgi_data_seg *data;
-} fcgi_hash;
-
-static void fcgi_hash_init(fcgi_hash *h)
-{
- memset(h->hash_table, 0, sizeof(h->hash_table));
- h->list = NULL;
- h->buckets = (fcgi_hash_buckets*)malloc(sizeof(fcgi_hash_buckets));
- h->buckets->idx = 0;
- h->buckets->next = NULL;
- h->data = (fcgi_data_seg*)malloc(sizeof(fcgi_data_seg) - 1 + FCGI_HASH_SEG_SIZE);
- h->data->pos = h->data->data;
- h->data->end = h->data->pos + FCGI_HASH_SEG_SIZE;
- h->data->next = NULL;
-}
-
-static void fcgi_hash_destroy(fcgi_hash *h)
-{
- fcgi_hash_buckets *b;
- fcgi_data_seg *p;
-
- b = h->buckets;
- while (b) {
- fcgi_hash_buckets *q = b;
- b = b->next;
- free(q);
- }
- p = h->data;
- while (p) {
- fcgi_data_seg *q = p;
- p = p->next;
- free(q);
- }
-}
-
-static void fcgi_hash_clean(fcgi_hash *h)
-{
- memset(h->hash_table, 0, sizeof(h->hash_table));
- h->list = NULL;
- /* delete all bucket blocks except the first one */
- while (h->buckets->next) {
- fcgi_hash_buckets *q = h->buckets;
-
- h->buckets = h->buckets->next;
- free(q);
- }
- h->buckets->idx = 0;
- /* delete all data segments except the first one */
- while (h->data->next) {
- fcgi_data_seg *q = h->data;
-
- h->data = h->data->next;
- free(q);
- }
- h->data->pos = h->data->data;
-}
-
-static inline char* fcgi_hash_strndup(fcgi_hash *h, char *str, unsigned int str_len)
-{
- char *ret;
-
- if (UNEXPECTED(h->data->pos + str_len + 1 >= h->data->end)) {
- unsigned int seg_size = (str_len + 1 > FCGI_HASH_SEG_SIZE) ? str_len + 1 : FCGI_HASH_SEG_SIZE;
- fcgi_data_seg *p = (fcgi_data_seg*)malloc(sizeof(fcgi_data_seg) - 1 + seg_size);
-
- p->pos = p->data;
- p->end = p->pos + seg_size;
- p->next = h->data;
- h->data = p;
- }
- ret = h->data->pos;
- memcpy(ret, str, str_len);
- ret[str_len] = 0;
- h->data->pos += str_len + 1;
- return ret;
-}
-
-static char* fcgi_hash_set(fcgi_hash *h, unsigned int hash_value, char *var, unsigned int var_len, char *val, unsigned int val_len)
-{
- unsigned int idx = hash_value & FCGI_HASH_TABLE_MASK;
- fcgi_hash_bucket *p = h->hash_table[idx];
-
- while (UNEXPECTED(p != NULL)) {
- if (UNEXPECTED(p->hash_value == hash_value) &&
- p->var_len == var_len &&
- memcmp(p->var, var, var_len) == 0) {
-
- p->val_len = val_len;
- p->val = fcgi_hash_strndup(h, val, val_len);
- return p->val;
- }
- p = p->next;
- }
-
- if (UNEXPECTED(h->buckets->idx >= FCGI_HASH_TABLE_SIZE)) {
- fcgi_hash_buckets *b = (fcgi_hash_buckets*)malloc(sizeof(fcgi_hash_buckets));
- b->idx = 0;
- b->next = h->buckets;
- h->buckets = b;
- }
- p = h->buckets->data + h->buckets->idx;
- h->buckets->idx++;
- p->next = h->hash_table[idx];
- h->hash_table[idx] = p;
- p->list_next = h->list;
- h->list = p;
- p->hash_value = hash_value;
- p->var_len = var_len;
- p->var = fcgi_hash_strndup(h, var, var_len);
- p->val_len = val_len;
- p->val = fcgi_hash_strndup(h, val, val_len);
- return p->val;
-}
-
-static void fcgi_hash_del(fcgi_hash *h, unsigned int hash_value, char *var, unsigned int var_len)
-{
- unsigned int idx = hash_value & FCGI_HASH_TABLE_MASK;
- fcgi_hash_bucket **p = &h->hash_table[idx];
-
- while (*p != NULL) {
- if ((*p)->hash_value == hash_value &&
- (*p)->var_len == var_len &&
- memcmp((*p)->var, var, var_len) == 0) {
-
- (*p)->val = NULL; /* NULL value means deleted */
- (*p)->val_len = 0;
- *p = (*p)->next;
- return;
- }
- p = &(*p)->next;
- }
-}
-
-static char *fcgi_hash_get(fcgi_hash *h, unsigned int hash_value, char *var, unsigned int var_len, unsigned int *val_len)
-{
- unsigned int idx = hash_value & FCGI_HASH_TABLE_MASK;
- fcgi_hash_bucket *p = h->hash_table[idx];
-
- while (p != NULL) {
- if (p->hash_value == hash_value &&
- p->var_len == var_len &&
- memcmp(p->var, var, var_len) == 0) {
- *val_len = p->val_len;
- return p->val;
- }
- p = p->next;
- }
- return NULL;
-}
-
-static void fcgi_hash_apply(fcgi_hash *h, fcgi_apply_func func, void *arg)
-{
- fcgi_hash_bucket *p = h->list;
-
- while (p) {
- if (EXPECTED(p->val != NULL)) {
- func(p->var, p->var_len, p->val, p->val_len, arg);
- }
- p = p->list_next;
- }
-}
-
-struct _fcgi_request {
- int listen_socket;
-#ifdef _WIN32
- int tcp;
-#endif
- int fd;
- int id;
- int keep;
-#ifdef TCP_NODELAY
- int nodelay;
-#endif
- int closed;
-
- int in_len;
- int in_pad;
-
- fcgi_header *out_hdr;
- unsigned char *out_pos;
- unsigned char out_buf[1024*8];
- unsigned char reserved[sizeof(fcgi_end_request_rec)];
-
- int has_env;
- fcgi_hash env;
-};
-
-#ifdef _WIN32
-
-static DWORD WINAPI fcgi_shutdown_thread(LPVOID arg)
-{
- HANDLE shutdown_event = (HANDLE) arg;
- WaitForSingleObject(shutdown_event, INFINITE);
- in_shutdown = 1;
- return 0;
-}
-
-#else
-
-static void fcgi_signal_handler(int signo)
-{
- if (signo == SIGUSR1 || signo == SIGTERM) {
- in_shutdown = 1;
- }
-}
-
-static void fcgi_setup_signals(void)
-{
- struct sigaction new_sa, old_sa;
-
- sigemptyset(&new_sa.sa_mask);
- new_sa.sa_flags = 0;
- new_sa.sa_handler = fcgi_signal_handler;
- sigaction(SIGUSR1, &new_sa, NULL);
- sigaction(SIGTERM, &new_sa, NULL);
- sigaction(SIGPIPE, NULL, &old_sa);
- if (old_sa.sa_handler == SIG_DFL) {
- sigaction(SIGPIPE, &new_sa, NULL);
- }
-}
-#endif
-
-int fcgi_in_shutdown(void)
-{
- return in_shutdown;
-}
-
-void fcgi_terminate(void)
-{
- in_shutdown = 1;
-}
-
-int fcgi_init(void)
-{
- if (!is_initialized) {
- zend_hash_init(&fcgi_mgmt_vars, 8, NULL, fcgi_free_mgmt_var_cb, 1);
- fcgi_set_mgmt_var("FCGI_MPXS_CONNS", sizeof("FCGI_MPXS_CONNS") - 1, "0", sizeof("0")-1);
-
- is_initialized = 1;
-#ifdef _WIN32
-# if 0
- /* TODO: Support for TCP sockets */
- WSADATA wsaData;
-
- if (WSAStartup(MAKEWORD(2,0), &wsaData)) {
- fprintf(stderr, "Error starting Windows Sockets. Error: %d", WSAGetLastError());
- return 0;
- }
-# endif
- {
- char *str;
- DWORD pipe_mode = PIPE_READMODE_BYTE | PIPE_WAIT;
- HANDLE pipe = GetStdHandle(STD_INPUT_HANDLE);
-
- SetNamedPipeHandleState(pipe, &pipe_mode, NULL, NULL);
-
- str = getenv("_FCGI_SHUTDOWN_EVENT_");
- if (str != NULL) {
- HANDLE shutdown_event = (HANDLE) atoi(str);
- if (!CreateThread(NULL, 0, fcgi_shutdown_thread,
- shutdown_event, 0, NULL)) {
- return -1;
- }
- }
- str = getenv("_FCGI_MUTEX_");
- if (str != NULL) {
- fcgi_accept_mutex = (HANDLE) atoi(str);
- }
- return 1;
- }
-#else
- fcgi_setup_signals();
- return 1;
-#endif
- }
- return 1;
-}
-
-void fcgi_set_in_shutdown(int new_value)
-{
- in_shutdown = new_value;
-}
-
-void fcgi_shutdown(void)
-{
- if (is_initialized) {
- zend_hash_destroy(&fcgi_mgmt_vars);
- }
- if (allowed_clients) {
- free(allowed_clients);
- }
-}
-
-void fcgi_set_allowed_clients(char *ip)
-{
- char *cur, *end;
- int n;
-
- if (ip) {
- ip = strdup(ip);
- cur = ip;
- n = 0;
- while (*cur) {
- if (*cur == ',') n++;
- cur++;
- }
- if (allowed_clients) free(allowed_clients);
- allowed_clients = malloc(sizeof(sa_t) * (n+2));
- n = 0;
- cur = ip;
- while (cur) {
- end = strchr(cur, ',');
- if (end) {
- *end = 0;
- end++;
- }
- if (inet_pton(AF_INET, cur, &allowed_clients[n].sa_inet.sin_addr)>0) {
- allowed_clients[n].sa.sa_family = AF_INET;
- n++;
- } else if (inet_pton(AF_INET6, cur, &allowed_clients[n].sa_inet6.sin6_addr)>0) {
- allowed_clients[n].sa.sa_family = AF_INET6;
- n++;
- } else {
- zlog(ZLOG_ERROR, "Wrong IP address '%s' in listen.allowed_clients", cur);
- }
- cur = end;
- }
- allowed_clients[n].sa.sa_family = 0;
- free(ip);
- if (!n) {
- zlog(ZLOG_ERROR, "There are no allowed addresses for this pool");
- /* don't clear allowed_clients as it will create an "open for all" security issue */
- }
- }
-}
-
-fcgi_request *fcgi_init_request(int listen_socket)
-{
- fcgi_request *req = (fcgi_request*)calloc(1, sizeof(fcgi_request));
- req->listen_socket = listen_socket;
- req->fd = -1;
- req->id = -1;
-
- req->in_len = 0;
- req->in_pad = 0;
-
- 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
-
-#ifdef TCP_NODELAY
- req->nodelay = 0;
-#endif
-
- fcgi_hash_init(&req->env);
-
- return req;
-}
-
-void fcgi_destroy_request(fcgi_request *req)
-{
- fcgi_hash_destroy(&req->env);
- free(req);
-}
-
-static inline ssize_t safe_write(fcgi_request *req, const void *buf, size_t count)
-{
- int ret;
- size_t n = 0;
-
- 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) {
- return ret;
- }
- } while (n != count);
- return n;
-}
-
-static inline ssize_t safe_read(fcgi_request *req, const void *buf, size_t count)
-{
- int ret;
- size_t n = 0;
-
- 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) {
- return n;
- } else if (ret <= 0 && errno != 0 && errno != EINTR) {
- return ret;
- }
- } while (n != count);
- return n;
-}
-
-static inline int fcgi_make_header(fcgi_header *hdr, fcgi_request_type type, int req_id, int len)
-{
- int pad = ((len + 7) & ~7) - len;
-
- hdr->contentLengthB0 = (unsigned char)(len & 0xff);
- hdr->contentLengthB1 = (unsigned char)((len >> 8) & 0xff);
- hdr->paddingLength = (unsigned char)pad;
- hdr->requestIdB0 = (unsigned char)(req_id & 0xff);
- hdr->requestIdB1 = (unsigned char)((req_id >> 8) & 0xff);
- hdr->reserved = 0;
- hdr->type = type;
- hdr->version = FCGI_VERSION_1;
- if (pad) {
- memset(((unsigned char*)hdr) + sizeof(fcgi_header) + len, 0, pad);
- }
- return pad;
-}
-
-static int fcgi_get_params(fcgi_request *req, unsigned char *p, unsigned char *end)
-{
- int name_len = 0;
- int val_len = 0;
-
- while (p < end) {
- name_len = *p++;
- if (UNEXPECTED(name_len >= 128)) {
- if (UNEXPECTED(p + 3 >= end)) return 0;
- name_len = ((name_len & 0x7f) << 24);
- name_len |= (*p++ << 16);
- name_len |= (*p++ << 8);
- name_len |= *p++;
- }
- if (UNEXPECTED(p >= end)) return 0;
- val_len = *p++;
- if (UNEXPECTED(val_len >= 128)) {
- if (UNEXPECTED(p + 3 >= end)) return 0;
- val_len = ((val_len & 0x7f) << 24);
- val_len |= (*p++ << 16);
- val_len |= (*p++ << 8);
- val_len |= *p++;
- }
- if (UNEXPECTED(name_len > (INT_MAX - val_len)) || /* would the addition overflow? */
- UNEXPECTED(name_len + val_len > end - p)) { /* would we exceed the buffer? */
- /* Malformated request */
- return 0;
- }
-
- /*
- * get the effective length of the name in case it's not a valid string
- * don't do this on the value because it can be binary data
- */
- if (UNEXPECTED(memchr(p, 0, name_len) != NULL)) {
- /* Malicious request */
- return 0;
- }
- fcgi_hash_set(&req->env, FCGI_HASH_FUNC(p, name_len), (char*)p, name_len, (char*)p + name_len, val_len);
- p += name_len + val_len;
- }
- return 1;
-}
-
-static void fcgi_free_var(zval *zv)
-{
- efree(Z_PTR_P(zv));
-}
-
-static int fcgi_read_request(fcgi_request *req)
-{
- fcgi_header hdr;
- int len, padding;
- unsigned char buf[FCGI_MAX_LENGTH+8];
-
- req->keep = 0;
- req->closed = 0;
- req->in_len = 0;
- req->out_hdr = NULL;
- req->out_pos = req->out_buf;
- req->has_env = 1;
-
- if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
- hdr.version < FCGI_VERSION_1) {
- return 0;
- }
-
- len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
- padding = hdr.paddingLength;
-
- while (hdr.type == FCGI_STDIN && len == 0) {
- if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
- hdr.version < FCGI_VERSION_1) {
- return 0;
- }
-
- len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
- padding = hdr.paddingLength;
- }
-
- if (len + padding > FCGI_MAX_LENGTH) {
- return 0;
- }
-
- req->id = (hdr.requestIdB1 << 8) + hdr.requestIdB0;
-
- if (hdr.type == FCGI_BEGIN_REQUEST && len == sizeof(fcgi_begin_request)) {
- if (safe_read(req, buf, len+padding) != len+padding) {
- return 0;
- }
-
- req->keep = (((fcgi_begin_request*)buf)->flags & FCGI_KEEP_CONN);
-#ifdef TCP_NODELAY
- if (req->keep && req->tcp && !req->nodelay) {
-# ifdef _WIN32
- BOOL on = 1;
-# else
- int on = 1;
-# endif
-
- setsockopt(req->fd, IPPROTO_TCP, TCP_NODELAY, (char*)&on, sizeof(on));
- req->nodelay = 1;
- }
-#endif
- switch ((((fcgi_begin_request*)buf)->roleB1 << 8) + ((fcgi_begin_request*)buf)->roleB0) {
- case FCGI_RESPONDER:
- fcgi_hash_set(&req->env, FCGI_HASH_FUNC("FCGI_ROLE", sizeof("FCGI_ROLE")-1), "FCGI_ROLE", sizeof("FCGI_ROLE")-1, "RESPONDER", sizeof("RESPONDER")-1);
- break;
- case FCGI_AUTHORIZER:
- fcgi_hash_set(&req->env, FCGI_HASH_FUNC("FCGI_ROLE", sizeof("FCGI_ROLE")-1), "FCGI_ROLE", sizeof("FCGI_ROLE")-1, "AUTHORIZER", sizeof("AUTHORIZER")-1);
- break;
- case FCGI_FILTER:
- fcgi_hash_set(&req->env, FCGI_HASH_FUNC("FCGI_ROLE", sizeof("FCGI_ROLE")-1), "FCGI_ROLE", sizeof("FCGI_ROLE")-1, "FILTER", sizeof("FILTER")-1);
- break;
- default:
- return 0;
- }
-
- if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
- hdr.version < FCGI_VERSION_1) {
- return 0;
- }
-
- len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
- padding = hdr.paddingLength;
-
- while (hdr.type == FCGI_PARAMS && len > 0) {
- if (len + padding > FCGI_MAX_LENGTH) {
- return 0;
- }
-
- if (safe_read(req, buf, len+padding) != len+padding) {
- req->keep = 0;
- return 0;
- }
-
- if (!fcgi_get_params(req, buf, buf+len)) {
- req->keep = 0;
- return 0;
- }
-
- if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
- hdr.version < FCGI_VERSION_1) {
- req->keep = 0;
- return 0;
- }
- len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
- padding = hdr.paddingLength;
- }
- } else if (hdr.type == FCGI_GET_VALUES) {
- unsigned char *p = buf + sizeof(fcgi_header);
- zval *value;
- unsigned int zlen;
- fcgi_hash_bucket *q;
-
- if (safe_read(req, buf, len+padding) != len+padding) {
- req->keep = 0;
- return 0;
- }
-
- if (!fcgi_get_params(req, buf, buf+len)) {
- req->keep = 0;
- return 0;
- }
-
- q = req->env.list;
- while (q != NULL) {
- if ((value = zend_hash_str_find(&fcgi_mgmt_vars, q->var, q->var_len)) == NULL) {
- q = q->list_next;
- continue;
- }
- zlen = (unsigned int)Z_STRLEN_P(value);
- if ((p + 4 + 4 + q->var_len + zlen) >= (buf + sizeof(buf))) {
- break;
- }
- if (q->var_len < 0x80) {
- *p++ = q->var_len;
- } else {
- *p++ = ((q->var_len >> 24) & 0xff) | 0x80;
- *p++ = (q->var_len >> 16) & 0xff;
- *p++ = (q->var_len >> 8) & 0xff;
- *p++ = q->var_len & 0xff;
- }
- if (zlen < 0x80) {
- *p++ = zlen;
- } else {
- *p++ = ((zlen >> 24) & 0xff) | 0x80;
- *p++ = (zlen >> 16) & 0xff;
- *p++ = (zlen >> 8) & 0xff;
- *p++ = zlen & 0xff;
- }
- memcpy(p, q->var, q->var_len);
- p += q->var_len;
- memcpy(p, Z_STRVAL_P(value), zlen);
- p += zlen;
- q = q->list_next;
- }
- len = p - buf - sizeof(fcgi_header);
- len += fcgi_make_header((fcgi_header*)buf, FCGI_GET_VALUES_RESULT, 0, len);
- if (safe_write(req, buf, sizeof(fcgi_header)+len) != (int)sizeof(fcgi_header)+len) {
- req->keep = 0;
- return 0;
- }
- return 0;
- } else {
- return 0;
- }
-
- return 1;
-}
-
-int fcgi_read(fcgi_request *req, char *str, int len)
-{
- int ret, n, rest;
- fcgi_header hdr;
- unsigned char buf[255];
-
- n = 0;
- rest = len;
- while (rest > 0) {
- if (req->in_len == 0) {
- if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
- hdr.version < FCGI_VERSION_1 ||
- hdr.type != FCGI_STDIN) {
- req->keep = 0;
- return 0;
- }
- req->in_len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
- req->in_pad = hdr.paddingLength;
- if (req->in_len == 0) {
- return n;
- }
- }
-
- if (req->in_len >= rest) {
- ret = safe_read(req, str, rest);
- } else {
- ret = safe_read(req, str, req->in_len);
- }
- if (ret < 0) {
- req->keep = 0;
- return ret;
- } else if (ret > 0) {
- req->in_len -= ret;
- rest -= ret;
- n += ret;
- str += ret;
- if (req->in_len == 0) {
- if (req->in_pad) {
- if (safe_read(req, buf, req->in_pad) != req->in_pad) {
- req->keep = 0;
- return ret;
- }
- }
- } else {
- return n;
- }
- } else {
- return n;
- }
- }
- return n;
-}
-
-void fcgi_close(fcgi_request *req, int force, int destroy)
-{
- if (destroy && req->has_env) {
- fcgi_hash_clean(&req->env);
- req->has_env = 0;
- }
-
-#ifdef _WIN32
- if (is_impersonate && !req->tcp) {
- RevertToSelf();
- }
-#endif
-
- if ((force || !req->keep) && req->fd >= 0) {
-#ifdef _WIN32
- if (!req->tcp) {
- HANDLE pipe = (HANDLE)_get_osfhandle(req->fd);
-
- 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);
- }
-#else
- if (!force) {
- char buf[8];
-
- shutdown(req->fd, 1);
- while (recv(req->fd, buf, sizeof(buf), 0) > 0) {}
- }
- close(req->fd);
-#endif
-#ifdef TCP_NODELAY
- req->nodelay = 0;
-#endif
- req->fd = -1;
- fpm_request_finished();
- }
-}
-
-int fcgi_is_closed(fcgi_request *req)
-{
- return (req->fd < 0);
-}
-
-static int fcgi_is_allowed() {
- int i;
-
- if (client_sa.sa.sa_family == AF_UNIX) {
- return 1;
- }
- if (!allowed_clients) {
- return 1;
- }
- if (client_sa.sa.sa_family == AF_INET) {
- for (i=0 ; allowed_clients[i].sa.sa_family ; i++) {
- if (allowed_clients[i].sa.sa_family == AF_INET
- && !memcmp(&client_sa.sa_inet.sin_addr, &allowed_clients[i].sa_inet.sin_addr, 4)) {
- return 1;
- }
- }
- }
- if (client_sa.sa.sa_family == AF_INET6) {
- for (i=0 ; allowed_clients[i].sa.sa_family ; i++) {
- if (allowed_clients[i].sa.sa_family == AF_INET6
- && !memcmp(&client_sa.sa_inet6.sin6_addr, &allowed_clients[i].sa_inet6.sin6_addr, 12)) {
- return 1;
- }
-#ifdef IN6_IS_ADDR_V4MAPPED
- if (allowed_clients[i].sa.sa_family == AF_INET
- && IN6_IS_ADDR_V4MAPPED(&client_sa.sa_inet6.sin6_addr)
- && !memcmp(((char *)&client_sa.sa_inet6.sin6_addr)+12, &allowed_clients[i].sa_inet.sin_addr, 4)) {
- return 1;
- }
-#endif
- }
- }
-
- zlog(ZLOG_ERROR, "Connection disallowed: IP address '%s' has been dropped.", fcgi_get_last_client_ip());
- return 0;
-}
-
-int fcgi_accept_request(fcgi_request *req)
-{
-#ifdef _WIN32
- HANDLE pipe;
- OVERLAPPED ov;
-#endif
-
- while (1) {
- if (req->fd < 0) {
- while (1) {
- if (in_shutdown) {
- return -1;
- }
-#ifdef _WIN32
- 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) {
- }
- }
- 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);
-
- fpm_request_accepting();
-
- FCGI_LOCK(req->listen_socket);
- req->fd = accept(listen_socket, (struct sockaddr *)&sa, &len);
- FCGI_UNLOCK(req->listen_socket);
-
- client_sa = sa;
- if (req->fd >= 0 && !fcgi_is_allowed()) {
- closesocket(req->fd);
- req->fd = -1;
- continue;
- }
- }
-
-#ifdef _WIN32
- if (req->fd < 0 && (in_shutdown || errno != EINTR)) {
-#else
- if (req->fd < 0 && (in_shutdown || (errno != EINTR && errno != ECONNABORTED))) {
-#endif
- return -1;
- }
-
-#ifdef _WIN32
- break;
-#else
- if (req->fd >= 0) {
-#if defined(HAVE_SYS_POLL_H) && defined(HAVE_POLL)
- struct pollfd fds;
- int ret;
-
- fpm_request_reading_headers();
-
- fds.fd = req->fd;
- fds.events = POLLIN;
- fds.revents = 0;
- do {
- errno = 0;
- ret = poll(&fds, 1, 5000);
- } while (ret < 0 && errno == EINTR);
- if (ret > 0 && (fds.revents & POLLIN)) {
- break;
- }
- fcgi_close(req, 1, 0);
-#else
- fpm_request_reading_headers();
-
- if (req->fd < FD_SETSIZE) {
- struct timeval tv = {5,0};
- fd_set set;
- int ret;
-
- FD_ZERO(&set);
- FD_SET(req->fd, &set);
- do {
- errno = 0;
- ret = select(req->fd + 1, &set, NULL, NULL, &tv) >= 0;
- } while (ret < 0 && errno == EINTR);
- if (ret > 0 && FD_ISSET(req->fd, &set)) {
- break;
- }
- fcgi_close(req, 1, 0);
- } else {
- zlog(ZLOG_ERROR, "Too many open file descriptors. FD_SETSIZE limit exceeded.");
- fcgi_close(req, 1, 0);
- }
-#endif
- }
-#endif
- }
- } else if (in_shutdown) {
- return -1;
- }
- if (fcgi_read_request(req)) {
-#ifdef _WIN32
- if (is_impersonate && !req->tcp) {
- pipe = (HANDLE)_get_osfhandle(req->fd);
- if (!ImpersonateNamedPipeClient(pipe)) {
- fcgi_close(req, 1, 1);
- continue;
- }
- }
-#endif
- return req->fd;
- } else {
- fcgi_close(req, 1, 1);
- }
- }
-}
-
-static inline fcgi_header* open_packet(fcgi_request *req, fcgi_request_type type)
-{
- req->out_hdr = (fcgi_header*) req->out_pos;
- req->out_hdr->type = type;
- req->out_pos += sizeof(fcgi_header);
- return req->out_hdr;
-}
-
-static inline void close_packet(fcgi_request *req)
-{
- if (req->out_hdr) {
- int len = req->out_pos - ((unsigned char*)req->out_hdr + sizeof(fcgi_header));
-
- req->out_pos += fcgi_make_header(req->out_hdr, (fcgi_request_type)req->out_hdr->type, req->id, len);
- req->out_hdr = NULL;
- }
-}
-
-int fcgi_flush(fcgi_request *req, int close)
-{
- int len;
-
- close_packet(req);
-
- len = req->out_pos - req->out_buf;
-
- if (close) {
- fcgi_end_request_rec *rec = (fcgi_end_request_rec*)(req->out_pos);
-
- fcgi_make_header(&rec->hdr, FCGI_END_REQUEST, req->id, sizeof(fcgi_end_request));
- rec->body.appStatusB3 = 0;
- rec->body.appStatusB2 = 0;
- rec->body.appStatusB1 = 0;
- rec->body.appStatusB0 = 0;
- rec->body.protocolStatus = FCGI_REQUEST_COMPLETE;
- len += sizeof(fcgi_end_request_rec);
- }
-
- if (safe_write(req, req->out_buf, len) != len) {
- req->keep = 0;
- req->out_pos = req->out_buf;
- return 0;
- }
-
- req->out_pos = req->out_buf;
- return 1;
-}
-
-ssize_t fcgi_write(fcgi_request *req, fcgi_request_type type, const char *str, int len)
-{
- int limit, rest;
-
- if (len <= 0) {
- return 0;
- }
-
- if (req->out_hdr && req->out_hdr->type != type) {
- close_packet(req);
- }
-
- /* Optimized version */
- limit = sizeof(req->out_buf) - (req->out_pos - req->out_buf);
- if (!req->out_hdr) {
- limit -= sizeof(fcgi_header);
- if (limit < 0) limit = 0;
- }
-
- if (len < limit) {
- if (!req->out_hdr) {
- open_packet(req, type);
- }
- memcpy(req->out_pos, str, len);
- req->out_pos += len;
- } else if (len - limit < sizeof(req->out_buf) - sizeof(fcgi_header)) {
- if (!req->out_hdr) {
- open_packet(req, type);
- }
- if (limit > 0) {
- memcpy(req->out_pos, str, limit);
- req->out_pos += limit;
- }
- if (!fcgi_flush(req, 0)) {
- return -1;
- }
- if (len > limit) {
- open_packet(req, type);
- memcpy(req->out_pos, str + limit, len - limit);
- req->out_pos += len - limit;
- }
- } else {
- int pos = 0;
- int pad;
-
- close_packet(req);
- while ((len - pos) > 0xffff) {
- open_packet(req, type);
- fcgi_make_header(req->out_hdr, type, req->id, 0xfff8);
- req->out_hdr = NULL;
- if (!fcgi_flush(req, 0)) {
- return -1;
- }
- if (safe_write(req, str + pos, 0xfff8) != 0xfff8) {
- req->keep = 0;
- return -1;
- }
- pos += 0xfff8;
- }
-
- pad = (((len - pos) + 7) & ~7) - (len - pos);
- rest = pad ? 8 - pad : 0;
-
- open_packet(req, type);
- fcgi_make_header(req->out_hdr, type, req->id, (len - pos) - rest);
- req->out_hdr = NULL;
- if (!fcgi_flush(req, 0)) {
- return -1;
- }
- if (safe_write(req, str + pos, (len - pos) - rest) != (len - pos) - rest) {
- req->keep = 0;
- return -1;
- }
- if (pad) {
- open_packet(req, type);
- memcpy(req->out_pos, str + len - rest, rest);
- req->out_pos += rest;
- }
- }
-
- return len;
-}
-
-int fcgi_finish_request(fcgi_request *req, int force_close)
-{
- int ret = 1;
-
- if (req->fd >= 0) {
- if (!req->closed) {
- ret = fcgi_flush(req, 1);
- req->closed = 1;
- }
- fcgi_close(req, force_close, 1);
- }
- return ret;
-}
-
-char* fcgi_getenv(fcgi_request *req, const char* var, int var_len)
-{
- unsigned int val_len;
-
- if (!req) return NULL;
-
- return fcgi_hash_get(&req->env, FCGI_HASH_FUNC(var, var_len), (char*)var, var_len, &val_len);
-}
-
-char* fcgi_quick_getenv(fcgi_request *req, const char* var, int var_len, unsigned int hash_value)
-{
- unsigned int val_len;
-
- return fcgi_hash_get(&req->env, hash_value, (char*)var, var_len, &val_len);
-}
-
-char* fcgi_putenv(fcgi_request *req, char* var, int var_len, char* val)
-{
- if (!req) return NULL;
- if (val == NULL) {
- fcgi_hash_del(&req->env, FCGI_HASH_FUNC(var, var_len), var, var_len);
- return NULL;
- } else {
- return fcgi_hash_set(&req->env, FCGI_HASH_FUNC(var, var_len), var, var_len, val, (unsigned int)strlen(val));
- }
-}
-
-char* fcgi_quick_putenv(fcgi_request *req, char* var, int var_len, unsigned int hash_value, char* val)
-{
- if (val == NULL) {
- fcgi_hash_del(&req->env, hash_value, var, var_len);
- return NULL;
- } else {
- return fcgi_hash_set(&req->env, hash_value, var, var_len, val, (unsigned int)strlen(val));
- }
-}
-
-void fcgi_loadenv(fcgi_request *req, fcgi_apply_func func, zval *array)
-{
- fcgi_hash_apply(&req->env, func, array);
-}
-
-void fcgi_set_mgmt_var(const char * name, size_t name_len, const char * value, size_t value_len)
-{
- zval zvalue;
- ZVAL_NEW_STR(&zvalue, zend_string_init(value, value_len, 1));
- zend_hash_str_add(&fcgi_mgmt_vars, name, name_len, &zvalue);
-}
-
-void fcgi_free_mgmt_var_cb(zval *zv)
-{
- zend_string_free(Z_STR_P(zv));
-}
-
-const char *fcgi_get_last_client_ip() /* {{{ */
-{
- static char str[INET6_ADDRSTRLEN];
-
- /* Ipv4 */
- if (client_sa.sa.sa_family == AF_INET) {
- return inet_ntop(client_sa.sa.sa_family, &client_sa.sa_inet.sin_addr, str, INET6_ADDRSTRLEN);
- }
-#ifdef IN6_IS_ADDR_V4MAPPED
- /* Ipv4-Mapped-Ipv6 */
- if (client_sa.sa.sa_family == AF_INET6
- && IN6_IS_ADDR_V4MAPPED(&client_sa.sa_inet6.sin6_addr)) {
- return inet_ntop(AF_INET, ((char *)&client_sa.sa_inet6.sin6_addr)+12, str, INET6_ADDRSTRLEN);
- }
-#endif
- /* Ipv6 */
- if (client_sa.sa.sa_family == AF_INET6) {
- return inet_ntop(client_sa.sa.sa_family, &client_sa.sa_inet6.sin6_addr, str, INET6_ADDRSTRLEN);
- }
- /* Unix socket */
- return NULL;
-}
-/* }}} */
-/*
- * Local variables:
- * tab-width: 4
- * c-basic-offset: 4
- * End:
- * vim600: sw=4 ts=4 fdm=marker
- * vim<600: sw=4 ts=4
- */
diff --git a/sapi/fpm/fpm/fastcgi.h b/sapi/fpm/fpm/fastcgi.h
deleted file mode 100644
index 31419dfdd0..0000000000
--- a/sapi/fpm/fpm/fastcgi.h
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- +----------------------------------------------------------------------+
- | PHP Version 7 |
- +----------------------------------------------------------------------+
- | Copyright (c) 1997-2015 The PHP Group |
- +----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Authors: Dmitry Stogov <dmitry@zend.com> |
- +----------------------------------------------------------------------+
-*/
-
-/* $Id: fastcgi.h 272370 2008-12-31 11:15:49Z sebastian $ */
-
-/* FastCGI protocol */
-
-#define FCGI_VERSION_1 1
-
-#define FCGI_MAX_LENGTH 0xffff
-
-#define FCGI_KEEP_CONN 1
-
-/* this is near the perfect hash function for most useful FastCGI variables
- * which combines efficiency and minimal hash collisions
- */
-
-#define FCGI_HASH_FUNC(var, var_len) \
- (UNEXPECTED(var_len < 3) ? var_len : \
- (((unsigned int)var[3]) << 2) + \
- (((unsigned int)var[var_len-2]) << 4) + \
- (((unsigned int)var[var_len-1]) << 2) + \
- var_len)
-
-#define FCGI_GETENV(request, name) \
- fcgi_quick_getenv(request, name, sizeof(name)-1, FCGI_HASH_FUNC(name, sizeof(name)-1))
-
-#define FCGI_PUTENV(request, name, value) \
- fcgi_quick_putenv(request, name, sizeof(name)-1, FCGI_HASH_FUNC(name, sizeof(name)-1), value)
-
-typedef enum _fcgi_role {
- FCGI_RESPONDER = 1,
- FCGI_AUTHORIZER = 2,
- FCGI_FILTER = 3
-} fcgi_role;
-
-typedef enum _fcgi_request_type {
- FCGI_BEGIN_REQUEST = 1, /* [in] */
- FCGI_ABORT_REQUEST = 2, /* [in] (not supported) */
- FCGI_END_REQUEST = 3, /* [out] */
- FCGI_PARAMS = 4, /* [in] environment variables */
- FCGI_STDIN = 5, /* [in] post data */
- FCGI_STDOUT = 6, /* [out] response */
- FCGI_STDERR = 7, /* [out] errors */
- FCGI_DATA = 8, /* [in] filter data (not supported) */
- FCGI_GET_VALUES = 9, /* [in] */
- FCGI_GET_VALUES_RESULT = 10 /* [out] */
-} fcgi_request_type;
-
-typedef enum _fcgi_protocol_status {
- FCGI_REQUEST_COMPLETE = 0,
- FCGI_CANT_MPX_CONN = 1,
- FCGI_OVERLOADED = 2,
- FCGI_UNKNOWN_ROLE = 3
-} dcgi_protocol_status;
-
-typedef struct _fcgi_header {
- unsigned char version;
- unsigned char type;
- unsigned char requestIdB1;
- unsigned char requestIdB0;
- unsigned char contentLengthB1;
- unsigned char contentLengthB0;
- unsigned char paddingLength;
- unsigned char reserved;
-} fcgi_header;
-
-typedef struct _fcgi_begin_request {
- unsigned char roleB1;
- unsigned char roleB0;
- unsigned char flags;
- unsigned char reserved[5];
-} fcgi_begin_request;
-
-typedef struct _fcgi_begin_request_rec {
- fcgi_header hdr;
- fcgi_begin_request body;
-} fcgi_begin_request_rec;
-
-typedef struct _fcgi_end_request {
- unsigned char appStatusB3;
- unsigned char appStatusB2;
- unsigned char appStatusB1;
- unsigned char appStatusB0;
- unsigned char protocolStatus;
- unsigned char reserved[3];
-} fcgi_end_request;
-
-typedef struct _fcgi_end_request_rec {
- fcgi_header hdr;
- fcgi_end_request body;
-} fcgi_end_request_rec;
-
-/* FastCGI client API */
-
-typedef void (*fcgi_apply_func)(char *var, unsigned int var_len, char *val, unsigned int val_len, void *arg);
-
-typedef struct _fcgi_request fcgi_request;
-
-int fcgi_init(void);
-void fcgi_shutdown(void);
-int fcgi_in_shutdown(void);
-void fcgi_terminate(void);
-fcgi_request* fcgi_init_request(int listen_socket);
-void fcgi_destroy_request(fcgi_request *req);
-int fcgi_accept_request(fcgi_request *req);
-int fcgi_finish_request(fcgi_request *req, int force_close);
-
-void fcgi_set_allowed_clients(char *);
-void fcgi_close(fcgi_request *req, int force, int destroy);
-int fcgi_is_closed(fcgi_request *req);
-
-char* fcgi_getenv(fcgi_request *req, const char* var, int var_len);
-char* fcgi_putenv(fcgi_request *req, char* var, int var_len, char* val);
-char* fcgi_quick_getenv(fcgi_request *req, const char* var, int var_len, unsigned int hash_value);
-char* fcgi_quick_putenv(fcgi_request *req, char* var, int var_len, unsigned int hash_value, char* val);
-void fcgi_loadenv(fcgi_request *req, fcgi_apply_func load_func, zval *array);
-
-int fcgi_read(fcgi_request *req, char *str, int len);
-
-ssize_t fcgi_write(fcgi_request *req, fcgi_request_type type, const char *str, int len);
-int fcgi_flush(fcgi_request *req, int close);
-
-void fcgi_set_mgmt_var(const char * name, size_t name_len, const char * value, size_t value_len);
-void fcgi_free_mgmt_var_cb(zval *ptr);
-
-const char *fcgi_get_last_client_ip();
-
-/*
- * Local variables:
- * tab-width: 4
- * c-basic-offset: 4
- * End:
- * vim600: sw=4 ts=4 fdm=marker
- * vim<600: sw=4 ts=4
- */
diff --git a/sapi/fpm/fpm/fpm_main.c b/sapi/fpm/fpm/fpm_main.c
index efd1f7155a..d861c3beee 100644
--- a/sapi/fpm/fpm/fpm_main.c
+++ b/sapi/fpm/fpm/fpm_main.c
@@ -219,14 +219,15 @@ static php_cgi_globals_struct php_cgi_globals;
#define TRANSLATE_SLASHES(path)
#endif
-static int print_module_info(zval *zv)
+static int print_module_info(zval *zv) /* {{{ */
{
zend_module_entry *module = Z_PTR_P(zv);
php_printf("%s\n", module->name);
return 0;
}
+/* }}} */
-static int module_name_cmp(const void *a, const void *b)
+static int module_name_cmp(const void *a, const void *b) /* {{{ */
{
Bucket *f = (Bucket *) a;
Bucket *s = (Bucket *) b;
@@ -234,8 +235,9 @@ static int module_name_cmp(const void *a, const void *b)
return strcasecmp( ((zend_module_entry *) Z_PTR(f->val))->name,
((zend_module_entry *) Z_PTR(s->val))->name);
}
+/* }}} */
-static void print_modules(void)
+static void print_modules(void) /* {{{ */
{
HashTable sorted_registry;
@@ -245,20 +247,23 @@ static void print_modules(void)
zend_hash_apply(&sorted_registry, print_module_info);
zend_hash_destroy(&sorted_registry);
}
+/* }}} */
-static int print_extension_info(zend_extension *ext, void *arg)
+static int print_extension_info(zend_extension *ext, void *arg) /* {{{ */
{
php_printf("%s\n", ext->name);
return 0;
}
+/* }}} */
-static int extension_name_cmp(const zend_llist_element **f, const zend_llist_element **s)
+static int extension_name_cmp(const zend_llist_element **f, const zend_llist_element **s) /* {{{ */
{
return strcmp( ((zend_extension *)(*f)->data)->name,
((zend_extension *)(*s)->data)->name);
}
+/* }}} */
-static void print_extensions(void)
+static void print_extensions(void) /* {{{ */
{
zend_llist sorted_exts;
@@ -268,12 +273,13 @@ static void print_extensions(void)
zend_llist_apply_with_argument(&sorted_exts, (llist_apply_with_arg_func_t) print_extension_info, NULL);
zend_llist_destroy(&sorted_exts);
}
+/* }}} */
#ifndef STDOUT_FILENO
#define STDOUT_FILENO 1
#endif
-static inline size_t sapi_cgibin_single_write(const char *str, uint str_length)
+static inline size_t sapi_cgibin_single_write(const char *str, uint str_length) /* {{{ */
{
ssize_t ret;
@@ -298,8 +304,9 @@ static inline size_t sapi_cgibin_single_write(const char *str, uint str_length)
return fwrite(str, 1, MIN(str_length, 16384), stdout);
#endif
}
+/* }}} */
-static size_t sapi_cgibin_ub_write(const char *str, size_t str_length)
+static size_t sapi_cgibin_ub_write(const char *str, size_t str_length) /* {{{ */
{
const char *ptr = str;
uint remaining = str_length;
@@ -317,9 +324,9 @@ static size_t sapi_cgibin_ub_write(const char *str, size_t str_length)
return str_length;
}
+/* }}} */
-
-static void sapi_cgibin_flush(void *server_context)
+static void sapi_cgibin_flush(void *server_context) /* {{{ */
{
/* fpm has started, let use fcgi instead of stdout */
if (fpm_is_running) {
@@ -339,10 +346,11 @@ static void sapi_cgibin_flush(void *server_context)
php_handle_aborted_connection();
}
}
+/* }}} */
#define SAPI_CGI_MAX_HEADER_LENGTH 1024
-static int sapi_cgi_send_headers(sapi_headers_struct *sapi_headers)
+static int sapi_cgi_send_headers(sapi_headers_struct *sapi_headers) /* {{{ */
{
char buf[SAPI_CGI_MAX_HEADER_LENGTH];
sapi_header_struct *h;
@@ -443,12 +451,22 @@ static int sapi_cgi_send_headers(sapi_headers_struct *sapi_headers)
return SAPI_HEADER_SENT_SUCCESSFULLY;
}
+/* }}} */
#ifndef STDIN_FILENO
# define STDIN_FILENO 0
#endif
-static size_t sapi_cgi_read_post(char *buffer, size_t count_bytes)
+static void fpm_fcgi_log(int type, const char *fmt, ...) /* {{{ */
+{
+ va_list args;
+ va_start(args, fmt);
+ vzlog("", 0, type, fmt, args);
+ va_end(args);
+}
+/* }}} */
+
+static size_t sapi_cgi_read_post(char *buffer, size_t count_bytes) /* {{{ */
{
uint read_bytes = 0;
int tmp_read_bytes;
@@ -486,8 +504,9 @@ static size_t sapi_cgi_read_post(char *buffer, size_t count_bytes)
}
return read_bytes;
}
+/* }}} */
-static char *sapi_cgibin_getenv(char *name, size_t name_len)
+static char *sapi_cgibin_getenv(char *name, size_t name_len) /* {{{ */
{
/* if fpm has started, use fcgi env */
if (fpm_is_running) {
@@ -498,8 +517,9 @@ static char *sapi_cgibin_getenv(char *name, size_t name_len)
/* if fpm has not started yet, use std env */
return getenv(name);
}
+/* }}} */
-static char *_sapi_cgibin_putenv(char *name, char *value)
+static char *_sapi_cgibin_putenv(char *name, char *value) /* {{{ */
{
int name_len;
@@ -511,15 +531,17 @@ static char *_sapi_cgibin_putenv(char *name, char *value)
fcgi_request *request = (fcgi_request*) SG(server_context);
return fcgi_putenv(request, name, name_len, value);
}
+/* }}} */
-static char *sapi_cgi_read_cookies(void)
+static char *sapi_cgi_read_cookies(void) /* {{{ */
{
fcgi_request *request = (fcgi_request*) SG(server_context);
return FCGI_GETENV(request, "HTTP_COOKIE");
}
+/* }}} */
-static void cgi_php_load_env_var(char *var, unsigned int var_len, char *val, unsigned int val_len, void *arg)
+static void cgi_php_load_env_var(char *var, unsigned int var_len, char *val, unsigned int val_len, void *arg) /* {{{ */
{
zval *array_ptr = (zval*)arg;
int filter_arg = (Z_ARR_P(array_ptr) == Z_ARR(PG(http_globals)[TRACK_VARS_ENV]))?PARSE_ENV:PARSE_SERVER;
@@ -529,13 +551,11 @@ static void cgi_php_load_env_var(char *var, unsigned int var_len, char *val, uns
php_register_variable_safe(var, val, new_val_len, array_ptr);
}
}
+/* }}} */
-void cgi_php_import_environment_variables(zval *array_ptr)
+void cgi_php_import_environment_variables(zval *array_ptr) /* {{{ */
{
fcgi_request *request;
- zend_string *var;
- char *val;
- int filter_arg;
if (Z_TYPE(PG(http_globals)[TRACK_VARS_ENV]) == IS_ARRAY &&
Z_ARR_P(array_ptr) != Z_ARR(PG(http_globals)[TRACK_VARS_ENV]) &&
@@ -559,8 +579,9 @@ void cgi_php_import_environment_variables(zval *array_ptr)
request = (fcgi_request*) SG(server_context);
fcgi_loadenv(request, cgi_php_load_env_var, array_ptr);
}
+/* }}} */
-static void sapi_cgi_register_variables(zval *track_vars_array)
+static void sapi_cgi_register_variables(zval *track_vars_array) /* {{{ */
{
fcgi_request *request = (fcgi_request*) SG(server_context);
size_t php_self_len;
@@ -601,6 +622,7 @@ static void sapi_cgi_register_variables(zval *track_vars_array)
}
}
}
+/* }}} */
/* {{{ sapi_cgi_log_fastcgi
*
@@ -713,7 +735,7 @@ static void php_cgi_ini_activate_user_config(char *path, int path_len, const cha
}
/* }}} */
-static int sapi_cgi_activate(void)
+static int sapi_cgi_activate(void) /* {{{ */
{
fcgi_request *request = (fcgi_request*) SG(server_context);
char *path, *doc_root, *server_name;
@@ -784,8 +806,9 @@ static int sapi_cgi_activate(void)
return SUCCESS;
}
+/* }}} */
-static int sapi_cgi_deactivate(void)
+static int sapi_cgi_deactivate(void) /* {{{ */
{
/* flush only when SAPI was started. The reasons are:
1. SAPI Deactivate is called from two places: module init and request shutdown
@@ -802,14 +825,16 @@ static int sapi_cgi_deactivate(void)
}
return SUCCESS;
}
+/* }}} */
-static int php_cgi_startup(sapi_module_struct *sapi_module)
+static int php_cgi_startup(sapi_module_struct *sapi_module) /* {{{ */
{
if (php_module_startup(sapi_module, &cgi_module_entry, 1) == FAILURE) {
return FAILURE;
}
return SUCCESS;
}
+/* }}} */
/* {{{ sapi_module_struct cgi_sapi_module
*/
@@ -1360,6 +1385,14 @@ static void init_request_info(void)
}
/* }}} */
+static void fpm_init_request(fcgi_request *req, int listen_fd) /* {{{ */ {
+ fcgi_init_request(req, listen_fd);
+ req->hook.on_accept = fpm_request_accepting;
+ req->hook.on_read = fpm_request_reading_headers;
+ req->hook.on_close = fpm_request_finished;
+}
+/* }}} */
+
static void fastcgi_ini_parser(zval *arg1, zval *arg2, zval *arg3, int callback_type, void *arg) /* {{{ */
{
int *mode = (int *)arg;
@@ -1523,7 +1556,7 @@ int main(int argc, char *argv[])
int max_requests = 500;
int requests = 0;
int fcgi_fd = 0;
- fcgi_request *request;
+ fcgi_request request;
char *fpm_config = NULL;
char *fpm_prefix = NULL;
char *fpm_pid = NULL;
@@ -1553,6 +1586,7 @@ int main(int argc, char *argv[])
cgi_sapi_module.php_ini_path_override = NULL;
cgi_sapi_module.php_ini_ignore_cwd = 1;
+ fcgi_set_logger(fpm_fcgi_log);
fcgi_init();
#ifdef PHP_WIN32
@@ -1819,12 +1853,12 @@ consult the installation file that came with this distribution, or visit \n\
php_import_environment_variables = cgi_php_import_environment_variables;
/* library is already initialized, now init our request */
- request = fcgi_init_request(fcgi_fd);
+ fpm_init_request(&request, fcgi_fd);
zend_first_try {
- while (fcgi_accept_request(request) >= 0) {
+ while (fcgi_accept_request(&request) >= 0) {
request_body_fd = -1;
- SG(server_context) = (void *) request;
+ SG(server_context) = (void *) &request;
init_request_info();
char *primary_script = NULL;
@@ -1833,7 +1867,7 @@ consult the installation file that came with this distribution, or visit \n\
/* request startup only after we've done all we can to
* get path_translated */
if (php_request_startup() == FAILURE) {
- fcgi_finish_request(request, 1);
+ fcgi_finish_request(&request, 1);
SG(server_context) = NULL;
php_module_shutdown();
return FPM_EXIT_SOFTWARE;
@@ -1926,12 +1960,11 @@ fastcgi_request_done:
requests++;
if (max_requests && (requests == max_requests)) {
- fcgi_finish_request(request, 1);
+ fcgi_finish_request(&request, 1);
break;
}
/* end of fastcgi loop */
}
- fcgi_destroy_request(request);
fcgi_shutdown();
if (cgi_sapi_module.php_ini_path_override) {
diff --git a/sapi/fpm/fpm/zlog.c b/sapi/fpm/fpm/zlog.c
index 6f17b99133..66b7fd2510 100644
--- a/sapi/fpm/fpm/zlog.c
+++ b/sapi/fpm/fpm/zlog.c
@@ -98,20 +98,17 @@ int zlog_set_level(int new_value) /* {{{ */
}
/* }}} */
-void zlog_ex(const char *function, int line, int flags, const char *fmt, ...) /* {{{ */
+void vzlog(const char *function, int line, int flags, const char *fmt, va_list args) /* {{{ */
{
struct timeval tv;
char buf[MAX_LINE_LENGTH];
const size_t buf_size = MAX_LINE_LENGTH;
- va_list args;
size_t len = 0;
int truncated = 0;
int saved_errno;
if (external_logger) {
- va_start(args, fmt);
len = vsnprintf(buf, buf_size, fmt, args);
- va_end(args);
if (len >= buf_size) {
memcpy(buf + buf_size - sizeof("..."), "...", sizeof("...") - 1);
len = buf_size - 1;
@@ -157,9 +154,7 @@ void zlog_ex(const char *function, int line, int flags, const char *fmt, ...) /*
}
if (!truncated) {
- va_start(args, fmt);
len += vsnprintf(buf + len, buf_size - len, fmt, args);
- va_end(args);
if (len >= buf_size) {
truncated = 1;
}
@@ -197,3 +192,10 @@ void zlog_ex(const char *function, int line, int flags, const char *fmt, ...) /*
}
/* }}} */
+void zlog_ex(const char *function, int line, int flags, const char *fmt, ...) /* {{{ */ {
+ va_list args;
+ va_start(args, fmt);
+ vzlog(function, line, flags, fmt, args);
+ va_end(args);
+}
+/* }}} */
diff --git a/sapi/fpm/fpm/zlog.h b/sapi/fpm/fpm/zlog.h
index 1945922da5..c2bf752b93 100644
--- a/sapi/fpm/fpm/zlog.h
+++ b/sapi/fpm/fpm/zlog.h
@@ -5,6 +5,8 @@
#ifndef ZLOG_H
#define ZLOG_H 1
+#include <stdarg.h>
+
#define zlog(flags,...) zlog_ex(__func__, __LINE__, flags, __VA_ARGS__)
struct timeval;
@@ -17,6 +19,7 @@ void zlog_set_launched(void);
size_t zlog_print_time(struct timeval *tv, char *timebuf, size_t timebuf_len);
+void vzlog(const char *function, int line, int flags, const char *fmt, va_list args);
void zlog_ex(const char *function, int line, int flags, const char *fmt, ...)
__attribute__ ((format(printf,4,5)));
@@ -24,6 +27,7 @@ void zlog_ex(const char *function, int line, int flags, const char *fmt, ...)
extern const int syslog_priorities[];
#endif
+/* keep this same as FCGI_ERROR */
enum {
ZLOG_DEBUG = 1,
ZLOG_NOTICE = 2,