- remove const qualifier from url param in http_request_*()
[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->sent = 0;
63 pool->unfinished = 0;
64 zend_llist_init(&pool->handles, sizeof(zval *), (llist_dtor_func_t) ZVAL_PTR_DTOR, 0);
65 zend_llist_init(&pool->bodies, sizeof(http_request_body *), (llist_dtor_func_t) http_request_pool_freebody, 0);
66 #if HTTP_DEBUG_REQPOOLS
67 fprintf(stderr, "Initialized request pool %p\n", pool);
68 #endif
69 return pool;
70 }
71 /* }}} */
72
73 /* {{{ STATUS http_request_pool_attach(http_request_pool *, zval *) */
74 PHP_HTTP_API STATUS _http_request_pool_attach(http_request_pool *pool, zval *request TSRMLS_DC)
75 {
76 getObjectEx(http_request_object, req, request);
77 #if HTTP_DEBUG_REQPOOLS
78 fprintf(stderr, "Attaching request %p to pool %p\n", req, pool);
79 #endif
80 if (req->pool) {
81 http_error(E_WARNING, HTTP_E_CURL, "HttpRequest object is already member of an HttpRequestPool");
82 } else {
83 CURLMcode code;
84 http_request_body *body = http_request_body_new();
85 zval *info = GET_PROP_EX(req, request, responseInfo);
86
87 if (SUCCESS != http_request_object_requesthandler(req, request, body)) {
88 http_error_ex(E_WARNING, HTTP_E_CURL, "Could not initialize HttpRequest object for attaching to the HttpRequestPool");
89 } else {
90 code = curl_multi_add_handle(pool->ch, req->ch);
91 if ((CURLM_OK != code) && (CURLM_CALL_MULTI_PERFORM != code)) {
92 http_error_ex(E_WARNING, HTTP_E_CURL, "Could not attach HttpRequest object to the HttpRequestPool: %s", curl_multi_strerror(code));
93 } else {
94 req->pool = pool;
95 zend_llist_add_element(&pool->handles, &request);
96 zend_llist_add_element(&pool->bodies, &body);
97 zval_add_ref(&request);
98 return SUCCESS;
99 }
100 }
101 efree(body);
102 }
103 return FAILURE;
104 }
105 /* }}} */
106
107 /* {{{ STATUS http_request_pool_detach(http_request_pool *, zval *) */
108 PHP_HTTP_API STATUS _http_request_pool_detach(http_request_pool *pool, zval *request TSRMLS_DC)
109 {
110 getObjectEx(http_request_object, req, request);
111 #if HTTP_DEBUG_REQPOOLS
112 fprintf(stderr, "Detaching request %p from pool %p\n", req, pool);
113 #endif
114 if (req->pool != pool) {
115 http_error(E_WARNING, HTTP_E_CURL, "HttpRequest object is not attached to this HttpRequestPool");
116 } else {
117 CURLMcode code;
118
119 if (CURLM_OK != (code = curl_multi_remove_handle(pool->ch, req->ch))) {
120 http_error_ex(E_WARNING, HTTP_E_CURL, "Could not detach HttpRequest object from the HttpRequestPool: %s", curl_multi_strerror(code));
121 } else {
122 req->pool = NULL;
123 zend_llist_del_element(&pool->handles, request, http_request_pool_compare_handles);
124 return SUCCESS;
125 }
126 }
127 return FAILURE;
128 }
129 /* }}} */
130
131 /* {{{ void http_request_pool_detach_all(http_request_pool *) */
132 PHP_HTTP_API void _http_request_pool_detach_all(http_request_pool *pool TSRMLS_DC)
133 {
134 int count = zend_llist_count(&pool->handles);
135 #if HTTP_DEBUG_REQPOOLS
136 fprintf(stderr, "Detaching %d requests from pool %p\n", count, pool);
137 #endif
138 /*
139 * we cannot apply a function to the llist which actually detaches
140 * the curl handle *and* removes the llist element --
141 * so let's get our hands dirty
142 */
143 if (count) {
144 int i = 0;
145 zend_llist_position pos;
146 zval **handle, **handles = emalloc(count * sizeof(zval *));
147
148 for (handle = zend_llist_get_first_ex(&pool->handles, &pos); handle; handle = zend_llist_get_next_ex(&pool->handles, &pos)) {
149 handles[i++] = *handle;
150 }
151 for (i = 0; i < count; ++i) {
152 http_request_pool_detach(pool, handles[i]);
153 }
154 efree(handles);
155 }
156 }
157
158
159 /* {{{ STATUS http_request_pool_send(http_request_pool *) */
160 PHP_HTTP_API STATUS _http_request_pool_send(http_request_pool *pool TSRMLS_DC)
161 {
162 #if HTTP_DEBUG_REQPOOLS
163 fprintf(stderr, "Attempt to send requests of pool %p\n", pool);
164 #endif
165 if (pool->sent) {
166 http_error(E_WARNING, HTTP_E_CURL, "HttpRequestPools can only be used once");
167 return FAILURE;
168 } else {
169 pool->sent = 1;
170 }
171 while (http_request_pool_perform(pool)) {
172 #if HTTP_DEBUG_REQPOOLS
173 fprintf(stderr, "%d unfinished requests of pool %p remaining\n", pool->unfinished, pool);
174 #endif
175 if (SUCCESS != http_request_pool_select(pool)) {
176 http_error(E_WARNING, HTTP_E_CURL, "Socket error");
177 return FAILURE;
178 }
179 }
180 zend_llist_apply(&pool->handles, (llist_apply_func_t) http_request_pool_responsehandler TSRMLS_CC);
181 return SUCCESS;
182 }
183 /* }}} */
184
185 /* {{{ void http_request_pool_dtor(http_request_pool *) */
186 PHP_HTTP_API void _http_request_pool_dtor(http_request_pool *pool TSRMLS_DC)
187 {
188 #if HTTP_DEBUG_REQPOOLS
189 fprintf(stderr, "Destructing request pool %p\n", pool);
190 #endif
191 pool->unfinished = 0;
192 zend_llist_clean(&pool->handles);
193 zend_llist_clean(&pool->bodies);
194 curl_multi_cleanup(pool->ch);
195 }
196 /* }}} */
197
198 /* {{{ STATUS http_request_pool_select(http_request_pool *) */
199 PHP_HTTP_API STATUS _http_request_pool_select(http_request_pool *pool)
200 {
201 int MAX;
202 fd_set R, W, E;
203 struct timeval timeout = {1, 0};
204
205 FD_ZERO(&R);
206 FD_ZERO(&W);
207 FD_ZERO(&E);
208
209 curl_multi_fdset(pool->ch, &R, &W, &E, &MAX);
210 return (-1 != select(MAX + 1, &R, &W, &E, &timeout)) ? SUCCESS : FAILURE;
211 }
212 /* }}} */
213
214 /* {{{ int http_request_pool_perform(http_request_pool *) */
215 PHP_HTTP_API int _http_request_pool_perform(http_request_pool *pool)
216 {
217 while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(pool->ch, &pool->unfinished));
218 return pool->unfinished;
219 }
220 /* }}} */
221
222 /* {{{ void http_request_pool_responsehandler(zval **) */
223 void _http_request_pool_responsehandler(zval **req TSRMLS_DC)
224 {
225 getObjectEx(http_request_object, obj, *req);
226 #if HTTP_DEBUG_REQPOOLS
227 fprintf(stderr, "Fetching data from request %p of pool %p\n", obj, obj->pool);
228 #endif
229 http_request_object_responsehandler(obj, *req);
230 }
231 /* }}} */
232
233 /*#*/
234
235 /* {{{ static void http_request_pool_freebody(http_request_body **) */
236 static void http_request_pool_freebody(http_request_body **body)
237 {
238 TSRMLS_FETCH();
239 http_request_body_free(*body);
240 }
241 /* }}} */
242
243 /* {{{ static int http_request_pool_compare_handles(void *, void *) */
244 static int http_request_pool_compare_handles(void *h1, void *h2)
245 {
246 return ((*((zval **) h1)) == ((zval *) h2));
247 }
248 /* }}} */
249
250 #endif /* ZEND_ENGINE_2 */
251
252
253 /*
254 * Local variables:
255 * tab-width: 4
256 * c-basic-offset: 4
257 * End:
258 * vim600: noet sw=4 ts=4 fdm=marker
259 * vim<600: noet sw=4 ts=4
260 */
261