Skip to content

Commit 15ba757

Browse files
globinTyrael
authored andcommitted
add IPv6 support to php-fpm
1 parent 2cf9418 commit 15ba757

File tree

4 files changed

+98
-48
lines changed

4 files changed

+98
-48
lines changed

sapi/fpm/fpm/fpm_sockets.c

+43-42
Original file line numberDiff line numberDiff line change
@@ -39,29 +39,6 @@ struct listening_socket_s {
3939

4040
static struct fpm_array_s sockets_list;
4141

42-
static int fpm_sockets_resolve_af_inet(char *node, char *service, struct sockaddr_in *addr) /* {{{ */
43-
{
44-
struct addrinfo *res;
45-
struct addrinfo hints;
46-
int ret;
47-
48-
memset(&hints, 0, sizeof(hints));
49-
hints.ai_family = AF_INET;
50-
ret = getaddrinfo(node, service, &hints, &res);
51-
52-
if (ret != 0) {
53-
zlog(ZLOG_ERROR, "can't resolve hostname '%s%s%s': getaddrinfo said: %s%s%s\n",
54-
node, service ? ":" : "", service ? service : "",
55-
gai_strerror(ret), ret == EAI_SYSTEM ? ", system error: " : "", ret == EAI_SYSTEM ? strerror(errno) : "");
56-
return -1;
57-
}
58-
59-
*addr = *(struct sockaddr_in *) res->ai_addr;
60-
freeaddrinfo(res);
61-
return 0;
62-
}
63-
/* }}} */
64-
6542
enum { FPM_GET_USE_SOCKET = 1, FPM_STORE_SOCKET = 2, FPM_STORE_USE_SOCKET = 3 };
6643

6744
static void fpm_sockets_cleanup(int which, void *arg) /* {{{ */
@@ -98,14 +75,23 @@ static void fpm_sockets_cleanup(int which, void *arg) /* {{{ */
9875
}
9976
/* }}} */
10077

78+
static void *fpm_get_in_addr(struct sockaddr *sa) /* {{{ */
79+
{
80+
if (sa->sa_family == AF_INET) {
81+
return &(((struct sockaddr_in*)sa)->sin_addr);
82+
}
83+
84+
return &(((struct sockaddr_in6*)sa)->sin6_addr);
85+
}
86+
/* }}} */
87+
10188
static int fpm_sockets_hash_op(int sock, struct sockaddr *sa, char *key, int type, int op) /* {{{ */
10289
{
10390
if (key == NULL) {
10491
switch (type) {
10592
case FPM_AF_INET : {
106-
struct sockaddr_in *sa_in = (struct sockaddr_in *) sa;
107-
key = alloca(sizeof("xxx.xxx.xxx.xxx:ppppp"));
108-
sprintf(key, "%u.%u.%u.%u:%u", IPQUAD(&sa_in->sin_addr), (unsigned int) ntohs(sa_in->sin_port));
93+
key = alloca(INET6_ADDRSTRLEN);
94+
inet_ntop(sa->sa_family, fpm_get_in_addr(sa), key, sizeof key);
10995
break;
11096
}
11197

@@ -254,11 +240,14 @@ enum fpm_address_domain fpm_sockets_domain_from_address(char *address) /* {{{ */
254240

255241
static int fpm_socket_af_inet_listening_socket(struct fpm_worker_pool_s *wp) /* {{{ */
256242
{
257-
struct sockaddr_in sa_in;
243+
struct addrinfo hints, *servinfo, *p;
258244
char *dup_address = strdup(wp->config->listen_address);
259-
char *port_str = strchr(dup_address, ':');
245+
char *port_str = strrchr(dup_address, ':');
260246
char *addr = NULL;
247+
int addr_len;
261248
int port = 0;
249+
int sock;
250+
int status;
262251

263252
if (port_str) { /* this is host:port pair */
264253
*port_str++ = '\0';
@@ -274,23 +263,35 @@ static int fpm_socket_af_inet_listening_socket(struct fpm_worker_pool_s *wp) /*
274263
return -1;
275264
}
276265

277-
memset(&sa_in, 0, sizeof(sa_in));
278-
279-
if (addr) {
280-
sa_in.sin_addr.s_addr = inet_addr(addr);
281-
if (sa_in.sin_addr.s_addr == INADDR_NONE) { /* do resolve */
282-
if (0 > fpm_sockets_resolve_af_inet(addr, NULL, &sa_in)) {
283-
return -1;
284-
}
285-
zlog(ZLOG_NOTICE, "address '%s' resolved as %u.%u.%u.%u", addr, IPQUAD(&sa_in.sin_addr));
266+
// strip brackets from address for getaddrinfo
267+
if (addr != NULL) {
268+
addr_len = strlen(addr);
269+
if (addr[0] == '[' && addr[addr_len - 1] == ']') {
270+
addr[addr_len - 1] = '\0';
271+
addr++;
286272
}
287-
} else {
288-
sa_in.sin_addr.s_addr = htonl(INADDR_ANY);
289273
}
290-
sa_in.sin_family = AF_INET;
291-
sa_in.sin_port = htons(port);
274+
275+
memset(&hints, 0, sizeof hints);
276+
hints.ai_family = AF_UNSPEC;
277+
hints.ai_socktype = SOCK_STREAM;
278+
279+
if ((status = getaddrinfo(addr, port_str, &hints, &servinfo)) != 0) {
280+
zlog(ZLOG_ERROR, "getaddrinfo: %s\n", gai_strerror(status));
281+
return -1;
282+
}
283+
292284
free(dup_address);
293-
return fpm_sockets_get_listening_socket(wp, (struct sockaddr *) &sa_in, sizeof(struct sockaddr_in));
285+
286+
for (p = servinfo; p != NULL; p = p->ai_next) {
287+
if ((sock = fpm_sockets_get_listening_socket(wp, p->ai_addr, p->ai_addrlen)) != -1) {
288+
break;
289+
}
290+
}
291+
292+
freeaddrinfo(servinfo);
293+
294+
return sock;
294295
}
295296
/* }}} */
296297

sapi/fpm/fpm/fpm_sockets.h

-6
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,4 @@ static inline int fd_set_blocked(int fd, int blocked) /* {{{ */
4545
}
4646
/* }}} */
4747

48-
#define IPQUAD(sin_addr) \
49-
(unsigned int) ((unsigned char *) &(sin_addr)->s_addr)[0], \
50-
(unsigned int) ((unsigned char *) &(sin_addr)->s_addr)[1], \
51-
(unsigned int) ((unsigned char *) &(sin_addr)->s_addr)[2], \
52-
(unsigned int) ((unsigned char *) &(sin_addr)->s_addr)[3]
53-
5448
#endif

sapi/fpm/php-fpm.conf.in

+2
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,8 @@ group = @php_fpm_group@
152152
; Valid syntaxes are:
153153
; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific address on
154154
; a specific port;
155+
; '[ip:6:addr:ess]:port' - to listen on a TCP socket to a specific IPv6 address on
156+
; a specific port;
155157
; 'port' - to listen on a TCP socket to all addresses on a
156158
; specific port;
157159
; '/path/to/unix/socket' - to listen on a unix socket.

sapi/fpm/tests/003.phpt

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
--TEST--
2+
FPM: Test IPv6 support
3+
--SKIPIF--
4+
<?php include "skipif.inc"; ?>
5+
--FILE--
6+
<?php
7+
8+
include "include.inc";
9+
10+
$logfile = dirname(__FILE__).'/php-fpm.log.tmp';
11+
12+
$cfg = <<<EOT
13+
[global]
14+
error_log = $logfile
15+
[unconfined]
16+
listen = [::1]:9000
17+
pm = dynamic
18+
pm.max_children = 5
19+
pm.start_servers = 2
20+
pm.min_spare_servers = 1
21+
pm.max_spare_servers = 3
22+
EOT;
23+
24+
$fpm = run_fpm($cfg, $tail);
25+
if (is_resource($fpm)) {
26+
var_dump(fgets($tail));
27+
var_dump(fgets($tail));
28+
$i = 0;
29+
while (($i++ < 30) && !($fp = fsockopen('[::1]', 9000))) {
30+
usleep(10000);
31+
}
32+
if ($fp) {
33+
echo "Done\n";
34+
fclose($fp);
35+
}
36+
proc_terminate($fpm);
37+
stream_get_contents($tail);
38+
fclose($tail);
39+
proc_close($fpm);
40+
}
41+
42+
?>
43+
--EXPECTF--
44+
string(%d) "[%d-%s-%d %d:%d:%d] NOTICE: fpm is running, pid %d
45+
"
46+
string(%d) "[%d-%s-%d %d:%d:%d] NOTICE: ready to handle connections
47+
"
48+
Done
49+
--CLEAN--
50+
<?php
51+
$logfile = dirname(__FILE__).'/php-fpm.log.tmp';
52+
@unlink($logfile);
53+
?>

0 commit comments

Comments
 (0)