Skip to content

Commit 8d25978

Browse files
committed
Merge branch 'PHP-8.3' into PHP-8.4
2 parents 6fca900 + 6f05d96 commit 8d25978

File tree

2 files changed

+74
-37
lines changed

2 files changed

+74
-37
lines changed

NEWS

+3
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ PHP NEWS
3636
. Fixed bug GH-16905 (Internal iterator functions can't handle UNDEF
3737
properties). (nielsdos)
3838

39+
- Streams:
40+
. Fixed network connect poll interuption handling. (Jakub Zelenka)
41+
3942
- Windows:
4043
. Fixed bug GH-16849 (Error dialog causes process to hang). (cmb)
4144
. Windows Server 2025 is now properly reported. (cmb)

main/network.c

+71-37
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,35 @@ typedef int php_non_blocking_flags_t;
297297
fcntl(sock, F_SETFL, save)
298298
#endif
299299

300+
#ifdef HAVE_GETTIMEOFDAY
301+
/* Subtract times */
302+
static inline void sub_times(struct timeval a, struct timeval b, struct timeval *result)
303+
{
304+
result->tv_usec = a.tv_usec - b.tv_usec;
305+
if (result->tv_usec < 0L) {
306+
a.tv_sec--;
307+
result->tv_usec += 1000000L;
308+
}
309+
result->tv_sec = a.tv_sec - b.tv_sec;
310+
if (result->tv_sec < 0L) {
311+
result->tv_sec++;
312+
result->tv_usec -= 1000000L;
313+
}
314+
}
315+
316+
static inline void php_network_set_limit_time(struct timeval *limit_time,
317+
struct timeval *timeout)
318+
{
319+
gettimeofday(limit_time, NULL);
320+
limit_time->tv_sec += timeout->tv_sec;
321+
limit_time->tv_usec += timeout->tv_usec;
322+
if (limit_time->tv_usec >= 1000000) {
323+
limit_time->tv_usec -= 1000000;
324+
limit_time->tv_sec++;
325+
}
326+
}
327+
#endif
328+
300329
/* Connect to a socket using an interruptible connect with optional timeout.
301330
* Optionally, the connect can be made asynchronously, which will implicitly
302331
* enable non-blocking mode on the socket.
@@ -349,25 +378,53 @@ PHPAPI int php_network_connect_socket(php_socket_t sockfd,
349378
* expected when a connection is actively refused. This way,
350379
* php_pollfd_for will return a mask with POLLOUT if the connection
351380
* is successful and with POLLPRI otherwise. */
352-
if ((n = php_pollfd_for(sockfd, POLLOUT|POLLPRI, timeout)) == 0) {
381+
int events = POLLOUT|POLLPRI;
353382
#else
354-
if ((n = php_pollfd_for(sockfd, PHP_POLLREADABLE|POLLOUT, timeout)) == 0) {
383+
int events = PHP_POLLREADABLE|POLLOUT;
384+
#endif
385+
struct timeval working_timeout;
386+
#ifdef HAVE_GETTIMEOFDAY
387+
struct timeval limit_time, time_now;
388+
#endif
389+
if (timeout) {
390+
memcpy(&working_timeout, timeout, sizeof(working_timeout));
391+
#ifdef HAVE_GETTIMEOFDAY
392+
php_network_set_limit_time(&limit_time, &working_timeout);
355393
#endif
356-
error = PHP_TIMEOUT_ERROR_VALUE;
357394
}
358395

359-
if (n > 0) {
360-
len = sizeof(error);
361-
/*
362-
BSD-derived systems set errno correctly
363-
Solaris returns -1 from getsockopt in case of error
364-
*/
365-
if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char*)&error, &len) != 0) {
396+
while (true) {
397+
n = php_pollfd_for(sockfd, events, timeout ? &working_timeout : NULL);
398+
if (n < 0) {
399+
if (errno == EINTR) {
400+
#ifdef HAVE_GETTIMEOFDAY
401+
if (timeout) {
402+
gettimeofday(&time_now, NULL);
403+
404+
if (!timercmp(&time_now, &limit_time, <)) {
405+
/* time limit expired; no need for another poll */
406+
error = PHP_TIMEOUT_ERROR_VALUE;
407+
break;
408+
} else {
409+
/* work out remaining time */
410+
sub_times(limit_time, time_now, &working_timeout);
411+
}
412+
}
413+
#endif
414+
continue;
415+
}
366416
ret = -1;
417+
} else if (n == 0) {
418+
error = PHP_TIMEOUT_ERROR_VALUE;
419+
} else {
420+
len = sizeof(error);
421+
/* BSD-derived systems set errno correctly.
422+
* Solaris returns -1 from getsockopt in case of error. */
423+
if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char*)&error, &len) != 0) {
424+
ret = -1;
425+
}
367426
}
368-
} else {
369-
/* whoops: sockfd has disappeared */
370-
ret = -1;
427+
break;
371428
}
372429

373430
ok:
@@ -390,22 +447,6 @@ PHPAPI int php_network_connect_socket(php_socket_t sockfd,
390447
}
391448
/* }}} */
392449

393-
/* {{{ sub_times */
394-
static inline void sub_times(struct timeval a, struct timeval b, struct timeval *result)
395-
{
396-
result->tv_usec = a.tv_usec - b.tv_usec;
397-
if (result->tv_usec < 0L) {
398-
a.tv_sec--;
399-
result->tv_usec += 1000000L;
400-
}
401-
result->tv_sec = a.tv_sec - b.tv_sec;
402-
if (result->tv_sec < 0L) {
403-
result->tv_sec++;
404-
result->tv_usec -= 1000000L;
405-
}
406-
}
407-
/* }}} */
408-
409450
/* Bind to a local IP address.
410451
* Returns the bound socket, or -1 on failure.
411452
* */
@@ -765,7 +806,6 @@ PHPAPI php_socket_t php_network_accept_incoming(php_socket_t srvsock,
765806
}
766807
/* }}} */
767808

768-
769809
/* Connect to a remote host using an interruptible connect with optional timeout.
770810
* Optionally, the connect can be made asynchronously, which will implicitly
771811
* enable non-blocking mode on the socket.
@@ -797,13 +837,7 @@ php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short
797837
if (timeout) {
798838
memcpy(&working_timeout, timeout, sizeof(working_timeout));
799839
#ifdef HAVE_GETTIMEOFDAY
800-
gettimeofday(&limit_time, NULL);
801-
limit_time.tv_sec += working_timeout.tv_sec;
802-
limit_time.tv_usec += working_timeout.tv_usec;
803-
if (limit_time.tv_usec >= 1000000) {
804-
limit_time.tv_usec -= 1000000;
805-
limit_time.tv_sec++;
806-
}
840+
php_network_set_limit_time(&limit_time, &working_timeout);
807841
#endif
808842
}
809843

0 commit comments

Comments
 (0)