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 */ |
28 | struct Tdata { |
29 | CURLSH *share; |
30 | char *url; |
31 | }; |
32 | |
33 | struct userdata { |
34 | const char *text; |
35 | int counter; |
36 | }; |
37 | |
38 | /* lock callback */ |
39 | static 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 */ |
70 | static 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 */ |
97 | static 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 */ |
130 | int 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 | |
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 | |