1 : /*
2 : +--------------------------------------------------------------------+
3 : | PECL :: http |
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-2007, Michael Wallner <mike@php.net> |
10 : +--------------------------------------------------------------------+
11 : */
12 :
13 : /* $Id: http_request_datashare_api.c,v 1.10 2007/02/09 14:19:39 mike Exp $ */
14 :
15 : #define HTTP_WANT_CURL
16 : #include "php_http.h"
17 :
18 : #if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL)
19 :
20 : #include "php_http_api.h"
21 : #include "php_http_persistent_handle_api.h"
22 : #include "php_http_request_datashare_api.h"
23 : #include "php_http_request_api.h"
24 : #include "php_http_request_object.h"
25 :
26 : static HashTable http_request_datashare_options;
27 : static http_request_datashare http_request_datashare_global;
28 : static int http_request_datashare_compare_handles(void *h1, void *h2);
29 : static void http_request_datashare_destroy_handles(void *el);
30 : #ifdef ZTS
31 : static void *http_request_datashare_locks_init(void);
32 : static void http_request_datashare_locks_dtor(void *l);
33 : static void http_request_datashare_lock_func(CURL *handle, curl_lock_data data, curl_lock_access locktype, void *userptr);
34 : static void http_request_datashare_unlock_func(CURL *handle, curl_lock_data data, void *userptr);
35 : #endif
36 :
37 : http_request_datashare *_http_request_datashare_global_get(void)
38 1 : {
39 1 : return &http_request_datashare_global;
40 : }
41 :
42 : PHP_MINIT_FUNCTION(http_request_datashare)
43 220 : {
44 : curl_lock_data val;
45 :
46 220 : if (SUCCESS != http_persistent_handle_provide("http_request_datashare", curl_share_init, (http_persistent_handle_dtor) curl_share_cleanup, NULL)) {
47 0 : return FAILURE;
48 : }
49 : #ifdef ZTS
50 : if (SUCCESS != http_persistent_handle_provide("http_request_datashare_lock", http_request_datashare_locks_init, http_request_datashare_locks_dtor, NULL)) {
51 : return FAILURE;
52 : }
53 : #endif
54 :
55 220 : if (!http_request_datashare_init_ex(&http_request_datashare_global, 1)) {
56 0 : return FAILURE;
57 : }
58 :
59 220 : zend_hash_init(&http_request_datashare_options, 4, NULL, NULL, 1);
60 : #define ADD_DATASHARE_OPT(name, opt) \
61 : val = opt; \
62 : zend_hash_add(&http_request_datashare_options, name, sizeof(name), &val, sizeof(curl_lock_data), NULL)
63 220 : ADD_DATASHARE_OPT("cookie", CURL_LOCK_DATA_COOKIE);
64 220 : ADD_DATASHARE_OPT("dns", CURL_LOCK_DATA_DNS);
65 220 : ADD_DATASHARE_OPT("ssl", CURL_LOCK_DATA_SSL_SESSION);
66 220 : ADD_DATASHARE_OPT("connect", CURL_LOCK_DATA_CONNECT);
67 :
68 220 : return SUCCESS;
69 : }
70 :
71 : PHP_MSHUTDOWN_FUNCTION(http_request_datashare)
72 219 : {
73 219 : http_request_datashare_dtor(&http_request_datashare_global);
74 219 : zend_hash_destroy(&http_request_datashare_options);
75 :
76 219 : return SUCCESS;
77 : }
78 :
79 : PHP_RINIT_FUNCTION(http_request_datashare)
80 219 : {
81 219 : zend_llist_init(&HTTP_G->request.datashare.handles, sizeof(zval *), http_request_datashare_destroy_handles, 0);
82 :
83 219 : return SUCCESS;
84 : }
85 :
86 : PHP_RSHUTDOWN_FUNCTION(http_request_datashare)
87 219 : {
88 219 : zend_llist_destroy(&HTTP_G->request.datashare.handles);
89 :
90 219 : return SUCCESS;
91 : }
92 :
93 : PHP_HTTP_API http_request_datashare *_http_request_datashare_init_ex(http_request_datashare *share, zend_bool persistent TSRMLS_DC)
94 221 : {
95 : zend_bool free_share;
96 :
97 221 : if ((free_share = !share)) {
98 1 : share = pemalloc(sizeof(http_request_datashare), persistent);
99 : }
100 221 : memset(share, 0, sizeof(http_request_datashare));
101 :
102 221 : if (SUCCESS != http_persistent_handle_acquire("http_request_datashare", &share->ch)) {
103 0 : if (free_share) {
104 0 : pefree(share, persistent);
105 : }
106 0 : return NULL;
107 : }
108 :
109 221 : if (!(share->persistent = persistent)) {
110 1 : share->handle.list = emalloc(sizeof(zend_llist));
111 1 : zend_llist_init(share->handle.list, sizeof(zval *), ZVAL_PTR_DTOR, 0);
112 : #ifdef ZTS
113 : } else {
114 : if (SUCCESS == http_persistent_handle_acquire("http_request_datashare_lock", (void *) &share->handle.locks)) {
115 : curl_share_setopt(share->ch, CURLSHOPT_LOCKFUNC, http_request_datashare_lock_func);
116 : curl_share_setopt(share->ch, CURLSHOPT_UNLOCKFUNC, http_request_datashare_unlock_func);
117 : curl_share_setopt(share->ch, CURLSHOPT_USERDATA, share->handle.locks);
118 : }
119 : #endif
120 : }
121 :
122 221 : return share;
123 : }
124 :
125 : PHP_HTTP_API STATUS _http_request_datashare_attach(http_request_datashare *share, zval *request TSRMLS_DC)
126 4 : {
127 : CURLcode rc;
128 4 : getObjectEx(http_request_object, obj, request);
129 :
130 4 : if (obj->share) {
131 0 : if (obj->share == share) {
132 0 : return SUCCESS;
133 0 : } else if (SUCCESS != http_request_datashare_detach(obj->share, request)) {
134 0 : return FAILURE;
135 : }
136 : }
137 :
138 4 : HTTP_CHECK_CURL_INIT(obj->request->ch, http_curl_init_ex(obj->request->ch, obj->request), return FAILURE);
139 4 : if (CURLE_OK != (rc = curl_easy_setopt(obj->request->ch, CURLOPT_SHARE, share->ch))) {
140 0 : http_error_ex(HE_WARNING, HTTP_E_REQUEST, "Could not attach HttpRequest object(#%d) to the HttpRequestDataShare: %s", Z_OBJ_HANDLE_P(request), curl_easy_strerror(rc));
141 0 : return FAILURE;
142 : }
143 :
144 4 : obj->share = share;
145 4 : ZVAL_ADDREF(request);
146 4 : zend_llist_add_element(HTTP_RSHARE_HANDLES(share), (void *) &request);
147 :
148 4 : return SUCCESS;
149 : }
150 :
151 : PHP_HTTP_API STATUS _http_request_datashare_detach(http_request_datashare *share, zval *request TSRMLS_DC)
152 4 : {
153 : CURLcode rc;
154 4 : getObjectEx(http_request_object, obj, request);
155 :
156 4 : if (!obj->share) {
157 0 : http_error_ex(HE_WARNING, HTTP_E_REQUEST, "HttpRequest object(#%d) is not attached to any HttpRequestDataShare", Z_OBJ_HANDLE_P(request));
158 4 : } else if (obj->share != share) {
159 0 : http_error_ex(HE_WARNING, HTTP_E_REQUEST, "HttpRequest object(#%d) is not attached to this HttpRequestDataShare", Z_OBJ_HANDLE_P(request));
160 4 : } else if (CURLE_OK != (rc = curl_easy_setopt(obj->request->ch, CURLOPT_SHARE, NULL))) {
161 0 : http_error_ex(HE_WARNING, HTTP_E_REQUEST, "Could not detach HttpRequest object(#%d) from the HttpRequestDataShare: %s", Z_OBJ_HANDLE_P(request), curl_share_strerror(rc));
162 : } else {
163 4 : obj->share = NULL;
164 4 : zend_llist_del_element(HTTP_RSHARE_HANDLES(share), request, http_request_datashare_compare_handles);
165 4 : return SUCCESS;
166 : }
167 0 : return FAILURE;
168 : }
169 :
170 : PHP_HTTP_API void _http_request_datashare_detach_all(http_request_datashare *share TSRMLS_DC)
171 4 : {
172 : zval **r;
173 :
174 12 : while ((r = zend_llist_get_first(HTTP_RSHARE_HANDLES(share)))) {
175 4 : http_request_datashare_detach(share, *r);
176 : }
177 4 : }
178 :
179 : PHP_HTTP_API void _http_request_datashare_dtor(http_request_datashare *share TSRMLS_DC)
180 220 : {
181 220 : if (!share->persistent) {
182 1 : zend_llist_destroy(share->handle.list);
183 1 : efree(share->handle.list);
184 : }
185 220 : http_persistent_handle_release("http_request_datashare", &share->ch);
186 : #ifdef ZTS
187 : if (share->persistent) {
188 : http_persistent_handle_release("http_request_datashare_lock", (void *) &share->handle.locks);
189 : }
190 : #endif
191 220 : }
192 :
193 : PHP_HTTP_API void _http_request_datashare_free(http_request_datashare **share TSRMLS_DC)
194 1 : {
195 1 : http_request_datashare_dtor(*share);
196 1 : pefree(*share, (*share)->persistent);
197 1 : *share = NULL;
198 1 : }
199 :
200 : PHP_HTTP_API STATUS _http_request_datashare_set(http_request_datashare *share, const char *option, size_t option_len, zend_bool enable TSRMLS_DC)
201 4 : {
202 : curl_lock_data *opt;
203 : CURLSHcode rc;
204 :
205 4 : if (SUCCESS == zend_hash_find(&http_request_datashare_options, (char *) option, option_len + 1, (void *) &opt)) {
206 4 : if (CURLSHE_OK == (rc = curl_share_setopt(share->ch, enable ? CURLSHOPT_SHARE : CURLSHOPT_UNSHARE, *opt))) {
207 4 : return SUCCESS;
208 : }
209 0 : http_error_ex(HE_WARNING, HTTP_E_REQUEST, "Could not %s sharing of %s data: %s", enable ? "enable" : "disable", option, curl_share_strerror(rc));
210 : }
211 0 : return FAILURE;
212 : }
213 :
214 : static int http_request_datashare_compare_handles(void *h1, void *h2)
215 4 : {
216 4 : return (Z_OBJ_HANDLE_PP((zval **) h1) == Z_OBJ_HANDLE_P((zval *) h2));
217 : }
218 :
219 : static void http_request_datashare_destroy_handles(void *el)
220 2 : {
221 2 : zval **r = (zval **) el;
222 : TSRMLS_FETCH();
223 :
224 : { /* gcc 2.95 needs these braces */
225 2 : getObjectEx(http_request_object, obj, *r);
226 :
227 2 : curl_easy_setopt(obj->request->ch, CURLOPT_SHARE, NULL);
228 2 : zval_ptr_dtor(r);
229 : }
230 2 : }
231 :
232 : #ifdef ZTS
233 : static void *http_request_datashare_locks_init(void)
234 : {
235 : int i;
236 : http_request_datashare_lock *locks = pecalloc(CURL_LOCK_DATA_LAST, sizeof(http_request_datashare_lock), 1);
237 :
238 : if (locks) {
239 : for (i = 0; i < CURL_LOCK_DATA_LAST; ++i) {
240 : locks[i].mx = tsrm_mutex_alloc();
241 : }
242 : }
243 :
244 : return locks;
245 : }
246 :
247 : static void http_request_datashare_locks_dtor(void *l)
248 : {
249 : int i;
250 : http_request_datashare_lock *locks = (http_request_datashare_lock *) l;
251 :
252 : for (i = 0; i < CURL_LOCK_DATA_LAST; ++i) {
253 : tsrm_mutex_free(locks[i].mx);
254 : }
255 : pefree(locks, 1);
256 : }
257 :
258 : static void http_request_datashare_lock_func(CURL *handle, curl_lock_data data, curl_lock_access locktype, void *userptr)
259 : {
260 : http_request_datashare_lock *locks = (http_request_datashare_lock *) userptr;
261 :
262 : /* TSRM can't distinguish shared/exclusive locks */
263 : tsrm_mutex_lock(locks[data].mx);
264 : locks[data].ch = handle;
265 : }
266 :
267 : static void http_request_datashare_unlock_func(CURL *handle, curl_lock_data data, void *userptr)
268 : {
269 : http_request_datashare_lock *locks = (http_request_datashare_lock *) userptr;
270 :
271 : if (locks[data].ch == handle) {
272 : tsrm_mutex_unlock(locks[data].mx);
273 : }
274 : }
275 : #endif
276 :
277 : #endif /* ZEND_ENGINE_2 && HTTP_HAVE_CURL */
278 :
279 :
280 : /*
281 : * Local variables:
282 : * tab-width: 4
283 : * c-basic-offset: 4
284 : * End:
285 : * vim600: noet sw=4 ts=4 fdm=marker
286 : * vim<600: noet sw=4 ts=4
287 : */
288 :
|