mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
Add stream socket keepalive context options
This adds so_keepalive, tcp_keepidle, tcp_keepintvl and tcp_keepcnt stream socket context options that are used to set their upper case C macro variants by setsockopt function. The test requires sockets extension and just tests that the values are being set. This is because a real test would be slow and difficult to show that those options really work due to how they work internally. Closes GH-20381
This commit is contained in:
2
NEWS
2
NEWS
@@ -73,6 +73,8 @@ PHP NEWS
|
||||
while COW violation flag is still set). (alexandre-daubois)
|
||||
|
||||
- Streams:
|
||||
. Added so_keepalive, tcp_keepidle, tcp_keepintvl and tcp_keepcnt stream
|
||||
socket context options.
|
||||
. Added so_reuseaddr streams context socket option that allows disabling
|
||||
address resuse.
|
||||
. Fixed bug GH-20370 (User stream filters could violate typed property
|
||||
|
||||
@@ -46,6 +46,9 @@ PHP 8.6 UPGRADE NOTES
|
||||
. Added stream socket context option so_reuseaddr that allows disabling
|
||||
address reuse (SO_REUSEADDR) and explicitly uses SO_EXCLUSIVEADDRUSE on
|
||||
Windows.
|
||||
. Added stream socket context options so_keepalive, tcp_keepidle,
|
||||
tcp_keepintvl and tcp_keepcnt that allow setting socket keepalive
|
||||
options.
|
||||
|
||||
========================================
|
||||
3. Changes in SAPI modules
|
||||
|
||||
151
ext/standard/tests/network/so_keepalive.phpt
Normal file
151
ext/standard/tests/network/so_keepalive.phpt
Normal file
@@ -0,0 +1,151 @@
|
||||
--TEST--
|
||||
stream_socket_server() and stream_socket_client() SO_KEEPALIVE context option test
|
||||
--EXTENSIONS--
|
||||
sockets
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (!defined('TCP_KEEPIDLE') && !defined('TCP_KEEPALIVE')) {
|
||||
die('skip TCP_KEEPIDLE/TCP_KEEPALIVE not available');
|
||||
}
|
||||
if (!defined('TCP_KEEPINTVL')) {
|
||||
die('skip TCP_KEEPINTVL not available');
|
||||
}
|
||||
if (!defined('TCP_KEEPCNT')) {
|
||||
die('skip TCP_KEEPCNT not available');
|
||||
}
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
// Test server with SO_KEEPALIVE enabled
|
||||
$server_context = stream_context_create([
|
||||
'socket' => [
|
||||
'so_keepalive' => true,
|
||||
'tcp_keepidle' => 60,
|
||||
'tcp_keepintvl' => 10,
|
||||
'tcp_keepcnt' => 5,
|
||||
]
|
||||
]);
|
||||
|
||||
$server = stream_socket_server("tcp://127.0.0.1:0", $errno, $errstr,
|
||||
STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $server_context);
|
||||
|
||||
if (!$server) {
|
||||
die('Unable to create server');
|
||||
}
|
||||
|
||||
$addr = stream_socket_get_name($server, false);
|
||||
$port = (int)substr(strrchr($addr, ':'), 1);
|
||||
|
||||
// Test client with SO_KEEPALIVE enabled
|
||||
$client_context = stream_context_create([
|
||||
'socket' => [
|
||||
'so_keepalive' => true,
|
||||
'tcp_keepidle' => 30,
|
||||
'tcp_keepintvl' => 5,
|
||||
'tcp_keepcnt' => 3,
|
||||
]
|
||||
]);
|
||||
|
||||
$client = stream_socket_client("tcp://127.0.0.1:$port", $errno, $errstr, 30,
|
||||
STREAM_CLIENT_CONNECT, $client_context);
|
||||
|
||||
if (!$client) {
|
||||
die('Unable to create client');
|
||||
}
|
||||
|
||||
$accepted = stream_socket_accept($server, 1);
|
||||
|
||||
if (!$accepted) {
|
||||
die('Unable to accept connection');
|
||||
}
|
||||
|
||||
// Verify server side (accepted connection)
|
||||
$server_sock = socket_import_stream($accepted);
|
||||
$server_keepalive = socket_get_option($server_sock, SOL_SOCKET, SO_KEEPALIVE);
|
||||
echo "Server SO_KEEPALIVE: " . ($server_keepalive ? "enabled" : "disabled") . "\n";
|
||||
|
||||
if (defined('TCP_KEEPIDLE')) {
|
||||
$server_idle = socket_get_option($server_sock, SOL_TCP, TCP_KEEPIDLE);
|
||||
echo "Server TCP_KEEPIDLE: $server_idle\n";
|
||||
} else {
|
||||
$server_idle = socket_get_option($server_sock, SOL_TCP, TCP_KEEPALIVE);
|
||||
echo "Server TCP_KEEPIDLE: $server_idle\n";
|
||||
}
|
||||
|
||||
$server_intvl = socket_get_option($server_sock, SOL_TCP, TCP_KEEPINTVL);
|
||||
echo "Server TCP_KEEPINTVL: $server_intvl\n";
|
||||
|
||||
$server_cnt = socket_get_option($server_sock, SOL_TCP, TCP_KEEPCNT);
|
||||
echo "Server TCP_KEEPCNT: $server_cnt\n";
|
||||
|
||||
// Verify client side
|
||||
$client_sock = socket_import_stream($client);
|
||||
$client_keepalive = socket_get_option($client_sock, SOL_SOCKET, SO_KEEPALIVE);
|
||||
echo "Client SO_KEEPALIVE: " . ($client_keepalive ? "enabled" : "disabled") . "\n";
|
||||
|
||||
if (defined('TCP_KEEPIDLE')) {
|
||||
$client_idle = socket_get_option($client_sock, SOL_TCP, TCP_KEEPIDLE);
|
||||
echo "Client TCP_KEEPIDLE: $client_idle\n";
|
||||
} else {
|
||||
$client_idle = socket_get_option($client_sock, SOL_TCP, TCP_KEEPALIVE);
|
||||
echo "Client TCP_KEEPIDLE: $client_idle\n";
|
||||
}
|
||||
|
||||
$client_intvl = socket_get_option($client_sock, SOL_TCP, TCP_KEEPINTVL);
|
||||
echo "Client TCP_KEEPINTVL: $client_intvl\n";
|
||||
|
||||
$client_cnt = socket_get_option($client_sock, SOL_TCP, TCP_KEEPCNT);
|
||||
echo "Client TCP_KEEPCNT: $client_cnt\n";
|
||||
|
||||
fclose($accepted);
|
||||
fclose($client);
|
||||
fclose($server);
|
||||
|
||||
// Test server with SO_KEEPALIVE disabled
|
||||
$server2_context = stream_context_create(['socket' => ['so_keepalive' => false]]);
|
||||
$server2 = stream_socket_server("tcp://127.0.0.1:0", $errno, $errstr,
|
||||
STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $server2_context);
|
||||
|
||||
$addr2 = stream_socket_get_name($server2, false);
|
||||
$port2 = (int)substr(strrchr($addr2, ':'), 1);
|
||||
|
||||
$client2 = stream_socket_client("tcp://127.0.0.1:$port2");
|
||||
$accepted2 = stream_socket_accept($server2, 1);
|
||||
|
||||
$server2_sock = socket_import_stream($accepted2);
|
||||
$server2_keepalive = socket_get_option($server2_sock, SOL_SOCKET, SO_KEEPALIVE);
|
||||
echo "Server disabled SO_KEEPALIVE: " . ($server2_keepalive ? "enabled" : "disabled") . "\n";
|
||||
|
||||
fclose($accepted2);
|
||||
fclose($client2);
|
||||
fclose($server2);
|
||||
|
||||
// Test client with SO_KEEPALIVE disabled
|
||||
$server3 = stream_socket_server("tcp://127.0.0.1:0", $errno, $errstr,
|
||||
STREAM_SERVER_BIND | STREAM_SERVER_LISTEN);
|
||||
|
||||
$addr3 = stream_socket_get_name($server3, false);
|
||||
$port3 = (int)substr(strrchr($addr3, ':'), 1);
|
||||
|
||||
$client3_context = stream_context_create(['socket' => ['so_keepalive' => false]]);
|
||||
$client3 = stream_socket_client("tcp://127.0.0.1:$port3", $errno, $errstr, 30,
|
||||
STREAM_CLIENT_CONNECT, $client3_context);
|
||||
|
||||
$client3_sock = socket_import_stream($client3);
|
||||
$client3_keepalive = socket_get_option($client3_sock, SOL_SOCKET, SO_KEEPALIVE);
|
||||
echo "Client disabled SO_KEEPALIVE: " . ($client3_keepalive ? "enabled" : "disabled") . "\n";
|
||||
|
||||
fclose($client3);
|
||||
fclose($server3);
|
||||
?>
|
||||
--EXPECT--
|
||||
Server SO_KEEPALIVE: enabled
|
||||
Server TCP_KEEPIDLE: 60
|
||||
Server TCP_KEEPINTVL: 10
|
||||
Server TCP_KEEPCNT: 5
|
||||
Client SO_KEEPALIVE: enabled
|
||||
Client TCP_KEEPIDLE: 30
|
||||
Client TCP_KEEPINTVL: 5
|
||||
Client TCP_KEEPCNT: 3
|
||||
Server disabled SO_KEEPALIVE: disabled
|
||||
Client disabled SO_KEEPALIVE: disabled
|
||||
@@ -452,9 +452,9 @@ ok:
|
||||
/* Bind to a local IP address.
|
||||
* Returns the bound socket, or -1 on failure.
|
||||
* */
|
||||
/* {{{ php_network_bind_socket_to_local_addr */
|
||||
php_socket_t php_network_bind_socket_to_local_addr(const char *host, unsigned port,
|
||||
int socktype, long sockopts, zend_string **error_string, int *error_code
|
||||
php_socket_t php_network_bind_socket_to_local_addr_ex(const char *host, unsigned port,
|
||||
int socktype, long sockopts, php_sockvals *sockvals, zend_string **error_string,
|
||||
int *error_code
|
||||
)
|
||||
{
|
||||
int num_addrs, n, err = 0;
|
||||
@@ -533,6 +533,35 @@ php_socket_t php_network_bind_socket_to_local_addr(const char *host, unsigned po
|
||||
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&sockoptval, sizeof(sockoptval));
|
||||
}
|
||||
#endif
|
||||
#ifdef SO_KEEPALIVE
|
||||
if (sockopts & STREAM_SOCKOP_SO_KEEPALIVE) {
|
||||
setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char*)&sockoptval, sizeof(sockoptval));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set socket values if provided */
|
||||
if (sockvals != NULL) {
|
||||
#if defined(TCP_KEEPIDLE)
|
||||
if (sockvals->mask & PHP_SOCKVAL_TCP_KEEPIDLE) {
|
||||
setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, (char*)&sockvals->keepalive.keepidle, sizeof(sockvals->keepalive.keepidle));
|
||||
}
|
||||
#elif defined(TCP_KEEPALIVE)
|
||||
/* macOS uses TCP_KEEPALIVE instead of TCP_KEEPIDLE */
|
||||
if (sockvals->mask & PHP_SOCKVAL_TCP_KEEPIDLE) {
|
||||
setsockopt(sock, IPPROTO_TCP, TCP_KEEPALIVE, (char*)&sockvals->keepalive.keepidle, sizeof(sockvals->keepalive.keepidle));
|
||||
}
|
||||
#endif
|
||||
#ifdef TCP_KEEPINTVL
|
||||
if (sockvals->mask & PHP_SOCKVAL_TCP_KEEPINTVL) {
|
||||
setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, (char*)&sockvals->keepalive.keepintvl, sizeof(sockvals->keepalive.keepintvl));
|
||||
}
|
||||
#endif
|
||||
#ifdef TCP_KEEPCNT
|
||||
if (sockvals->mask & PHP_SOCKVAL_TCP_KEEPCNT) {
|
||||
setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, (char*)&sockvals->keepalive.keepcnt, sizeof(sockvals->keepalive.keepcnt));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
n = bind(sock, sa, socklen);
|
||||
|
||||
@@ -560,7 +589,13 @@ bound:
|
||||
return sock;
|
||||
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
php_socket_t php_network_bind_socket_to_local_addr(const char *host, unsigned port,
|
||||
int socktype, long sockopts, zend_string **error_string, int *error_code
|
||||
)
|
||||
{
|
||||
return php_network_bind_socket_to_local_addr_ex(host, port, socktype, sockopts, NULL, error_string, error_code);
|
||||
}
|
||||
|
||||
PHPAPI zend_result php_network_parse_network_address_with_port(const char *addr, size_t addrlen, struct sockaddr *sa, socklen_t *sl)
|
||||
{
|
||||
@@ -824,11 +859,9 @@ PHPAPI php_socket_t php_network_accept_incoming(php_socket_t srvsock,
|
||||
* enable non-blocking mode on the socket.
|
||||
* Returns the connected (or connecting) socket, or -1 on failure.
|
||||
* */
|
||||
|
||||
/* {{{ php_network_connect_socket_to_host */
|
||||
php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short port,
|
||||
php_socket_t php_network_connect_socket_to_host_ex(const char *host, unsigned short port,
|
||||
int socktype, int asynchronous, struct timeval *timeout, zend_string **error_string,
|
||||
int *error_code, const char *bindto, unsigned short bindport, long sockopts
|
||||
int *error_code, const char *bindto, unsigned short bindport, long sockopts, php_sockvals *sockvals
|
||||
)
|
||||
{
|
||||
int num_addrs, n, fatal = 0;
|
||||
@@ -952,6 +985,40 @@ php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SO_KEEPALIVE
|
||||
{
|
||||
int val = 1;
|
||||
if (sockopts & STREAM_SOCKOP_SO_KEEPALIVE) {
|
||||
setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char*)&val, sizeof(val));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set socket values if provided */
|
||||
if (sockvals != NULL) {
|
||||
#if defined(TCP_KEEPIDLE)
|
||||
if (sockvals->mask & PHP_SOCKVAL_TCP_KEEPIDLE) {
|
||||
setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, (char*)&sockvals->keepalive.keepidle, sizeof(sockvals->keepalive.keepidle));
|
||||
}
|
||||
#elif defined(TCP_KEEPALIVE)
|
||||
/* macOS uses TCP_KEEPALIVE instead of TCP_KEEPIDLE */
|
||||
if (sockvals->mask & PHP_SOCKVAL_TCP_KEEPIDLE) {
|
||||
setsockopt(sock, IPPROTO_TCP, TCP_KEEPALIVE, (char*)&sockvals->keepalive.keepidle, sizeof(sockvals->keepalive.keepidle));
|
||||
}
|
||||
#endif
|
||||
#ifdef TCP_KEEPINTVL
|
||||
if (sockvals->mask & PHP_SOCKVAL_TCP_KEEPINTVL) {
|
||||
setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, (char*)&sockvals->keepalive.keepintvl, sizeof(sockvals->keepalive.keepintvl));
|
||||
}
|
||||
#endif
|
||||
#ifdef TCP_KEEPCNT
|
||||
if (sockvals->mask & PHP_SOCKVAL_TCP_KEEPCNT) {
|
||||
setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, (char*)&sockvals->keepalive.keepcnt, sizeof(sockvals->keepalive.keepcnt));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
n = php_network_connect_socket(sock, sa, socklen, asynchronous,
|
||||
timeout ? &working_timeout : NULL,
|
||||
error_string, error_code);
|
||||
@@ -998,7 +1065,15 @@ connected:
|
||||
|
||||
return sock;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short port,
|
||||
int socktype, int asynchronous, struct timeval *timeout, zend_string **error_string,
|
||||
int *error_code, const char *bindto, unsigned short bindport, long sockopts
|
||||
)
|
||||
{
|
||||
return php_network_connect_socket_to_host_ex(host, port, socktype, asynchronous, timeout,
|
||||
error_string, error_code, bindto, bindport, sockopts, NULL);
|
||||
}
|
||||
|
||||
/* {{{ php_any_addr
|
||||
* Fills any (wildcard) address into php_sockaddr_storage
|
||||
|
||||
@@ -124,6 +124,7 @@ typedef int php_socket_t;
|
||||
#define STREAM_SOCKOP_IPV6_V6ONLY_ENABLED (1 << 4)
|
||||
#define STREAM_SOCKOP_TCP_NODELAY (1 << 5)
|
||||
#define STREAM_SOCKOP_SO_REUSEADDR (1 << 6)
|
||||
#define STREAM_SOCKOP_SO_KEEPALIVE (1 << 7)
|
||||
|
||||
/* uncomment this to debug poll(2) emulation on systems that have poll(2) */
|
||||
/* #define PHP_USE_POLL_2_EMULATION 1 */
|
||||
@@ -266,10 +267,28 @@ typedef struct {
|
||||
} php_sockaddr_storage;
|
||||
#endif
|
||||
|
||||
#define PHP_SOCKVAL_TCP_KEEPIDLE (1 << 0)
|
||||
#define PHP_SOCKVAL_TCP_KEEPCNT (1 << 1)
|
||||
#define PHP_SOCKVAL_TCP_KEEPINTVL (1 << 2)
|
||||
|
||||
typedef struct {
|
||||
unsigned int mask;
|
||||
struct {
|
||||
int keepidle;
|
||||
int keepcnt;
|
||||
int keepintvl;
|
||||
} keepalive;
|
||||
} php_sockvals;
|
||||
|
||||
BEGIN_EXTERN_C()
|
||||
PHPAPI int php_network_getaddresses(const char *host, int socktype, struct sockaddr ***sal, zend_string **error_string);
|
||||
PHPAPI void php_network_freeaddresses(struct sockaddr **sal);
|
||||
|
||||
PHPAPI php_socket_t php_network_connect_socket_to_host_ex(const char *host, unsigned short port,
|
||||
int socktype, int asynchronous, struct timeval *timeout, zend_string **error_string,
|
||||
int *error_code, const char *bindto, unsigned short bindport, long sockopts, php_sockvals *sockvals
|
||||
);
|
||||
|
||||
PHPAPI php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short port,
|
||||
int socktype, int asynchronous, struct timeval *timeout, zend_string **error_string,
|
||||
int *error_code, const char *bindto, unsigned short bindport, long sockopts
|
||||
@@ -286,6 +305,10 @@ PHPAPI int php_network_connect_socket(php_socket_t sockfd,
|
||||
#define php_connect_nonb(sock, addr, addrlen, timeout) \
|
||||
php_network_connect_socket((sock), (addr), (addrlen), 0, (timeout), NULL, NULL)
|
||||
|
||||
PHPAPI php_socket_t php_network_bind_socket_to_local_addr_ex(const char *host, unsigned port,
|
||||
int socktype, long sockopts, php_sockvals *sockvals, zend_string **error_string, int *error_code
|
||||
);
|
||||
|
||||
PHPAPI php_socket_t php_network_bind_socket_to_local_addr(const char *host, unsigned port,
|
||||
int socktype, long sockopts, zend_string **error_string, int *error_code
|
||||
);
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#include "php.h"
|
||||
#include "ext/standard/file.h"
|
||||
#include "streams/php_streams_int.h"
|
||||
#include "php_streams.h"
|
||||
#include "php_network.h"
|
||||
|
||||
#if defined(PHP_WIN32) || defined(__riscos__)
|
||||
@@ -48,8 +48,18 @@ static const php_stream_ops php_stream_udp_socket_ops;
|
||||
#ifdef AF_UNIX
|
||||
static const php_stream_ops php_stream_unix_socket_ops;
|
||||
static const php_stream_ops php_stream_unixdg_socket_ops;
|
||||
#endif
|
||||
|
||||
#define PHP_STREAM_XPORT_IS_UNIX_DG(stream) php_stream_is(stream, &php_stream_unixdg_socket_ops)
|
||||
#define PHP_STREAM_XPORT_IS_UNIX_ST(stream) php_stream_is(stream, &php_stream_unix_socket_ops)
|
||||
#define PHP_STREAM_XPORT_IS_UNIX(stream) \
|
||||
(PHP_STREAM_XPORT_IS_UNIX_DG(stream) || PHP_STREAM_XPORT_IS_UNIX_ST(stream))
|
||||
#else
|
||||
#define PHP_STREAM_XPORT_IS_UNIX_DG(stream) false
|
||||
#define PHP_STREAM_XPORT_IS_UNIX_STD(stream) false
|
||||
#define PHP_STREAM_XPORT_IS_UNIX(stream) false
|
||||
#endif
|
||||
#define PHP_STREAM_XPORT_IS_UDP(stream) (php_stream_is(stream, &php_stream_udp_socket_ops))
|
||||
#define PHP_STREAM_XPORT_IS_TCP(stream) (!PHP_STREAM_XPORT_IS_UNIX(stream) && !PHP_STREAM_XPORT_IS_UDP(stream))
|
||||
|
||||
static int php_tcp_sockop_set_option(php_stream *stream, int option, int value, void *ptrparam);
|
||||
|
||||
@@ -669,18 +679,19 @@ static inline int php_tcp_sockop_bind(php_stream *stream, php_netstream_data_t *
|
||||
int portno, err;
|
||||
long sockopts = STREAM_SOCKOP_NONE;
|
||||
zval *tmpzval = NULL;
|
||||
php_sockvals sockvals = {0};
|
||||
|
||||
#ifdef AF_UNIX
|
||||
if (stream->ops == &php_stream_unix_socket_ops || stream->ops == &php_stream_unixdg_socket_ops) {
|
||||
if (PHP_STREAM_XPORT_IS_UNIX(stream)) {
|
||||
struct sockaddr_un unix_addr;
|
||||
|
||||
sock->socket = socket(PF_UNIX, stream->ops == &php_stream_unix_socket_ops ? SOCK_STREAM : SOCK_DGRAM, 0);
|
||||
sock->socket = socket(PF_UNIX, PHP_STREAM_XPORT_IS_UNIX_ST(stream) ? SOCK_STREAM : SOCK_DGRAM, 0);
|
||||
|
||||
if (sock->socket == SOCK_ERR) {
|
||||
if (xparam->want_errortext) {
|
||||
char errstr[256];
|
||||
xparam->outputs.error_text = strpprintf(0, "Failed to create unix%s socket %s",
|
||||
stream->ops == &php_stream_unix_socket_ops ? "" : "datagram",
|
||||
PHP_STREAM_XPORT_IS_UNIX_ST(stream) ? "" : " datagram",
|
||||
php_socket_strerror_s(errno, errstr, sizeof(errstr)));
|
||||
}
|
||||
return -1;
|
||||
@@ -729,7 +740,7 @@ static inline int php_tcp_sockop_bind(php_stream *stream, php_netstream_data_t *
|
||||
#endif
|
||||
|
||||
#ifdef SO_BROADCAST
|
||||
if (stream->ops == &php_stream_udp_socket_ops /* SO_BROADCAST is only applicable for UDP */
|
||||
if (PHP_STREAM_XPORT_IS_UDP(stream) /* SO_BROADCAST is only applicable for UDP */
|
||||
&& PHP_STREAM_CONTEXT(stream)
|
||||
&& (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "so_broadcast")) != NULL
|
||||
&& zend_is_true(tmpzval)
|
||||
@@ -738,9 +749,53 @@ static inline int php_tcp_sockop_bind(php_stream *stream, php_netstream_data_t *
|
||||
}
|
||||
#endif
|
||||
|
||||
sock->socket = php_network_bind_socket_to_local_addr(host, portno,
|
||||
stream->ops == &php_stream_udp_socket_ops ? SOCK_DGRAM : SOCK_STREAM,
|
||||
#ifdef SO_KEEPALIVE
|
||||
if (PHP_STREAM_XPORT_IS_TCP(stream) /* SO_KEEPALIVE is only applicable for TCP */
|
||||
&& PHP_STREAM_CONTEXT(stream)
|
||||
&& (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "so_keepalive")) != NULL
|
||||
&& zend_is_true(tmpzval)
|
||||
) {
|
||||
sockopts |= STREAM_SOCKOP_SO_KEEPALIVE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Parse TCP keepalive parameters - only for TCP streams */
|
||||
if (PHP_STREAM_XPORT_IS_TCP(stream)) {
|
||||
#if defined(TCP_KEEPIDLE) || defined(TCP_KEEPALIVE)
|
||||
if (PHP_STREAM_CONTEXT(stream)
|
||||
&& (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "tcp_keepidle")) != NULL
|
||||
&& Z_TYPE_P(tmpzval) == IS_LONG
|
||||
) {
|
||||
sockvals.mask |= PHP_SOCKVAL_TCP_KEEPIDLE;
|
||||
sockvals.keepalive.keepidle = (int)Z_LVAL_P(tmpzval);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TCP_KEEPINTVL
|
||||
if (PHP_STREAM_CONTEXT(stream)
|
||||
&& (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "tcp_keepintvl")) != NULL
|
||||
&& Z_TYPE_P(tmpzval) == IS_LONG
|
||||
) {
|
||||
sockvals.mask |= PHP_SOCKVAL_TCP_KEEPINTVL;
|
||||
sockvals.keepalive.keepintvl = (int)Z_LVAL_P(tmpzval);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TCP_KEEPCNT
|
||||
if (PHP_STREAM_CONTEXT(stream)
|
||||
&& (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "tcp_keepcnt")) != NULL
|
||||
&& Z_TYPE_P(tmpzval) == IS_LONG
|
||||
) {
|
||||
sockvals.mask |= PHP_SOCKVAL_TCP_KEEPCNT;
|
||||
sockvals.keepalive.keepcnt = (int)Z_LVAL_P(tmpzval);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
sock->socket = php_network_bind_socket_to_local_addr_ex(host, portno,
|
||||
PHP_STREAM_XPORT_IS_UDP(stream) ? SOCK_DGRAM : SOCK_STREAM,
|
||||
sockopts,
|
||||
sockvals.mask ? &sockvals : NULL,
|
||||
xparam->want_errortext ? &xparam->outputs.error_text : NULL,
|
||||
&err
|
||||
);
|
||||
@@ -761,12 +816,13 @@ static inline int php_tcp_sockop_connect(php_stream *stream, php_netstream_data_
|
||||
int ret;
|
||||
zval *tmpzval = NULL;
|
||||
long sockopts = STREAM_SOCKOP_NONE;
|
||||
php_sockvals sockvals = {0};
|
||||
|
||||
#ifdef AF_UNIX
|
||||
if (stream->ops == &php_stream_unix_socket_ops || stream->ops == &php_stream_unixdg_socket_ops) {
|
||||
if (PHP_STREAM_XPORT_IS_UNIX(stream)) {
|
||||
struct sockaddr_un unix_addr;
|
||||
|
||||
sock->socket = socket(PF_UNIX, stream->ops == &php_stream_unix_socket_ops ? SOCK_STREAM : SOCK_DGRAM, 0);
|
||||
sock->socket = socket(PF_UNIX, PHP_STREAM_XPORT_IS_UNIX_ST(stream) ? SOCK_STREAM : SOCK_DGRAM, 0);
|
||||
|
||||
if (sock->socket == SOCK_ERR) {
|
||||
if (xparam->want_errortext) {
|
||||
@@ -807,7 +863,7 @@ static inline int php_tcp_sockop_connect(php_stream *stream, php_netstream_data_
|
||||
}
|
||||
|
||||
#ifdef SO_BROADCAST
|
||||
if (stream->ops == &php_stream_udp_socket_ops /* SO_BROADCAST is only applicable for UDP */
|
||||
if (PHP_STREAM_XPORT_IS_UDP(stream) /* SO_BROADCAST is only applicable for UDP */
|
||||
&& PHP_STREAM_CONTEXT(stream)
|
||||
&& (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "so_broadcast")) != NULL
|
||||
&& zend_is_true(tmpzval)
|
||||
@@ -816,11 +872,7 @@ static inline int php_tcp_sockop_connect(php_stream *stream, php_netstream_data_
|
||||
}
|
||||
#endif
|
||||
|
||||
if (stream->ops != &php_stream_udp_socket_ops /* TCP_NODELAY is only applicable for TCP */
|
||||
#ifdef AF_UNIX
|
||||
&& stream->ops != &php_stream_unix_socket_ops
|
||||
&& stream->ops != &php_stream_unixdg_socket_ops
|
||||
#endif
|
||||
if (PHP_STREAM_XPORT_IS_TCP(stream) /* TCP_NODELAY is only applicable for TCP */
|
||||
&& PHP_STREAM_CONTEXT(stream)
|
||||
&& (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "tcp_nodelay")) != NULL
|
||||
&& zend_is_true(tmpzval)
|
||||
@@ -828,19 +880,63 @@ static inline int php_tcp_sockop_connect(php_stream *stream, php_netstream_data_
|
||||
sockopts |= STREAM_SOCKOP_TCP_NODELAY;
|
||||
}
|
||||
|
||||
#ifdef SO_KEEPALIVE
|
||||
if (PHP_STREAM_XPORT_IS_TCP(stream) /* SO_KEEPALIVE is only applicable for TCP */
|
||||
&& PHP_STREAM_CONTEXT(stream)
|
||||
&& (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "so_keepalive")) != NULL
|
||||
&& zend_is_true(tmpzval)
|
||||
) {
|
||||
sockopts |= STREAM_SOCKOP_SO_KEEPALIVE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Parse TCP keepalive parameters - only for TCP streams */
|
||||
if (PHP_STREAM_XPORT_IS_TCP(stream)) {
|
||||
#if defined(TCP_KEEPIDLE) || defined(TCP_KEEPALIVE)
|
||||
if (PHP_STREAM_CONTEXT(stream)
|
||||
&& (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "tcp_keepidle")) != NULL
|
||||
&& Z_TYPE_P(tmpzval) == IS_LONG
|
||||
) {
|
||||
sockvals.mask |= PHP_SOCKVAL_TCP_KEEPIDLE;
|
||||
sockvals.keepalive.keepidle = (int)Z_LVAL_P(tmpzval);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TCP_KEEPINTVL
|
||||
if (PHP_STREAM_CONTEXT(stream)
|
||||
&& (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "tcp_keepintvl")) != NULL
|
||||
&& Z_TYPE_P(tmpzval) == IS_LONG
|
||||
) {
|
||||
sockvals.mask |= PHP_SOCKVAL_TCP_KEEPINTVL;
|
||||
sockvals.keepalive.keepintvl = (int)Z_LVAL_P(tmpzval);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TCP_KEEPCNT
|
||||
if (PHP_STREAM_CONTEXT(stream)
|
||||
&& (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "tcp_keepcnt")) != NULL
|
||||
&& Z_TYPE_P(tmpzval) == IS_LONG
|
||||
) {
|
||||
sockvals.mask |= PHP_SOCKVAL_TCP_KEEPCNT;
|
||||
sockvals.keepalive.keepcnt = (int)Z_LVAL_P(tmpzval);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Note: the test here for php_stream_udp_socket_ops is important, because we
|
||||
* want the default to be TCP sockets so that the openssl extension can
|
||||
* re-use this code. */
|
||||
|
||||
sock->socket = php_network_connect_socket_to_host(host, portno,
|
||||
stream->ops == &php_stream_udp_socket_ops ? SOCK_DGRAM : SOCK_STREAM,
|
||||
sock->socket = php_network_connect_socket_to_host_ex(host, portno,
|
||||
PHP_STREAM_XPORT_IS_UDP(stream) ? SOCK_DGRAM : SOCK_STREAM,
|
||||
xparam->op == STREAM_XPORT_OP_CONNECT_ASYNC,
|
||||
xparam->inputs.timeout,
|
||||
xparam->want_errortext ? &xparam->outputs.error_text : NULL,
|
||||
&err,
|
||||
bindto,
|
||||
bindport,
|
||||
sockopts
|
||||
sockopts,
|
||||
sockvals.mask ? &sockvals : NULL
|
||||
);
|
||||
|
||||
ret = sock->socket == -1 ? -1 : 0;
|
||||
|
||||
Reference in New Issue
Block a user