]> granicus.if.org Git - php/commitdiff
add multi support and reorganize things a bit...
authorSterling Hughes <sterling@php.net>
Wed, 13 Nov 2002 22:25:33 +0000 (22:25 +0000)
committerSterling Hughes <sterling@php.net>
Wed, 13 Nov 2002 22:25:33 +0000 (22:25 +0000)
ext/curl/CREDITS
ext/curl/config.m4
ext/curl/curl.dsp
ext/curl/interface.c [moved from ext/curl/curl.c with 92% similarity]
ext/curl/multi.c [new file with mode: 0644]
ext/curl/php_curl.h
ext/curl/streams.c [moved from ext/curl/curlstreams.c with 100% similarity]

index 1e9f272a3952d398caf7f3aa93f73ff0e14409e5..610e036787aa323ca5da9df9edf94eb73542648e 100644 (file)
@@ -1,2 +1,2 @@
-CURL
+cURL
 Sterling Hughes
index 5841c173df5bbfb4bbac4c3c6cfa1a6d7e40611b..505f7b0104ab4b7268850e03581d3ced1ffa9bab 100644 (file)
@@ -1,5 +1,5 @@
 dnl
-dnl $Id$
+dnl $Id$ 
 dnl
 
 PHP_ARG_WITH(curl, for CURL support,
@@ -29,7 +29,7 @@ if test "$PHP_CURL" != "no"; then
   fi
 
   CURL_CONFIG="curl-config"
-  AC_MSG_CHECKING(for cURL 7.9.8 or greater)
+  AC_MSG_CHECKING(for cURL 7.10.2 or greater)
 
   if ${CURL_DIR}/bin/curl-config --libs print > /dev/null 2>&1; then
     CURL_CONFIG=${CURL_DIR}/bin/curl-config
@@ -41,11 +41,11 @@ if test "$PHP_CURL" != "no"; then
 
   curl_version_full=`$CURL_CONFIG --version`
   curl_version=`echo ${curl_version_full} | sed -e 's/libcurl //' | awk 'BEGIN { FS = "."; } { printf "%d", ($1 * 1000 + $2) * 1000 + $3;}'`
-  if test "$curl_version" -ge 7009008; then
+  if test "$curl_version" -ge 7010002; then
     AC_MSG_RESULT($curl_version_full)
     CURL_LIBS=`$CURL_CONFIG --libs`
   else
-    AC_MSG_ERROR(cURL version 7.9.8 or later is required to compile php with cURL support)
+    AC_MSG_ERROR(cURL version 7.10.2 or later is required to compile php with cURL support)
   fi
 
   PHP_ADD_INCLUDE($CURL_DIR/include)
@@ -72,6 +72,6 @@ dnl  if test "$PHP_CURLWRAPPERS" != "no" ; then
 dnl    AC_DEFINE(PHP_CURL_URL_WRAPPERS,1,[ ])
 dnl  fi
 
-  PHP_NEW_EXTENSION(curl, curl.c curlstreams.c, $ext_shared)
+  PHP_NEW_EXTENSION(curl, interface.c multi.c streams.c, $ext_shared)
   PHP_SUBST(CURL_SHARED_LIBADD)
 fi
index 66095f0b8ab5c840aae33ec1190240a3f45eac6f..d0a7167a9b988cbd10fca41de292b937680a64a8 100644 (file)
@@ -158,8 +158,17 @@ LINK32=link.exe
 # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
 # Begin Source File\r
 \r
-SOURCE=.\curl.c\r
+SOURCE=.\interface.c\r
 # End Source File\r
+\r
+# Begin Source File\r
+SOURCE=.\multi.c\r
+# End Source File\r
+\r
+# Begin Source File\r
+SOURCE=.\streams.c\r
+# End Source File\r
+\r
 # End Group\r
 # Begin Group "Header Files"\r
 \r
similarity index 92%
rename from ext/curl/curl.c
rename to ext/curl/interface.c
index dd5409b1d09f788c837e7792bfb76e2c7b7d48e9..38992c7e3b950b7b8da477e72a503a0128f8b847 100644 (file)
@@ -44,8 +44,7 @@
 #include "ext/standard/file.h"
 #include "php_curl.h"
 
-static int  le_curl;
-#define le_curl_name "cURL handle"
+static unsigned char second_arg_force_ref[] = {2, BYREF_NONE, BYREF_FORCE};
 
 static void _php_curl_close(zend_rsrc_list_entry *rsrc TSRMLS_DC);
 
@@ -59,14 +58,22 @@ static void _php_curl_close(zend_rsrc_list_entry *rsrc TSRMLS_DC);
 /* {{{ curl_functions[]
  */
 function_entry curl_functions[] = {
-       PHP_FE(curl_init,     NULL)
-       PHP_FE(curl_version,  NULL)
-       PHP_FE(curl_setopt,   NULL)
-       PHP_FE(curl_exec,     NULL)
-       PHP_FE(curl_getinfo,  NULL)
-       PHP_FE(curl_error,    NULL)
-       PHP_FE(curl_errno,    NULL)
-       PHP_FE(curl_close,    NULL)
+       PHP_FE(curl_init,                NULL)
+       PHP_FE(curl_version,             NULL)
+       PHP_FE(curl_setopt,              NULL)
+       PHP_FE(curl_exec,                NULL)
+       PHP_FE(curl_getinfo,             NULL)
+       PHP_FE(curl_error,               NULL)
+       PHP_FE(curl_errno,               NULL)
+       PHP_FE(curl_close,               NULL)
+       PHP_FE(curl_multi_init,          NULL)
+       PHP_FE(curl_multi_add_handle,    NULL)
+       PHP_FE(curl_multi_remove_handle, NULL)
+       PHP_FE(curl_multi_select,        NULL)
+       PHP_FE(curl_multi_exec,          second_arg_force_ref)
+       PHP_FE(curl_multi_getcontent,    NULL)
+       PHP_FE(curl_multi_info_read,     NULL)
+       PHP_FE(curl_multi_close,         NULL)
        {NULL, NULL, NULL}
 };
 /* }}} */
@@ -109,6 +116,7 @@ PHP_MINFO_FUNCTION(curl)
 PHP_MINIT_FUNCTION(curl)
 {
        le_curl = zend_register_list_destructors_ex(_php_curl_close, NULL, "curl", module_number);
+       le_curl_multi_handle = zend_register_list_destructors_ex(_php_curl_multi_close, NULL, "curl", module_number);
        
        /* Constants for curl_setopt() */
        REGISTER_CURL_CONSTANT(CURLOPT_DNS_USE_GLOBAL_CACHE);
@@ -183,6 +191,9 @@ PHP_MINIT_FUNCTION(curl)
        REGISTER_CURL_CONSTANT(CURLOPT_COOKIEJAR);
        REGISTER_CURL_CONSTANT(CURLOPT_SSL_CIPHER_LIST);
        REGISTER_CURL_CONSTANT(CURLOPT_BINARYTRANSFER);
+       REGISTER_CURL_CONSTANT(CURLOPT_NOSIGNAL);
+       REGISTER_CURL_CONSTANT(CURLOPT_PROXYTYPE);
+       REGISTER_CURL_CONSTANT(CURLOPT_BUFFERSIZE);
        REGISTER_CURL_CONSTANT(CURLOPT_HTTPGET);
        REGISTER_CURL_CONSTANT(CURLOPT_HTTP_VERSION);
        REGISTER_CURL_CONSTANT(CURLOPT_SSLKEY);
@@ -221,6 +232,15 @@ PHP_MINIT_FUNCTION(curl)
        REGISTER_CURL_CONSTANT(CURLINFO_REDIRECT_TIME);
        REGISTER_CURL_CONSTANT(CURLINFO_REDIRECT_COUNT);
 
+       /* cURL protocol constants (curl_version) */
+       REGISTER_CURL_CONSTANT(CURL_VERSION_IPV6);
+       REGISTER_CURL_CONSTANT(CURL_VERSION_KERBEROS4);
+       REGISTER_CURL_CONSTANT(CURL_VERSION_SSL);
+       REGISTER_CURL_CONSTANT(CURL_VERSION_LIBZ);
+       
+       /* version constants */
+       REGISTER_CURL_CONSTANT(CURLVERSION_NOW);
+
        /* Error Constants */
        REGISTER_CURL_CONSTANT(CURLE_OK);
        REGISTER_CURL_CONSTANT(CURLE_UNSUPPORTED_PROTOCOL);
@@ -275,6 +295,9 @@ PHP_MINIT_FUNCTION(curl)
        REGISTER_CURL_CONSTANT(CURLE_OBSOLETE);
        REGISTER_CURL_CONSTANT(CURLE_SSL_PEER_CERTIFICATE);
 
+       REGISTER_CURL_CONSTANT(CURLPROXY_HTTP);
+       REGISTER_CURL_CONSTANT(CURLPROXY_SOCKS5);
+
        REGISTER_CURL_CONSTANT(CURL_NETRC_OPTIONAL);
        REGISTER_CURL_CONSTANT(CURL_NETRC_IGNORED);
        REGISTER_CURL_CONSTANT(CURL_NETRC_REQUIRED);
@@ -283,6 +306,14 @@ PHP_MINIT_FUNCTION(curl)
        REGISTER_CURL_CONSTANT(CURL_HTTP_VERSION_1_0);
        REGISTER_CURL_CONSTANT(CURL_HTTP_VERSION_1_1);
        
+       REGISTER_CURL_CONSTANT(CURLM_CALL_MULTI_PERFORM);
+       REGISTER_CURL_CONSTANT(CURLM_OK);
+       REGISTER_CURL_CONSTANT(CURLM_BAD_HANDLE);
+       REGISTER_CURL_CONSTANT(CURLM_BAD_EASY_HANDLE);
+       REGISTER_CURL_CONSTANT(CURLM_OUT_OF_MEMORY);
+       REGISTER_CURL_CONSTANT(CURLM_INTERNAL_ERROR);
+
+       REGISTER_CURL_CONSTANT(CURLMSG_DONE);
        
        if (curl_global_init(CURL_GLOBAL_SSL) != CURLE_OK) {
                return FAILURE;
@@ -315,15 +346,6 @@ PHP_MSHUTDOWN_FUNCTION(curl)
 }
 /* }}} */
 
-#define PHP_CURL_STDOUT 0
-#define PHP_CURL_FILE   1
-#define PHP_CURL_USER   2
-#define PHP_CURL_DIRECT 3
-#define PHP_CURL_RETURN 4
-#define PHP_CURL_ASCII  5
-#define PHP_CURL_BINARY 6
-#define PHP_CURL_IGNORE 7
-
 /* {{{ curl_write
  */
 static size_t curl_write(char *data, size_t size, size_t nmemb, void *ctx)
@@ -333,6 +355,12 @@ static size_t curl_write(char *data, size_t size, size_t nmemb, void *ctx)
        size_t          length = size * nmemb;
        TSRMLS_FETCH();
 
+#if PHP_CURL_DEBUG
+       fprintf(stderr, "curl_write() called\n");
+       fprintf(stderr, "data = %s, size = %d, nmemb = %d, ctx = %x\n", 
+                       data, size, nmemb, ctx);
+#endif
+       
        switch (t->method) {
        case PHP_CURL_STDOUT:
                PUTS(data);
@@ -569,15 +597,45 @@ static void curl_free_slist(void **slist)
 /* }}} */
 
 
-/* {{{ proto array curl_version(void)
+/* {{{ proto array curl_version([int version])
    Return cURL version information. */
 PHP_FUNCTION(curl_version)
 {
-       if (ZEND_NUM_ARGS() != 0) {
-               WRONG_PARAM_COUNT;
+       curl_version_info_data *d;
+       long                    uversion = CURLVERSION_NOW;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &uversion) == FAILURE) {
+               return;
+       }
+
+       d = curl_version_info(uversion);
+       if (d == NULL) {
+               RETURN_FALSE;
        }
 
-       RETURN_STRING(curl_version(), 1);
+       array_init(return_value);
+
+       CAAL("version_number", d->version_num);
+       CAAL("age", d->age);
+       CAAL("features", d->features);
+       CAAL("ssl_version_number", d->ssl_version_num);
+       CAAS("version", d->version);
+       CAAS("host", d->host);
+       CAAS("ssl_version", d->ssl_version);
+       CAAS("libz_version", d->libz_version);
+       /* Add an array of protocols */
+       {
+               char **p = (char **) d->protocols;
+               zval  *protocol_list = NULL;
+
+               MAKE_STD_ZVAL(protocol_list);
+               array_init(protocol_list);
+
+               while (*p != NULL) {
+                       add_next_index_string(protocol_list,  *p++, 1);
+               }
+               CAAZ("protocols", protocol_list);
+       }
 }
 /* }}} */
 
@@ -707,6 +765,9 @@ PHP_FUNCTION(curl_setopt)
                case CURLOPT_SSL_VERIFYHOST:
                case CURLOPT_SSL_VERIFYPEER:
                case CURLOPT_DNS_USE_GLOBAL_CACHE:
+               case CURLOPT_NOSIGNAL:
+               case CURLOPT_PROXYTYPE:
+               case CURLOPT_BUFFERSIZE:
                case CURLOPT_HTTPGET:
                case CURLOPT_HTTP_VERSION:
                case CURLOPT_CRLF:
@@ -956,10 +1017,10 @@ PHP_FUNCTION(curl_setopt)
 }
 /* }}} */
 
-/* {{{ cleanup_handle(ch) 
+/* {{{ _php_curl_cleanup_handle(ch) 
    Cleanup an execution phase */
-static void 
-cleanup_handle(php_curl *ch)
+void 
+_php_curl_cleanup_handle(php_curl *ch)
 {
        if (ch->uses < 1) {
                return;
@@ -988,7 +1049,7 @@ PHP_FUNCTION(curl_exec)
        }
        ZEND_FETCH_RESOURCE(ch, php_curl *, zid, -1, le_curl_name, le_curl);
 
-       cleanup_handle(ch);
+       _php_curl_cleanup_handle(ch);
        
        error = curl_easy_perform(ch->cp);
        SAVE_CURL_ERROR(ch, error);
@@ -1005,7 +1066,7 @@ PHP_FUNCTION(curl_exec)
        if (ch->handlers->write->method == PHP_CURL_RETURN && ch->handlers->write->buf.len > 0) {
                if (ch->handlers->write->type != PHP_CURL_BINARY) 
                        smart_str_0(&ch->handlers->write->buf);
-               RETURN_STRINGL(ch->handlers->write->buf.c, ch->handlers->write->buf.len, 1);
+               RETURN_STRINGL(ch->handlers->write->buf.c, ch->handlers->write->buf.len, 0);
        }
 
        RETURN_TRUE;
@@ -1182,6 +1243,10 @@ static void _php_curl_close(zend_rsrc_list_entry *rsrc TSRMLS_DC)
 {
        php_curl *ch = (php_curl *) rsrc->ptr;
 
+#if PHP_CURL_DEBUG
+       fprintf(stderr, "DTOR CALLED, ch = %x\n", ch);
+#endif
+       
        curl_easy_cleanup(ch->cp);
        zend_llist_clean(&ch->to_free.str);
        zend_llist_clean(&ch->to_free.slist);
diff --git a/ext/curl/multi.c b/ext/curl/multi.c
new file mode 100644 (file)
index 0000000..ea9a0af
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+   +----------------------------------------------------------------------+
+   | PHP Version 4                                                        |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997-2002 The PHP Group                                |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 2.02 of the PHP license,      |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available at through the world-wide-web at                           |
+   | http://www.php.net/license/2_02.txt.                                 |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+   | Author: Sterling Hughes <sterling@php.net>                           |
+   +----------------------------------------------------------------------+
+*/
+
+/* $Id: */ 
+
+#include "php.h"
+
+#if HAVE_CURL
+
+#include "php_curl.h"
+
+#include <curl/curl.h>
+#include <curl/multi.h>
+
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+/* {{{ proto resource curl_multi_init(void)
+   Returns a new cURL multi handle */
+PHP_FUNCTION(curl_multi_init)
+{
+       php_curlm *mh;
+       
+       if (ZEND_NUM_ARGS() != 0) {
+               WRONG_PARAM_COUNT;
+       }
+
+       mh = ecalloc(1, sizeof(php_curlm));
+       mh->multi = curl_multi_init();
+
+       ZEND_REGISTER_RESOURCE(return_value, mh, le_curl_multi_handle);
+}
+/* }}} */
+
+/* {{{ int curl_multi_add_handle(resource multi, resource ch)
+   Add a normal cURL handle to a cURL multi handle */
+PHP_FUNCTION(curl_multi_add_handle)
+{
+       zval      *z_mh;
+       zval      *z_ch;
+       php_curlm *mh;
+       php_curl  *ch;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr", &z_mh, &z_ch) == FAILURE) {
+               return;
+       }
+       ZEND_FETCH_RESOURCE(mh, php_curlm *, &z_mh, -1, le_curl_multi_handle_name, 
+                       le_curl_multi_handle);
+       ZEND_FETCH_RESOURCE(ch, php_curl *, &z_ch, -1, le_curl_name, le_curl);
+
+       zval_add_ref(&z_ch);
+
+       _php_curl_cleanup_handle(ch);
+       ch->uses++;
+       
+       RETURN_LONG((long) curl_multi_add_handle(mh->multi, ch->cp));   
+}
+/* }}} */
+
+/* {{{ proto int curl_multi_remove_handle(resource mh, resource ch)
+   Remove a multi handle from a set of cURL handles */
+PHP_FUNCTION(curl_multi_remove_handle)
+{
+       zval      *z_mh;
+       zval      *z_ch;
+       php_curlm *mh;
+       php_curl  *ch;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr", &z_mh, &z_ch) == FAILURE) {
+               return;
+       }
+       ZEND_FETCH_RESOURCE(mh, php_curlm *, &z_mh, -1, le_curl_multi_handle_name,
+                       le_curl_multi_handle);
+       ZEND_FETCH_RESOURCE(ch, php_curl *, &z_ch, -1, le_curl_name, le_curl);
+
+       zval_ptr_dtor(&z_ch);
+       
+       RETURN_LONG((long) curl_multi_remove_handle(mh->multi, ch->cp));
+}
+/* }}} */
+
+
+static void _make_timeval_struct(struct timeval *to, double timeout)
+{
+       unsigned long conv;
+
+       conv = (unsigned long) (timeout * 1000000.0);
+       to->tv_sec = conv / 1000000;
+       to->tv_usec = conv % 1000000;
+}
+
+/* {{{ int curl_multi_select(resource mh[, double timeout])
+   Get all the sockets associated with the cURL extension, which can then be "selected" */
+PHP_FUNCTION(curl_multi_select)
+{
+       zval           *z_mh;
+       php_curlm      *mh;
+       fd_set          readfds;
+       fd_set          writefds;
+       fd_set          exceptfds;
+       int             maxfd;
+       double          timeout = 1.0;
+       struct timeval  to;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|d", &z_mh, 
+                               &timeout) == FAILURE) {
+               return;
+       }
+       ZEND_FETCH_RESOURCE(mh, php_curlm *, &z_mh, -1, le_curl_multi_handle_name,
+                       le_curl_multi_handle);
+
+       _make_timeval_struct(&to, timeout);
+       
+       FD_ZERO(&readfds);
+       FD_ZERO(&writefds);
+       FD_ZERO(&exceptfds);
+
+       curl_multi_fdset(mh->multi, &readfds, &writefds, &exceptfds, &maxfd);
+       RETURN_LONG(select(maxfd + 1, &readfds, &writefds, &exceptfds, &to));
+}
+/* }}} */
+
+/* {{{ proto int curl_multi_exec(resource mh) 
+   Run the sub-connections of the current cURL handle */
+PHP_FUNCTION(curl_multi_exec)
+{
+       zval      *z_mh;
+       zval      *z_still_running;
+       php_curlm *mh;
+       int        still_running;
+       int        result;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz", &z_mh, 
+                               &z_still_running) == FAILURE) {
+               return;
+       }
+       ZEND_FETCH_RESOURCE(mh, php_curlm *, &z_mh, -1, le_curl_multi_handle_name, 
+                       le_curl_multi_handle);
+
+       convert_to_long_ex(&z_still_running);
+       still_running = Z_LVAL_P(z_still_running);
+       result = curl_multi_perform(mh->multi, &still_running);
+       ZVAL_LONG(z_still_running, still_running);
+
+       RETURN_LONG(result);
+}
+/* }}} */
+
+/* {{{ proto string curl_multi_getcontent(resource ch)
+   Return the content of a cURL handle if CURLOPT_RETURNTRANSFER is set */
+PHP_FUNCTION(curl_multi_getcontent)
+{
+       zval     *z_ch;
+       php_curl *ch;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &z_ch) == FAILURE) {
+               return;
+       }
+       ZEND_FETCH_RESOURCE(ch, php_curl *, &z_ch, -1, le_curl_name, le_curl);
+
+       if (ch->handlers->write->method == PHP_CURL_RETURN && 
+                       ch->handlers->write->buf.len > 0) {
+               if (ch->handlers->write->type == PHP_CURL_BINARY) {
+                       smart_str_0(&ch->handlers->write->buf);
+               }
+               
+               RETURN_STRINGL(ch->handlers->write->buf.c, ch->handlers->write->buf.len, 0);
+       }
+}
+
+
+/* {{{ proto array curl_multi_info_read(resource mh)
+   Get information about the current transfers */
+PHP_FUNCTION(curl_multi_info_read)
+{
+       zval      *z_mh;
+       php_curlm *mh;
+       CURLMsg   *tmp_msg;
+       int        queued_msgs;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &z_mh) == FAILURE) {
+               return;
+       }
+       ZEND_FETCH_RESOURCE(mh, php_curlm *, &z_mh, -1, le_curl_multi_handle_name,
+                       le_curl_multi_handle);
+
+       tmp_msg = curl_multi_info_read(mh->multi, &queued_msgs);
+       if (tmp_msg == NULL) {
+               RETURN_FALSE;
+       }
+
+       array_init(return_value);
+       add_assoc_long(return_value, "msg", tmp_msg->msg);
+       add_assoc_long(return_value, "result", tmp_msg->data.result);
+//     add_assoc_resource(return_value, "handle", _find_handle(tmp_msg->easy_handle));
+       add_assoc_string(return_value, "whatever", (char *) tmp_msg->data.whatever, 1);
+}
+/* }}} */
+
+PHP_FUNCTION(curl_multi_close)
+{
+       zval      *z_mh;
+       php_curlm *mh;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &z_mh) == FAILURE) {
+               return;
+       }
+       ZEND_FETCH_RESOURCE(mh, php_curlm *, &z_mh, -1, le_curl_multi_handle_name,
+                       le_curl_multi_handle);
+
+       zend_list_delete(Z_LVAL_P(z_mh));
+}
+
+void _php_curl_multi_close(zend_rsrc_list_entry *rsrc)
+{
+       php_curlm *mh = (php_curlm *) rsrc->ptr;
+       curl_multi_cleanup(mh->multi);
+       // XXX: keep track of all curl handles and zval_ptr_dtor them here
+}
+
+#endif
index 7881c2f26b0b82a7b660b7bb4b8074c5ab25c101..95a4e9c29430c8d2d94055b20ac243147ff4b73b 100644 (file)
@@ -13,7 +13,7 @@
    | license@php.net so we can mail you a copy immediately.               |
    +----------------------------------------------------------------------+
    | Author: Sterling Hughes <sterling@php.net>                           |
-   | Wez Furlong <wez@thebrainroom.com>                                   |
+   |         Wez Furlong <wez@thebrainroom.com>                           |
    +----------------------------------------------------------------------+
 */
 
 
 #if HAVE_CURL
 
-#include <curl/curl.h>
+#define PHP_CURL_DEBUG 0
 
+#include <curl/curl.h>
+#include <curl/multi.h>
 
 extern zend_module_entry curl_module_entry;
 #define curl_module_ptr &curl_module_entry
 
 #define CURLOPT_RETURNTRANSFER 19913
 #define CURLOPT_BINARYTRANSFER 19914
+#define PHP_CURL_STDOUT 0
+#define PHP_CURL_FILE   1
+#define PHP_CURL_USER   2
+#define PHP_CURL_DIRECT 3
+#define PHP_CURL_RETURN 4
+#define PHP_CURL_ASCII  5
+#define PHP_CURL_BINARY 6
+#define PHP_CURL_IGNORE 7
+
+int  le_curl;
+#define le_curl_name "cURL handle"
+int  le_curl_multi_handle;
+#define le_curl_multi_handle_name "cURL Multi Handle"
 
 PHP_MINIT_FUNCTION(curl);
 PHP_MSHUTDOWN_FUNCTION(curl);
@@ -52,6 +67,15 @@ PHP_FUNCTION(curl_getinfo);
 PHP_FUNCTION(curl_error);
 PHP_FUNCTION(curl_errno);
 PHP_FUNCTION(curl_close);
+PHP_FUNCTION(curl_multi_init);
+PHP_FUNCTION(curl_multi_add_handle);
+PHP_FUNCTION(curl_multi_remove_handle);
+PHP_FUNCTION(curl_multi_select);
+PHP_FUNCTION(curl_multi_exec);
+PHP_FUNCTION(curl_multi_getcontent);
+PHP_FUNCTION(curl_multi_info_read);
+PHP_FUNCTION(curl_multi_close);
+void _php_curl_multi_close(zend_rsrc_list_entry *);
 
 typedef struct {
        zval         *func;
@@ -87,14 +111,21 @@ struct _php_curl_free {
 };
 
 typedef struct {
-       CURL                    *cp;
-       php_curl_handlers       *handlers;
        struct _php_curl_error   err;
        struct _php_curl_free    to_free;
+       CURL                    *cp;
+       php_curl_handlers       *handlers;
        long                     id;
        unsigned int             uses;
 } php_curl;
 
+typedef struct {
+       int    still_running;
+       CURLM *multi;
+} php_curlm;
+
+void _php_curl_cleanup_handle(php_curl *);
+
 /* streams support */
 
 PHPAPI extern php_stream_ops php_curl_stream_ops;
similarity index 100%
rename from ext/curl/curlstreams.c
rename to ext/curl/streams.c