Return to multi.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / curl |
1.1 ! misho 1: /* ! 2: +----------------------------------------------------------------------+ ! 3: | PHP Version 5 | ! 4: +----------------------------------------------------------------------+ ! 5: | Copyright (c) 1997-2012 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 321634 2012-01-01 13:15:04Z felipe $ */ ! 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: RETURN_LONG(select(maxfd + 1, &readfds, &writefds, &exceptfds, &to)); ! 195: } ! 196: /* }}} */ ! 197: ! 198: /* {{{ proto int curl_multi_exec(resource mh, int &still_running) ! 199: Run the sub-connections of the current cURL handle */ ! 200: PHP_FUNCTION(curl_multi_exec) ! 201: { ! 202: zval *z_mh; ! 203: zval *z_still_running; ! 204: php_curlm *mh; ! 205: int still_running; ! 206: int result; ! 207: ! 208: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz", &z_mh, &z_still_running) == FAILURE) { ! 209: return; ! 210: } ! 211: ! 212: ZEND_FETCH_RESOURCE(mh, php_curlm *, &z_mh, -1, le_curl_multi_handle_name, le_curl_multi_handle); ! 213: ! 214: { ! 215: zend_llist_position pos; ! 216: php_curl *ch; ! 217: zval *pz_ch; ! 218: ! 219: for(pz_ch = (zval *)zend_llist_get_first_ex(&mh->easyh, &pos); pz_ch; ! 220: pz_ch = (zval *)zend_llist_get_next_ex(&mh->easyh, &pos)) { ! 221: ! 222: ZEND_FETCH_RESOURCE(ch, php_curl *, &pz_ch, -1, le_curl_name, le_curl); ! 223: _php_curl_verify_handlers(ch, 1 TSRMLS_CC); ! 224: } ! 225: } ! 226: ! 227: convert_to_long_ex(&z_still_running); ! 228: still_running = Z_LVAL_P(z_still_running); ! 229: result = curl_multi_perform(mh->multi, &still_running); ! 230: ZVAL_LONG(z_still_running, still_running); ! 231: ! 232: RETURN_LONG(result); ! 233: } ! 234: /* }}} */ ! 235: ! 236: /* {{{ proto string curl_multi_getcontent(resource ch) ! 237: Return the content of a cURL handle if CURLOPT_RETURNTRANSFER is set */ ! 238: PHP_FUNCTION(curl_multi_getcontent) ! 239: { ! 240: zval *z_ch; ! 241: php_curl *ch; ! 242: ! 243: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &z_ch) == FAILURE) { ! 244: return; ! 245: } ! 246: ! 247: ZEND_FETCH_RESOURCE(ch, php_curl *, &z_ch, -1, le_curl_name, le_curl); ! 248: ! 249: if (ch->handlers->write->method == PHP_CURL_RETURN && ch->handlers->write->buf.len > 0) { ! 250: smart_str_0(&ch->handlers->write->buf); ! 251: RETURN_STRINGL(ch->handlers->write->buf.c, ch->handlers->write->buf.len, 1); ! 252: } ! 253: } ! 254: /* }}} */ ! 255: ! 256: /* {{{ proto array curl_multi_info_read(resource mh [, long msgs_in_queue]) ! 257: Get information about the current transfers */ ! 258: PHP_FUNCTION(curl_multi_info_read) ! 259: { ! 260: zval *z_mh; ! 261: php_curlm *mh; ! 262: CURLMsg *tmp_msg; ! 263: int queued_msgs; ! 264: zval *zmsgs_in_queue = NULL; ! 265: ! 266: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|z", &z_mh, &zmsgs_in_queue) == FAILURE) { ! 267: return; ! 268: } ! 269: ! 270: ZEND_FETCH_RESOURCE(mh, php_curlm *, &z_mh, -1, le_curl_multi_handle_name, le_curl_multi_handle); ! 271: ! 272: tmp_msg = curl_multi_info_read(mh->multi, &queued_msgs); ! 273: if (tmp_msg == NULL) { ! 274: RETURN_FALSE; ! 275: } ! 276: if (zmsgs_in_queue) { ! 277: zval_dtor(zmsgs_in_queue); ! 278: ZVAL_LONG(zmsgs_in_queue, queued_msgs); ! 279: } ! 280: ! 281: array_init(return_value); ! 282: add_assoc_long(return_value, "msg", tmp_msg->msg); ! 283: add_assoc_long(return_value, "result", tmp_msg->data.result); ! 284: ! 285: /* find the original easy curl handle */ ! 286: { ! 287: zend_llist_position pos; ! 288: php_curl *ch; ! 289: zval *pz_ch; ! 290: ! 291: /* search the list of easy handles hanging off the multi-handle */ ! 292: for(pz_ch = (zval *)zend_llist_get_first_ex(&mh->easyh, &pos); pz_ch; ! 293: pz_ch = (zval *)zend_llist_get_next_ex(&mh->easyh, &pos)) { ! 294: ZEND_FETCH_RESOURCE(ch, php_curl *, &pz_ch, -1, le_curl_name, le_curl); ! 295: if (ch->cp == tmp_msg->easy_handle) { ! 296: ! 297: /* we are adding a reference to the underlying php_curl ! 298: resource, so we need to add one to the resource's refcount ! 299: in order to ensure it doesn't get destroyed when the ! 300: underlying curl easy handle goes out of scope. ! 301: Normally you would call zval_copy_ctor( pz_ch ), or ! 302: SEPARATE_ZVAL, but those create new zvals, which is already ! 303: being done in add_assoc_resource */ ! 304: ! 305: zend_list_addref( Z_RESVAL_P( pz_ch ) ); ! 306: ! 307: /* add_assoc_resource automatically creates a new zval to ! 308: wrap the "resource" represented by the current pz_ch */ ! 309: ! 310: add_assoc_resource(return_value, "handle", Z_RESVAL_P(pz_ch)); ! 311: ! 312: break; ! 313: } ! 314: } ! 315: } ! 316: } ! 317: /* }}} */ ! 318: ! 319: /* {{{ proto void curl_multi_close(resource mh) ! 320: Close a set of cURL handles */ ! 321: PHP_FUNCTION(curl_multi_close) ! 322: { ! 323: zval *z_mh; ! 324: php_curlm *mh; ! 325: ! 326: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &z_mh) == FAILURE) { ! 327: return; ! 328: } ! 329: ! 330: ZEND_FETCH_RESOURCE(mh, php_curlm *, &z_mh, -1, le_curl_multi_handle_name, le_curl_multi_handle); ! 331: ! 332: zend_list_delete(Z_LVAL_P(z_mh)); ! 333: } ! 334: /* }}} */ ! 335: ! 336: void _php_curl_multi_close(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */ ! 337: { ! 338: php_curlm *mh = (php_curlm *) rsrc->ptr; ! 339: if (mh) { ! 340: zend_llist_position pos; ! 341: php_curl *ch; ! 342: zval *pz_ch; ! 343: ! 344: for(pz_ch = (zval *)zend_llist_get_first_ex(&mh->easyh, &pos); pz_ch; ! 345: pz_ch = (zval *)zend_llist_get_next_ex(&mh->easyh, &pos)) { ! 346: ! 347: ch = (php_curl *) zend_fetch_resource(&pz_ch TSRMLS_CC, -1, le_curl_name, NULL, 1, le_curl); ! 348: _php_curl_verify_handlers(ch, 0 TSRMLS_CC); ! 349: } ! 350: ! 351: curl_multi_cleanup(mh->multi); ! 352: zend_llist_clean(&mh->easyh); ! 353: efree(mh); ! 354: rsrc->ptr = NULL; ! 355: } ! 356: } ! 357: /* }}} */ ! 358: ! 359: #endif ! 360: ! 361: /* ! 362: * Local variables: ! 363: * tab-width: 4 ! 364: * c-basic-offset: 4 ! 365: * End: ! 366: * vim600: noet sw=4 ts=4 fdm=marker ! 367: * vim<600: noet sw=4 ts=4 ! 368: */