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