2 +--------------------------------------------------------------------+
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 +--------------------------------------------------------------------+
13 #include "php_http_api.h"
14 #include "php_http_client.h"
15 #include "php_http_client_curl.h"
17 #if PHP_HTTP_HAVE_CURL
18 #if PHP_HTTP_HAVE_EVENT
19 # if !PHP_HTTP_HAVE_EVENT2 && /* just be really sure */ !(LIBEVENT_VERSION_NUMBER >= 0x02000000)
21 # define event_base_new event_init
22 # define event_assign(e, b, s, a, cb, d) do {\
23 event_set(e, s, a, cb, d); \
24 event_base_set(b, e); \
27 # if PHP_HTTP_HAVE_EVENT2
28 # include <event2/event.h>
29 # include <event2/event_struct.h>
31 # error "libevent presence is unknown"
38 typedef struct php_http_client_curl_event_context
{
39 php_http_client_t
*client
;
40 struct event_base
*evbase
;
41 struct event
*timeout
;
42 } php_http_client_curl_event_context_t
;
44 typedef struct php_http_client_curl_event_ev
{
46 php_http_client_curl_event_context_t
*context
;
47 } php_http_client_curl_event_ev_t
;
49 static inline int etoca(short action
) {
50 switch (action
& (EV_READ
|EV_WRITE
)) {
52 return CURL_CSELECT_IN
;
55 return CURL_CSELECT_OUT
;
57 case EV_READ
|EV_WRITE
:
58 return CURL_CSELECT_IN
|CURL_CSELECT_OUT
;
65 static void php_http_client_curl_event_handler(void *context
, curl_socket_t s
, int curl_action
)
68 php_http_client_curl_event_context_t
*ctx
= context
;
69 php_http_client_curl_t
*curl
= ctx
->client
->ctx
;
70 TSRMLS_FETCH_FROM_CTX(ctx
->client
->ts
);
77 rc
= curl_multi_socket_action(curl
->handle
->multi
, s
, curl_action
, &curl
->unfinished
);
78 } while (CURLM_CALL_MULTI_PERFORM
== rc
);
81 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "%s", curl_multi_strerror(rc
));
84 php_http_client_curl_responsehandler(ctx
->client
);
87 static void php_http_client_curl_event_timeout_callback(int socket
, short action
, void *event_data
)
93 /* ignore and use -1,0 on timeout */
97 php_http_client_curl_event_handler(event_data
, CURL_SOCKET_TIMEOUT
, 0);
100 static void php_http_client_curl_event_timer(CURLM
*multi
, long timeout_ms
, void *timer_data
)
102 php_http_client_curl_event_context_t
*context
= timer_data
;
103 struct timeval timeout
;
106 fprintf(stderr
, "(%ld)", timeout_ms
);
109 switch (timeout_ms
) {
111 if (event_initialized(context
->timeout
) && event_pending(context
->timeout
, EV_TIMEOUT
, NULL
)) {
112 event_del(context
->timeout
);
116 php_http_client_curl_event_handler(context
, CURL_SOCKET_TIMEOUT
, 0);
119 if (!event_initialized(context
->timeout
)) {
120 event_assign(context
->timeout
, context
->evbase
, CURL_SOCKET_TIMEOUT
, 0, php_http_client_curl_event_timeout_callback
, context
);
123 timeout
.tv_sec
= timeout_ms
/ 1000;
124 timeout
.tv_usec
= (timeout_ms
% 1000) * 1000;
126 if (!event_pending(context
->timeout
, EV_TIMEOUT
, &timeout
)) {
127 event_add(context
->timeout
, &timeout
);
133 static void php_http_client_curl_event_callback(int socket
, short action
, void *event_data
)
135 php_http_client_curl_event_context_t
*ctx
= event_data
;
136 php_http_client_curl_t
*curl
= ctx
->client
->ctx
;
139 fprintf(stderr
, "E");
142 php_http_client_curl_event_handler(event_data
, socket
, etoca(action
));
144 /* remove timeout if there are no transfers left */
145 if (!curl
->unfinished
&& event_initialized(ctx
->timeout
) && event_pending(ctx
->timeout
, EV_TIMEOUT
, NULL
)) {
146 event_del(ctx
->timeout
);
150 static int php_http_client_curl_event_socket(CURL
*easy
, curl_socket_t sock
, int action
, void *socket_data
, void *assign_data
)
152 php_http_client_curl_event_context_t
*ctx
= socket_data
;
153 php_http_client_curl_t
*curl
= ctx
->client
->ctx
;
154 int events
= EV_PERSIST
;
155 php_http_client_curl_event_ev_t
*ev
= assign_data
;
156 TSRMLS_FETCH_FROM_CTX(ctx
->client
->ts
);
159 fprintf(stderr
, "S");
163 ev
= ecalloc(1, sizeof(*ev
));
165 curl_multi_assign(curl
->handle
->multi
, sock
, ev
);
167 event_del(&ev
->evnt
);
177 case CURL_POLL_INOUT
:
178 events
|= EV_READ
|EV_WRITE
;
181 case CURL_POLL_REMOVE
:
188 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Unknown socket action %d", action
);
192 event_assign(&ev
->evnt
, ctx
->evbase
, sock
, events
, php_http_client_curl_event_callback
, ctx
);
193 event_add(&ev
->evnt
, NULL
);
198 static ZEND_RESULT_CODE
php_http_client_curl_event_once(void *context
)
200 php_http_client_curl_event_context_t
*ctx
= context
;
203 fprintf(stderr
, "O");
206 if (0 > event_base_loop(ctx
->evbase
, EVLOOP_NONBLOCK
)) {
212 static ZEND_RESULT_CODE
php_http_client_curl_event_wait(void *context
, struct timeval
*custom_timeout
)
214 php_http_client_curl_event_context_t
*ctx
= context
;
215 struct timeval timeout
;
218 fprintf(stderr
, "W");
221 if (!event_initialized(ctx
->timeout
)) {
222 if (0 > event_assign(ctx
->timeout
, ctx
->evbase
, CURL_SOCKET_TIMEOUT
, 0, php_http_client_curl_event_timeout_callback
, ctx
)) {
225 } else if (custom_timeout
&& timerisset(custom_timeout
)) {
226 if (0 > event_add(ctx
->timeout
, custom_timeout
)) {
229 } else if (!event_pending(ctx
->timeout
, EV_TIMEOUT
, NULL
)) {
230 php_http_client_curl_get_timeout(ctx
->client
->ctx
, 1000, &timeout
);
231 if (0 > event_add(ctx
->timeout
, &timeout
)) {
236 if (0 > event_base_loop(ctx
->evbase
, EVLOOP_ONCE
)) {
243 static ZEND_RESULT_CODE
php_http_client_curl_event_exec(void *context
)
245 php_http_client_curl_event_context_t
*ctx
= context
;
246 php_http_client_curl_t
*curl
= ctx
->client
->ctx
;
247 TSRMLS_FETCH_FROM_CTX(ctx
->client
->ts
);
250 fprintf(stderr
, "E");
254 php_http_client_curl_event_handler(ctx
, CURL_SOCKET_TIMEOUT
, 0);
257 if (0 > event_base_dispatch(ctx
->evbase
)) {
260 } while (curl
->unfinished
&& !EG(exception
));
265 static void *php_http_client_curl_event_init(php_http_client_t
*client
)
267 php_http_client_curl_t
*curl
= client
->ctx
;
268 php_http_client_curl_event_context_t
*ctx
;
269 struct event_base
*evb
= event_base_new();
272 fprintf(stderr
, "I");
279 ctx
= ecalloc(1, sizeof(*ctx
));
280 ctx
->client
= client
;
282 ctx
->timeout
= ecalloc(1, sizeof(struct event
));
284 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETDATA
, ctx
);
285 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETFUNCTION
, php_http_client_curl_event_socket
);
286 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERDATA
, ctx
);
287 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERFUNCTION
, php_http_client_curl_event_timer
);
292 static void php_http_client_curl_event_dtor(void **context
)
294 php_http_client_curl_event_context_t
*ctx
= *context
;
295 php_http_client_curl_t
*curl
;
298 fprintf(stderr
, "D");
301 curl
= ctx
->client
->ctx
;
303 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETDATA
, NULL
);
304 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETFUNCTION
, NULL
);
305 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERDATA
, NULL
);
306 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERFUNCTION
, NULL
);
308 if (event_initialized(ctx
->timeout
) && event_pending(ctx
->timeout
, EV_TIMEOUT
, NULL
)) {
309 event_del(ctx
->timeout
);
312 event_base_free(ctx
->evbase
);
318 static php_http_client_curl_ops_t php_http_client_curl_event_ops
= {
319 &php_http_client_curl_event_init
,
320 &php_http_client_curl_event_dtor
,
321 &php_http_client_curl_event_once
,
322 &php_http_client_curl_event_wait
,
323 &php_http_client_curl_event_exec
,
326 php_http_client_curl_ops_t
*php_http_client_curl_event_ops_get()
328 return &php_http_client_curl_event_ops
;
331 #endif /* PHP_HTTP_HAVE_EVENT */
332 #endif /* PHP_HTTP_HAVE_CURL */
339 * vim600: noet sw=4 ts=4 fdm=marker
340 * vim<600: noet sw=4 ts=4