Skip to content

Commit 6f05d96

Browse files
committed
Merge branch 'PHP-8.2' into PHP-8.3
2 parents 6a195bd + 69765d9 commit 6f05d96

File tree

2 files changed

+74
-37
lines changed

2 files changed

+74
-37
lines changed

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ PHP NEWS
7373
. Fixed bug GH-16905 (Internal iterator functions can't handle UNDEF
7474
properties). (nielsdos)
7575

76+
- Streams:
77+
. Fixed network connect poll interuption handling. (Jakub Zelenka)
78+
7679
- Windows:
7780
. Fixed bug GH-16849 (Error dialog causes process to hang). (cmb)
7881

main/network.c

Lines changed: 71 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,35 @@ typedef int php_non_blocking_flags_t;
299299
fcntl(sock, F_SETFL, save)
300300
#endif
301301

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

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

375432
ok:
@@ -392,22 +449,6 @@ PHPAPI int php_network_connect_socket(php_socket_t sockfd,
392449
}
393450
/* }}} */
394451

395-
/* {{{ sub_times */
396-
static inline void sub_times(struct timeval a, struct timeval b, struct timeval *result)
397-
{
398-
result->tv_usec = a.tv_usec - b.tv_usec;
399-
if (result->tv_usec < 0L) {
400-
a.tv_sec--;
401-
result->tv_usec += 1000000L;
402-
}
403-
result->tv_sec = a.tv_sec - b.tv_sec;
404-
if (result->tv_sec < 0L) {
405-
result->tv_sec++;
406-
result->tv_usec -= 1000000L;
407-
}
408-
}
409-
/* }}} */
410-
411452
/* Bind to a local IP address.
412453
* Returns the bound socket, or -1 on failure.
413454
* */
@@ -777,7 +818,6 @@ PHPAPI php_socket_t php_network_accept_incoming(php_socket_t srvsock,
777818
}
778819
/* }}} */
779820

780-
781821
/* Connect to a remote host using an interruptible connect with optional timeout.
782822
* Optionally, the connect can be made asynchronously, which will implicitly
783823
* enable non-blocking mode on the socket.
@@ -809,13 +849,7 @@ php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short
809849
if (timeout) {
810850
memcpy(&working_timeout, timeout, sizeof(working_timeout));
811851
#if HAVE_GETTIMEOFDAY
812-
gettimeofday(&limit_time, NULL);
813-
limit_time.tv_sec += working_timeout.tv_sec;
814-
limit_time.tv_usec += working_timeout.tv_usec;
815-
if (limit_time.tv_usec >= 1000000) {
816-
limit_time.tv_usec -= 1000000;
817-
limit_time.tv_sec++;
818-
}
852+
php_network_set_limit_time(&limit_time, &working_timeout);
819853
#endif
820854
}
821855

0 commit comments

Comments
 (0)