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"
15 #if PHP_HTTP_HAVE_LIBCURL
16 #if PHP_HTTP_HAVE_LIBEVENT
23 typedef struct php_http_client_curl_event_context
{
24 php_http_client_t
*client
;
25 struct event_base
*evbase
;
26 struct event
*timeout
;
27 } php_http_client_curl_event_context_t
;
29 typedef struct php_http_client_curl_event_ev
{
31 php_http_client_curl_event_context_t
*context
;
32 } php_http_client_curl_event_ev_t
;
34 static inline int etoca(short action
) {
35 switch (action
& (EV_READ
|EV_WRITE
)) {
37 return CURL_CSELECT_IN
;
40 return CURL_CSELECT_OUT
;
42 case EV_READ
|EV_WRITE
:
43 return CURL_CSELECT_IN
|CURL_CSELECT_OUT
;
50 static void php_http_client_curl_event_handler(void *context
, curl_socket_t s
, int curl_action
)
53 php_http_client_curl_event_context_t
*ctx
= context
;
54 php_http_client_curl_t
*curl
= ctx
->client
->ctx
;
61 rc
= curl_multi_socket_action(curl
->handle
->multi
, s
, curl_action
, &curl
->unfinished
);
62 } while (CURLM_CALL_MULTI_PERFORM
== rc
);
65 php_error_docref(NULL
, E_WARNING
, "%s", curl_multi_strerror(rc
));
68 php_http_client_curl_responsehandler(ctx
->client
);
71 static void php_http_client_curl_event_timeout_callback(int socket
, short action
, void *event_data
)
77 /* ignore and use -1,0 on timeout */
81 php_http_client_curl_event_handler(event_data
, CURL_SOCKET_TIMEOUT
, 0);
84 static void php_http_client_curl_event_timer(CURLM
*multi
, long timeout_ms
, void *timer_data
)
86 php_http_client_curl_event_context_t
*context
= timer_data
;
87 struct timeval timeout
;
90 fprintf(stderr
, "(%ld)", timeout_ms
);
95 if (event_initialized(context
->timeout
) && event_pending(context
->timeout
, EV_TIMEOUT
, NULL
)) {
96 event_del(context
->timeout
);
100 php_http_client_curl_event_handler(context
, CURL_SOCKET_TIMEOUT
, 0);
103 if (!event_initialized(context
->timeout
)) {
104 event_assign(context
->timeout
, context
->evbase
, CURL_SOCKET_TIMEOUT
, 0, php_http_client_curl_event_timeout_callback
, context
);
107 timeout
.tv_sec
= timeout_ms
/ 1000;
108 timeout
.tv_usec
= (timeout_ms
% 1000) * 1000;
110 if (!event_pending(context
->timeout
, EV_TIMEOUT
, &timeout
)) {
111 event_add(context
->timeout
, &timeout
);
117 static void php_http_client_curl_event_callback(int socket
, short action
, void *event_data
)
119 php_http_client_curl_event_context_t
*ctx
= event_data
;
120 php_http_client_curl_t
*curl
= ctx
->client
->ctx
;
123 fprintf(stderr
, "E");
126 php_http_client_curl_event_handler(event_data
, socket
, etoca(action
));
128 /* remove timeout if there are no transfers left */
129 if (!curl
->unfinished
&& event_initialized(ctx
->timeout
) && event_pending(ctx
->timeout
, EV_TIMEOUT
, NULL
)) {
130 event_del(ctx
->timeout
);
134 static int php_http_client_curl_event_socket(CURL
*easy
, curl_socket_t sock
, int action
, void *socket_data
, void *assign_data
)
136 php_http_client_curl_event_context_t
*ctx
= socket_data
;
137 php_http_client_curl_t
*curl
= ctx
->client
->ctx
;
138 int events
= EV_PERSIST
;
139 php_http_client_curl_event_ev_t
*ev
= assign_data
;
142 fprintf(stderr
, "S");
146 ev
= ecalloc(1, sizeof(*ev
));
148 curl_multi_assign(curl
->handle
->multi
, sock
, ev
);
150 event_del(&ev
->evnt
);
160 case CURL_POLL_INOUT
:
161 events
|= EV_READ
|EV_WRITE
;
164 case CURL_POLL_REMOVE
:
171 php_error_docref(NULL
, E_WARNING
, "Unknown socket action %d", action
);
175 event_assign(&ev
->evnt
, ctx
->evbase
, sock
, events
, php_http_client_curl_event_callback
, ctx
);
176 event_add(&ev
->evnt
, NULL
);
181 static ZEND_RESULT_CODE
php_http_client_curl_event_once(void *context
)
183 php_http_client_curl_event_context_t
*ctx
= context
;
186 fprintf(stderr
, "O");
189 if (0 > event_base_loop(ctx
->evbase
, EVLOOP_NONBLOCK
)) {
195 static ZEND_RESULT_CODE
php_http_client_curl_event_wait(void *context
, struct timeval
*custom_timeout
)
197 php_http_client_curl_event_context_t
*ctx
= context
;
198 struct timeval timeout
;
201 fprintf(stderr
, "W");
204 if (!event_initialized(ctx
->timeout
)) {
205 if (0 > event_assign(ctx
->timeout
, ctx
->evbase
, CURL_SOCKET_TIMEOUT
, 0, php_http_client_curl_event_timeout_callback
, ctx
)) {
208 } else if (custom_timeout
&& timerisset(custom_timeout
)) {
209 if (0 > event_add(ctx
->timeout
, custom_timeout
)) {
212 } else if (!event_pending(ctx
->timeout
, EV_TIMEOUT
, NULL
)) {
213 php_http_client_curl_get_timeout(ctx
->client
->ctx
, 1000, &timeout
);
214 if (0 > event_add(ctx
->timeout
, &timeout
)) {
219 if (0 > event_base_loop(ctx
->evbase
, EVLOOP_ONCE
)) {
226 static ZEND_RESULT_CODE
php_http_client_curl_event_exec(void *context
)
228 php_http_client_curl_event_context_t
*ctx
= context
;
229 php_http_client_curl_t
*curl
= ctx
->client
->ctx
;
232 fprintf(stderr
, "E");
236 php_http_client_curl_event_handler(ctx
, CURL_SOCKET_TIMEOUT
, 0);
239 if (0 > event_base_dispatch(ctx
->evbase
)) {
242 } while (curl
->unfinished
&& !EG(exception
));
247 static void *php_http_client_curl_event_init(php_http_client_t
*client
)
249 php_http_client_curl_t
*curl
= client
->ctx
;
250 php_http_client_curl_event_context_t
*ctx
;
251 struct event_base
*evb
= event_base_new();
254 fprintf(stderr
, "I");
261 ctx
= ecalloc(1, sizeof(*ctx
));
262 ctx
->client
= client
;
264 ctx
->timeout
= ecalloc(1, sizeof(struct event
));
266 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETDATA
, ctx
);
267 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETFUNCTION
, php_http_client_curl_event_socket
);
268 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERDATA
, ctx
);
269 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERFUNCTION
, php_http_client_curl_event_timer
);
274 static void php_http_client_curl_event_dtor(void **context
)
276 php_http_client_curl_event_context_t
*ctx
= *context
;
277 php_http_client_curl_t
*curl
;
280 fprintf(stderr
, "D");
283 curl
= ctx
->client
->ctx
;
285 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETDATA
, NULL
);
286 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETFUNCTION
, NULL
);
287 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERDATA
, NULL
);
288 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERFUNCTION
, NULL
);
290 if (event_initialized(ctx
->timeout
) && event_pending(ctx
->timeout
, EV_TIMEOUT
, NULL
)) {
291 event_del(ctx
->timeout
);
294 event_base_free(ctx
->evbase
);
300 static php_http_client_curl_ops_t php_http_client_curl_event_ops
= {
301 &php_http_client_curl_event_init
,
302 &php_http_client_curl_event_dtor
,
303 &php_http_client_curl_event_once
,
304 &php_http_client_curl_event_wait
,
305 &php_http_client_curl_event_exec
,
308 php_http_client_curl_ops_t
*php_http_client_curl_event_ops_get()
310 return &php_http_client_curl_event_ops
;
313 #endif /* PHP_HTTP_HAVE_LIBEVENT */
314 #endif /* PHP_HTTP_HAVE_LIBCURL */
321 * vim600: noet sw=4 ts=4 fdm=marker
322 * vim<600: noet sw=4 ts=4