Skip to content

Commit 5842e34

Browse files
committed
socket functions initial import
1 parent 17d4002 commit 5842e34

File tree

4 files changed

+237
-1
lines changed

4 files changed

+237
-1
lines changed

ext/curl/curl.stub.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2713,6 +2713,56 @@
27132713
* @cvalue CURLMOPT_PUSHFUNCTION
27142714
*/
27152715
const CURLMOPT_PUSHFUNCTION = UNKNOWN;
2716+
/**
2717+
* @var int
2718+
* @cvalue CURLMOPT_SOCKETFUNCTION
2719+
*/
2720+
const CURLMOPT_SOCKETFUNCTION = UNKNOWN;
2721+
/**
2722+
* @var int
2723+
* @cvalue CURLMOPT_TIMERFUNCTION
2724+
*/
2725+
const CURLMOPT_TIMERFUNCTION = UNKNOWN;
2726+
/**
2727+
* @var int
2728+
* @cvalue CURL_POLL_IN
2729+
*/
2730+
const CURL_POLL_IN = UNKNOWN;
2731+
/**
2732+
* @var int
2733+
* @cvalue CURL_POLL_OUT
2734+
*/
2735+
const CURL_POLL_OUT = UNKNOWN;
2736+
/**
2737+
* @var int
2738+
* @cvalue CURL_POLL_INOUT
2739+
*/
2740+
const CURL_POLL_INOUT = UNKNOWN;
2741+
/**
2742+
* @var int
2743+
* @cvalue CURL_POLL_REMOVE
2744+
*/
2745+
const CURL_POLL_REMOVE = UNKNOWN;
2746+
/**
2747+
* @var int
2748+
* @cvalue CURL_CSELECT_IN
2749+
*/
2750+
const CURL_CSELECT_IN = UNKNOWN;
2751+
/**
2752+
* @var int
2753+
* @cvalue CURL_CSELECT_OUT
2754+
*/
2755+
const CURL_CSELECT_OUT = UNKNOWN;
2756+
/**
2757+
* @var int
2758+
* @cvalue CURL_CSELECT_ERR
2759+
*/
2760+
const CURL_CSELECT_ERR = UNKNOWN;
2761+
/**
2762+
* @var int
2763+
* @cvalue CURL_SOCKET_TIMEOUT
2764+
*/
2765+
const CURL_SOCKET_TIMEOUT = UNKNOWN;
27162766
/**
27172767
* @var int
27182768
* @cvalue CURL_PUSH_OK
@@ -3759,6 +3809,9 @@ function curl_unescape(CurlHandle $handle, string $string): string|false {}
37593809

37603810
function curl_multi_setopt(CurlMultiHandle $multi_handle, int $option, mixed $value): bool {}
37613811

3812+
/** @param mixed $socket */
3813+
function curl_multi_socket_action(CurlMultiHandle $multi_handle, $socket, int $what, int &$still_running): int {};
3814+
37623815
function curl_exec(CurlHandle $handle): string|bool {}
37633816

37643817
/** @refcount 1 */

ext/curl/curl_arginfo.h

Lines changed: 20 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/curl/curl_private.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ typedef struct {
123123

124124
typedef struct {
125125
zend_fcall_info_cache server_push;
126+
zend_fcall_info_cache socket_function;
127+
zend_fcall_info_cache timer_function;
126128
} php_curlm_handlers;
127129

128130
typedef struct {

ext/curl/multi.c

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
451554
static 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

Comments
 (0)