@@ -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
373430ok :
@@ -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