Back to index

php5  5.3.10
multi.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Author: Sterling Hughes <sterling@php.net>                           |
00016    +----------------------------------------------------------------------+
00017 */
00018 
00019 /* $Id: multi.c 321634 2012-01-01 13:15:04Z felipe $ */
00020 
00021 #define ZEND_INCLUDE_FULL_WINDOWS_HEADERS
00022 
00023 #ifdef HAVE_CONFIG_H
00024 #include "config.h"
00025 #endif
00026 
00027 #include "php.h"
00028 
00029 #if HAVE_CURL
00030 
00031 #include "php_curl.h"
00032 
00033 #include <curl/curl.h>
00034 #include <curl/multi.h>
00035 
00036 #ifdef HAVE_SYS_SELECT_H
00037 #include <sys/select.h>
00038 #endif
00039 
00040 #ifdef HAVE_SYS_TIME_H
00041 #include <sys/time.h>
00042 #endif
00043 
00044 #ifdef HAVE_SYS_TYPES_H
00045 #include <sys/types.h>
00046 #endif
00047 
00048 #ifdef HAVE_UNISTD_H
00049 #include <unistd.h>
00050 #endif
00051 
00052 /* {{{ proto resource curl_multi_init(void)
00053    Returns a new cURL multi handle */
00054 PHP_FUNCTION(curl_multi_init)
00055 {
00056        php_curlm *mh;
00057        
00058        if (zend_parse_parameters_none() == FAILURE) {
00059               return;
00060        }
00061 
00062        mh = ecalloc(1, sizeof(php_curlm));
00063        mh->multi = curl_multi_init();
00064 
00065        zend_llist_init(&mh->easyh, sizeof(zval), _php_curl_multi_cleanup_list, 0);
00066 
00067        ZEND_REGISTER_RESOURCE(return_value, mh, le_curl_multi_handle);
00068 }
00069 /* }}} */
00070 
00071 /* {{{ proto int curl_multi_add_handle(resource mh, resource ch)
00072    Add a normal cURL handle to a cURL multi handle */
00073 PHP_FUNCTION(curl_multi_add_handle)
00074 {
00075        zval      *z_mh;
00076        zval      *z_ch;
00077        php_curlm *mh;
00078        php_curl  *ch;
00079        zval tmp_val;
00080 
00081        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr", &z_mh, &z_ch) == FAILURE) {
00082               return;
00083        }
00084 
00085        ZEND_FETCH_RESOURCE(mh, php_curlm *, &z_mh, -1, le_curl_multi_handle_name, le_curl_multi_handle);
00086        ZEND_FETCH_RESOURCE(ch, php_curl *, &z_ch, -1, le_curl_name, le_curl);
00087 
00088        _php_curl_cleanup_handle(ch);
00089        ch->uses++;
00090 
00091        /* we want to create a copy of this zval that we store in the multihandle structure element "easyh" */
00092        tmp_val = *z_ch;
00093        zval_copy_ctor(&tmp_val);
00094 
00095        zend_llist_add_element(&mh->easyh, &tmp_val);
00096 
00097        RETURN_LONG((long) curl_multi_add_handle(mh->multi, ch->cp));  
00098 }
00099 /* }}} */
00100 
00101 void _php_curl_multi_cleanup_list(void *data) /* {{{ */
00102 {
00103        zval *z_ch = (zval *)data;
00104        php_curl *ch;
00105        TSRMLS_FETCH();
00106 
00107        if (!z_ch) {
00108               return;
00109        }
00110        
00111        ch = (php_curl *) zend_fetch_resource(&z_ch TSRMLS_CC, -1, le_curl_name, NULL, 1, le_curl);
00112        if (!ch) {
00113               return;
00114        }
00115 
00116        if (ch->uses) {      
00117               ch->uses--;
00118        } else {
00119               zend_list_delete(Z_LVAL_P(z_ch));
00120        }
00121 }
00122 /* }}} */
00123 
00124 /* Used internally as comparison routine passed to zend_list_del_element */
00125 static int curl_compare_resources( zval *z1, zval **z2 ) /* {{{ */
00126 {
00127        return (Z_TYPE_P( z1 ) == Z_TYPE_PP( z2 ) && 
00128             Z_TYPE_P( z1 ) == IS_RESOURCE     &&
00129             Z_LVAL_P( z1 ) == Z_LVAL_PP( z2 ) );
00130 }
00131 /* }}} */
00132 
00133 /* {{{ proto int curl_multi_remove_handle(resource mh, resource ch)
00134    Remove a multi handle from a set of cURL handles */
00135 PHP_FUNCTION(curl_multi_remove_handle)
00136 {
00137        zval      *z_mh;
00138        zval      *z_ch;
00139        php_curlm *mh;
00140        php_curl  *ch;
00141 
00142        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr", &z_mh, &z_ch) == FAILURE) {
00143               return;
00144        }
00145 
00146        ZEND_FETCH_RESOURCE(mh, php_curlm *, &z_mh, -1, le_curl_multi_handle_name, le_curl_multi_handle);
00147        ZEND_FETCH_RESOURCE(ch, php_curl *, &z_ch, -1, le_curl_name, le_curl);
00148 
00149        --ch->uses;
00150 
00151        zend_llist_del_element( &mh->easyh, &z_ch, 
00152                                                  (int (*)(void *, void *)) curl_compare_resources );
00153        
00154        RETURN_LONG((long) curl_multi_remove_handle(mh->multi, ch->cp));
00155 }
00156 /* }}} */
00157 
00158 static void _make_timeval_struct(struct timeval *to, double timeout) /* {{{ */
00159 {
00160        unsigned long conv;
00161 
00162        conv = (unsigned long) (timeout * 1000000.0);
00163        to->tv_sec = conv / 1000000;
00164        to->tv_usec = conv % 1000000;
00165 }
00166 /* }}} */
00167 
00168 /* {{{ proto int curl_multi_select(resource mh[, double timeout])
00169    Get all the sockets associated with the cURL extension, which can then be "selected" */
00170 PHP_FUNCTION(curl_multi_select)
00171 {
00172        zval           *z_mh;
00173        php_curlm      *mh;
00174        fd_set          readfds;
00175        fd_set          writefds;
00176        fd_set          exceptfds;
00177        int             maxfd;
00178        double          timeout = 1.0;
00179        struct timeval  to;
00180 
00181        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|d", &z_mh, &timeout) == FAILURE) {
00182               return;
00183        }
00184 
00185        ZEND_FETCH_RESOURCE(mh, php_curlm *, &z_mh, -1, le_curl_multi_handle_name, le_curl_multi_handle);
00186 
00187        _make_timeval_struct(&to, timeout);
00188        
00189        FD_ZERO(&readfds);
00190        FD_ZERO(&writefds);
00191        FD_ZERO(&exceptfds);
00192 
00193        curl_multi_fdset(mh->multi, &readfds, &writefds, &exceptfds, &maxfd);
00194        RETURN_LONG(select(maxfd + 1, &readfds, &writefds, &exceptfds, &to));
00195 }
00196 /* }}} */
00197 
00198 /* {{{ proto int curl_multi_exec(resource mh, int &still_running) 
00199    Run the sub-connections of the current cURL handle */
00200 PHP_FUNCTION(curl_multi_exec)
00201 {
00202        zval      *z_mh;
00203        zval      *z_still_running;
00204        php_curlm *mh;
00205        int        still_running;
00206        int        result;
00207 
00208        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz", &z_mh, &z_still_running) == FAILURE) {
00209               return;
00210        }
00211 
00212        ZEND_FETCH_RESOURCE(mh, php_curlm *, &z_mh, -1, le_curl_multi_handle_name, le_curl_multi_handle);
00213 
00214        {
00215               zend_llist_position pos;
00216               php_curl *ch;
00217               zval   *pz_ch;
00218 
00219               for(pz_ch = (zval *)zend_llist_get_first_ex(&mh->easyh, &pos); pz_ch;
00220                      pz_ch = (zval *)zend_llist_get_next_ex(&mh->easyh, &pos)) {
00221 
00222                      ZEND_FETCH_RESOURCE(ch, php_curl *, &pz_ch, -1, le_curl_name, le_curl);
00223                      _php_curl_verify_handlers(ch, 1 TSRMLS_CC);
00224               }
00225        }
00226 
00227        convert_to_long_ex(&z_still_running);
00228        still_running = Z_LVAL_P(z_still_running);
00229        result = curl_multi_perform(mh->multi, &still_running);
00230        ZVAL_LONG(z_still_running, still_running);
00231 
00232        RETURN_LONG(result);
00233 }
00234 /* }}} */
00235 
00236 /* {{{ proto string curl_multi_getcontent(resource ch)
00237    Return the content of a cURL handle if CURLOPT_RETURNTRANSFER is set */
00238 PHP_FUNCTION(curl_multi_getcontent)
00239 {
00240        zval     *z_ch;
00241        php_curl *ch;
00242 
00243        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &z_ch) == FAILURE) {
00244               return;
00245        }
00246 
00247        ZEND_FETCH_RESOURCE(ch, php_curl *, &z_ch, -1, le_curl_name, le_curl);
00248 
00249        if (ch->handlers->write->method == PHP_CURL_RETURN && ch->handlers->write->buf.len > 0) {
00250               smart_str_0(&ch->handlers->write->buf);
00251               RETURN_STRINGL(ch->handlers->write->buf.c, ch->handlers->write->buf.len, 1);
00252        }
00253 }
00254 /* }}} */
00255 
00256 /* {{{ proto array curl_multi_info_read(resource mh [, long msgs_in_queue])
00257    Get information about the current transfers */
00258 PHP_FUNCTION(curl_multi_info_read)
00259 {
00260        zval      *z_mh;
00261        php_curlm *mh;
00262        CURLMsg         *tmp_msg;
00263        int        queued_msgs;
00264        zval      *zmsgs_in_queue = NULL;
00265 
00266        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|z", &z_mh, &zmsgs_in_queue) == FAILURE) {
00267               return;
00268        }
00269 
00270        ZEND_FETCH_RESOURCE(mh, php_curlm *, &z_mh, -1, le_curl_multi_handle_name, le_curl_multi_handle);
00271 
00272        tmp_msg = curl_multi_info_read(mh->multi, &queued_msgs);
00273        if (tmp_msg == NULL) {
00274               RETURN_FALSE;
00275        }
00276        if (zmsgs_in_queue) {
00277               zval_dtor(zmsgs_in_queue);
00278               ZVAL_LONG(zmsgs_in_queue, queued_msgs);
00279        }
00280 
00281        array_init(return_value);
00282        add_assoc_long(return_value, "msg", tmp_msg->msg);
00283        add_assoc_long(return_value, "result", tmp_msg->data.result);
00284 
00285        /* find the original easy curl handle */
00286        {
00287               zend_llist_position pos;
00288               php_curl *ch;
00289               zval   *pz_ch;
00290 
00291               /* search the list of easy handles hanging off the multi-handle */
00292               for(pz_ch = (zval *)zend_llist_get_first_ex(&mh->easyh, &pos); pz_ch;
00293                      pz_ch = (zval *)zend_llist_get_next_ex(&mh->easyh, &pos)) {
00294                      ZEND_FETCH_RESOURCE(ch, php_curl *, &pz_ch, -1, le_curl_name, le_curl);
00295                      if (ch->cp == tmp_msg->easy_handle) {
00296 
00297                             /* we are adding a reference to the underlying php_curl
00298                                resource, so we need to add one to the resource's refcount 
00299                                in order to ensure it doesn't get destroyed when the 
00300                                underlying curl easy handle goes out of scope.
00301                                Normally you would call zval_copy_ctor( pz_ch ), or
00302                                SEPARATE_ZVAL, but those create new zvals, which is already
00303                                being done in add_assoc_resource */
00304 
00305                             zend_list_addref( Z_RESVAL_P( pz_ch ) );
00306 
00307                             /* add_assoc_resource automatically creates a new zval to 
00308                                wrap the "resource" represented by the current pz_ch */
00309 
00310                             add_assoc_resource(return_value, "handle", Z_RESVAL_P(pz_ch));
00311 
00312                             break;
00313                      }
00314               }
00315        }
00316 }
00317 /* }}} */
00318 
00319 /* {{{ proto void curl_multi_close(resource mh)
00320    Close a set of cURL handles */
00321 PHP_FUNCTION(curl_multi_close)
00322 {
00323        zval      *z_mh;
00324        php_curlm *mh;
00325 
00326        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &z_mh) == FAILURE) {
00327               return;
00328        }
00329 
00330        ZEND_FETCH_RESOURCE(mh, php_curlm *, &z_mh, -1, le_curl_multi_handle_name, le_curl_multi_handle);
00331 
00332        zend_list_delete(Z_LVAL_P(z_mh));
00333 }
00334 /* }}} */
00335 
00336 void _php_curl_multi_close(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
00337 {
00338        php_curlm *mh = (php_curlm *) rsrc->ptr;
00339        if (mh) {
00340               zend_llist_position pos;
00341               php_curl *ch;
00342               zval   *pz_ch;
00343 
00344               for(pz_ch = (zval *)zend_llist_get_first_ex(&mh->easyh, &pos); pz_ch;
00345                      pz_ch = (zval *)zend_llist_get_next_ex(&mh->easyh, &pos)) {
00346 
00347                      ch = (php_curl *) zend_fetch_resource(&pz_ch TSRMLS_CC, -1, le_curl_name, NULL, 1, le_curl);
00348                      _php_curl_verify_handlers(ch, 0 TSRMLS_CC);
00349               }
00350 
00351               curl_multi_cleanup(mh->multi);
00352               zend_llist_clean(&mh->easyh);
00353               efree(mh);
00354               rsrc->ptr = NULL;
00355        }
00356 }
00357 /* }}} */
00358 
00359 #endif
00360 
00361 /*
00362  * Local variables:
00363  * tab-width: 4
00364  * c-basic-offset: 4
00365  * End:
00366  * vim600: noet sw=4 ts=4 fdm=marker
00367  * vim<600: noet sw=4 ts=4
00368  */