diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2021-02-04 15:18:45 +0100 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2021-02-04 15:22:34 +0100 |
commit | 5cb25a2d32df8073df7c191dd6c7694b4495af62 (patch) | |
tree | 5adba558b35e119da1761b9a5c9eaac88243bfe5 /sapi | |
parent | 767ddb1cd53ffc5fe4f6ca2e3072be68586f38d2 (diff) | |
download | php-git-5cb25a2d32df8073df7c191dd6c7694b4495af62.tar.gz |
Fix CLI server worker support
If we create separate listening sockets in each worker using
SO_REUSEADDR, then an incoming connection may be load-balanced
to a process that is already busy, either due to a long-running
request, or because it is a recursive request (in which case we
would deadlock).
Instead, only create one listening socket, and only create worker
forks afterwards. This way the incoming request will be served
by one of the workers that is currently listening for an incoming
connection.
Diffstat (limited to 'sapi')
-rw-r--r-- | sapi/cli/php_cli_server.c | 106 |
1 files changed, 47 insertions, 59 deletions
diff --git a/sapi/cli/php_cli_server.c b/sapi/cli/php_cli_server.c index a32b51e3d3..4fe975d6a4 100644 --- a/sapi/cli/php_cli_server.c +++ b/sapi/cli/php_cli_server.c @@ -498,58 +498,7 @@ const zend_function_entry server_additional_functions[] = { static int sapi_cli_server_startup(sapi_module_struct *sapi_module) /* {{{ */ { - char *workers; - - if (php_module_startup(sapi_module, &cli_server_module_entry, 1) == FAILURE) { - return FAILURE; - } - - if ((workers = getenv("PHP_CLI_SERVER_WORKERS"))) { -#ifndef SO_REUSEPORT - fprintf(stderr, "platform does not support SO_REUSEPORT, cannot create workers\n"); -#elif HAVE_FORK - ZEND_ATOL(php_cli_server_workers_max, workers); - - if (php_cli_server_workers_max > 1) { - zend_long php_cli_server_worker; - - php_cli_server_workers = calloc( - php_cli_server_workers_max, sizeof(pid_t)); - if (!php_cli_server_workers) { - php_cli_server_workers_max = 1; - - return SUCCESS; - } - - php_cli_server_master = getpid(); - - for (php_cli_server_worker = 0; - php_cli_server_worker < php_cli_server_workers_max; - php_cli_server_worker++) { - pid_t pid = fork(); - - if (pid == FAILURE) { - /* no more forks allowed, work with what we have ... */ - php_cli_server_workers_max = - php_cli_server_worker + 1; - return SUCCESS; - } else if (pid == SUCCESS) { - return SUCCESS; - } else { - php_cli_server_workers[ - php_cli_server_worker - ] = pid; - } - } - } else { - fprintf(stderr, "number of workers must be larger than 1\n"); - } -#else - fprintf(stderr, "forking is not supported on this platform\n"); -#endif - } - - return SUCCESS; + return php_module_startup(sapi_module, &cli_server_module_entry, 1); } /* }}} */ static size_t sapi_cli_server_ub_write(const char *str, size_t str_length) /* {{{ */ @@ -1317,13 +1266,6 @@ static php_socket_t php_network_listen_socket(const char *host, int *port, int s } #endif -#if defined(HAVE_FORK) && defined(SO_REUSEPORT) - if (php_cli_server_workers_max > 1) { - int val = 1; - setsockopt(retval, SOL_SOCKET, SO_REUSEPORT, (char*)&val, sizeof(val)); - } -#endif - if (bind(retval, sa, *socklen) == SOCK_CONN_ERR) { err = php_socket_errno(); if (err == SOCK_EINVAL || err == SOCK_EADDRINUSE) { @@ -2412,6 +2354,50 @@ static char *php_cli_server_parse_addr(const char *addr, int *pport) { return pestrndup(addr, end - addr, 1); } +static void php_cli_server_startup_workers() { + char *workers = getenv("PHP_CLI_SERVER_WORKERS"); + if (!workers) { + return; + } + +#if HAVE_FORK + ZEND_ATOL(php_cli_server_workers_max, workers); + if (php_cli_server_workers_max > 1) { + zend_long php_cli_server_worker; + + php_cli_server_workers = calloc( + php_cli_server_workers_max, sizeof(pid_t)); + if (!php_cli_server_workers) { + php_cli_server_workers_max = 1; + return; + } + + php_cli_server_master = getpid(); + + for (php_cli_server_worker = 0; + php_cli_server_worker < php_cli_server_workers_max; + php_cli_server_worker++) { + pid_t pid = fork(); + + if (pid == FAILURE) { + /* no more forks allowed, work with what we have ... */ + php_cli_server_workers_max = + php_cli_server_worker + 1; + return; + } else if (pid == SUCCESS) { + return; + } else { + php_cli_server_workers[php_cli_server_worker] = pid; + } + } + } else { + fprintf(stderr, "number of workers must be larger than 1\n"); + } +#else + fprintf(stderr, "forking is not supported on this platform\n"); +#endif +} + static int php_cli_server_ctor(php_cli_server *server, const char *addr, const char *document_root, const char *router) /* {{{ */ { int retval = SUCCESS; @@ -2441,6 +2427,8 @@ static int php_cli_server_ctor(php_cli_server *server, const char *addr, const c } server->server_sock = server_sock; + php_cli_server_startup_workers(); + err = php_cli_server_poller_ctor(&server->poller); if (SUCCESS != err) { goto out; |