a38e73fc10f6f2f5a0148d97b0cf0f7aa0251ee3
[m6w6/ext-http] / http_request_pool_api.c
1 /*
2 +----------------------------------------------------------------------+
3 | PECL :: http |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.0 of the PHP license, that |
6 | is bundled with this package in the file LICENSE, and is available |
7 | through the world-wide-web at http://www.php.net/license/3_0.txt. |
8 | If you did not receive a copy of the PHP license and are unable to |
9 | obtain it through the world-wide-web, please send a note to |
10 | license@php.net so we can mail you a copy immediately. |
11 +----------------------------------------------------------------------+
12 | Copyright (c) 2004-2005 Michael Wallner <mike@php.net> |
13 +----------------------------------------------------------------------+
14 */
15
16 /* $Id$ */
17
18 #ifdef HAVE_CONFIG_H
19 # include "config.h"
20 #endif
21
22 #include "php.h"
23 #include "php_http.h"
24 #include "php_http_std_defs.h"
25 #include "php_http_api.h"
26 #include "php_http_request_api.h"
27 #include "php_http_request_pool_api.h"
28 #include "php_http_request_object.h"
29 #include "php_http_requestpool_object.h"
30
31 #ifdef ZEND_ENGINE_2
32
33 #ifndef HTTP_DEBUG_REQPOOLS
34 # define HTTP_DEBUG_REQPOOLS 0
35 #endif
36
37 static void http_request_pool_freebody(http_request_body **body);
38 static int http_request_pool_compare_handles(void *h1, void *h2);
39
40 /* {{{ http_request_pool *http_request_pool_init(http_request_pool *) */
41 PHP_HTTP_API http_request_pool *_http_request_pool_init(http_request_pool *pool TSRMLS_DC)
42 {
43 zend_bool free_pool;
44 #if HTTP_DEBUG_REQPOOLS
45 fprintf(stderr, "Initializing request pool\n");
46 #endif
47 if ((free_pool = (!pool))) {
48 pool = emalloc(sizeof(http_request_pool));
49 pool->ch = NULL;
50 }
51
52 if (!pool->ch) {
53 if (!(pool->ch = curl_multi_init())) {
54 http_error(E_WARNING, HTTP_E_CURL, "Could not initialize curl");
55 if (free_pool) {
56 efree(pool);
57 }
58 return NULL;
59 }
60 }
61
62 pool->unfinished = 0;
63 zend_llist_init(&pool->handles, sizeof(zval *), (llist_dtor_func_t) ZVAL_PTR_DTOR, 0);
64 zend_llist_init(&pool->bodies, sizeof(http_request_body *), (llist_dtor_func_t) http_request_pool_freebody, 0);
65 #if HTTP_DEBUG_REQPOOLS
66 fprintf(stderr, "Initialized request pool %p\n", pool);
67 #endif
68 return pool;
69 }
70 /* }}} */
71
72 /* {{{ STATUS http_request_pool_attach(http_request_pool *, zval *) */
73 PHP_HTTP_API STATUS _http_request_pool_attach(http_request_pool *pool, zval *request TSRMLS_DC)
74 {
75 getObjectEx(http_request_object, req, request);
76 #if HTTP_DEBUG_REQPOOLS
77 fprintf(stderr, "Attaching request %p to pool %p\n", req, pool);
78 #endif
79 if (req->pool) {
80 http_error(E_WARNING, HTTP_E_CURL, "HttpRequest object is already member of an HttpRequestPool");
81 } else {
82 CURLMcode code;
83 http_request_body *body = http_request_body_new();
84 zval *info = GET_PROP_EX(req, request, responseInfo);
85
86 if (SUCCESS != http_request_object_requesthandler(req, request, body)) {
87 http_error_ex(E_WARNING, HTTP_E_CURL, "Could not initialize HttpRequest object for attaching to the HttpRequestPool");
88 } else {
89 code = curl_multi_add_handle(pool->ch, req->ch);
90 if ((CURLM_OK != code) && (CURLM_CALL_MULTI_PERFORM != code)) {
91 http_error_ex(E_WARNING, HTTP_E_CURL, "Could not attach HttpRequest object to the HttpRequestPool: %s", curl_multi_strerror(code));
92 } else {
93 req->pool = pool;
94 zend_llist_add_element(&pool->handles, &request);
95 zend_llist_add_element(&pool->bodies, &body);
96 zval_add_ref(&request);
97 return SUCCESS;
98 }
99 }
100 efree(body);
101 }
102 return FAILURE;
103 }
104 /* }}} */
105
106 /* {{{ STATUS http_request_pool_detach(http_request_pool *, zval *) */
107 PHP_HTTP_API STATUS _http_request_pool_detach(http_request_pool *pool, zval *request TSRMLS_DC)
108 {
109 getObjectEx(http_request_object, req, request);
110 #if HTTP_DEBUG_REQPOOLS
111 fprintf(stderr, "Detaching request %p (pool: %p) from pool %p\n", req, req->pool, pool);
112 #endif
113 if (req->pool != pool) {
114 http_error(E_WARNING, HTTP_E_CURL, "HttpRequest object is not attached to this HttpRequestPool");
115 } else {
116 CURLMcode code;
117
118 if (CURLM_OK != (code = curl_multi_remove_handle(pool->ch, req->ch))) {
119 http_error_ex(E_WARNING, HTTP_E_CURL, "Could not detach HttpRequest object from the HttpRequestPool: %s", curl_multi_strerror(code));
120 } else {
121 req->pool = NULL;
122 zend_llist_del_element(&pool->handles, request, http_request_pool_compare_handles);
123 return SUCCESS;
124 }
125 }
126 return FAILURE;
127 }
128 /* }}} */
129
130 /* {{{ void http_request_pool_detach_all(http_request_pool *) */
131 PHP_HTTP_API void _http_request_pool_detach_all(http_request_pool *pool TSRMLS_DC)
132 {
133 int count = zend_llist_count(&pool->handles);
134 #if HTTP_DEBUG_REQPOOLS
135 fprintf(stderr, "Detaching %d requests from pool %p\n", count, pool);
136 #endif
137 /*
138 * we cannot apply a function to the llist which actually detaches
139 * the curl handle *and* removes the llist element --
140 * so let's get our hands dirty
141 */
142 if (count) {
143 int i = 0;
144 zend_llist_position pos;
145 zval **handle, **handles = emalloc(count * sizeof(zval *));
146
147 for (handle = zend_llist_get_first_ex(&pool->handles, &pos); handle; handle = zend_llist_get_next_ex(&pool->handles, &pos)) {
148 handles[i++] = *handle;
149 }
150 for (i = 0; i < count; ++i) {
151 http_request_pool_detach(pool, handles[i]);
152 }
153 }
154 }
155
156
157 /* {{{ STATUS http_request_pool_send(http_request_pool *) */
158 PHP_HTTP_API STATUS _http_request_pool_send(http_request_pool *pool TSRMLS_DC)
159 {
160 #if HTTP_DEBUG_REQPOOLS
161 fprintf(stderr, "Attempt to send requests of pool %p\n", pool);
162 #endif
163 while (http_request_pool_perform(pool)) {
164 #if HTTP_DEBUG_REQPOOLS
165 fprintf(stderr, "%d unfinished requests of pool %p remaining\n", pool->unfinished, pool);
166 #endif
167 if (SUCCESS != http_request_pool_select(pool)) {
168 http_error(E_WARNING, HTTP_E_CURL, "Socket error");
169 return FAILURE;
170 }
171 }
172 zend_llist_apply(&pool->handles, (llist_apply_func_t) http_request_pool_responsehandler TSRMLS_CC);
173 return SUCCESS;
174 }
175 /* }}} */
176
177 /* {{{ void http_request_pool_dtor(http_request_pool *) */
178 PHP_HTTP_API void _http_request_pool_dtor(http_request_pool *pool TSRMLS_DC)
179 {
180 #if HTTP_DEBUG_REQPOOLS
181 fprintf(stderr, "Destructing request pool %p\n", pool);
182 #endif
183 pool->unfinished = 0;
184 zend_llist_clean(&pool->handles);
185 zend_llist_clean(&pool->bodies);
186 curl_multi_cleanup(pool->ch);
187 }
188 /* }}} */
189
190 /* {{{ STATUS http_request_pool_select(http_request_pool *) */
191 PHP_HTTP_API STATUS _http_request_pool_select(http_request_pool *pool)
192 {
193 int MAX;
194 fd_set R, W, E;
195 struct timeval timeout = {1, 0};
196
197 FD_ZERO(&R);
198 FD_ZERO(&W);
199 FD_ZERO(&E);
200
201 curl_multi_fdset(pool->ch, &R, &W, &E, &MAX);
202 return (-1 != select(MAX + 1, &R, &W, &E, &timeout)) ? SUCCESS : FAILURE;
203 }
204 /* }}} */
205
206 /* {{{ int http_request_pool_perform(http_request_pool *) */
207 PHP_HTTP_API int _http_request_pool_perform(http_request_pool *pool)
208 {
209 while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(pool->ch, &pool->unfinished));
210 return pool->unfinished;
211 }
212 /* }}} */
213
214 /* {{{ void http_request_pool_responsehandler(zval **) */
215 void _http_request_pool_responsehandler(zval **req TSRMLS_DC)
216 {
217 getObjectEx(http_request_object, obj, *req);
218 #if HTTP_DEBUG_REQPOOLS
219 fprintf(stderr, "Fetching data from request %p of pool %p\n", obj, obj->pool);
220 #endif
221 http_request_object_responsehandler(obj, *req);
222 }
223 /* }}} */
224
225 /*#*/
226
227 /* {{{ static void http_request_pool_freebody(http_request_body **) */
228 static void http_request_pool_freebody(http_request_body **body)
229 {
230 TSRMLS_FETCH();
231 http_request_body_free(*body);
232 }
233 /* }}} */
234
235 /* {{{ static int http_request_pool_compare_handles(void *, void *) */
236 static int http_request_pool_compare_handles(void *h1, void *h2)
237 {
238 return ((*((zval **) h1)) == ((zval *) h2));
239 }
240 /* }}} */
241
242 #endif /* ZEND_ENGINE_2 */
243
244
245 /*
246 * Local variables:
247 * tab-width: 4
248 * c-basic-offset: 4
249 * End:
250 * vim600: noet sw=4 ts=4 fdm=marker
251 * vim<600: noet sw=4 ts=4
252 */
253