Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit f3df534

Browse files
committed
Add so_reuseaddr stream context option
This is to allow disabling of SO_REUSEADDR that is enabled by default
1 parent 65b9306 commit f3df534

File tree

4 files changed

+82
-4
lines changed

4 files changed

+82
-4
lines changed
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
--TEST--
2+
stream_socket_server() SO_REUSEADDR context option test
3+
--FILE--
4+
<?php
5+
// Test default behavior (SO_REUSEADDR enabled)
6+
$server1 = stream_socket_server("tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN);
7+
if (!$server1) {
8+
die('Unable to create server3');
9+
}
10+
11+
$addr = stream_socket_get_name($server1, false);
12+
$port = (int)substr(strrchr($addr, ':'), 1);
13+
14+
$client1 = stream_socket_client("tcp://127.0.0.1:$port");
15+
$accepted = stream_socket_accept($server1, 1);
16+
17+
// Force real TCP connection with data
18+
fwrite($client1, "test");
19+
fread($accepted, 4);
20+
fwrite($accepted, "response");
21+
fread($client1, 8);
22+
23+
fclose($client1);
24+
fclose($server1);
25+
26+
$server2 = @stream_socket_server("tcp://127.0.0.1:$port", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN);
27+
if ($server2) {
28+
echo "Default: Server restart succeeded\n";
29+
fclose($server2);
30+
} else {
31+
echo "Default: Server restart failed\n";
32+
}
33+
34+
// Test with SO_REUSEADDR explicitly disabled
35+
$context = stream_context_create(['socket' => ['so_reuseaddr' => false]]);
36+
$server3 = stream_socket_server("tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $context);
37+
if (!$server3) {
38+
die('Unable to create server3');
39+
}
40+
41+
$addr = stream_socket_get_name($server3, false);
42+
$port = (int)substr(strrchr($addr, ':'), 1);
43+
44+
$client3 = stream_socket_client("tcp://127.0.0.1:$port");
45+
$accepted = stream_socket_accept($server3, 1);
46+
47+
// Force real TCP connection with data
48+
fwrite($client3, "test");
49+
fread($accepted, 4);
50+
fwrite($accepted, "response");
51+
fread($client3, 8);
52+
53+
// Client closes first (becomes active closer)
54+
fclose($client3); // This enters TIME_WAIT
55+
fclose($server3);
56+
57+
// Try immediate bind with SO_REUSEADDR disabled (should fail)
58+
$server4 = @stream_socket_server("tcp://127.0.0.1:$port", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $context);
59+
if ($server4) {
60+
echo "Disabled: Server restart succeeded\n";
61+
fclose($server4);
62+
} else {
63+
echo "Disabled: Server restart failed\n";
64+
}
65+
?>
66+
--EXPECT--
67+
Default: Server restart succeeded
68+
Disabled: Server restart failed

‎main/network.c‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -496,9 +496,9 @@ php_socket_t php_network_bind_socket_to_local_addr(const char *host, unsigned po
496496

497497
/* attempt to bind */
498498

499-
#ifdefSO_REUSEADDR
500-
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&sockoptval, sizeof(sockoptval));
501-
#endif
499+
if (sockopts&STREAM_SOCKOP_SO_REUSEADDR) {
500+
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&sockoptval, sizeof(sockoptval));
501+
}
502502
#ifdef IPV6_V6ONLY
503503
if (sockopts & STREAM_SOCKOP_IPV6_V6ONLY) {
504504
int ipv6_val = !!(sockopts & STREAM_SOCKOP_IPV6_V6ONLY_ENABLED);

‎main/php_network.h‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ typedef int php_socket_t;
118118
#define STREAM_SOCKOP_IPV6_V6ONLY (1 << 3)
119119
#define STREAM_SOCKOP_IPV6_V6ONLY_ENABLED (1 << 4)
120120
#define STREAM_SOCKOP_TCP_NODELAY (1 << 5)
121-
121+
#defineSTREAM_SOCKOP_SO_REUSEADDR (1 << 6)
122122

123123
/* uncomment this to debug poll(2) emulation on systems that have poll(2) */
124124
/* #define PHP_USE_POLL_2_EMULATION 1 */

‎main/streams/xp_socket.c‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,16 @@ static inline int php_tcp_sockop_bind(php_stream *stream, php_netstream_data_t *
717717
}
718718
#endif
719719

720+
#ifdef SO_REUSEADDR
721+
/* SO_REUSEADDR is enabled by default so this option is just to disable it if set to false. */
722+
if (!PHP_STREAM_CONTEXT(stream)
723+
|| (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "so_reuseaddr")) == NULL
724+
|| zend_is_true(tmpzval)
725+
) {
726+
sockopts |= STREAM_SOCKOP_SO_REUSEADDR;
727+
}
728+
#endif
729+
720730
#ifdef SO_BROADCAST
721731
if (stream->ops == &php_stream_udp_socket_ops /* SO_BROADCAST is only applicable for UDP */
722732
&& PHP_STREAM_CONTEXT(stream)

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /