root/ext/curl/multi.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. PHP_FUNCTION
  2. PHP_FUNCTION
  3. _php_curl_multi_cleanup_list
  4. curl_compare_resources
  5. PHP_FUNCTION
  6. _make_timeval_struct
  7. PHP_FUNCTION
  8. PHP_FUNCTION
  9. PHP_FUNCTION
  10. PHP_FUNCTION
  11. PHP_FUNCTION
  12. _php_curl_multi_close
  13. PHP_FUNCTION
  14. _php_curl_multi_setopt
  15. PHP_FUNCTION

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 5                                                        |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1997-2016 The PHP Group                                |
   6    +----------------------------------------------------------------------+
   7    | This source file is subject to version 3.01 of the PHP license,      |
   8    | that is bundled with this package in the file LICENSE, and is        |
   9    | available through the world-wide-web at the following url:           |
  10    | http://www.php.net/license/3_01.txt                                  |
  11    | If you did not receive a copy of the PHP license and are unable to   |
  12    | obtain it through the world-wide-web, please send a note to          |
  13    | license@php.net so we can mail you a copy immediately.               |
  14    +----------------------------------------------------------------------+
  15    | Author: Sterling Hughes <sterling@php.net>                           |
  16    +----------------------------------------------------------------------+
  17 */
  18 
  19 /* $Id$ */
  20 
  21 #define ZEND_INCLUDE_FULL_WINDOWS_HEADERS
  22 
  23 #ifdef HAVE_CONFIG_H
  24 #include "config.h"
  25 #endif
  26 
  27 #include "php.h"
  28 
  29 #if HAVE_CURL
  30 
  31 #include "php_curl.h"
  32 
  33 #include <curl/curl.h>
  34 #include <curl/multi.h>
  35 
  36 #ifdef HAVE_SYS_SELECT_H
  37 #include <sys/select.h>
  38 #endif
  39 
  40 #ifdef HAVE_SYS_TIME_H
  41 #include <sys/time.h>
  42 #endif
  43 
  44 #ifdef HAVE_SYS_TYPES_H
  45 #include <sys/types.h>
  46 #endif
  47 
  48 #ifdef HAVE_UNISTD_H
  49 #include <unistd.h>
  50 #endif
  51 
  52 /* {{{ proto resource curl_multi_init(void)
  53    Returns a new cURL multi handle */
  54 PHP_FUNCTION(curl_multi_init)
  55 {
  56         php_curlm *mh;
  57         
  58         if (zend_parse_parameters_none() == FAILURE) {
  59                 return;
  60         }
  61 
  62         mh = ecalloc(1, sizeof(php_curlm));
  63         mh->multi = curl_multi_init();
  64 
  65         zend_llist_init(&mh->easyh, sizeof(zval), _php_curl_multi_cleanup_list, 0);
  66 
  67         ZEND_REGISTER_RESOURCE(return_value, mh, le_curl_multi_handle);
  68 }
  69 /* }}} */
  70 
  71 /* {{{ proto int curl_multi_add_handle(resource mh, resource ch)
  72    Add a normal cURL handle to a cURL multi handle */
  73 PHP_FUNCTION(curl_multi_add_handle)
  74 {
  75         zval      *z_mh;
  76         zval      *z_ch;
  77         php_curlm *mh;
  78         php_curl  *ch;
  79         zval tmp_val;
  80 
  81         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr", &z_mh, &z_ch) == FAILURE) {
  82                 return;
  83         }
  84 
  85         ZEND_FETCH_RESOURCE(mh, php_curlm *, &z_mh, -1, le_curl_multi_handle_name, le_curl_multi_handle);
  86         ZEND_FETCH_RESOURCE(ch, php_curl *, &z_ch, -1, le_curl_name, le_curl);
  87 
  88         _php_curl_cleanup_handle(ch);
  89 
  90         /* we want to create a copy of this zval that we store in the multihandle structure element "easyh" */
  91         tmp_val = *z_ch;
  92         zval_copy_ctor(&tmp_val);
  93 
  94         zend_llist_add_element(&mh->easyh, &tmp_val);
  95 
  96         RETURN_LONG((long) curl_multi_add_handle(mh->multi, ch->cp));   
  97 }
  98 /* }}} */
  99 
 100 void _php_curl_multi_cleanup_list(void *data) /* {{{ */
 101 {
 102         zval *z_ch = (zval *)data;
 103         php_curl *ch;
 104         TSRMLS_FETCH();
 105 
 106         if (!z_ch) {
 107                 return;
 108         }
 109         
 110         ch = (php_curl *) zend_fetch_resource(&z_ch TSRMLS_CC, -1, le_curl_name, NULL, 1, le_curl);
 111         if (!ch) {
 112                 return;
 113         }
 114 
 115         zend_list_delete(Z_LVAL_P(z_ch));
 116 }
 117 /* }}} */
 118 
 119 /* Used internally as comparison routine passed to zend_list_del_element */
 120 static int curl_compare_resources( zval *z1, zval **z2 ) /* {{{ */
 121 {
 122         return (Z_TYPE_P( z1 ) == Z_TYPE_PP( z2 ) && 
 123                         Z_TYPE_P( z1 ) == IS_RESOURCE     &&
 124                         Z_LVAL_P( z1 ) == Z_LVAL_PP( z2 ) );
 125 }
 126 /* }}} */
 127 
 128 /* {{{ proto int curl_multi_remove_handle(resource mh, resource ch)
 129    Remove a multi handle from a set of cURL handles */
 130 PHP_FUNCTION(curl_multi_remove_handle)
 131 {
 132         zval      *z_mh;
 133         zval      *z_ch;
 134         php_curlm *mh;
 135         php_curl  *ch;
 136 
 137         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr", &z_mh, &z_ch) == FAILURE) {
 138                 return;
 139         }
 140 
 141         ZEND_FETCH_RESOURCE(mh, php_curlm *, &z_mh, -1, le_curl_multi_handle_name, le_curl_multi_handle);
 142         ZEND_FETCH_RESOURCE(ch, php_curl *, &z_ch, -1, le_curl_name, le_curl);
 143 
 144 
 145 
 146         RETVAL_LONG((long) curl_multi_remove_handle(mh->multi, ch->cp));
 147         zend_llist_del_element( &mh->easyh, &z_ch, 
 148                                                         (int (*)(void *, void *)) curl_compare_resources );
 149 
 150 }
 151 /* }}} */
 152 
 153 static void _make_timeval_struct(struct timeval *to, double timeout) /* {{{ */
 154 {
 155         unsigned long conv;
 156 
 157         conv = (unsigned long) (timeout * 1000000.0);
 158         to->tv_sec = conv / 1000000;
 159         to->tv_usec = conv % 1000000;
 160 }
 161 /* }}} */
 162 
 163 /* {{{ proto int curl_multi_select(resource mh[, double timeout])
 164    Get all the sockets associated with the cURL extension, which can then be "selected" */
 165 PHP_FUNCTION(curl_multi_select)
 166 {
 167         zval           *z_mh;
 168         php_curlm      *mh;
 169         fd_set          readfds;
 170         fd_set          writefds;
 171         fd_set          exceptfds;
 172         int             maxfd;
 173         double          timeout = 1.0;
 174         struct timeval  to;
 175 
 176         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|d", &z_mh, &timeout) == FAILURE) {
 177                 return;
 178         }
 179 
 180         ZEND_FETCH_RESOURCE(mh, php_curlm *, &z_mh, -1, le_curl_multi_handle_name, le_curl_multi_handle);
 181 
 182         _make_timeval_struct(&to, timeout);
 183         
 184         FD_ZERO(&readfds);
 185         FD_ZERO(&writefds);
 186         FD_ZERO(&exceptfds);
 187 
 188         curl_multi_fdset(mh->multi, &readfds, &writefds, &exceptfds, &maxfd);
 189         if (maxfd == -1) {
 190                 RETURN_LONG(-1);
 191         }
 192         RETURN_LONG(select(maxfd + 1, &readfds, &writefds, &exceptfds, &to));
 193 }
 194 /* }}} */
 195 
 196 /* {{{ proto int curl_multi_exec(resource mh, int &still_running) 
 197    Run the sub-connections of the current cURL handle */
 198 PHP_FUNCTION(curl_multi_exec)
 199 {
 200         zval      *z_mh;
 201         zval      *z_still_running;
 202         php_curlm *mh;
 203         int        still_running;
 204         int        result;
 205 
 206         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz", &z_mh, &z_still_running) == FAILURE) {
 207                 return;
 208         }
 209 
 210         ZEND_FETCH_RESOURCE(mh, php_curlm *, &z_mh, -1, le_curl_multi_handle_name, le_curl_multi_handle);
 211 
 212         {
 213                 zend_llist_position pos;
 214                 php_curl *ch;
 215                 zval    *pz_ch;
 216 
 217                 for(pz_ch = (zval *)zend_llist_get_first_ex(&mh->easyh, &pos); pz_ch;
 218                         pz_ch = (zval *)zend_llist_get_next_ex(&mh->easyh, &pos)) {
 219 
 220                         ZEND_FETCH_RESOURCE(ch, php_curl *, &pz_ch, -1, le_curl_name, le_curl);
 221                         _php_curl_verify_handlers(ch, 1 TSRMLS_CC);
 222                 }
 223         }
 224 
 225         convert_to_long_ex(&z_still_running);
 226         still_running = Z_LVAL_P(z_still_running);
 227         result = curl_multi_perform(mh->multi, &still_running);
 228         ZVAL_LONG(z_still_running, still_running);
 229 
 230         RETURN_LONG(result);
 231 }
 232 /* }}} */
 233 
 234 /* {{{ proto string curl_multi_getcontent(resource ch)
 235    Return the content of a cURL handle if CURLOPT_RETURNTRANSFER is set */
 236 PHP_FUNCTION(curl_multi_getcontent)
 237 {
 238         zval     *z_ch;
 239         php_curl *ch;
 240 
 241         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &z_ch) == FAILURE) {
 242                 return;
 243         }
 244 
 245         ZEND_FETCH_RESOURCE(ch, php_curl *, &z_ch, -1, le_curl_name, le_curl);
 246 
 247         if (ch->handlers->write->method == PHP_CURL_RETURN) {
 248                 if (ch->handlers->write->buf.len == 0) {
 249                         RETURN_EMPTY_STRING();
 250                 }
 251                 smart_str_0(&ch->handlers->write->buf);
 252                 RETURN_STRINGL(ch->handlers->write->buf.c, ch->handlers->write->buf.len, 1);
 253         }
 254 
 255         RETURN_NULL();
 256 }
 257 /* }}} */
 258 
 259 /* {{{ proto array curl_multi_info_read(resource mh [, long msgs_in_queue])
 260    Get information about the current transfers */
 261 PHP_FUNCTION(curl_multi_info_read)
 262 {
 263         zval      *z_mh;
 264         php_curlm *mh;
 265         CURLMsg   *tmp_msg;
 266         int        queued_msgs;
 267         zval      *zmsgs_in_queue = NULL;
 268 
 269         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|z", &z_mh, &zmsgs_in_queue) == FAILURE) {
 270                 return;
 271         }
 272 
 273         ZEND_FETCH_RESOURCE(mh, php_curlm *, &z_mh, -1, le_curl_multi_handle_name, le_curl_multi_handle);
 274 
 275         tmp_msg = curl_multi_info_read(mh->multi, &queued_msgs);
 276         if (tmp_msg == NULL) {
 277                 RETURN_FALSE;
 278         }
 279         if (zmsgs_in_queue) {
 280                 zval_dtor(zmsgs_in_queue);
 281                 ZVAL_LONG(zmsgs_in_queue, queued_msgs);
 282         }
 283 
 284         array_init(return_value);
 285         add_assoc_long(return_value, "msg", tmp_msg->msg);
 286         add_assoc_long(return_value, "result", tmp_msg->data.result);
 287 
 288         /* find the original easy curl handle */
 289         {
 290                 zend_llist_position pos;
 291                 php_curl *ch;
 292                 zval    *pz_ch;
 293 
 294                 /* search the list of easy handles hanging off the multi-handle */
 295                 for(pz_ch = (zval *)zend_llist_get_first_ex(&mh->easyh, &pos); pz_ch;
 296                         pz_ch = (zval *)zend_llist_get_next_ex(&mh->easyh, &pos)) {
 297                         ZEND_FETCH_RESOURCE(ch, php_curl *, &pz_ch, -1, le_curl_name, le_curl);
 298                         if (ch->cp == tmp_msg->easy_handle) {
 299 
 300                                 /* we are adding a reference to the underlying php_curl
 301                                    resource, so we need to add one to the resource's refcount 
 302                                    in order to ensure it doesn't get destroyed when the 
 303                                    underlying curl easy handle goes out of scope.
 304                                    Normally you would call zval_copy_ctor( pz_ch ), or
 305                                    SEPARATE_ZVAL, but those create new zvals, which is already
 306                                    being done in add_assoc_resource */
 307 
 308                                 zend_list_addref( Z_RESVAL_P( pz_ch ) );
 309 
 310                                 /* add_assoc_resource automatically creates a new zval to 
 311                                    wrap the "resource" represented by the current pz_ch */
 312 
 313                                 add_assoc_resource(return_value, "handle", Z_RESVAL_P(pz_ch));
 314 
 315                                 break;
 316                         }
 317                 }
 318         }
 319 }
 320 /* }}} */
 321 
 322 /* {{{ proto void curl_multi_close(resource mh)
 323    Close a set of cURL handles */
 324 PHP_FUNCTION(curl_multi_close)
 325 {
 326         zval      *z_mh;
 327         php_curlm *mh;
 328 
 329         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &z_mh) == FAILURE) {
 330                 return;
 331         }
 332 
 333         ZEND_FETCH_RESOURCE(mh, php_curlm *, &z_mh, -1, le_curl_multi_handle_name, le_curl_multi_handle);
 334 
 335         zend_list_delete(Z_LVAL_P(z_mh));
 336 }
 337 /* }}} */
 338 
 339 void _php_curl_multi_close(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
 340 {
 341         php_curlm *mh = (php_curlm *) rsrc->ptr;
 342         if (mh) {
 343                 zend_llist_position pos;
 344                 php_curl *ch;
 345                 zval    *pz_ch;
 346 
 347                 for(pz_ch = (zval *)zend_llist_get_first_ex(&mh->easyh, &pos); pz_ch;
 348                         pz_ch = (zval *)zend_llist_get_next_ex(&mh->easyh, &pos)) {
 349 
 350                         ch = (php_curl *) zend_fetch_resource(&pz_ch TSRMLS_CC, -1, le_curl_name, NULL, 1, le_curl);
 351                         _php_curl_verify_handlers(ch, 0 TSRMLS_CC);
 352                 }
 353 
 354                 curl_multi_cleanup(mh->multi);
 355                 zend_llist_clean(&mh->easyh);
 356                 efree(mh);
 357                 rsrc->ptr = NULL;
 358         }
 359 }
 360 /* }}} */
 361 
 362 #if LIBCURL_VERSION_NUM >= 0x070c00 /* Available since 7.12.0 */
 363 /* {{{ proto bool curl_multi_strerror(int code)
 364          return string describing error code */
 365 PHP_FUNCTION(curl_multi_strerror)
 366 {
 367         long code;
 368         const char *str;
 369 
 370         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &code) == FAILURE) {
 371                 return;
 372         }
 373 
 374         str = curl_multi_strerror(code);
 375         if (str) {
 376                 RETURN_STRING(str, 1);
 377         } else {
 378                 RETURN_NULL();
 379         }
 380 }
 381 /* }}} */
 382 #endif
 383 
 384 #if LIBCURL_VERSION_NUM >= 0x070f04 /* 7.15.4 */
 385 static int _php_curl_multi_setopt(php_curlm *mh, long option, zval **zvalue, zval *return_value TSRMLS_DC) /* {{{ */
 386 { 
 387         CURLMcode error = CURLM_OK;
 388 
 389         switch (option) {
 390 #if LIBCURL_VERSION_NUM >= 0x071000 /* 7.16.0 */
 391                 case CURLMOPT_PIPELINING:
 392 #endif
 393 #if LIBCURL_VERSION_NUM >= 0x071003 /* 7.16.3 */
 394                 case CURLMOPT_MAXCONNECTS:
 395 #endif
 396                         convert_to_long_ex(zvalue);
 397                         error = curl_multi_setopt(mh->multi, option, Z_LVAL_PP(zvalue));
 398                         break;
 399 
 400                 default:
 401                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid curl multi configuration option");
 402                         error = CURLM_UNKNOWN_OPTION;
 403                         break;
 404         }
 405 
 406         if (error != CURLM_OK) {
 407                 return 1;
 408         } else {
 409                 return 0;
 410         }
 411 }
 412 /* }}} */
 413 
 414 /* {{{ proto int curl_multi_setopt(resource mh, int option, mixed value)
 415        Set an option for the curl multi handle */
 416 PHP_FUNCTION(curl_multi_setopt)
 417 {
 418         zval       *z_mh, **zvalue;
 419         long        options;
 420         php_curlm *mh;
 421 
 422         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlZ", &z_mh, &options, &zvalue) == FAILURE) {
 423                 return;
 424         }
 425 
 426         ZEND_FETCH_RESOURCE(mh, php_curlm *, &z_mh, -1, le_curl_multi_handle_name, le_curl_multi_handle);
 427 
 428         if (!_php_curl_multi_setopt(mh, options, zvalue, return_value TSRMLS_CC)) {
 429                 RETURN_TRUE;
 430         } else {
 431                 RETURN_FALSE;
 432         }
 433 }
 434 /* }}} */
 435 #endif
 436 
 437 #endif
 438 
 439 /*
 440  * Local variables:
 441  * tab-width: 4
 442  * c-basic-offset: 4
 443  * End:
 444  * vim600: noet sw=4 ts=4 fdm=marker
 445  * vim<600: noet sw=4 ts=4
 446  */

/* [<][>][^][v][top][bottom][index][help] */