@@ -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