1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2020, 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 ***************************************************************************/
22#include "test.h"
23#include "memdebug.h"
24
25#define THREADS 2
26
27/* struct containing data of a thread */
28struct Tdata {
29 CURLSH *share;
30 char *url;
31};
32
33struct userdata {
34 const char *text;
35 int counter;
36};
37
38/* lock callback */
39static void my_lock(CURL *handle, curl_lock_data data,
40 curl_lock_access laccess, void *useptr)
41{
42 const char *what;
43 struct userdata *user = (struct userdata *)useptr;
44
45 (void)handle;
46 (void)laccess;
47
48 switch(data) {
49 case CURL_LOCK_DATA_SHARE:
50 what = "share";
51 break;
52 case CURL_LOCK_DATA_DNS:
53 what = "dns";
54 break;
55 case CURL_LOCK_DATA_COOKIE:
56 what = "cookie";
57 break;
58 case CURL_LOCK_DATA_SSL_SESSION:
59 what = "ssl_session";
60 break;
61 default:
62 fprintf(stderr, "lock: no such data: %d\n", (int)data);
63 return;
64 }
65 printf("lock: %-6s [%s]: %d\n", what, user->text, user->counter);
66 user->counter++;
67}
68
69/* unlock callback */
70static void my_unlock(CURL *handle, curl_lock_data data, void *useptr)
71{
72 const char *what;
73 struct userdata *user = (struct userdata *)useptr;
74 (void)handle;
75 switch(data) {
76 case CURL_LOCK_DATA_SHARE:
77 what = "share";
78 break;
79 case CURL_LOCK_DATA_DNS:
80 what = "dns";
81 break;
82 case CURL_LOCK_DATA_COOKIE:
83 what = "cookie";
84 break;
85 case CURL_LOCK_DATA_SSL_SESSION:
86 what = "ssl_session";
87 break;
88 default:
89 fprintf(stderr, "unlock: no such data: %d\n", (int)data);
90 return;
91 }
92 printf("unlock: %-6s [%s]: %d\n", what, user->text, user->counter);
93 user->counter++;
94}
95
96/* the dummy thread function */
97static void *fire(void *ptr)
98{
99 CURLcode code;
100 struct Tdata *tdata = (struct Tdata*)ptr;
101 CURL *curl;
102
103 curl = curl_easy_init();
104 if(!curl) {
105 fprintf(stderr, "curl_easy_init() failed\n");
106 return NULL;
107 }
108
109 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
110 curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
111 curl_easy_setopt(curl, CURLOPT_URL, tdata->url);
112 printf("CURLOPT_SHARE\n");
113 curl_easy_setopt(curl, CURLOPT_SHARE, tdata->share);
114
115 printf("PERFORM\n");
116 code = curl_easy_perform(curl);
117 if(code != CURLE_OK) {
118 int i = 0;
119 fprintf(stderr, "perform url '%s' repeat %d failed, curlcode %d\n",
120 tdata->url, i, (int)code);
121 }
122
123 printf("CLEANUP\n");
124 curl_easy_cleanup(curl);
125
126 return NULL;
127}
128
129/* test function */
130int test(char *URL)
131{
132 int res;
133 CURLSHcode scode = CURLSHE_OK;
134 char *url;
135 struct Tdata tdata;
136 CURL *curl;
137 CURLSH *share;
138 int i;
139 struct userdata user;
140
141 user.text = "Pigs in space";
142 user.counter = 0;
143
144 printf("GLOBAL_INIT\n");
145 if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
146 fprintf(stderr, "curl_global_init() failed\n");
147 return TEST_ERR_MAJOR_BAD;
148 }
149
150 /* prepare share */
151 printf("SHARE_INIT\n");
152 share = curl_share_init();
153 if(!share) {
154 fprintf(stderr, "curl_share_init() failed\n");
155 curl_global_cleanup();
156 return TEST_ERR_MAJOR_BAD;
157 }
158
159 if(CURLSHE_OK == scode) {
160 printf("CURLSHOPT_LOCKFUNC\n");
161 scode = curl_share_setopt(share, CURLSHOPT_LOCKFUNC, my_lock);
162 }
163 if(CURLSHE_OK == scode) {
164 printf("CURLSHOPT_UNLOCKFUNC\n");
165 scode = curl_share_setopt(share, CURLSHOPT_UNLOCKFUNC, my_unlock);
166 }
167 if(CURLSHE_OK == scode) {
168 printf("CURLSHOPT_USERDATA\n");
169 scode = curl_share_setopt(share, CURLSHOPT_USERDATA, &user);
170 }
171 if(CURLSHE_OK == scode) {
172 printf("CURL_LOCK_DATA_SSL_SESSION\n");
173 scode = curl_share_setopt(share, CURLSHOPT_SHARE,
174 CURL_LOCK_DATA_SSL_SESSION);
175 }
176
177 if(CURLSHE_OK != scode) {
178 fprintf(stderr, "curl_share_setopt() failed\n");
179 curl_share_cleanup(share);
180 curl_global_cleanup();
181 return TEST_ERR_MAJOR_BAD;
182 }
183
184
185 res = 0;
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 fire(&tdata);
197 }
198
199
200 /* fetch a 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 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
229test_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