Skip to content

Commit e90243a

Browse files
committed
Merge branch 'PHP-8.3' into PHP-8.4
* PHP-8.3: Fix GH-16800: ftp functions can abort with EINTR
2 parents 862ed7e + 412a6b2 commit e90243a

File tree

2 files changed

+51
-8
lines changed

2 files changed

+51
-8
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ PHP NEWS
22
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33
?? ??? ????, PHP 8.4.4
44

5+
- FTP:
6+
. Fixed bug GH-16800 (ftp functions can abort with EINTR). (nielsdos)
57

68
02 Jan 2025, PHP 8.4.3
79

ext/ftp/ftp.c

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1407,6 +1407,22 @@ ftp_getresp(ftpbuf_t *ftp)
14071407
}
14081408
/* }}} */
14091409

1410+
static ssize_t my_send_wrapper_with_restart(php_socket_t fd, const void *buf, size_t size, int flags) {
1411+
ssize_t n;
1412+
do {
1413+
n = send(fd, buf, size, flags);
1414+
} while (n == -1 && php_socket_errno() == EINTR);
1415+
return n;
1416+
}
1417+
1418+
static ssize_t my_recv_wrapper_with_restart(php_socket_t fd, void *buf, size_t size, int flags) {
1419+
ssize_t n;
1420+
do {
1421+
n = recv(fd, buf, size, flags);
1422+
} while (n == -1 && php_socket_errno() == EINTR);
1423+
return n;
1424+
}
1425+
14101426
int single_send(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t size) {
14111427
#ifdef HAVE_FTP_SSL
14121428
int err;
@@ -1422,7 +1438,7 @@ int single_send(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t size) {
14221438
handle = ftp->data->ssl_handle;
14231439
fd = ftp->data->fd;
14241440
} else {
1425-
return send(s, buf, size, 0);
1441+
return my_send_wrapper_with_restart(s, buf, size, 0);
14261442
}
14271443

14281444
do {
@@ -1461,8 +1477,33 @@ int single_send(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t size) {
14611477
} while (retry);
14621478
return sent;
14631479
#else
1464-
return send(s, buf, size, 0);
1480+
return my_send_wrapper_with_restart(s, buf, size, 0);
1481+
#endif
1482+
}
1483+
1484+
static int my_poll(php_socket_t fd, int events, int timeout) {
1485+
int n;
1486+
zend_hrtime_t timeout_hr = (zend_hrtime_t) timeout * 1000000;
1487+
1488+
while (true) {
1489+
zend_hrtime_t start_ns = zend_hrtime();
1490+
n = php_pollfd_for_ms(fd, events, (int) (timeout_hr / 1000000));
1491+
1492+
if (n == -1 && php_socket_errno() == EINTR) {
1493+
zend_hrtime_t delta_ns = zend_hrtime() - start_ns;
1494+
if (delta_ns > timeout_hr) {
1495+
#ifndef PHP_WIN32
1496+
errno = ETIMEDOUT;
14651497
#endif
1498+
break;
1499+
}
1500+
timeout_hr -= delta_ns;
1501+
} else {
1502+
break;
1503+
}
1504+
}
1505+
1506+
return n;
14661507
}
14671508

14681509
/* {{{ my_send */
@@ -1474,7 +1515,7 @@ my_send(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len)
14741515

14751516
size = len;
14761517
while (size) {
1477-
n = php_pollfd_for_ms(s, POLLOUT, ftp->timeout_sec * 1000);
1518+
n = my_poll(s, POLLOUT, ftp->timeout_sec * 1000);
14781519

14791520
if (n < 1) {
14801521
char buf[256];
@@ -1513,7 +1554,7 @@ my_recv(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len)
15131554
SSL *handle = NULL;
15141555
php_socket_t fd;
15151556
#endif
1516-
n = php_pollfd_for_ms(s, PHP_POLLREADABLE, ftp->timeout_sec * 1000);
1557+
n = my_poll(s, PHP_POLLREADABLE, ftp->timeout_sec * 1000);
15171558
if (n < 1) {
15181559
char buf[256];
15191560
if (n == 0) {
@@ -1573,7 +1614,7 @@ my_recv(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len)
15731614
} while (retry);
15741615
} else {
15751616
#endif
1576-
nr_bytes = recv(s, buf, len, 0);
1617+
nr_bytes = my_recv_wrapper_with_restart(s, buf, len, 0);
15771618
#ifdef HAVE_FTP_SSL
15781619
}
15791620
#endif
@@ -1587,7 +1628,7 @@ data_available(ftpbuf_t *ftp, php_socket_t s)
15871628
{
15881629
int n;
15891630

1590-
n = php_pollfd_for_ms(s, PHP_POLLREADABLE, 1000);
1631+
n = my_poll(s, PHP_POLLREADABLE, 1000);
15911632
if (n < 1) {
15921633
char buf[256];
15931634
if (n == 0) {
@@ -1610,7 +1651,7 @@ data_writeable(ftpbuf_t *ftp, php_socket_t s)
16101651
{
16111652
int n;
16121653

1613-
n = php_pollfd_for_ms(s, POLLOUT, 1000);
1654+
n = my_poll(s, POLLOUT, 1000);
16141655
if (n < 1) {
16151656
char buf[256];
16161657
if (n == 0) {
@@ -1634,7 +1675,7 @@ my_accept(ftpbuf_t *ftp, php_socket_t s, struct sockaddr *addr, socklen_t *addrl
16341675
{
16351676
int n;
16361677

1637-
n = php_pollfd_for_ms(s, PHP_POLLREADABLE, ftp->timeout_sec * 1000);
1678+
n = my_poll(s, PHP_POLLREADABLE, ftp->timeout_sec * 1000);
16381679
if (n < 1) {
16391680
char buf[256];
16401681
if (n == 0) {

0 commit comments

Comments
 (0)