File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / curl / multi.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 20:03:41 2014 UTC (10 years, 10 months ago) by misho
Branches: php, MAIN
CVS tags: v5_4_29, HEAD
php 5.4.29

    1: /*
    2:    +----------------------------------------------------------------------+
    3:    | PHP Version 5                                                        |
    4:    +----------------------------------------------------------------------+
    5:    | Copyright (c) 1997-2014 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: multi.c,v 1.1.1.4 2014/06/15 20:03:41 misho Exp $ */
   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: 	ch->uses++;
   90: 
   91: 	/* we want to create a copy of this zval that we store in the multihandle structure element "easyh" */
   92: 	tmp_val = *z_ch;
   93: 	zval_copy_ctor(&tmp_val);
   94: 
   95: 	zend_llist_add_element(&mh->easyh, &tmp_val);
   96: 
   97: 	RETURN_LONG((long) curl_multi_add_handle(mh->multi, ch->cp));	
   98: }
   99: /* }}} */
  100: 
  101: void _php_curl_multi_cleanup_list(void *data) /* {{{ */
  102: {
  103: 	zval *z_ch = (zval *)data;
  104: 	php_curl *ch;
  105: 	TSRMLS_FETCH();
  106: 
  107: 	if (!z_ch) {
  108: 		return;
  109: 	}
  110: 	
  111: 	ch = (php_curl *) zend_fetch_resource(&z_ch TSRMLS_CC, -1, le_curl_name, NULL, 1, le_curl);
  112: 	if (!ch) {
  113: 		return;
  114: 	}
  115: 
  116: 	if (ch->uses) {	
  117: 		ch->uses--;
  118: 	} else {
  119: 		zend_list_delete(Z_LVAL_P(z_ch));
  120: 	}
  121: }
  122: /* }}} */
  123: 
  124: /* Used internally as comparison routine passed to zend_list_del_element */
  125: static int curl_compare_resources( zval *z1, zval **z2 ) /* {{{ */
  126: {
  127: 	return (Z_TYPE_P( z1 ) == Z_TYPE_PP( z2 ) && 
  128:             Z_TYPE_P( z1 ) == IS_RESOURCE     &&
  129:             Z_LVAL_P( z1 ) == Z_LVAL_PP( z2 ) );
  130: }
  131: /* }}} */
  132: 
  133: /* {{{ proto int curl_multi_remove_handle(resource mh, resource ch)
  134:    Remove a multi handle from a set of cURL handles */
  135: PHP_FUNCTION(curl_multi_remove_handle)
  136: {
  137: 	zval      *z_mh;
  138: 	zval      *z_ch;
  139: 	php_curlm *mh;
  140: 	php_curl  *ch;
  141: 
  142: 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr", &z_mh, &z_ch) == FAILURE) {
  143: 		return;
  144: 	}
  145: 
  146: 	ZEND_FETCH_RESOURCE(mh, php_curlm *, &z_mh, -1, le_curl_multi_handle_name, le_curl_multi_handle);
  147: 	ZEND_FETCH_RESOURCE(ch, php_curl *, &z_ch, -1, le_curl_name, le_curl);
  148: 
  149: 	--ch->uses;
  150: 
  151: 	zend_llist_del_element( &mh->easyh, &z_ch, 
  152: 							(int (*)(void *, void *)) curl_compare_resources );
  153: 	
  154: 	RETURN_LONG((long) curl_multi_remove_handle(mh->multi, ch->cp));
  155: }
  156: /* }}} */
  157: 
  158: static void _make_timeval_struct(struct timeval *to, double timeout) /* {{{ */
  159: {
  160: 	unsigned long conv;
  161: 
  162: 	conv = (unsigned long) (timeout * 1000000.0);
  163: 	to->tv_sec = conv / 1000000;
  164: 	to->tv_usec = conv % 1000000;
  165: }
  166: /* }}} */
  167: 
  168: /* {{{ proto int curl_multi_select(resource mh[, double timeout])
  169:    Get all the sockets associated with the cURL extension, which can then be "selected" */
  170: PHP_FUNCTION(curl_multi_select)
  171: {
  172: 	zval           *z_mh;
  173: 	php_curlm      *mh;
  174: 	fd_set          readfds;
  175: 	fd_set          writefds;
  176: 	fd_set          exceptfds;
  177: 	int             maxfd;
  178: 	double          timeout = 1.0;
  179: 	struct timeval  to;
  180: 
  181: 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|d", &z_mh, &timeout) == FAILURE) {
  182: 		return;
  183: 	}
  184: 
  185: 	ZEND_FETCH_RESOURCE(mh, php_curlm *, &z_mh, -1, le_curl_multi_handle_name, le_curl_multi_handle);
  186: 
  187: 	_make_timeval_struct(&to, timeout);
  188: 	
  189: 	FD_ZERO(&readfds);
  190: 	FD_ZERO(&writefds);
  191: 	FD_ZERO(&exceptfds);
  192: 
  193: 	curl_multi_fdset(mh->multi, &readfds, &writefds, &exceptfds, &maxfd);
  194: 	if (maxfd == -1) {
  195: 		RETURN_LONG(-1);
  196: 	}
  197: 	RETURN_LONG(select(maxfd + 1, &readfds, &writefds, &exceptfds, &to));
  198: }
  199: /* }}} */
  200: 
  201: /* {{{ proto int curl_multi_exec(resource mh, int &still_running) 
  202:    Run the sub-connections of the current cURL handle */
  203: PHP_FUNCTION(curl_multi_exec)
  204: {
  205: 	zval      *z_mh;
  206: 	zval      *z_still_running;
  207: 	php_curlm *mh;
  208: 	int        still_running;
  209: 	int        result;
  210: 
  211: 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz", &z_mh, &z_still_running) == FAILURE) {
  212: 		return;
  213: 	}
  214: 
  215: 	ZEND_FETCH_RESOURCE(mh, php_curlm *, &z_mh, -1, le_curl_multi_handle_name, le_curl_multi_handle);
  216: 
  217: 	{
  218: 		zend_llist_position pos;
  219: 		php_curl *ch;
  220: 		zval	*pz_ch;
  221: 
  222: 		for(pz_ch = (zval *)zend_llist_get_first_ex(&mh->easyh, &pos); pz_ch;
  223: 			pz_ch = (zval *)zend_llist_get_next_ex(&mh->easyh, &pos)) {
  224: 
  225: 			ZEND_FETCH_RESOURCE(ch, php_curl *, &pz_ch, -1, le_curl_name, le_curl);
  226: 			_php_curl_verify_handlers(ch, 1 TSRMLS_CC);
  227: 		}
  228: 	}
  229: 
  230: 	convert_to_long_ex(&z_still_running);
  231: 	still_running = Z_LVAL_P(z_still_running);
  232: 	result = curl_multi_perform(mh->multi, &still_running);
  233: 	ZVAL_LONG(z_still_running, still_running);
  234: 
  235: 	RETURN_LONG(result);
  236: }
  237: /* }}} */
  238: 
  239: /* {{{ proto string curl_multi_getcontent(resource ch)
  240:    Return the content of a cURL handle if CURLOPT_RETURNTRANSFER is set */
  241: PHP_FUNCTION(curl_multi_getcontent)
  242: {
  243: 	zval     *z_ch;
  244: 	php_curl *ch;
  245: 
  246: 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &z_ch) == FAILURE) {
  247: 		return;
  248: 	}
  249: 
  250: 	ZEND_FETCH_RESOURCE(ch, php_curl *, &z_ch, -1, le_curl_name, le_curl);
  251: 
  252: 	if (ch->handlers->write->method == PHP_CURL_RETURN && ch->handlers->write->buf.len > 0) {
  253: 		smart_str_0(&ch->handlers->write->buf);
  254: 		RETURN_STRINGL(ch->handlers->write->buf.c, ch->handlers->write->buf.len, 1);
  255: 	}
  256: 
  257:         RETURN_EMPTY_STRING();
  258: }
  259: /* }}} */
  260: 
  261: /* {{{ proto array curl_multi_info_read(resource mh [, long msgs_in_queue])
  262:    Get information about the current transfers */
  263: PHP_FUNCTION(curl_multi_info_read)
  264: {
  265: 	zval      *z_mh;
  266: 	php_curlm *mh;
  267: 	CURLMsg	  *tmp_msg;
  268: 	int        queued_msgs;
  269: 	zval      *zmsgs_in_queue = NULL;
  270: 
  271: 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|z", &z_mh, &zmsgs_in_queue) == FAILURE) {
  272: 		return;
  273: 	}
  274: 
  275: 	ZEND_FETCH_RESOURCE(mh, php_curlm *, &z_mh, -1, le_curl_multi_handle_name, le_curl_multi_handle);
  276: 
  277: 	tmp_msg = curl_multi_info_read(mh->multi, &queued_msgs);
  278: 	if (tmp_msg == NULL) {
  279: 		RETURN_FALSE;
  280: 	}
  281: 	if (zmsgs_in_queue) {
  282: 		zval_dtor(zmsgs_in_queue);
  283: 		ZVAL_LONG(zmsgs_in_queue, queued_msgs);
  284: 	}
  285: 
  286: 	array_init(return_value);
  287: 	add_assoc_long(return_value, "msg", tmp_msg->msg);
  288: 	add_assoc_long(return_value, "result", tmp_msg->data.result);
  289: 
  290: 	/* find the original easy curl handle */
  291: 	{
  292: 		zend_llist_position pos;
  293: 		php_curl *ch;
  294: 		zval	*pz_ch;
  295: 
  296: 		/* search the list of easy handles hanging off the multi-handle */
  297: 		for(pz_ch = (zval *)zend_llist_get_first_ex(&mh->easyh, &pos); pz_ch;
  298: 			pz_ch = (zval *)zend_llist_get_next_ex(&mh->easyh, &pos)) {
  299: 			ZEND_FETCH_RESOURCE(ch, php_curl *, &pz_ch, -1, le_curl_name, le_curl);
  300: 			if (ch->cp == tmp_msg->easy_handle) {
  301: 
  302: 				/* we are adding a reference to the underlying php_curl
  303: 				   resource, so we need to add one to the resource's refcount 
  304: 				   in order to ensure it doesn't get destroyed when the 
  305: 				   underlying curl easy handle goes out of scope.
  306: 				   Normally you would call zval_copy_ctor( pz_ch ), or
  307: 				   SEPARATE_ZVAL, but those create new zvals, which is already
  308: 				   being done in add_assoc_resource */
  309: 
  310: 				zend_list_addref( Z_RESVAL_P( pz_ch ) );
  311: 
  312: 				/* add_assoc_resource automatically creates a new zval to 
  313: 				   wrap the "resource" represented by the current pz_ch */
  314: 
  315: 				add_assoc_resource(return_value, "handle", Z_RESVAL_P(pz_ch));
  316: 
  317: 				break;
  318: 			}
  319: 		}
  320: 	}
  321: }
  322: /* }}} */
  323: 
  324: /* {{{ proto void curl_multi_close(resource mh)
  325:    Close a set of cURL handles */
  326: PHP_FUNCTION(curl_multi_close)
  327: {
  328: 	zval      *z_mh;
  329: 	php_curlm *mh;
  330: 
  331: 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &z_mh) == FAILURE) {
  332: 		return;
  333: 	}
  334: 
  335: 	ZEND_FETCH_RESOURCE(mh, php_curlm *, &z_mh, -1, le_curl_multi_handle_name, le_curl_multi_handle);
  336: 
  337: 	zend_list_delete(Z_LVAL_P(z_mh));
  338: }
  339: /* }}} */
  340: 
  341: void _php_curl_multi_close(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
  342: {
  343: 	php_curlm *mh = (php_curlm *) rsrc->ptr;
  344: 	if (mh) {
  345: 		zend_llist_position pos;
  346: 		php_curl *ch;
  347: 		zval	*pz_ch;
  348: 
  349: 		for(pz_ch = (zval *)zend_llist_get_first_ex(&mh->easyh, &pos); pz_ch;
  350: 			pz_ch = (zval *)zend_llist_get_next_ex(&mh->easyh, &pos)) {
  351: 
  352: 			ch = (php_curl *) zend_fetch_resource(&pz_ch TSRMLS_CC, -1, le_curl_name, NULL, 1, le_curl);
  353: 			_php_curl_verify_handlers(ch, 0 TSRMLS_CC);
  354: 		}
  355: 
  356: 		curl_multi_cleanup(mh->multi);
  357: 		zend_llist_clean(&mh->easyh);
  358: 		efree(mh);
  359: 		rsrc->ptr = NULL;
  360: 	}
  361: }
  362: /* }}} */
  363: 
  364: #endif
  365: 
  366: /*
  367:  * Local variables:
  368:  * tab-width: 4
  369:  * c-basic-offset: 4
  370:  * End:
  371:  * vim600: noet sw=4 ts=4 fdm=marker
  372:  * vim<600: noet sw=4 ts=4
  373:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>