@@ -448,6 +448,109 @@ static int _php_server_push_callback(CURL *parent_ch, CURL *easy, size_t num_hea
448448}
449449/* }}} */
450450
451+ /* {{{ */
452+ PHP_FUNCTION (curl_multi_socket_action )
453+ {
454+ zval * z_mh ;
455+ zval * z_socket ;
456+ zend_long ev_bitmask ;
457+ zval * z_still_running ;
458+
459+ ZEND_PARSE_PARAMETERS_START (4 ,4 )
460+ Z_PARAM_OBJECT_OF_CLASS (z_mh , curl_multi_ce )
461+ Z_PARAM_ZVAL (z_socket )
462+ Z_PARAM_LONG (ev_bitmask )
463+ Z_PARAM_ZVAL (z_still_running )
464+ ZEND_PARSE_PARAMETERS_END ();
465+
466+ php_curlm * mh = Z_CURL_MULTI_P (z_mh );
467+
468+ curl_socket_t socket ;
469+
470+ if (Z_TYPE_P (z_socket ) == IS_LONG ) {
471+ socket = (curl_socket_t ) Z_LVAL_P (z_socket );
472+ } else {
473+ php_stream * p_stream ;
474+ php_stream_from_zval (p_stream , z_socket );
475+ if (php_stream_cast (
476+ p_stream , PHP_STREAM_AS_FD ,
477+ (void * * ) & socket , REPORT_ERRORS ) != SUCCESS ) {
478+ return ;
479+ }
480+ }
481+
482+ int still_running = zval_get_long (z_still_running );
483+ CURLMcode error = curl_multi_socket_action (
484+ mh -> multi , socket , ev_bitmask , & still_running );
485+ ZEND_TRY_ASSIGN_REF_LONG (z_still_running , still_running );
486+
487+ SAVE_CURLM_ERROR (mh , error );
488+ RETURN_LONG ((zend_long ) error );
489+ }
490+
491+ static int _php_curl_multi_timerfunction (CURLM * multi , zend_long timeout , void * userp ) {
492+ php_curlm * mh = (php_curlm * ) userp ;
493+
494+ zval z_object ;
495+ ZVAL_OBJ_COPY (& z_object , & mh -> std );
496+
497+ zval z_timeout ;
498+ ZVAL_LONG (& z_timeout , timeout );
499+
500+ zval call_args [2 ] = {z_object , z_timeout };
501+ zval retval ;
502+ zend_call_known_fcc (& mh -> handlers .timer_function , & retval , /* param_count */ 2 , call_args , /* named_params */ NULL );
503+
504+ if (!Z_ISUNDEF (retval )) {
505+ zval_ptr_dtor (& retval );
506+ }
507+
508+ zval_ptr_dtor (& z_object );
509+ return SUCCESS ;
510+ }
511+
512+ static int _php_curl_multi_socketfunction (CURL * easy , curl_socket_t socket , int what , void * userp , void * stream ) {
513+ php_curlm * mh = (php_curlm * ) userp ;
514+ php_stream * p_stream ;
515+
516+ if (stream == NULL && what != CURL_POLL_REMOVE ) {
517+ p_stream = (void * ) php_stream_fopen_from_fd (socket , "rw" , NULL );
518+ if (!p_stream ) {
519+ return FAILURE ;
520+ }
521+
522+ if (curl_multi_assign (mh -> multi , socket , p_stream ) != CURLM_OK ) {
523+ php_stream_close (p_stream );
524+ return FAILURE ;
525+ }
526+ } else {
527+ p_stream = (php_stream * ) stream ;
528+ }
529+
530+ zval z_stream ;
531+ php_stream_to_zval (p_stream , & z_stream );
532+
533+ zval * z_easy = _php_curl_multi_find_easy_handle (mh , easy );
534+
535+ zval z_what ;
536+ ZVAL_LONG (& z_what , what );
537+ zval call_args [3 ] = {* z_easy , z_stream , z_what };
538+ zval retval ;
539+ zend_call_known_fcc (& mh -> handlers .socket_function , & retval , /* param_count */ 3 , call_args , /* named_params */ NULL );
540+
541+ if (!Z_ISUNDEF (retval )) {
542+ zval_ptr_dtor (& retval );
543+ }
544+
545+ if (what == CURL_POLL_REMOVE && p_stream != NULL ) {
546+ curl_multi_assign (mh -> multi , socket , NULL );
547+ php_stream_close (p_stream );
548+ }
549+
550+ return SUCCESS ;
551+ }
552+ /* }}} */
553+
451554static bool _php_curl_multi_setopt (php_curlm * mh , zend_long option , zval * zvalue , zval * return_value ) /* {{{ */
452555{
453556 CURLMcode error = CURLM_OK ;
@@ -499,6 +602,49 @@ static bool _php_curl_multi_setopt(php_curlm *mh, zend_long option, zval *zvalue
499602 error = curl_multi_setopt (mh -> multi , CURLMOPT_PUSHDATA , mh );
500603 break ;
501604 }
605+ case CURLMOPT_SOCKETFUNCTION : {
606+ if (ZEND_FCC_INITIALIZED (mh -> handlers .socket_function )) {
607+ zend_fcc_dtor (& mh -> handlers .socket_function );
608+ }
609+
610+ char * error_str = NULL ;
611+ if (UNEXPECTED (!zend_is_callable_ex (zvalue , /* object */ NULL , /* check_flags */ 0 , /* callable_name */ NULL , & mh -> handlers .socket_function , /* error */ & error_str ))) {
612+ if (!EG (exception )) {
613+ zend_argument_type_error (2 , "must be a valid callback for option CURLMOPT_SOCKETFUNCTION, %s" , error_str );
614+ }
615+ efree (error_str );
616+ return false;
617+ }
618+ zend_fcc_addref (& mh -> handlers .socket_function );
619+
620+ error = curl_multi_setopt (mh -> multi , CURLMOPT_SOCKETFUNCTION , _php_curl_multi_socketfunction );
621+ if (error != CURLM_OK ) {
622+ return false;
623+ }
624+ error = curl_multi_setopt (mh -> multi , CURLMOPT_SOCKETDATA , mh );
625+ break ;
626+ }
627+ case CURLMOPT_TIMERFUNCTION : {
628+ if (ZEND_FCC_INITIALIZED (mh -> handlers .timer_function )) {
629+ zend_fcc_dtor (& mh -> handlers .timer_function );
630+ }
631+
632+ char * error_str = NULL ;
633+ if (UNEXPECTED (!zend_is_callable_ex (zvalue , /* object */ NULL , /* check_flags */ 0 , /* callable_name */ NULL , & mh -> handlers .timer_function , /* error */ & error_str ))) {
634+ if (!EG (exception )) {
635+ zend_argument_type_error (2 , "must be a valid callback for option CURLMOPT_TIMERFUNCTION, %s" , error_str );
636+ }
637+ efree (error_str );
638+ return false;
639+ }
640+ zend_fcc_addref (& mh -> handlers .timer_function );
641+ error = curl_multi_setopt (mh -> multi , CURLMOPT_TIMERFUNCTION , _php_curl_multi_timerfunction );
642+ if (error != CURLM_OK ) {
643+ return false;
644+ }
645+ error = curl_multi_setopt (mh -> multi , CURLMOPT_TIMERDATA , mh );
646+ break ;
647+ }
502648 default :
503649 zend_argument_value_error (2 , "is not a valid cURL multi option" );
504650 error = CURLM_UNKNOWN_OPTION ;
@@ -575,6 +721,14 @@ static void curl_multi_free_obj(zend_object *object)
575721 zend_fcc_dtor (& mh -> handlers .server_push );
576722 }
577723
724+ if (ZEND_FCC_INITIALIZED (mh -> handlers .timer_function )) {
725+ zend_fcc_dtor (& mh -> handlers .timer_function );
726+ }
727+
728+ if (ZEND_FCC_INITIALIZED (mh -> handlers .socket_function )) {
729+ zend_fcc_dtor (& mh -> handlers .socket_function );
730+ }
731+
578732 zend_object_std_dtor (& mh -> std );
579733}
580734
@@ -588,6 +742,14 @@ static HashTable *curl_multi_get_gc(zend_object *object, zval **table, int *n)
588742 zend_get_gc_buffer_add_fcc (gc_buffer , & curl_multi -> handlers .server_push );
589743 }
590744
745+ if (ZEND_FCC_INITIALIZED (curl_multi -> handlers .timer_function )) {
746+ zend_get_gc_buffer_add_fcc (gc_buffer , & curl_multi -> handlers .timer_function );
747+ }
748+
749+ if (ZEND_FCC_INITIALIZED (curl_multi -> handlers .socket_function )) {
750+ zend_get_gc_buffer_add_fcc (gc_buffer , & curl_multi -> handlers .socket_function );
751+ }
752+
591753 zend_llist_position pos ;
592754 for (zval * pz_ch = (zval * ) zend_llist_get_first_ex (& curl_multi -> easyh , & pos ); pz_ch ;
593755 pz_ch = (zval * ) zend_llist_get_next_ex (& curl_multi -> easyh , & pos )) {
0 commit comments