diff options
author | Xinchen Hui <laruence@gmail.com> | 2015-05-23 10:31:50 +0800 |
---|---|---|
committer | Xinchen Hui <laruence@gmail.com> | 2015-05-23 19:01:41 +0800 |
commit | 18cf4e0a8a574034f60f4d123407c173e57e54ec (patch) | |
tree | 08392346acfd0bc45d1a4449bcee0ebd44f101a3 | |
parent | fef18f4bea1980a59a9283c2197bd090aaf500cb (diff) | |
download | php-git-18cf4e0a8a574034f60f4d123407c173e57e54ec.tar.gz |
Fixed fpm-side (tests passes)
-rw-r--r-- | main/fastcgi.c | 307 | ||||
-rw-r--r-- | main/fastcgi.h | 92 | ||||
-rw-r--r-- | sapi/cgi/cgi_main.c | 184 | ||||
-rw-r--r-- | sapi/fpm/config.m4 | 3 | ||||
-rw-r--r-- | sapi/fpm/fpm/fastcgi.c | 1340 | ||||
-rw-r--r-- | sapi/fpm/fpm/fastcgi.h | 151 | ||||
-rw-r--r-- | sapi/fpm/fpm/fpm_main.c | 95 | ||||
-rw-r--r-- | sapi/fpm/fpm/zlog.c | 14 | ||||
-rw-r--r-- | sapi/fpm/fpm/zlog.h | 4 |
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, |