LTP GCOV extension - code coverage report
Current view: directory - ext/http - http_request_pool_api.c
Test: PHP Code Coverage
Date: 2007-04-10 Instrumented lines: 126
Code covered: 82.5 % Executed lines: 104
Legend: not executed executed

       1                 : /*
       2                 :     +--------------------------------------------------------------------+
       3                 :     | PECL :: http                                                       |
       4                 :     +--------------------------------------------------------------------+
       5                 :     | Redistribution and use in source and binary forms, with or without |
       6                 :     | modification, are permitted provided that the conditions mentioned |
       7                 :     | in the accompanying LICENSE file are met.                          |
       8                 :     +--------------------------------------------------------------------+
       9                 :     | Copyright (c) 2004-2007, Michael Wallner <mike@php.net>            |
      10                 :     +--------------------------------------------------------------------+
      11                 : */
      12                 : 
      13                 : /* $Id: http_request_pool_api.c,v 1.51 2007/02/09 14:19:39 mike Exp $ */
      14                 : 
      15                 : #define HTTP_WANT_CURL
      16                 : #include "php_http.h"
      17                 : 
      18                 : #if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL)
      19                 : 
      20                 : #include "php_http_api.h"
      21                 : #include "php_http_exception_object.h"
      22                 : #include "php_http_persistent_handle_api.h"
      23                 : #include "php_http_request_api.h"
      24                 : #include "php_http_request_object.h"
      25                 : #include "php_http_request_pool_api.h"
      26                 : #include "php_http_requestpool_object.h"
      27                 : 
      28                 : #ifndef HTTP_DEBUG_REQPOOLS
      29                 : #       define HTTP_DEBUG_REQPOOLS 0
      30                 : #endif
      31                 : 
      32                 : static int http_request_pool_compare_handles(void *h1, void *h2);
      33                 : 
      34                 : PHP_MINIT_FUNCTION(http_request_pool)
      35             220 : {
      36             220 :         if (SUCCESS != http_persistent_handle_provide("http_request_pool", curl_multi_init, (http_persistent_handle_dtor) curl_multi_cleanup, NULL)) {
      37               0 :                 return FAILURE;
      38                 :         }
      39             220 :         return SUCCESS;
      40                 : }
      41                 : 
      42                 : /* {{{ http_request_pool *http_request_pool_init(http_request_pool *) */
      43                 : PHP_HTTP_API http_request_pool *_http_request_pool_init(http_request_pool *pool TSRMLS_DC)
      44               7 : {
      45                 :         zend_bool free_pool;
      46                 :         
      47                 : #if HTTP_DEBUG_REQPOOLS
      48                 :         fprintf(stderr, "Initializing request pool %p\n", pool);
      49                 : #endif
      50                 :         
      51               7 :         if ((free_pool = (!pool))) {
      52               0 :                 pool = emalloc(sizeof(http_request_pool));
      53               0 :                 pool->ch = NULL;
      54                 :         }
      55                 : 
      56               7 :         if (SUCCESS != http_persistent_handle_acquire("http_request_pool", &pool->ch)) {
      57               0 :                 if (free_pool) {
      58               0 :                         efree(pool);
      59                 :                 }
      60               0 :                 return NULL;
      61                 :         }
      62                 : 
      63               7 :         pool->unfinished = 0;
      64               7 :         zend_llist_init(&pool->finished, sizeof(zval *), (llist_dtor_func_t) ZVAL_PTR_DTOR, 0);
      65               7 :         zend_llist_init(&pool->handles, sizeof(zval *), (llist_dtor_func_t) ZVAL_PTR_DTOR, 0);
      66                 :         
      67                 : #if HTTP_DEBUG_REQPOOLS
      68                 :         fprintf(stderr, "Initialized request pool %p\n", pool);
      69                 : #endif
      70                 :         
      71               7 :         return pool;
      72                 : }
      73                 : /* }}} */
      74                 : 
      75                 : /* {{{ STATUS http_request_pool_attach(http_request_pool *, zval *) */
      76                 : PHP_HTTP_API STATUS _http_request_pool_attach(http_request_pool *pool, zval *request TSRMLS_DC)
      77              63 : {
      78              63 :         getObjectEx(http_request_object, req, request);
      79                 :         
      80                 : #if HTTP_DEBUG_REQPOOLS
      81                 :         fprintf(stderr, "Attaching HttpRequest(#%d) %p to pool %p\n", Z_OBJ_HANDLE_P(request), req, pool);
      82                 : #endif
      83                 :         
      84              63 :         if (req->pool) {
      85               0 :                 http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "HttpRequest object(#%d) is already member of %s HttpRequestPool", Z_OBJ_HANDLE_P(request), req->pool == pool ? "this" : "another");
      86              63 :         } else if (SUCCESS != http_request_object_requesthandler(req, request)) {
      87               0 :                 http_error_ex(HE_WARNING, HTTP_E_REQUEST, "Could not initialize HttpRequest object(#%d) for attaching to the HttpRequestPool", Z_OBJ_HANDLE_P(request));
      88                 :         } else {
      89              63 :                 CURLMcode code = curl_multi_add_handle(pool->ch, req->request->ch);
      90                 : 
      91              63 :                 if ((CURLM_OK != code) && (CURLM_CALL_MULTI_PERFORM != code)) {
      92               0 :                         http_error_ex(HE_WARNING, HTTP_E_REQUEST_POOL, "Could not attach HttpRequest object(#%d) to the HttpRequestPool: %s", Z_OBJ_HANDLE_P(request), curl_multi_strerror(code));
      93                 :                 } else {
      94              63 :                         req->pool = pool;
      95                 : 
      96              63 :                         ZVAL_ADDREF(request);
      97              63 :                         zend_llist_add_element(&pool->handles, &request);
      98                 : 
      99                 : #if HTTP_DEBUG_REQPOOLS
     100                 :                         fprintf(stderr, "> %d HttpRequests attached to pool %p\n", zend_llist_count(&pool->handles), pool);
     101                 : #endif
     102              63 :                         return SUCCESS;
     103                 :                 }
     104                 :         }
     105               0 :         return FAILURE;
     106                 : }
     107                 : /* }}} */
     108                 : 
     109                 : /* {{{ STATUS http_request_pool_detach(http_request_pool *, zval *) */
     110                 : PHP_HTTP_API STATUS _http_request_pool_detach(http_request_pool *pool, zval *request TSRMLS_DC)
     111              65 : {
     112                 :         CURLMcode code;
     113              65 :         getObjectEx(http_request_object, req, request);
     114                 :         
     115                 : #if HTTP_DEBUG_REQPOOLS
     116                 :         fprintf(stderr, "Detaching HttpRequest(#%d) %p from pool %p\n", Z_OBJ_HANDLE_P(request), req, pool);
     117                 : #endif
     118                 :         
     119              65 :         if (!req->pool) {
     120                 :                 /* not attached to any pool */
     121                 : #if HTTP_DEBUG_REQPOOLS
     122                 :                 fprintf(stderr, "HttpRequest object(#%d) %p is not attached to any HttpRequestPool\n", Z_OBJ_HANDLE_P(request), req);
     123                 : #endif
     124              65 :         } else if (req->pool != pool) {
     125               0 :                 http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "HttpRequest object(#%d) is not attached to this HttpRequestPool", Z_OBJ_HANDLE_P(request));
     126              65 :         } else if (req->request->_in_progress_cb) {
     127               2 :                 http_error_ex(HE_WARNING, HTTP_E_REQUEST_POOL, "HttpRequest object(#%d) cannot be detached from the HttpRequestPool while executing the progress callback", Z_OBJ_HANDLE_P(request));
     128              63 :         } else if (CURLM_OK != (code = curl_multi_remove_handle(pool->ch, req->request->ch))) {
     129               0 :                 http_error_ex(HE_WARNING, HTTP_E_REQUEST_POOL, "Could not detach HttpRequest object(#%d) from the HttpRequestPool: %s", Z_OBJ_HANDLE_P(request), curl_multi_strerror(code));
     130                 :         } else {
     131              63 :                 req->pool = NULL;
     132              63 :                 zend_llist_del_element(&pool->finished, request, http_request_pool_compare_handles);
     133              63 :                 zend_llist_del_element(&pool->handles, request, http_request_pool_compare_handles);
     134                 :                 
     135                 : #if HTTP_DEBUG_REQPOOLS
     136                 :                 fprintf(stderr, "> %d HttpRequests remaining in pool %p\n", zend_llist_count(&pool->handles), pool);
     137                 : #endif
     138                 :         
     139              63 :                 return SUCCESS;
     140                 :         }
     141               2 :         return FAILURE;
     142                 : }
     143                 : /* }}} */
     144                 : 
     145                 : /* {{{ void http_request_pool_apply(http_request_pool *, http_request_pool_apply_func) */
     146                 : PHP_HTTP_API void _http_request_pool_apply(http_request_pool *pool, http_request_pool_apply_func cb TSRMLS_DC)
     147               7 : {
     148               7 :         int count = zend_llist_count(&pool->handles);
     149                 :         
     150               7 :         if (count) {
     151               3 :                 int i = 0;
     152                 :                 zend_llist_position pos;
     153               3 :                 zval **handle, **handles = emalloc(count * sizeof(zval *));
     154                 : 
     155               7 :                 for (handle = zend_llist_get_first_ex(&pool->handles, &pos); handle; handle = zend_llist_get_next_ex(&pool->handles, &pos)) {
     156               4 :                         handles[i++] = *handle;
     157                 :                 }
     158                 :                 
     159                 :                 /* should never happen */
     160               3 :                 if (i != count) {
     161               0 :                         zend_error(E_ERROR, "number of fetched request handles do not match overall count");
     162               0 :                         count = i;
     163                 :                 }
     164                 :                 
     165               7 :                 for (i = 0; i < count; ++i) {
     166               4 :                         if (cb(pool, handles[i] TSRMLS_CC)) {
     167               0 :                                 break;
     168                 :                         }
     169                 :                 }
     170               3 :                 efree(handles);
     171                 :         }
     172               7 : }
     173                 : /* }}} */
     174                 : 
     175                 : /* {{{ void http_request_pool_apply_with_arg(http_request_pool *, http_request_pool_apply_with_arg_func, void *) */
     176                 : PHP_HTTP_API void _http_request_pool_apply_with_arg(http_request_pool *pool, http_request_pool_apply_with_arg_func cb, void *arg TSRMLS_DC)
     177              61 : {
     178              61 :         int count = zend_llist_count(&pool->handles);
     179                 :         
     180              61 :         if (count) {
     181              61 :                 int i = 0;
     182                 :                 zend_llist_position pos;
     183              61 :                 zval **handle, **handles = emalloc(count * sizeof(zval *));
     184                 : 
     185             536 :                 for (handle = zend_llist_get_first_ex(&pool->handles, &pos); handle; handle = zend_llist_get_next_ex(&pool->handles, &pos)) {
     186             475 :                         handles[i++] = *handle;
     187                 :                 }
     188                 :                 
     189                 :                 /* should never happen */
     190              61 :                 if (i != count) {
     191               0 :                         zend_error(E_ERROR, "number of fetched request handles do not match overall count");
     192               0 :                         count = i;
     193                 :                 }
     194                 :                 
     195             237 :                 for (i = 0; i < count; ++i) {
     196             237 :                         if (cb(pool, handles[i], arg TSRMLS_CC)) {
     197              61 :                                 break;
     198                 :                         }
     199                 :                 }
     200              61 :                 efree(handles);
     201                 :         }
     202              61 : }
     203                 : /* }}} */
     204                 : 
     205                 : /* {{{ void http_request_pool_detach_all(http_request_pool *) */
     206                 : PHP_HTTP_API void _http_request_pool_detach_all(http_request_pool *pool TSRMLS_DC)
     207               7 : {
     208                 : #if HTTP_DEBUG_REQPOOLS
     209                 :         fprintf(stderr, "Detaching %d requests from pool %p\n", zend_llist_count(&pool->handles), pool);
     210                 : #endif
     211               7 :         http_request_pool_apply(pool, _http_request_pool_detach);
     212               7 : }
     213                 : /* }}} */
     214                 : 
     215                 : /* {{{ STATUS http_request_pool_send(http_request_pool *) */
     216                 : PHP_HTTP_API STATUS _http_request_pool_send(http_request_pool *pool TSRMLS_DC)
     217               4 : {
     218                 : #if HTTP_DEBUG_REQPOOLS
     219                 :         fprintf(stderr, "Attempt to send %d requests of pool %p\n", zend_llist_count(&pool->handles), pool);
     220                 : #endif
     221                 :         
     222              58 :         while (http_request_pool_perform(pool)) {
     223              50 :                 if (SUCCESS != http_request_pool_select(pool)) {
     224                 : #ifdef PHP_WIN32
     225                 :                         /* see http://msdn.microsoft.com/library/en-us/winsock/winsock/windows_sockets_error_codes_2.asp */
     226                 :                         http_error_ex(HE_WARNING, HTTP_E_SOCKET, "WinSock error: %d", WSAGetLastError());
     227                 : #else
     228               0 :                         http_error(HE_WARNING, HTTP_E_SOCKET, strerror(errno));
     229                 : #endif
     230               0 :                         return FAILURE;
     231                 :                 }
     232                 :         }
     233                 :         
     234                 : #if HTTP_DEBUG_REQPOOLS
     235                 :         fprintf(stderr, "Finished sending %d HttpRequests of pool %p (still unfinished: %d)\n", zend_llist_count(&pool->handles), pool, pool->unfinished);
     236                 : #endif
     237                 :         
     238               4 :         return SUCCESS;
     239                 : }
     240                 : /* }}} */
     241                 : 
     242                 : /* {{{ void http_request_pool_dtor(http_request_pool *) */
     243                 : PHP_HTTP_API void _http_request_pool_dtor(http_request_pool *pool TSRMLS_DC)
     244               7 : {
     245                 : #if HTTP_DEBUG_REQPOOLS
     246                 :         fprintf(stderr, "Destructing request pool %p\n", pool);
     247                 : #endif
     248                 :         
     249               7 :         pool->unfinished = 0;
     250               7 :         zend_llist_clean(&pool->finished);
     251               7 :         zend_llist_clean(&pool->handles);
     252               7 :         http_persistent_handle_release("http_request_pool", &pool->ch);
     253               7 : }
     254                 : /* }}} */
     255                 : 
     256                 : #ifdef PHP_WIN32
     257                 : #       define SELECT_ERROR SOCKET_ERROR
     258                 : #else
     259                 : #       define SELECT_ERROR -1
     260                 : #endif
     261                 : 
     262                 : /* {{{ STATUS http_request_pool_select(http_request_pool *) */
     263                 : PHP_HTTP_API STATUS _http_request_pool_select(http_request_pool *pool)
     264             298 : {
     265                 :         int MAX;
     266                 :         fd_set R, W, E;
     267             298 :         struct timeval timeout = {1, 0};
     268                 : #ifdef HAVE_CURL_MULTI_TIMEOUT
     269             298 :         long max_tout = 1000;
     270                 :         
     271             298 :         if ((CURLM_OK == curl_multi_timeout(pool->ch, &max_tout)) && (max_tout != -1)) {
     272             278 :                 timeout.tv_sec = max_tout / 1000;
     273             278 :                 timeout.tv_usec = (max_tout % 1000) * 1000;
     274                 :         }
     275                 : #endif
     276                 : 
     277             298 :         FD_ZERO(&R);
     278             298 :         FD_ZERO(&W);
     279             298 :         FD_ZERO(&E);
     280                 : 
     281             298 :         if (CURLM_OK == curl_multi_fdset(pool->ch, &R, &W, &E, &MAX)) {
     282             298 :                 if (MAX == -1) {
     283               0 :                         http_sleep((double) timeout.tv_sec + (double) (timeout.tv_usec / HTTP_MCROSEC));
     284               0 :                         return SUCCESS;
     285             298 :                 } else if (SELECT_ERROR != select(MAX + 1, &R, &W, &E, &timeout)) {
     286             298 :                         return SUCCESS;
     287                 :                 }
     288                 :         }
     289               0 :         return FAILURE;
     290                 : }
     291                 : /* }}} */
     292                 : 
     293                 : /* {{{ int http_request_pool_perform(http_request_pool *) */
     294                 : PHP_HTTP_API int _http_request_pool_perform(http_request_pool *pool TSRMLS_DC)
     295             304 : {
     296                 :         CURLMsg *msg;
     297             304 :         int remaining = 0;
     298                 :         
     299             414 :         while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(pool->ch, &pool->unfinished));
     300                 :         
     301             669 :         while ((msg = curl_multi_info_read(pool->ch, &remaining))) {
     302              61 :                 if (CURLMSG_DONE == msg->msg) {
     303              61 :                                 if (CURLE_OK != msg->data.result) {
     304               3 :                                         http_request *r = NULL;
     305               3 :                                         curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &r);
     306               3 :                                         http_error_ex(HE_WARNING, HTTP_E_REQUEST, "%s; %s (%s)", curl_easy_strerror(msg->data.result), r?r->_error:"", r?r->url:"");
     307                 :                                 }
     308              61 :                                 http_request_pool_apply_with_arg(pool, _http_request_pool_responsehandler, msg->easy_handle);
     309                 :                 }
     310                 :         }
     311                 :         
     312             304 :         return pool->unfinished;
     313                 : }
     314                 : /* }}} */
     315                 : 
     316                 : /* {{{ void http_request_pool_responsehandler(http_request_pool *, zval *, void *) */
     317                 : int _http_request_pool_responsehandler(http_request_pool *pool, zval *req, void *ch TSRMLS_DC)
     318             237 : {
     319             237 :         getObjectEx(http_request_object, obj, req);
     320                 :         
     321             237 :         if ((!ch) || obj->request->ch == (CURL *) ch) {
     322                 :                 
     323                 : #if HTTP_DEBUG_REQPOOLS
     324                 :                 fprintf(stderr, "Fetching data from HttpRequest(#%d) %p of pool %p\n", Z_OBJ_HANDLE_P(req), obj, obj->pool);
     325                 : #endif
     326                 :                 
     327              61 :                 ZVAL_ADDREF(req);
     328              61 :                 zend_llist_add_element(&obj->pool->finished, &req);
     329              61 :                 http_request_object_responsehandler(obj, req);
     330              61 :                 return 1;
     331                 :         }
     332             176 :         return 0;
     333                 : }
     334                 : /* }}} */
     335                 : 
     336                 : /*#*/
     337                 : 
     338                 : /* {{{ static int http_request_pool_compare_handles(void *, void *) */
     339                 : static int http_request_pool_compare_handles(void *h1, void *h2)
     340             299 : {
     341             299 :         return (Z_OBJ_HANDLE_PP((zval **) h1) == Z_OBJ_HANDLE_P((zval *) h2));
     342                 : }
     343                 : /* }}} */
     344                 : 
     345                 : #endif /* ZEND_ENGINE_2 && HTTP_HAVE_CURL */
     346                 : 
     347                 : 
     348                 : /*
     349                 :  * Local variables:
     350                 :  * tab-width: 4
     351                 :  * c-basic-offset: 4
     352                 :  * End:
     353                 :  * vim600: noet sw=4 ts=4 fdm=marker
     354                 :  * vim<600: noet sw=4 ts=4
     355                 :  */
     356                 : 

Generated by: LTP GCOV extension version 1.5