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
);
101 if (!event_initialized(context
->timeout
)) {
102 event_assign(context
->timeout
, context
->evbase
, CURL_SOCKET_TIMEOUT
, 0, php_http_client_curl_event_timeout_callback
, context
);
105 timeout
.tv_sec
= timeout_ms
/ 1000;
106 timeout
.tv_usec
= (timeout_ms
% 1000) * 1000;
108 if (!event_pending(context
->timeout
, EV_TIMEOUT
, &timeout
)) {
109 event_add(context
->timeout
, &timeout
);
115 static void php_http_client_curl_event_callback(int socket
, short action
, void *event_data
)
117 php_http_client_curl_event_context_t
*ctx
= event_data
;
118 php_http_client_curl_t
*curl
= ctx
->client
->ctx
;
121 fprintf(stderr
, "E");
124 php_http_client_curl_event_handler(event_data
, socket
, etoca(action
));
126 /* remove timeout if there are no transfers left */
127 if (!curl
->unfinished
&& event_initialized(ctx
->timeout
) && event_pending(ctx
->timeout
, EV_TIMEOUT
, NULL
)) {
128 event_del(ctx
->timeout
);
132 static int php_http_client_curl_event_socket(CURL
*easy
, curl_socket_t sock
, int action
, void *socket_data
, void *assign_data
)
134 php_http_client_curl_event_context_t
*ctx
= socket_data
;
135 php_http_client_curl_t
*curl
= ctx
->client
->ctx
;
136 int events
= EV_PERSIST
;
137 php_http_client_curl_event_ev_t
*ev
= assign_data
;
140 fprintf(stderr
, "S");
144 ev
= ecalloc(1, sizeof(*ev
));
146 curl_multi_assign(curl
->handle
->multi
, sock
, ev
);
148 event_del(&ev
->evnt
);
158 case CURL_POLL_INOUT
:
159 events
|= EV_READ
|EV_WRITE
;
162 case CURL_POLL_REMOVE
:
169 php_error_docref(NULL
, E_WARNING
, "Unknown socket action %d", action
);
173 event_assign(&ev
->evnt
, ctx
->evbase
, sock
, events
, php_http_client_curl_event_callback
, ctx
);
174 event_add(&ev
->evnt
, NULL
);
179 static ZEND_RESULT_CODE
php_http_client_curl_event_once(void *context
)
181 php_http_client_curl_event_context_t
*ctx
= context
;
184 fprintf(stderr
, "O");
187 if (0 > event_base_loop(ctx
->evbase
, EVLOOP_NONBLOCK
)) {
193 static ZEND_RESULT_CODE
php_http_client_curl_event_wait(void *context
, struct timeval
*custom_timeout
)
195 php_http_client_curl_event_context_t
*ctx
= context
;
196 struct timeval timeout
;
199 fprintf(stderr
, "W");
202 if (!event_initialized(ctx
->timeout
)) {
203 if (0 > event_assign(ctx
->timeout
, ctx
->evbase
, CURL_SOCKET_TIMEOUT
, 0, php_http_client_curl_event_timeout_callback
, ctx
)) {
206 } else if (custom_timeout
&& timerisset(custom_timeout
)) {
207 if (0 > event_add(ctx
->timeout
, custom_timeout
)) {
210 } else if (!event_pending(ctx
->timeout
, EV_TIMEOUT
, NULL
)) {
211 php_http_client_curl_get_timeout(ctx
->client
->ctx
, 1000, &timeout
);
212 if (0 > event_add(ctx
->timeout
, &timeout
)) {
217 if (0 > event_base_loop(ctx
->evbase
, EVLOOP_ONCE
)) {
224 static ZEND_RESULT_CODE
php_http_client_curl_event_exec(void *context
)
226 php_http_client_curl_event_context_t
*ctx
= context
;
227 php_http_client_curl_t
*curl
= ctx
->client
->ctx
;
230 fprintf(stderr
, "E");
234 php_http_client_curl_event_handler(ctx
, CURL_SOCKET_TIMEOUT
, 0);
237 if (0 > event_base_dispatch(ctx
->evbase
)) {
240 } while (curl
->unfinished
&& !EG(exception
));
245 static void *php_http_client_curl_event_init(php_http_client_t
*client
)
247 php_http_client_curl_t
*curl
= client
->ctx
;
248 php_http_client_curl_event_context_t
*ctx
;
249 struct event_base
*evb
= event_base_new();
252 fprintf(stderr
, "I");
259 ctx
= ecalloc(1, sizeof(*ctx
));
260 ctx
->client
= client
;
262 ctx
->timeout
= ecalloc(1, sizeof(struct event
));
264 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETDATA
, ctx
);
265 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETFUNCTION
, php_http_client_curl_event_socket
);
266 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERDATA
, ctx
);
267 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERFUNCTION
, php_http_client_curl_event_timer
);
272 static void php_http_client_curl_event_dtor(void **context
)
274 php_http_client_curl_event_context_t
*ctx
= *context
;
275 php_http_client_curl_t
*curl
;
278 fprintf(stderr
, "D");
281 curl
= ctx
->client
->ctx
;
283 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETDATA
, NULL
);
284 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETFUNCTION
, NULL
);
285 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERDATA
, NULL
);
286 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERFUNCTION
, NULL
);
288 if (event_initialized(ctx
->timeout
) && event_pending(ctx
->timeout
, EV_TIMEOUT
, NULL
)) {
289 event_del(ctx
->timeout
);
292 event_base_free(ctx
->evbase
);
298 static php_http_client_curl_ops_t php_http_client_curl_event_ops
= {
299 &php_http_client_curl_event_init
,
300 &php_http_client_curl_event_dtor
,
301 &php_http_client_curl_event_once
,
302 &php_http_client_curl_event_wait
,
303 &php_http_client_curl_event_exec
,
306 php_http_client_curl_ops_t
*php_http_client_curl_event_ops_get()
308 return &php_http_client_curl_event_ops
;
311 #endif /* PHP_HTTP_HAVE_LIBEVENT */
312 #endif /* PHP_HTTP_HAVE_LIBCURL */
319 * vim600: noet sw=4 ts=4 fdm=marker
320 * vim<600: noet sw=4 ts=4