1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 * SPDX-License-Identifier: curl
22 *
23 ***************************************************************************/
24 #include "test.h"
25 #include "memdebug.h"
26
27 #define THREADS 2
28
29 /* struct containing data of a thread */
30 struct Tdata {
31 CURLSH *share;
32 char *url;
33 };
34
35 struct userdata {
36 const char *text;
37 int counter;
38 };
39
40 /* lock callback */
test_lock(CURL * handle,curl_lock_data data,curl_lock_access laccess,void * useptr)41 static void test_lock(CURL *handle, curl_lock_data data,
42 curl_lock_access laccess, void *useptr)
43 {
44 const char *what;
45 struct userdata *user = (struct userdata *)useptr;
46
47 (void)handle;
48 (void)laccess;
49
50 switch(data) {
51 case CURL_LOCK_DATA_SHARE:
52 what = "share";
53 break;
54 case CURL_LOCK_DATA_DNS:
55 what = "dns";
56 break;
57 case CURL_LOCK_DATA_COOKIE:
58 what = "cookie";
59 break;
60 case CURL_LOCK_DATA_SSL_SESSION:
61 what = "ssl_session";
62 break;
63 default:
64 fprintf(stderr, "lock: no such data: %d\n", (int)data);
65 return;
66 }
67 printf("lock: %-6s [%s]: %d\n", what, user->text, user->counter);
68 user->counter++;
69 }
70
71 /* unlock callback */
test_unlock(CURL * handle,curl_lock_data data,void * useptr)72 static void test_unlock(CURL *handle, curl_lock_data data, void *useptr)
73 {
74 const char *what;
75 struct userdata *user = (struct userdata *)useptr;
76 (void)handle;
77 switch(data) {
78 case CURL_LOCK_DATA_SHARE:
79 what = "share";
80 break;
81 case CURL_LOCK_DATA_DNS:
82 what = "dns";
83 break;
84 case CURL_LOCK_DATA_COOKIE:
85 what = "cookie";
86 break;
87 case CURL_LOCK_DATA_SSL_SESSION:
88 what = "ssl_session";
89 break;
90 default:
91 fprintf(stderr, "unlock: no such data: %d\n", (int)data);
92 return;
93 }
94 printf("unlock: %-6s [%s]: %d\n", what, user->text, user->counter);
95 user->counter++;
96 }
97
98 /* the dummy thread function */
test_fire(void * ptr)99 static void *test_fire(void *ptr)
100 {
101 CURLcode code;
102 struct Tdata *tdata = (struct Tdata*)ptr;
103 CURL *curl;
104
105 curl = curl_easy_init();
106 if(!curl) {
107 fprintf(stderr, "curl_easy_init() failed\n");
108 return NULL;
109 }
110
111 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
112 curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
113 curl_easy_setopt(curl, CURLOPT_URL, tdata->url);
114 printf("CURLOPT_SHARE\n");
115 curl_easy_setopt(curl, CURLOPT_SHARE, tdata->share);
116
117 printf("PERFORM\n");
118 code = curl_easy_perform(curl);
119 if(code != CURLE_OK) {
120 int i = 0;
121 fprintf(stderr, "perform url '%s' repeat %d failed, curlcode %d\n",
122 tdata->url, i, (int)code);
123 }
124
125 printf("CLEANUP\n");
126 curl_easy_cleanup(curl);
127
128 return NULL;
129 }
130
131 /* test function */
test(char * URL)132 CURLcode test(char *URL)
133 {
134 CURLcode res = CURLE_OK;
135 CURLSHcode scode = CURLSHE_OK;
136 char *url;
137 struct Tdata tdata;
138 CURL *curl;
139 CURLSH *share;
140 int i;
141 struct userdata user;
142
143 user.text = "Pigs in space";
144 user.counter = 0;
145
146 printf("GLOBAL_INIT\n");
147 if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
148 fprintf(stderr, "curl_global_init() failed\n");
149 return TEST_ERR_MAJOR_BAD;
150 }
151
152 /* prepare share */
153 printf("SHARE_INIT\n");
154 share = curl_share_init();
155 if(!share) {
156 fprintf(stderr, "curl_share_init() failed\n");
157 curl_global_cleanup();
158 return TEST_ERR_MAJOR_BAD;
159 }
160
161 if(CURLSHE_OK == scode) {
162 printf("CURLSHOPT_LOCKFUNC\n");
163 scode = curl_share_setopt(share, CURLSHOPT_LOCKFUNC, test_lock);
164 }
165 if(CURLSHE_OK == scode) {
166 printf("CURLSHOPT_UNLOCKFUNC\n");
167 scode = curl_share_setopt(share, CURLSHOPT_UNLOCKFUNC, test_unlock);
168 }
169 if(CURLSHE_OK == scode) {
170 printf("CURLSHOPT_USERDATA\n");
171 scode = curl_share_setopt(share, CURLSHOPT_USERDATA, &user);
172 }
173 if(CURLSHE_OK == scode) {
174 printf("CURL_LOCK_DATA_SSL_SESSION\n");
175 scode = curl_share_setopt(share, CURLSHOPT_SHARE,
176 CURL_LOCK_DATA_SSL_SESSION);
177 }
178
179 if(CURLSHE_OK != scode) {
180 fprintf(stderr, "curl_share_setopt() failed\n");
181 curl_share_cleanup(share);
182 curl_global_cleanup();
183 return TEST_ERR_MAJOR_BAD;
184 }
185
186
187 /* start treads */
188 for(i = 1; i <= THREADS; i++) {
189
190 /* set thread data */
191 tdata.url = URL;
192 tdata.share = share;
193
194 /* simulate thread, direct call of "thread" function */
195 printf("*** run %d\n",i);
196 test_fire(&tdata);
197 }
198
199
200 /* fetch another one */
201 printf("*** run %d\n", i);
202 curl = curl_easy_init();
203 if(!curl) {
204 fprintf(stderr, "curl_easy_init() failed\n");
205 curl_share_cleanup(share);
206 curl_global_cleanup();
207 return TEST_ERR_MAJOR_BAD;
208 }
209
210 url = URL;
211 test_setopt(curl, CURLOPT_URL, url);
212 printf("CURLOPT_SHARE\n");
213 test_setopt(curl, CURLOPT_SHARE, share);
214
215 printf("PERFORM\n");
216 res = curl_easy_perform(curl);
217
218 /* try to free share, expect to fail because share is in use */
219 printf("try SHARE_CLEANUP...\n");
220 scode = curl_share_cleanup(share);
221 if(scode == CURLSHE_OK) {
222 fprintf(stderr, "curl_share_cleanup succeed but error expected\n");
223 share = NULL;
224 }
225 else {
226 printf("SHARE_CLEANUP failed, correct\n");
227 }
228
229 test_cleanup:
230
231 /* clean up last handle */
232 printf("CLEANUP\n");
233 curl_easy_cleanup(curl);
234
235 /* free share */
236 printf("SHARE_CLEANUP\n");
237 scode = curl_share_cleanup(share);
238 if(scode != CURLSHE_OK)
239 fprintf(stderr, "curl_share_cleanup failed, code errno %d\n",
240 (int)scode);
241
242 printf("GLOBAL_CLEANUP\n");
243 curl_global_cleanup();
244
245 return res;
246 }
247