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 7                                                        |
   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         RETURN_RES(zend_register_resource(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(), "rr", &z_mh, &z_ch) == FAILURE) {
  82                 return;
  83         }
  84 
  85         if ((mh = (php_curlm *)zend_fetch_resource(Z_RES_P(z_mh), le_curl_multi_handle_name, le_curl_multi_handle)) == NULL) {
  86                 RETURN_FALSE;
  87         }
  88 
  89         if ((ch = (php_curl *)zend_fetch_resource(Z_RES_P(z_ch), le_curl_name, le_curl)) == NULL) {
  90                 RETURN_FALSE;
  91         }
  92 
  93         _php_curl_cleanup_handle(ch);
  94 
  95         /* we want to create a copy of this zval that we store in the multihandle structure element "easyh" */
  96         ZVAL_DUP(&tmp_val, z_ch);
  97 
  98         zend_llist_add_element(&mh->easyh, &tmp_val);
  99 
 100         RETURN_LONG((zend_long)curl_multi_add_handle(mh->multi, ch->cp));
 101 }
 102 /* }}} */
 103 
 104 void _php_curl_multi_cleanup_list(void *data) /* {{{ */
 105 {
 106         zval *z_ch = (zval *)data;
 107         php_curl *ch;
 108 
 109         if (!z_ch) {
 110                 return;
 111         }
 112         if (!Z_RES_P(z_ch)->ptr) {
 113                 return;
 114         }
 115         if ((ch = (php_curl *)zend_fetch_resource(Z_RES_P(z_ch), le_curl_name, le_curl)) == NULL) {
 116                 return;
 117         }
 118 
 119         zend_list_delete(Z_RES_P(z_ch));
 120 }
 121 /* }}} */
 122 
 123 /* Used internally as comparison routine passed to zend_list_del_element */
 124 static int curl_compare_resources( zval *z1, zval *z2 ) /* {{{ */
 125 {
 126         return (Z_TYPE_P(z1) == Z_TYPE_P(z2) &&
 127                         Z_TYPE_P(z1) == IS_RESOURCE &&
 128                         Z_RES_P(z1) == Z_RES_P(z2));
 129 }
 130 /* }}} */
 131 
 132 /* {{{ proto int curl_multi_remove_handle(resource mh, resource ch)
 133    Remove a multi handle from a set of cURL handles */
 134 PHP_FUNCTION(curl_multi_remove_handle)
 135 {
 136         zval      *z_mh;
 137         zval      *z_ch;
 138         php_curlm *mh;
 139         php_curl  *ch;
 140 
 141         if (zend_parse_parameters(ZEND_NUM_ARGS(), "rr", &z_mh, &z_ch) == FAILURE) {
 142                 return;
 143         }
 144 
 145         if ((mh = (php_curlm *)zend_fetch_resource(Z_RES_P(z_mh), le_curl_multi_handle_name, le_curl_multi_handle)) == NULL) {
 146                 RETURN_FALSE;
 147         }
 148 
 149         if ((ch = (php_curl *)zend_fetch_resource(Z_RES_P(z_ch), le_curl_name, le_curl)) == NULL) {
 150                 RETURN_FALSE;
 151         }
 152 
 153         RETVAL_LONG((zend_long)curl_multi_remove_handle(mh->multi, ch->cp));
 154         zend_llist_del_element(&mh->easyh, z_ch, (int (*)(void *, void *))curl_compare_resources);
 155 
 156 }
 157 /* }}} */
 158 
 159 static void _make_timeval_struct(struct timeval *to, double timeout) /* {{{ */
 160 {
 161         unsigned long conv;
 162 
 163         conv = (unsigned long) (timeout * 1000000.0);
 164         to->tv_sec = conv / 1000000;
 165         to->tv_usec = conv % 1000000;
 166 }
 167 /* }}} */
 168 
 169 /* {{{ proto int curl_multi_select(resource mh[, double timeout])
 170    Get all the sockets associated with the cURL extension, which can then be "selected" */
 171 PHP_FUNCTION(curl_multi_select)
 172 {
 173         zval           *z_mh;
 174         php_curlm      *mh;
 175         fd_set          readfds;
 176         fd_set          writefds;
 177         fd_set          exceptfds;
 178         int             maxfd;
 179         double          timeout = 1.0;
 180         struct timeval  to;
 181 
 182         if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|d", &z_mh, &timeout) == FAILURE) {
 183                 return;
 184         }
 185 
 186         if ((mh = (php_curlm *)zend_fetch_resource(Z_RES_P(z_mh), le_curl_multi_handle_name, le_curl_multi_handle)) == NULL) {
 187                 RETURN_FALSE;
 188         }
 189 
 190         _make_timeval_struct(&to, timeout);
 191 
 192         FD_ZERO(&readfds);
 193         FD_ZERO(&writefds);
 194         FD_ZERO(&exceptfds);
 195 
 196         curl_multi_fdset(mh->multi, &readfds, &writefds, &exceptfds, &maxfd);
 197         if (maxfd == -1) {
 198                 RETURN_LONG(-1);
 199         }
 200         RETURN_LONG(select(maxfd + 1, &readfds, &writefds, &exceptfds, &to));
 201 }
 202 /* }}} */
 203 
 204 /* {{{ proto int curl_multi_exec(resource mh, int &still_running)
 205    Run the sub-connections of the current cURL handle */
 206 PHP_FUNCTION(curl_multi_exec)
 207 {
 208         zval      *z_mh;
 209         zval      *z_still_running;
 210         php_curlm *mh;
 211         int        still_running;
 212         int        result;
 213 
 214         if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz/", &z_mh, &z_still_running) == FAILURE) {
 215                 return;
 216         }
 217 
 218         if ((mh = (php_curlm *)zend_fetch_resource(Z_RES_P(z_mh), le_curl_multi_handle_name, le_curl_multi_handle)) == NULL) {
 219                 RETURN_FALSE;
 220         }
 221 
 222         {
 223                 zend_llist_position pos;
 224                 php_curl *ch;
 225                 zval    *pz_ch;
 226 
 227                 for (pz_ch = (zval *)zend_llist_get_first_ex(&mh->easyh, &pos); pz_ch;
 228                         pz_ch = (zval *)zend_llist_get_next_ex(&mh->easyh, &pos)) {
 229 
 230                         if ((ch = (php_curl *)zend_fetch_resource(Z_RES_P(pz_ch), le_curl_name, le_curl)) == NULL) {
 231                                 RETURN_FALSE;
 232                         }
 233 
 234                         _php_curl_verify_handlers(ch, 1);
 235                 }
 236         }
 237 
 238         convert_to_long(z_still_running);
 239         still_running = Z_LVAL_P(z_still_running);
 240         result = curl_multi_perform(mh->multi, &still_running);
 241         ZVAL_LONG(z_still_running, still_running);
 242 
 243         RETURN_LONG(result);
 244 }
 245 /* }}} */
 246 
 247 /* {{{ proto string curl_multi_getcontent(resource ch)
 248    Return the content of a cURL handle if CURLOPT_RETURNTRANSFER is set */
 249 PHP_FUNCTION(curl_multi_getcontent)
 250 {
 251         zval     *z_ch;
 252         php_curl *ch;
 253 
 254         if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &z_ch) == FAILURE) {
 255                 return;
 256         }
 257 
 258         if ((ch = (php_curl *)zend_fetch_resource(Z_RES_P(z_ch), le_curl_name, le_curl)) == NULL) {
 259                 RETURN_FALSE;
 260         }
 261 
 262         if (ch->handlers->write->method == PHP_CURL_RETURN) {
 263                 if (!ch->handlers->write->buf.s) {
 264                         RETURN_EMPTY_STRING();
 265                 }
 266                 smart_str_0(&ch->handlers->write->buf);
 267                 RETURN_STR_COPY(ch->handlers->write->buf.s);
 268         }
 269 
 270         RETURN_NULL();
 271 }
 272 /* }}} */
 273 
 274 /* {{{ proto array curl_multi_info_read(resource mh [, long msgs_in_queue])
 275    Get information about the current transfers */
 276 PHP_FUNCTION(curl_multi_info_read)
 277 {
 278         zval      *z_mh;
 279         php_curlm *mh;
 280         CURLMsg   *tmp_msg;
 281         int        queued_msgs;
 282         zval      *zmsgs_in_queue = NULL;
 283 
 284         if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|z/", &z_mh, &zmsgs_in_queue) == FAILURE) {
 285                 return;
 286         }
 287 
 288         if ((mh = (php_curlm *)zend_fetch_resource(Z_RES_P(z_mh), le_curl_multi_handle_name, le_curl_multi_handle)) == NULL) {
 289                 RETURN_FALSE;
 290         }
 291 
 292         tmp_msg = curl_multi_info_read(mh->multi, &queued_msgs);
 293         if (tmp_msg == NULL) {
 294                 RETURN_FALSE;
 295         }
 296         if (zmsgs_in_queue) {
 297                 zval_dtor(zmsgs_in_queue);
 298                 ZVAL_LONG(zmsgs_in_queue, queued_msgs);
 299         }
 300 
 301         array_init(return_value);
 302         add_assoc_long(return_value, "msg", tmp_msg->msg);
 303         add_assoc_long(return_value, "result", tmp_msg->data.result);
 304 
 305         /* find the original easy curl handle */
 306         {
 307                 zend_llist_position pos;
 308                 php_curl *ch;
 309                 zval    *pz_ch;
 310 
 311                 /* search the list of easy handles hanging off the multi-handle */
 312                 for(pz_ch = (zval *)zend_llist_get_first_ex(&mh->easyh, &pos); pz_ch;
 313                         pz_ch = (zval *)zend_llist_get_next_ex(&mh->easyh, &pos)) {
 314 
 315                         if ((ch = (php_curl *)zend_fetch_resource(Z_RES_P(pz_ch), le_curl_name, le_curl)) == NULL) {
 316                                 RETURN_FALSE;
 317                         }
 318                         if (ch->cp == tmp_msg->easy_handle) {
 319 
 320                                 /* we are adding a reference to the underlying php_curl
 321                                    resource, so we need to add one to the resource's refcount
 322                                    in order to ensure it doesn't get destroyed when the
 323                                    underlying curl easy handle goes out of scope.
 324                                    Normally you would call zval_copy_ctor( pz_ch ), or
 325                                    SEPARATE_ZVAL, but those create new zvals, which is already
 326                                    being done in add_assoc_resource */
 327                                 Z_ADDREF_P(pz_ch);
 328 
 329                                 /* add_assoc_resource automatically creates a new zval to
 330                                    wrap the "resource" represented by the current pz_ch */
 331 
 332                                 add_assoc_zval(return_value, "handle", pz_ch);
 333 
 334                                 break;
 335                         }
 336                 }
 337         }
 338 }
 339 /* }}} */
 340 
 341 /* {{{ proto void curl_multi_close(resource mh)
 342    Close a set of cURL handles */
 343 PHP_FUNCTION(curl_multi_close)
 344 {
 345         zval      *z_mh;
 346         php_curlm *mh;
 347 
 348         if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &z_mh) == FAILURE) {
 349                 return;
 350         }
 351 
 352         if ((mh = (php_curlm *)zend_fetch_resource(Z_RES_P(z_mh), le_curl_multi_handle_name, le_curl_multi_handle)) == NULL) {
 353                 RETURN_FALSE;
 354         }
 355 
 356         zend_list_close(Z_RES_P(z_mh));
 357 }
 358 /* }}} */
 359 
 360 void _php_curl_multi_close(zend_resource *rsrc) /* {{{ */
 361 {
 362         php_curlm *mh = (php_curlm *)rsrc->ptr;
 363         if (mh) {
 364                 zend_llist_position pos;
 365                 php_curl *ch;
 366                 zval    *pz_ch;
 367 
 368                 for (pz_ch = (zval *)zend_llist_get_first_ex(&mh->easyh, &pos); pz_ch;
 369                         pz_ch = (zval *)zend_llist_get_next_ex(&mh->easyh, &pos)) {
 370                         /* ptr is NULL means it already be freed */
 371                         if (Z_RES_P(pz_ch)->ptr) {
 372                                 if ((ch = (php_curl *) zend_fetch_resource(Z_RES_P(pz_ch), le_curl_name, le_curl))) {
 373                                         _php_curl_verify_handlers(ch, 0);
 374                                 }
 375                         }
 376                 }
 377 
 378                 curl_multi_cleanup(mh->multi);
 379                 zend_llist_clean(&mh->easyh);
 380                 efree(mh);
 381                 rsrc->ptr = NULL;
 382         }
 383 }
 384 /* }}} */
 385 
 386 #if LIBCURL_VERSION_NUM >= 0x070c00 /* Available since 7.12.0 */
 387 /* {{{ proto bool curl_multi_strerror(int code)
 388          return string describing error code */
 389 PHP_FUNCTION(curl_multi_strerror)
 390 {
 391         zend_long code;
 392         const char *str;
 393 
 394         if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &code) == FAILURE) {
 395                 return;
 396         }
 397 
 398         str = curl_multi_strerror(code);
 399         if (str) {
 400                 RETURN_STRING(str);
 401         } else {
 402                 RETURN_NULL();
 403         }
 404 }
 405 /* }}} */
 406 #endif
 407 
 408 #if LIBCURL_VERSION_NUM >= 0x070f04 /* 7.15.4 */
 409 static int _php_curl_multi_setopt(php_curlm *mh, zend_long option, zval *zvalue, zval *return_value) /* {{{ */
 410 {
 411         CURLMcode error = CURLM_OK;
 412 
 413         switch (option) {
 414 #if LIBCURL_VERSION_NUM >= 0x071000 /* 7.16.0 */
 415                 case CURLMOPT_PIPELINING:
 416 #endif
 417 #if LIBCURL_VERSION_NUM >= 0x071003 /* 7.16.3 */
 418                 case CURLMOPT_MAXCONNECTS:
 419 #endif
 420                         error = curl_multi_setopt(mh->multi, option, zval_get_long(zvalue));
 421                         break;
 422 
 423                 default:
 424                         php_error_docref(NULL, E_WARNING, "Invalid curl multi configuration option");
 425                         error = CURLM_UNKNOWN_OPTION;
 426                         break;
 427         }
 428 
 429         if (error != CURLM_OK) {
 430                 return 1;
 431         } else {
 432                 return 0;
 433         }
 434 }
 435 /* }}} */
 436 
 437 /* {{{ proto int curl_multi_setopt(resource mh, int option, mixed value)
 438        Set an option for the curl multi handle */
 439 PHP_FUNCTION(curl_multi_setopt)
 440 {
 441         zval       *z_mh, *zvalue;
 442         zend_long        options;
 443         php_curlm *mh;
 444 
 445         if (zend_parse_parameters(ZEND_NUM_ARGS(), "rlz", &z_mh, &options, &zvalue) == FAILURE) {
 446                 return;
 447         }
 448 
 449         if ((mh = (php_curlm *)zend_fetch_resource(Z_RES_P(z_mh), le_curl_multi_handle_name, le_curl_multi_handle)) == NULL) {
 450                 RETURN_FALSE;
 451         }
 452 
 453         if (!_php_curl_multi_setopt(mh, options, zvalue, return_value)) {
 454                 RETURN_TRUE;
 455         } else {
 456                 RETURN_FALSE;
 457         }
 458 }
 459 /* }}} */
 460 #endif
 461 
 462 #endif
 463 
 464 /*
 465  * Local variables:
 466  * tab-width: 4
 467  * c-basic-offset: 4
 468  * End:
 469  * vim600: noet sw=4 ts=4 fdm=marker
 470  * vim<600: noet sw=4 ts=4
 471  */

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