Skip to content

Commit 53f2c75

Browse files
committed
ext/sockets: socket_connectx and optional socket_disconnectx for macOs.
Native calls to allow multipath connections for better reliability (several interfaces possible at once, wired + Wifi etc) and performance optimisations.
1 parent 677a1f8 commit 53f2c75

File tree

4 files changed

+136
-1
lines changed

4 files changed

+136
-1
lines changed

ext/sockets/config.m4

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ if test "$PHP_SOCKETS" != "no"; then
2323

2424
AC_CHECK_TYPES([struct cmsgcred],,, [#include <sys/socket.h>])
2525

26+
AC_CHECK_FUNCS(m4_normalize([connectx]))
27+
2628
PHP_SOCKETS_CFLAGS=-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1
2729
AS_CASE([$host_alias],
2830
[*darwin*],

ext/sockets/sockets.c

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3135,3 +3135,91 @@ PHP_FUNCTION(socket_wsaprotocol_info_release)
31353135
}
31363136
/* }}} */
31373137
#endif
3138+
3139+
#ifdef HAVE_CONNECTX
3140+
PHP_FUNCTION(socket_connectx)
3141+
{
3142+
zval *arg1, *buffers = NULL;
3143+
php_socket *php_sock;
3144+
php_addrinfo *ai;
3145+
zend_long flags = 0;
3146+
struct iovec *raw_buffers = NULL;
3147+
uint32_t raw_buffers_len = 0;
3148+
size_t buffers_len = 0;
3149+
3150+
ZEND_PARSE_PARAMETERS_START(1, 3)
3151+
Z_PARAM_OBJECT_OF_CLASS(arg1, socket_ce)
3152+
Z_PARAM_OPTIONAL
3153+
Z_PARAM_ARRAY(buffers)
3154+
Z_PARAM_LONG(flags)
3155+
ZEND_PARSE_PARAMETERS_END();
3156+
3157+
php_sock = Z_SOCKET_P(arg1);
3158+
ENSURE_SOCKET_VALID(php_sock);
3159+
3160+
if (buffers != NULL) {
3161+
raw_buffers_len = zend_hash_num_elements(Z_ARRVAL_P(buffers));
3162+
if (raw_buffers_len == 0) {
3163+
zend_argument_value_error(3, "must contain at least one entry");
3164+
RETURN_THROWS();
3165+
}
3166+
raw_buffers = emalloc(raw_buffers_len * sizeof(struct iovec));
3167+
zval *buffer;
3168+
raw_buffers_len = 0;
3169+
3170+
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(buffers), buffer) {
3171+
if (Z_TYPE_P(buffer) != IS_STRING) {
3172+
zend_argument_type_error(2, "must only have elements of type string, %s given", zend_zval_value_name(buffer));
3173+
RETURN_THROWS();
3174+
}
3175+
const struct iovec vec = {
3176+
.iov_base = (void *)Z_STRVAL_P(buffer),
3177+
.iov_len = Z_STRLEN_P(buffer)
3178+
};
3179+
raw_buffers[raw_buffers_len] = vec;
3180+
raw_buffers_len ++;
3181+
} ZEND_HASH_FOREACH_END();
3182+
}
3183+
3184+
if (flags > 0 && flags & ~(CONNECT_DATA_IDEMPOTENT|CONNECT_RESUME_ON_READ_WRITE)) {
3185+
zend_argument_value_error(4, "must be CONNECT_DATA_IDEMPOTENT and/or CONNECT_RESUME_ON_READ_WRITE");
3186+
RETURN_THROWS();
3187+
}
3188+
3189+
ai = Z_ADDRESS_INFO_P(arg1);
3190+
// TODO: multiple interfaces support ?
3191+
struct sa_endpoints epoints = {0};
3192+
epoints.sae_dstaddr = ai->addrinfo.ai_addr;
3193+
epoints.sae_dstaddrlen = ai->addrinfo.ai_addrlen;
3194+
3195+
// TODO: using final length result ?
3196+
if (connectx(php_sock->bsd_socket, &epoints, SAE_ASSOCID_ANY, (unsigned int)flags, raw_buffers, raw_buffers_len, &buffers_len, NULL) < 0) {
3197+
efree(raw_buffers);
3198+
PHP_SOCKET_ERROR(php_sock, "Unable to connect", errno);
3199+
RETURN_FALSE;
3200+
}
3201+
3202+
efree(raw_buffers);
3203+
RETURN_TRUE;
3204+
}
3205+
3206+
PHP_FUNCTION(socket_disconnectx)
3207+
{
3208+
zval *arg1;
3209+
php_socket *php_sock;
3210+
3211+
ZEND_PARSE_PARAMETERS_START(1, 1)
3212+
Z_PARAM_OBJECT_OF_CLASS(arg1, socket_ce)
3213+
ZEND_PARSE_PARAMETERS_END();
3214+
3215+
php_sock = Z_SOCKET_P(arg1);
3216+
ENSURE_SOCKET_VALID(php_sock);
3217+
3218+
if (disconnectx(php_sock->bsd_socket, SAE_ASSOCID_ANY, SAE_CONNID_ANY) < 0) {
3219+
PHP_SOCKET_ERROR(php_sock, "Unable to disconnect", errno);
3220+
RETURN_FALSE;
3221+
}
3222+
3223+
RETURN_TRUE;
3224+
}
3225+
#endif

ext/sockets/sockets.stub.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,20 @@
3333
*/
3434
const AF_PACKET = UNKNOWN;
3535
#endif
36+
#ifdef CONNECT_DATA_IDEMPOTENT
37+
/**
38+
* @var int
39+
* @cvalue CONNECT_DATA_IDEMPOTENT
40+
*/
41+
const CONNECT_DATA_IDEMPOTENT = UNKNOWN;
42+
#endif
43+
#ifdef CONNECT_RESUME_ON_READ_WRITE
44+
/**
45+
* @var int
46+
* @cvalue CONNECT_RESUME_ON_READ_WRITE
47+
*/
48+
const CONNECT_RESUME_ON_READ_WRITE = UNKNOWN;
49+
#endif
3650
/**
3751
* @var int
3852
* @cvalue SOCK_STREAM
@@ -2190,3 +2204,8 @@ function socket_wsaprotocol_info_import(string $info_id): Socket|false {}
21902204

21912205
function socket_wsaprotocol_info_release(string $info_id): bool {}
21922206
#endif
2207+
2208+
#ifdef HAVE_CONNECTX
2209+
function socket_connectx(Socket $socket, ?array $buffers = null, ?int $flags = 0): bool {}
2210+
function socket_disconnectx(Socket $socket): bool {}
2211+
#endif

ext/sockets/sockets_arginfo.h

Lines changed: 27 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)