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
;
89 fprintf(stderr
, "\ntimer <- timeout_ms: %ld\n", timeout_ms
);
93 php_http_client_curl_event_handler(context
, CURL_SOCKET_TIMEOUT
, 0);
94 } else if (timeout_ms
> 0 || !event_initialized(context
->timeout
) || !event_pending(context
->timeout
, EV_TIMEOUT
, NULL
)) {
95 struct timeval timeout
;
97 if (!event_initialized(context
->timeout
)) {
98 event_assign(context
->timeout
, context
->evbase
, CURL_SOCKET_TIMEOUT
, 0, php_http_client_curl_event_timeout_callback
, context
);
101 timeout
.tv_sec
= timeout_ms
/ 1000;
102 timeout
.tv_usec
= (timeout_ms
% 1000) * 1000;
104 event_add(context
->timeout
, &timeout
);
108 static void php_http_client_curl_event_callback(int socket
, short action
, void *event_data
)
110 php_http_client_curl_event_context_t
*ctx
= event_data
;
111 php_http_client_curl_t
*curl
= ctx
->client
->ctx
;
114 fprintf(stderr
, "E");
117 php_http_client_curl_event_handler(event_data
, socket
, etoca(action
));
119 /* remove timeout if there are no transfers left */
120 if (!curl
->unfinished
&& event_initialized(ctx
->timeout
) && event_pending(ctx
->timeout
, EV_TIMEOUT
, NULL
)) {
121 event_del(ctx
->timeout
);
125 static int php_http_client_curl_event_socket(CURL
*easy
, curl_socket_t sock
, int action
, void *socket_data
, void *assign_data
)
127 php_http_client_curl_event_context_t
*ctx
= socket_data
;
128 php_http_client_curl_t
*curl
= ctx
->client
->ctx
;
129 int events
= EV_PERSIST
;
130 php_http_client_curl_event_ev_t
*ev
= assign_data
;
133 fprintf(stderr
, "S");
137 ev
= ecalloc(1, sizeof(*ev
));
139 curl_multi_assign(curl
->handle
->multi
, sock
, ev
);
141 event_del(&ev
->evnt
);
151 case CURL_POLL_INOUT
:
152 events
|= EV_READ
|EV_WRITE
;
155 case CURL_POLL_REMOVE
:
162 php_error_docref(NULL
, E_WARNING
, "Unknown socket action %d", action
);
166 event_assign(&ev
->evnt
, ctx
->evbase
, sock
, events
, php_http_client_curl_event_callback
, ctx
);
167 event_add(&ev
->evnt
, NULL
);
172 static ZEND_RESULT_CODE
php_http_client_curl_event_once(void *context
)
174 php_http_client_curl_event_context_t
*ctx
= context
;
177 fprintf(stderr
, "O");
180 if (0 > event_base_loop(ctx
->evbase
, EVLOOP_NONBLOCK
)) {
186 static ZEND_RESULT_CODE
php_http_client_curl_event_wait(void *context
, struct timeval
*custom_timeout
)
188 php_http_client_curl_event_context_t
*ctx
= context
;
189 struct timeval timeout
;
192 fprintf(stderr
, "W");
195 if (!event_initialized(ctx
->timeout
)) {
196 if (0 > event_assign(ctx
->timeout
, ctx
->evbase
, CURL_SOCKET_TIMEOUT
, 0, php_http_client_curl_event_timeout_callback
, ctx
)) {
199 } else if (custom_timeout
&& timerisset(custom_timeout
)) {
200 if (0 > event_add(ctx
->timeout
, custom_timeout
)) {
203 } else if (!event_pending(ctx
->timeout
, EV_TIMEOUT
, NULL
)) {
204 php_http_client_curl_get_timeout(ctx
->client
->ctx
, 1000, &timeout
);
205 if (0 > event_add(ctx
->timeout
, &timeout
)) {
210 if (0 > event_base_loop(ctx
->evbase
, EVLOOP_ONCE
)) {
217 static ZEND_RESULT_CODE
php_http_client_curl_event_exec(void *context
)
219 php_http_client_curl_event_context_t
*ctx
= context
;
220 php_http_client_curl_t
*curl
= ctx
->client
->ctx
;
223 fprintf(stderr
, "E");
227 php_http_client_curl_event_handler(ctx
, CURL_SOCKET_TIMEOUT
, 0);
230 if (0 > event_base_dispatch(ctx
->evbase
)) {
233 } while (curl
->unfinished
&& !EG(exception
));
238 static void *php_http_client_curl_event_init(php_http_client_t
*client
)
240 php_http_client_curl_t
*curl
= client
->ctx
;
241 php_http_client_curl_event_context_t
*ctx
;
242 struct event_base
*evb
= event_base_new();
245 fprintf(stderr
, "I");
252 ctx
= ecalloc(1, sizeof(*ctx
));
253 ctx
->client
= client
;
255 ctx
->timeout
= ecalloc(1, sizeof(struct event
));
257 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETDATA
, ctx
);
258 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETFUNCTION
, php_http_client_curl_event_socket
);
259 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERDATA
, ctx
);
260 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERFUNCTION
, php_http_client_curl_event_timer
);
265 static void php_http_client_curl_event_dtor(void **context
)
267 php_http_client_curl_event_context_t
*ctx
= *context
;
268 php_http_client_curl_t
*curl
;
271 fprintf(stderr
, "D");
274 curl
= ctx
->client
->ctx
;
276 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETDATA
, NULL
);
277 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETFUNCTION
, NULL
);
278 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERDATA
, NULL
);
279 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERFUNCTION
, NULL
);
281 if (event_initialized(ctx
->timeout
) && event_pending(ctx
->timeout
, EV_TIMEOUT
, NULL
)) {
282 event_del(ctx
->timeout
);
285 event_base_free(ctx
->evbase
);
291 static php_http_client_curl_ops_t php_http_client_curl_event_ops
= {
292 &php_http_client_curl_event_init
,
293 &php_http_client_curl_event_dtor
,
294 &php_http_client_curl_event_once
,
295 &php_http_client_curl_event_wait
,
296 &php_http_client_curl_event_exec
,
299 php_http_client_curl_ops_t
*php_http_client_curl_event_ops_get()
301 return &php_http_client_curl_event_ops
;
304 #endif /* PHP_HTTP_HAVE_LIBEVENT */
305 #endif /* PHP_HTTP_HAVE_LIBCURL */
312 * vim600: noet sw=4 ts=4 fdm=marker
313 * vim<600: noet sw=4 ts=4