fix undefined symbol ZEND_ASSERT
[m6w6/ext-http] / src / php_http_client_curl_user.c
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-2014, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
11 */
12
13 #include "php_http_api.h"
14 #include "php_http_client.h"
15 #include "php_http_client_curl.h"
16 #include "php_http_client_curl_user.h"
17
18 #include "php_network.h"
19 #include "zend_closures.h"
20
21 #if PHP_HTTP_HAVE_CURL
22
23 typedef struct php_http_client_curl_user_context {
24 php_http_client_t *client;
25 zval *user;
26 zend_function closure;
27 php_http_object_method_t timer;
28 php_http_object_method_t socket;
29 php_http_object_method_t once;
30 php_http_object_method_t wait;
31 php_http_object_method_t send;
32 } php_http_client_curl_user_context_t;
33
34 typedef struct php_http_client_curl_user_ev {
35 php_stream *socket;
36 php_http_client_curl_user_context_t *context;
37 } php_http_client_curl_user_ev_t;
38
39 static void php_http_client_curl_user_handler(INTERNAL_FUNCTION_PARAMETERS)
40 {
41 zval *zstream = NULL, *zclient = NULL;
42 php_stream *stream = NULL;
43 long action = 0;
44 php_socket_t fd = CURL_SOCKET_TIMEOUT;
45 php_http_client_object_t *client = NULL;
46
47 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|rl", &zclient, php_http_client_class_entry, &zstream, &action)) {
48 return;
49 }
50
51 client = zend_object_store_get_object(zclient TSRMLS_CC);
52 if (zstream) {
53 php_stream_from_zval(stream, &zstream);
54
55 if (SUCCESS != php_stream_cast(stream, PHP_STREAM_AS_SOCKETD, (void *) &fd, 1)) {
56 return;
57 }
58 }
59 php_http_client_curl_loop(client->client, fd, action);
60 }
61
62 static void php_http_client_curl_user_timer(CURLM *multi, long timeout_ms, void *timer_data)
63 {
64 php_http_client_curl_user_context_t *context = timer_data;
65
66 #if DBG_EVENTS
67 fprintf(stderr, "\ntimer <- timeout_ms: %ld\n", timeout_ms);
68 #endif
69
70 if (timeout_ms <= 0) {
71 php_http_client_curl_loop(context->client, CURL_SOCKET_TIMEOUT, 0);
72 } else if (timeout_ms > 0) {
73 zval **args[1], *ztimeout;
74 TSRMLS_FETCH_FROM_CTX(context->client->ts);
75
76 MAKE_STD_ZVAL(ztimeout);
77 ZVAL_LONG(ztimeout, timeout_ms);
78 args[0] = &ztimeout;
79 php_http_object_method_call(&context->timer, context->user, NULL, 1, args TSRMLS_CC);
80 zval_ptr_dtor(&ztimeout);
81 }
82 }
83
84 static int php_http_client_curl_user_socket(CURL *easy, curl_socket_t sock, int action, void *socket_data, void *assign_data)
85 {
86 php_http_client_curl_user_context_t *ctx = socket_data;
87 php_http_client_curl_t *curl = ctx->client->ctx;
88 php_http_client_curl_user_ev_t *ev = assign_data;
89 zval **args[2], *zaction, *zsocket;
90 TSRMLS_FETCH_FROM_CTX(ctx->client->ts);
91
92 #if DBG_EVENTS
93 fprintf(stderr, "S");
94 #endif
95
96 if (!ev) {
97 ev = ecalloc(1, sizeof(*ev));
98 ev->context = ctx;
99 ev->socket = php_stream_sock_open_from_socket(sock, NULL);
100
101 curl_multi_assign(curl->handle->multi, sock, ev);
102 }
103
104 switch (action) {
105 case CURL_POLL_IN:
106 case CURL_POLL_OUT:
107 case CURL_POLL_INOUT:
108 case CURL_POLL_REMOVE:
109 case CURL_POLL_NONE:
110 MAKE_STD_ZVAL(zsocket);
111 php_stream_to_zval(ev->socket, zsocket);
112 args[0] = &zsocket;
113 MAKE_STD_ZVAL(zaction);
114 ZVAL_LONG(zaction, action);
115 args[1] = &zaction;
116 php_http_object_method_call(&ctx->socket, ctx->user, NULL, 2, args TSRMLS_CC);
117 zval_ptr_dtor(&zsocket);
118 zval_ptr_dtor(&zaction);
119 break;
120
121 default:
122 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown socket action %d", action);
123 return -1;
124 }
125
126 if (action == CURL_POLL_REMOVE && ev) {
127 efree(ev);
128 }
129 return 0;
130 }
131
132 static ZEND_RESULT_CODE php_http_client_curl_user_once(void *context)
133 {
134 php_http_client_curl_user_context_t *ctx = context;
135 TSRMLS_FETCH_FROM_CTX(ctx->client->ts);
136
137 #if DBG_EVENTS
138 fprintf(stderr, "O");
139 #endif
140
141 return php_http_object_method_call(&ctx->once, ctx->user, NULL, 0, NULL TSRMLS_CC);
142 }
143
144 static ZEND_RESULT_CODE php_http_client_curl_user_wait(void *context, struct timeval *custom_timeout)
145 {
146 php_http_client_curl_user_context_t *ctx = context;
147 struct timeval timeout;
148 zval **args[1], *ztimeout;
149 ZEND_RESULT_CODE rv;
150 TSRMLS_FETCH_FROM_CTX(ctx->client->ts);
151
152 #if DBG_EVENTS
153 fprintf(stderr, "W");
154 #endif
155
156 if (!custom_timeout || !timerisset(custom_timeout)) {
157 php_http_client_curl_get_timeout(ctx->client->ctx, 1000, &timeout);
158 custom_timeout = &timeout;
159 }
160
161 MAKE_STD_ZVAL(ztimeout);
162 ZVAL_LONG(ztimeout, custom_timeout->tv_sec * 1000 + custom_timeout->tv_usec / 1000);
163 args[0] = &ztimeout;
164 rv = php_http_object_method_call(&ctx->wait, ctx->user, NULL, 1, args TSRMLS_CC);
165 zval_ptr_dtor(&ztimeout);
166
167 return rv;
168 }
169
170 static ZEND_RESULT_CODE php_http_client_curl_user_exec(void *context)
171 {
172 php_http_client_curl_user_context_t *ctx = context;
173 php_http_client_curl_t *curl = ctx->client->ctx;
174 TSRMLS_FETCH_FROM_CTX(ctx->client->ts);
175
176 #if DBG_EVENTS
177 fprintf(stderr, "E");
178 #endif
179
180 /* kickstart */
181 php_http_client_curl_loop(ctx->client, CURL_SOCKET_TIMEOUT, 0);
182
183 do {
184 if (SUCCESS != php_http_object_method_call(&ctx->send, ctx->user, NULL, 0, NULL TSRMLS_CC)) {
185 return FAILURE;
186 }
187 } while (curl->unfinished && !EG(exception));
188
189 return SUCCESS;
190 }
191
192 static void *php_http_client_curl_user_init(php_http_client_t *client, void *user_data)
193 {
194 php_http_client_curl_t *curl = client->ctx;
195 php_http_client_curl_user_context_t *ctx;
196 php_http_object_method_t init;
197 zval *zclosure, **args[1];
198 TSRMLS_FETCH_FROM_CTX(client->ts);
199
200 #if DBG_EVENTS
201 fprintf(stderr, "I");
202 #endif
203
204 ctx = ecalloc(1, sizeof(*ctx));
205 ctx->client = client;
206 ctx->user = user_data;
207 Z_ADDREF_P(ctx->user);
208
209 memset(&ctx->closure, 0, sizeof(ctx->closure));
210 ctx->closure.common.type = ZEND_INTERNAL_FUNCTION;
211 ctx->closure.common.function_name = "php_http_client_curl_user_handler";
212 ctx->closure.internal_function.handler = php_http_client_curl_user_handler;
213
214 MAKE_STD_ZVAL(zclosure);
215 zend_create_closure(zclosure, &ctx->closure, NULL, NULL TSRMLS_CC);
216 args[0] = &zclosure;
217
218 php_http_object_method_init(&init, ctx->user, ZEND_STRL("init") TSRMLS_CC);
219 php_http_object_method_call(&init, ctx->user, NULL, 1, args TSRMLS_CC);
220 php_http_object_method_dtor(&init);
221 zval_ptr_dtor(&zclosure);
222
223 php_http_object_method_init(&ctx->timer, ctx->user, ZEND_STRL("timer") TSRMLS_CC);
224 php_http_object_method_init(&ctx->socket, ctx->user, ZEND_STRL("socket") TSRMLS_CC);
225 php_http_object_method_init(&ctx->once, ctx->user, ZEND_STRL("once") TSRMLS_CC);
226 php_http_object_method_init(&ctx->wait, ctx->user, ZEND_STRL("wait") TSRMLS_CC);
227 php_http_object_method_init(&ctx->send, ctx->user, ZEND_STRL("send") TSRMLS_CC);
228
229 curl_multi_setopt(curl->handle->multi, CURLMOPT_SOCKETDATA, ctx);
230 curl_multi_setopt(curl->handle->multi, CURLMOPT_SOCKETFUNCTION, php_http_client_curl_user_socket);
231 curl_multi_setopt(curl->handle->multi, CURLMOPT_TIMERDATA, ctx);
232 curl_multi_setopt(curl->handle->multi, CURLMOPT_TIMERFUNCTION, php_http_client_curl_user_timer);
233
234 return ctx;
235 }
236
237 static void php_http_client_curl_user_dtor(void **context)
238 {
239 php_http_client_curl_user_context_t *ctx = *context;
240 php_http_client_curl_t *curl;
241
242 #if DBG_EVENTS
243 fprintf(stderr, "D");
244 #endif
245
246 curl = ctx->client->ctx;
247
248 curl_multi_setopt(curl->handle->multi, CURLMOPT_SOCKETDATA, NULL);
249 curl_multi_setopt(curl->handle->multi, CURLMOPT_SOCKETFUNCTION, NULL);
250 curl_multi_setopt(curl->handle->multi, CURLMOPT_TIMERDATA, NULL);
251 curl_multi_setopt(curl->handle->multi, CURLMOPT_TIMERFUNCTION, NULL);
252
253 php_http_object_method_dtor(&ctx->timer);
254 php_http_object_method_dtor(&ctx->socket);
255 php_http_object_method_dtor(&ctx->once);
256 php_http_object_method_dtor(&ctx->wait);
257 php_http_object_method_dtor(&ctx->send);
258
259 zval_ptr_dtor(&ctx->user);
260
261 efree(ctx);
262 *context = NULL;
263 }
264
265 static php_http_client_curl_ops_t php_http_client_curl_user_ops = {
266 &php_http_client_curl_user_init,
267 &php_http_client_curl_user_dtor,
268 &php_http_client_curl_user_once,
269 &php_http_client_curl_user_wait,
270 &php_http_client_curl_user_exec,
271 };
272
273 php_http_client_curl_ops_t *php_http_client_curl_user_ops_get()
274 {
275 return &php_http_client_curl_user_ops;
276 }
277
278 zend_class_entry *php_http_client_curl_user_class_entry;
279
280 ZEND_BEGIN_ARG_INFO_EX(ai_init, 0, 0, 1)
281 ZEND_ARG_TYPE_INFO(0, run, IS_CALLABLE, 0)
282 ZEND_END_ARG_INFO();
283 ZEND_BEGIN_ARG_INFO_EX(ai_timer, 0, 0, 1)
284 #if PHP_VERSION_ID >= 70000
285 ZEND_ARG_TYPE_INFO(0, timeout_ms, IS_LONG, 0)
286 #else
287 ZEND_ARG_INFO(0, timeout_ms)
288 #endif
289 ZEND_END_ARG_INFO();
290 ZEND_BEGIN_ARG_INFO_EX(ai_socket, 0, 0, 2)
291 #if PHP_VERSION_ID >= 70000
292 ZEND_ARG_TYPE_INFO(0, socket, IS_RESOURCE, 0)
293 ZEND_ARG_TYPE_INFO(0, action, IS_LONG, 0)
294 #else
295 ZEND_ARG_INFO(0, socket)
296 ZEND_ARG_INFO(0, action)
297 #endif
298 ZEND_END_ARG_INFO();
299 ZEND_BEGIN_ARG_INFO_EX(ai_once, 0, 0, 0)
300 ZEND_END_ARG_INFO();
301 ZEND_BEGIN_ARG_INFO_EX(ai_wait, 0, 0, 0)
302 #if PHP_VERSION_ID >= 70000
303 ZEND_ARG_TYPE_INFO(0, timeout_ms, IS_LONG, 0)
304 #else
305 ZEND_ARG_INFO(0, timeout_ms)
306 #endif
307 ZEND_END_ARG_INFO();
308 ZEND_BEGIN_ARG_INFO_EX(ai_send, 0, 0, 0)
309 ZEND_END_ARG_INFO();
310
311 static zend_function_entry php_http_client_curl_user_methods[] = {
312 PHP_ABSTRACT_ME(HttpClientCurlUser, init, ai_init)
313 PHP_ABSTRACT_ME(HttpClientCurlUser, timer, ai_timer)
314 PHP_ABSTRACT_ME(HttpClientCurlUser, socket, ai_socket)
315 PHP_ABSTRACT_ME(HttpClientCurlUser, once, ai_once)
316 PHP_ABSTRACT_ME(HttpClientCurlUser, wait, ai_wait)
317 PHP_ABSTRACT_ME(HttpClientCulrUser, send, ai_send)
318 {0}
319 };
320
321 PHP_MINIT_FUNCTION(http_client_curl_user)
322 {
323 zend_class_entry ce = {0};
324
325 INIT_NS_CLASS_ENTRY(ce, "http\\Client\\Curl", "User", php_http_client_curl_user_methods);
326 php_http_client_curl_user_class_entry = zend_register_internal_interface(&ce TSRMLS_CC);
327
328 zend_declare_class_constant_long(php_http_client_curl_user_class_entry, ZEND_STRL("POLL_NONE"), CURL_POLL_NONE TSRMLS_CC);
329 zend_declare_class_constant_long(php_http_client_curl_user_class_entry, ZEND_STRL("POLL_IN"), CURL_POLL_IN TSRMLS_CC);
330 zend_declare_class_constant_long(php_http_client_curl_user_class_entry, ZEND_STRL("POLL_OUT"), CURL_POLL_OUT TSRMLS_CC);
331 zend_declare_class_constant_long(php_http_client_curl_user_class_entry, ZEND_STRL("POLL_INOUT"), CURL_POLL_INOUT TSRMLS_CC);
332 zend_declare_class_constant_long(php_http_client_curl_user_class_entry, ZEND_STRL("POLL_REMOVE"), CURL_POLL_REMOVE TSRMLS_CC);
333
334 return SUCCESS;
335 }
336
337 #endif /* PHP_HTTP_HAVE_CURL */
338
339 /*
340 * Local variables:
341 * tab-width: 4
342 * c-basic-offset: 4
343 * End:
344 * vim600: noet sw=4 ts=4 fdm=marker
345 * vim<600: noet sw=4 ts=4
346 */