Skip to content

Commit

Permalink
ext/sockets: further timeout handling changes. (#17210)
Browse files Browse the repository at this point in the history
close GH-17210
  • Loading branch information
devnexen authored Dec 20, 2024
1 parent 420365d commit c4bb6e6
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 10 deletions.
2 changes: 2 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ PHP NEWS
(David Carlier)
. Added TCP_FUNCTION_BLK to change the TCP stack algorithm on FreeBSD.
(David Carlier)
. socket_set_option() catches possible overflow with SO_RCVTIMEO/SO_SNDTIMEO
with timeout setting on windows. (David Carlier)

- Standard:
. Fixed crypt() tests on musl when using --with-external-libcrypt
Expand Down
35 changes: 25 additions & 10 deletions ext/sockets/sockets.c
Original file line number Diff line number Diff line change
Expand Up @@ -1646,6 +1646,8 @@ PHP_FUNCTION(socket_get_option)
struct timeval tv;
#ifdef PHP_WIN32
DWORD timeout = 0;
#else
struct timeval timeout;
#endif
socklen_t optlen;
php_socket *php_sock;
Expand Down Expand Up @@ -1749,23 +1751,19 @@ PHP_FUNCTION(socket_get_option)

case SO_RCVTIMEO:
case SO_SNDTIMEO:
#ifndef PHP_WIN32
optlen = sizeof(tv);

if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&tv, &optlen) != 0) {
PHP_SOCKET_ERROR(php_sock, "Unable to retrieve socket option", errno);
RETURN_FALSE;
}
#else
optlen = sizeof(timeout);

if (getsockopt(php_sock->bsd_socket, level, optname, (char*)&timeout, &optlen) != 0) {
PHP_SOCKET_ERROR(php_sock, "Unable to retrieve socket option", errno);
RETURN_FALSE;
}

#ifndef PHP_WIN32
tv.tv_sec = timeout.tv_sec;
tv.tv_usec = timeout.tv_usec;
#else
tv.tv_sec = timeout ? (long)(timeout / 1000) : 0;
tv.tv_usec = timeout ? (long)((timeout * 1000) % 1000000) : 0;
tv.tv_usec = timeout ? (long)((timeout % 1000) * 1000) : 0;
#endif

array_init(return_value);
Expand Down Expand Up @@ -2046,7 +2044,24 @@ PHP_FUNCTION(socket_set_option)
optlen = sizeof(tv);
opt_ptr = &tv;
#else
timeout = Z_LVAL_P(sec) * 1000 + Z_LVAL_P(usec) / 1000;
if (valsec < 0 || valsec > ULONG_MAX / 1000) {
zend_argument_value_error(4, "\"%s\" must be between 0 and %u", sec_key, (ULONG_MAX / 1000));
RETURN_THROWS();
}

timeout = valsec * 1000;


/*
* We deliberately throw if (valusec / 1000) > ULONG_MAX, treating it as a programmer error.
* On Windows, ULONG_MAX = 2^32, unlike ZEND_LONG_MAX = 2^63.
*/
if (valusec < 0 || timeout > ULONG_MAX - (valusec / 1000)) {
zend_argument_value_error(4, "\"%s\" must be between 0 and %u", usec_key, (DWORD)(ULONG_MAX - (valusec / 1000)));
RETURN_THROWS();
}

timeout += valusec / 1000;
optlen = sizeof(timeout);
opt_ptr = &timeout;
#endif
Expand Down

0 comments on commit c4bb6e6

Please sign in to comment.