Skip to content

Commit 5cb25a2

Browse files
committed
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.
1 parent 767ddb1 commit 5cb25a2

File tree

1 file changed

+47
-59
lines changed

1 file changed

+47
-59
lines changed

sapi/cli/php_cli_server.c

Lines changed: 47 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -498,58 +498,7 @@ const zend_function_entry server_additional_functions[] = {
498498

499499
static int sapi_cli_server_startup(sapi_module_struct *sapi_module) /* {{{ */
500500
{
501-
char *workers;
502-
503-
if (php_module_startup(sapi_module, &cli_server_module_entry, 1) == FAILURE) {
504-
return FAILURE;
505-
}
506-
507-
if ((workers = getenv("PHP_CLI_SERVER_WORKERS"))) {
508-
#ifndef SO_REUSEPORT
509-
fprintf(stderr, "platform does not support SO_REUSEPORT, cannot create workers\n");
510-
#elif HAVE_FORK
511-
ZEND_ATOL(php_cli_server_workers_max, workers);
512-
513-
if (php_cli_server_workers_max > 1) {
514-
zend_long php_cli_server_worker;
515-
516-
php_cli_server_workers = calloc(
517-
php_cli_server_workers_max, sizeof(pid_t));
518-
if (!php_cli_server_workers) {
519-
php_cli_server_workers_max = 1;
520-
521-
return SUCCESS;
522-
}
523-
524-
php_cli_server_master = getpid();
525-
526-
for (php_cli_server_worker = 0;
527-
php_cli_server_worker < php_cli_server_workers_max;
528-
php_cli_server_worker++) {
529-
pid_t pid = fork();
530-
531-
if (pid == FAILURE) {
532-
/* no more forks allowed, work with what we have ... */
533-
php_cli_server_workers_max =
534-
php_cli_server_worker + 1;
535-
return SUCCESS;
536-
} else if (pid == SUCCESS) {
537-
return SUCCESS;
538-
} else {
539-
php_cli_server_workers[
540-
php_cli_server_worker
541-
] = pid;
542-
}
543-
}
544-
} else {
545-
fprintf(stderr, "number of workers must be larger than 1\n");
546-
}
547-
#else
548-
fprintf(stderr, "forking is not supported on this platform\n");
549-
#endif
550-
}
551-
552-
return SUCCESS;
501+
return php_module_startup(sapi_module, &cli_server_module_entry, 1);
553502
} /* }}} */
554503

555504
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
13171266
}
13181267
#endif
13191268

1320-
#if defined(HAVE_FORK) && defined(SO_REUSEPORT)
1321-
if (php_cli_server_workers_max > 1) {
1322-
int val = 1;
1323-
setsockopt(retval, SOL_SOCKET, SO_REUSEPORT, (char*)&val, sizeof(val));
1324-
}
1325-
#endif
1326-
13271269
if (bind(retval, sa, *socklen) == SOCK_CONN_ERR) {
13281270
err = php_socket_errno();
13291271
if (err == SOCK_EINVAL || err == SOCK_EADDRINUSE) {
@@ -2412,6 +2354,50 @@ static char *php_cli_server_parse_addr(const char *addr, int *pport) {
24122354
return pestrndup(addr, end - addr, 1);
24132355
}
24142356

2357+
static void php_cli_server_startup_workers() {
2358+
char *workers = getenv("PHP_CLI_SERVER_WORKERS");
2359+
if (!workers) {
2360+
return;
2361+
}
2362+
2363+
#if HAVE_FORK
2364+
ZEND_ATOL(php_cli_server_workers_max, workers);
2365+
if (php_cli_server_workers_max > 1) {
2366+
zend_long php_cli_server_worker;
2367+
2368+
php_cli_server_workers = calloc(
2369+
php_cli_server_workers_max, sizeof(pid_t));
2370+
if (!php_cli_server_workers) {
2371+
php_cli_server_workers_max = 1;
2372+
return;
2373+
}
2374+
2375+
php_cli_server_master = getpid();
2376+
2377+
for (php_cli_server_worker = 0;
2378+
php_cli_server_worker < php_cli_server_workers_max;
2379+
php_cli_server_worker++) {
2380+
pid_t pid = fork();
2381+
2382+
if (pid == FAILURE) {
2383+
/* no more forks allowed, work with what we have ... */
2384+
php_cli_server_workers_max =
2385+
php_cli_server_worker + 1;
2386+
return;
2387+
} else if (pid == SUCCESS) {
2388+
return;
2389+
} else {
2390+
php_cli_server_workers[php_cli_server_worker] = pid;
2391+
}
2392+
}
2393+
} else {
2394+
fprintf(stderr, "number of workers must be larger than 1\n");
2395+
}
2396+
#else
2397+
fprintf(stderr, "forking is not supported on this platform\n");
2398+
#endif
2399+
}
2400+
24152401
static int php_cli_server_ctor(php_cli_server *server, const char *addr, const char *document_root, const char *router) /* {{{ */
24162402
{
24172403
int retval = SUCCESS;
@@ -2441,6 +2427,8 @@ static int php_cli_server_ctor(php_cli_server *server, const char *addr, const c
24412427
}
24422428
server->server_sock = server_sock;
24432429

2430+
php_cli_server_startup_workers();
2431+
24442432
err = php_cli_server_poller_ctor(&server->poller);
24452433
if (SUCCESS != err) {
24462434
goto out;

0 commit comments

Comments
 (0)