@@ -648,7 +648,7 @@ PHP_FUNCTION(stream_clear_errors)
648648}
649649
650650/* {{{ stream_select related functions */
651- static int stream_array_to_fd_set (const HashTable * stream_array , fd_set * fds , php_socket_t * max_fd )
651+ static int stream_array_to_fd_set (const HashTable * stream_array , php_growable_fd_set * fds , php_socket_t * max_fd )
652652{
653653 zval * elem ;
654654 php_stream * stream ;
@@ -672,7 +672,7 @@ static int stream_array_to_fd_set(const HashTable *stream_array, fd_set *fds, ph
672672 * */
673673 if (SUCCESS == php_stream_cast (stream , PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL , (void * )& this_fd , 1 ) && this_fd != -1 ) {
674674
675- PHP_SAFE_FD_SET ( this_fd , fds );
675+ php_growable_fd_set_add ( fds , this_fd );
676676
677677 if (this_fd > * max_fd ) {
678678 * max_fd = this_fd ;
@@ -683,19 +683,14 @@ static int stream_array_to_fd_set(const HashTable *stream_array, fd_set *fds, ph
683683 return cnt ? 1 : 0 ;
684684}
685685
686- static int stream_array_from_fd_set (zval * stream_array , const fd_set * fds )
686+ static int stream_array_from_fd_set (zval * stream_array , const php_growable_fd_set * fds )
687687{
688- zval * elem , * dest_elem ;
689- HashTable * ht ;
690- php_stream * stream ;
691- int ret = 0 ;
692- zend_string * key ;
693- zend_ulong num_ind ;
694-
695688 ZEND_ASSERT (Z_TYPE_P (stream_array ) == IS_ARRAY );
696- ht = zend_new_array (zend_hash_num_elements (Z_ARRVAL_P (stream_array )));
689+ HashTable * ht = zend_new_array (zend_hash_num_elements (Z_ARRVAL_P (stream_array )));
690+ int ret = 0 ;
697691
698- ZEND_HASH_FOREACH_KEY_VAL (Z_ARRVAL_P (stream_array ), num_ind , key , elem ) {
692+ ZEND_HASH_FOREACH_KEY_VAL (Z_ARRVAL_P (stream_array ), zend_ulong num_ind , zend_string * key , zval * elem ) {
693+ php_stream * stream ;
699694 php_socket_t this_fd ;
700695
701696 ZVAL_DEREF (elem );
@@ -709,7 +704,8 @@ static int stream_array_from_fd_set(zval *stream_array, const fd_set *fds)
709704 * is not displayed.
710705 */
711706 if (SUCCESS == php_stream_cast (stream , PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL , (void * )& this_fd , 1 ) && this_fd != SOCK_ERR ) {
712- if (PHP_SAFE_FD_ISSET (this_fd , fds )) {
707+ if (php_growable_fd_set_isset (fds , this_fd )) {
708+ zval * dest_elem ;
713709 if (!key ) {
714710 dest_elem = zend_hash_index_update (ht , num_ind , elem );
715711 } else {
@@ -780,15 +776,9 @@ static int stream_array_emulate_read_fd_set(zval *stream_array)
780776PHP_FUNCTION (stream_select )
781777{
782778 zval * r_array , * w_array , * e_array , * zcontext = NULL ;
783- struct timeval tv , * tv_p = NULL ;
784- fd_set rfds , wfds , efds ;
785- php_socket_t max_fd = 0 ;
786- int retval , sets = 0 ;
787779 zend_long sec , usec = 0 ;
788780 bool secnull ;
789781 bool usecnull = 1 ;
790- int set_count , max_set_count = 0 ;
791- php_stream_context * context = NULL ;
792782
793783 ZEND_PARSE_PARAMETERS_START (4 , 6 )
794784 Z_PARAM_ARRAY_EX2 (r_array , 1 , 1 , 0 )
@@ -800,62 +790,52 @@ PHP_FUNCTION(stream_select)
800790 Z_PARAM_RESOURCE_OR_NULL (zcontext )
801791 ZEND_PARSE_PARAMETERS_END ();
802792
803- FD_ZERO (& rfds );
804- FD_ZERO (& wfds );
805- FD_ZERO (& efds );
806-
807793 php_stream_error_operation_begin ();
808- context = php_stream_context_from_zval (zcontext , 0 );
794+ php_stream_context * context = php_stream_context_from_zval (zcontext , 0 );
795+
796+ /* The sets grow as streams are added, past FD_SETSIZE */
797+ php_growable_fd_set rfds , wfds , efds ;
798+ php_growable_fd_set_init (& rfds , FD_SETSIZE );
799+ php_growable_fd_set_init (& wfds , FD_SETSIZE );
800+ php_growable_fd_set_init (& efds , FD_SETSIZE ) ;
809801
802+ php_socket_t max_fd = 0 ;
803+ int sets = 0 ;
810804 if (r_array != NULL) {
811- set_count = stream_array_to_fd_set (Z_ARR_P (r_array ), & rfds , & max_fd );
812- if (set_count > max_set_count )
813- max_set_count = set_count ;
814- sets += set_count ;
805+ sets += stream_array_to_fd_set (Z_ARR_P (r_array ), & rfds , & max_fd );
815806 }
816-
817807 if (w_array != NULL ) {
818- set_count = stream_array_to_fd_set (Z_ARR_P (w_array ), & wfds , & max_fd );
819- if (set_count > max_set_count )
820- max_set_count = set_count ;
821- sets += set_count ;
808+ sets += stream_array_to_fd_set (Z_ARR_P (w_array ), & wfds , & max_fd );
822809 }
823-
824810 if (e_array != NULL ) {
825- set_count = stream_array_to_fd_set (Z_ARR_P (e_array ), & efds , & max_fd );
826- if (set_count > max_set_count )
827- max_set_count = set_count ;
828- sets += set_count ;
811+ sets += stream_array_to_fd_set (Z_ARR_P (e_array ), & efds , & max_fd );
829812 }
830813
831814 if (!sets ) {
832815 php_stream_error_operation_end (context );
833816 zend_value_error ("No stream arrays were passed" );
834- RETURN_THROWS ();
835- }
836-
837- if (!PHP_SAFE_MAX_FD (max_fd , max_set_count )) {
838- RETURN_FALSE ;
817+ goto cleanup ;
839818 }
840819
841820 if (secnull && !usecnull ) {
842821 if (usec != 0 ) {
843822 php_stream_error_operation_end (context );
844823 zend_argument_value_error (5 , "must be null when argument #4 ($seconds) is null" );
845- RETURN_THROWS () ;
824+ goto cleanup ;
846825 }
847826 }
848827
849828 /* If seconds is not set to null, build the timeval, else we wait indefinitely */
829+ struct timeval tv , * tv_p = NULL ;
850830 if (!secnull ) {
851831 if (sec < 0 ) {
852832 php_stream_error_operation_end (context );
853833 zend_argument_value_error (4 , "must be greater than or equal to 0" );
854- RETURN_THROWS () ;
834+ goto cleanup ;
855835 } else if (usec < 0 ) {
856836 php_stream_error_operation_end (context );
857837 zend_argument_value_error (5 , "must be greater than or equal to 0" );
858- RETURN_THROWS () ;
838+ goto cleanup ;
859839 }
860840
861841 /* Windows, Solaris and BSD do not like microsecond values which are >= 1 sec */
@@ -867,6 +847,7 @@ PHP_FUNCTION(stream_select)
867847 /* slight hack to support buffered data; if there is data sitting in the
868848 * read buffer of any of the streams in the read array, let's pretend
869849 * that we selected, but return only the readable sockets */
850+ int retval ;
870851 if (r_array != NULL ) {
871852 retval = stream_array_emulate_read_fd_set (r_array );
872853 if (retval > 0 ) {
@@ -879,24 +860,37 @@ PHP_FUNCTION(stream_select)
879860 zval_ptr_dtor (e_array );
880861 ZVAL_EMPTY_ARRAY (e_array );
881862 }
882- RETURN_LONG (retval );
863+ RETVAL_LONG (retval );
864+ goto cleanup ;
883865 }
884866 }
885867
886- retval = php_select (max_fd + 1 , & rfds , & wfds , & efds , tv_p );
868+ #ifndef PHP_WIN32
869+ /* select() reads max_fd + 1 bits of each set */
870+ php_growable_fd_set_reserve (& rfds , max_fd + 1 );
871+ php_growable_fd_set_reserve (& wfds , max_fd + 1 );
872+ php_growable_fd_set_reserve (& efds , max_fd + 1 );
873+ #endif
874+ retval = php_select (max_fd + 1 , rfds .set , wfds .set , efds .set , tv_p );
887875 php_stream_error_operation_end (context );
888876
889877 if (retval == -1 ) {
890878 php_error_docref (NULL , E_WARNING , "Unable to select [%d]: %s (max_fd=" PHP_SOCKET_FMT ")" ,
891879 errno , strerror (errno ), max_fd );
892- RETURN_FALSE ;
880+ RETVAL_FALSE ;
881+ goto cleanup ;
893882 }
894883
895884 if (r_array != NULL ) stream_array_from_fd_set (r_array , & rfds );
896885 if (w_array != NULL ) stream_array_from_fd_set (w_array , & wfds );
897886 if (e_array != NULL ) stream_array_from_fd_set (e_array , & efds );
898887
899- RETURN_LONG (retval );
888+ RETVAL_LONG (retval );
889+
890+ cleanup :
891+ php_growable_fd_set_destroy (& rfds );
892+ php_growable_fd_set_destroy (& wfds );
893+ php_growable_fd_set_destroy (& efds );
900894}
901895/* }}} */
902896
0 commit comments