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_CURL
16 #if PHP_HTTP_HAVE_EVENT
17 # if !PHP_HTTP_HAVE_EVENT2 && /* just be really sure */ !(LIBEVENT_VERSION_NUMBER >= 0x02000000)
19 # define event_base_new event_init
20 # define event_assign(e, b, s, a, cb, d) do {\
21 event_set(e, s, a, cb, d); \
22 event_base_set(b, e); \
25 # if PHP_HTTP_HAVE_EVENT2
26 # include <event2/event.h>
27 # include <event2/event_struct.h>
29 # error "libevent presence is unknown"
36 typedef struct php_http_client_curl_event_context
{
37 php_http_client_t
*client
;
38 struct event_base
*evbase
;
39 struct event
*timeout
;
40 } php_http_client_curl_event_context_t
;
42 typedef struct php_http_client_curl_event_ev
{
44 php_http_client_curl_event_context_t
*context
;
45 } php_http_client_curl_event_ev_t
;
47 static inline int etoca(short action
) {
48 switch (action
& (EV_READ
|EV_WRITE
)) {
50 return CURL_CSELECT_IN
;
53 return CURL_CSELECT_OUT
;
55 case EV_READ
|EV_WRITE
:
56 return CURL_CSELECT_IN
|CURL_CSELECT_OUT
;
63 static void php_http_client_curl_event_handler(void *context
, curl_socket_t s
, int curl_action
)
66 php_http_client_curl_event_context_t
*ctx
= context
;
67 php_http_client_curl_t
*curl
= ctx
->client
->ctx
;
74 rc
= curl_multi_socket_action(curl
->handle
->multi
, s
, curl_action
, &curl
->unfinished
);
75 } while (CURLM_CALL_MULTI_PERFORM
== rc
);
78 php_error_docref(NULL
, E_WARNING
, "%s", curl_multi_strerror(rc
));
81 php_http_client_curl_responsehandler(ctx
->client
);
84 static void php_http_client_curl_event_timeout_callback(int socket
, short action
, void *event_data
)
90 /* ignore and use -1,0 on timeout */
94 php_http_client_curl_event_handler(event_data
, CURL_SOCKET_TIMEOUT
, 0);
97 static void php_http_client_curl_event_timer(CURLM
*multi
, long timeout_ms
, void *timer_data
)
99 php_http_client_curl_event_context_t
*context
= timer_data
;
102 fprintf(stderr
, "\ntimer <- timeout_ms: %ld\n", timeout_ms
);
105 if (timeout_ms
< 0) {
106 php_http_client_curl_event_handler(context
, CURL_SOCKET_TIMEOUT
, 0);
107 } else if (timeout_ms
> 0 || !event_initialized(context
->timeout
) || !event_pending(context
->timeout
, EV_TIMEOUT
, NULL
)) {
108 struct timeval timeout
;
110 if (!event_initialized(context
->timeout
)) {
111 event_assign(context
->timeout
, context
->evbase
, CURL_SOCKET_TIMEOUT
, 0, php_http_client_curl_event_timeout_callback
, context
);
114 timeout
.tv_sec
= timeout_ms
/ 1000;
115 timeout
.tv_usec
= (timeout_ms
% 1000) * 1000;
117 event_add(context
->timeout
, &timeout
);
121 static void php_http_client_curl_event_callback(int socket
, short action
, void *event_data
)
123 php_http_client_curl_event_context_t
*ctx
= event_data
;
124 php_http_client_curl_t
*curl
= ctx
->client
->ctx
;
127 fprintf(stderr
, "E");
130 php_http_client_curl_event_handler(event_data
, socket
, etoca(action
));
132 /* remove timeout if there are no transfers left */
133 if (!curl
->unfinished
&& event_initialized(ctx
->timeout
) && event_pending(ctx
->timeout
, EV_TIMEOUT
, NULL
)) {
134 event_del(ctx
->timeout
);
138 static int php_http_client_curl_event_socket(CURL
*easy
, curl_socket_t sock
, int action
, void *socket_data
, void *assign_data
)
140 php_http_client_curl_event_context_t
*ctx
= socket_data
;
141 php_http_client_curl_t
*curl
= ctx
->client
->ctx
;
142 int events
= EV_PERSIST
;
143 php_http_client_curl_event_ev_t
*ev
= assign_data
;
146 fprintf(stderr
, "S");
150 ev
= ecalloc(1, sizeof(*ev
));
152 curl_multi_assign(curl
->handle
->multi
, sock
, ev
);
154 event_del(&ev
->evnt
);
164 case CURL_POLL_INOUT
:
165 events
|= EV_READ
|EV_WRITE
;
168 case CURL_POLL_REMOVE
:
175 php_error_docref(NULL
, E_WARNING
, "Unknown socket action %d", action
);
179 event_assign(&ev
->evnt
, ctx
->evbase
, sock
, events
, php_http_client_curl_event_callback
, ctx
);
180 event_add(&ev
->evnt
, NULL
);
185 static ZEND_RESULT_CODE
php_http_client_curl_event_once(void *context
)
187 php_http_client_curl_event_context_t
*ctx
= context
;
190 fprintf(stderr
, "O");
193 if (0 > event_base_loop(ctx
->evbase
, EVLOOP_NONBLOCK
)) {
199 static ZEND_RESULT_CODE
php_http_client_curl_event_wait(void *context
, struct timeval
*custom_timeout
)
201 php_http_client_curl_event_context_t
*ctx
= context
;
202 struct timeval timeout
;
205 fprintf(stderr
, "W");
208 if (!event_initialized(ctx
->timeout
)) {
209 if (0 > event_assign(ctx
->timeout
, ctx
->evbase
, CURL_SOCKET_TIMEOUT
, 0, php_http_client_curl_event_timeout_callback
, ctx
)) {
212 } else if (custom_timeout
&& timerisset(custom_timeout
)) {
213 if (0 > event_add(ctx
->timeout
, custom_timeout
)) {
216 } else if (!event_pending(ctx
->timeout
, EV_TIMEOUT
, NULL
)) {
217 php_http_client_curl_get_timeout(ctx
->client
->ctx
, 1000, &timeout
);
218 if (0 > event_add(ctx
->timeout
, &timeout
)) {
223 if (0 > event_base_loop(ctx
->evbase
, EVLOOP_ONCE
)) {
230 static ZEND_RESULT_CODE
php_http_client_curl_event_exec(void *context
)
232 php_http_client_curl_event_context_t
*ctx
= context
;
233 php_http_client_curl_t
*curl
= ctx
->client
->ctx
;
236 fprintf(stderr
, "E");
240 php_http_client_curl_event_handler(ctx
, CURL_SOCKET_TIMEOUT
, 0);
243 if (0 > event_base_dispatch(ctx
->evbase
)) {
246 } while (curl
->unfinished
&& !EG(exception
));
251 static void *php_http_client_curl_event_init(php_http_client_t
*client
)
253 php_http_client_curl_t
*curl
= client
->ctx
;
254 php_http_client_curl_event_context_t
*ctx
;
255 struct event_base
*evb
= event_base_new();
258 fprintf(stderr
, "I");
265 ctx
= ecalloc(1, sizeof(*ctx
));
266 ctx
->client
= client
;
268 ctx
->timeout
= ecalloc(1, sizeof(struct event
));
270 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETDATA
, ctx
);
271 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETFUNCTION
, php_http_client_curl_event_socket
);
272 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERDATA
, ctx
);
273 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERFUNCTION
, php_http_client_curl_event_timer
);
278 static void php_http_client_curl_event_dtor(void **context
)
280 php_http_client_curl_event_context_t
*ctx
= *context
;
281 php_http_client_curl_t
*curl
;
284 fprintf(stderr
, "D");
287 curl
= ctx
->client
->ctx
;
289 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETDATA
, NULL
);
290 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETFUNCTION
, NULL
);
291 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERDATA
, NULL
);
292 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERFUNCTION
, NULL
);
294 if (event_initialized(ctx
->timeout
) && event_pending(ctx
->timeout
, EV_TIMEOUT
, NULL
)) {
295 event_del(ctx
->timeout
);
298 event_base_free(ctx
->evbase
);
304 static php_http_client_curl_ops_t php_http_client_curl_event_ops
= {
305 &php_http_client_curl_event_init
,
306 &php_http_client_curl_event_dtor
,
307 &php_http_client_curl_event_once
,
308 &php_http_client_curl_event_wait
,
309 &php_http_client_curl_event_exec
,
312 php_http_client_curl_ops_t
*php_http_client_curl_event_ops_get()
314 return &php_http_client_curl_event_ops
;
317 #endif /* PHP_HTTP_HAVE_EVENT */
318 #endif /* PHP_HTTP_HAVE_CURL */
325 * vim600: noet sw=4 ts=4 fdm=marker
326 * vim<600: noet sw=4 ts=4