1/***************************************************************************
2 *                                  _   _ ____  _
3 *  Project                     ___| | | |  _ \| |
4 *                             / __| | | | |_) | |
5 *                            | (__| |_| |  _ <| |___
6 *                             \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2011, 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 http://curl.haxx.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 <stdlib.h>
24#include <ctype.h>
25#include <errno.h>
26
27#include <curl/mprintf.h>
28
29#include "memdebug.h"
30
31static const char *HOSTHEADER = "Host: www.host.foo.com";
32static const char *JAR = "log/jar506";
33#define THREADS 2
34
35/* struct containing data of a thread */
36struct Tdata {
37  CURLSH *share;
38  char *url;
39};
40
41struct userdata {
42  char *text;
43  int counter;
44};
45
46/* lock callback */
47static void my_lock(CURL *handle, curl_lock_data data, curl_lock_access laccess,
48          void *useptr )
49{
50  const char *what;
51  struct userdata *user = (struct userdata *)useptr;
52
53  (void)handle;
54  (void)laccess;
55
56  switch ( data ) {
57    case CURL_LOCK_DATA_SHARE:
58      what = "share";
59      break;
60    case CURL_LOCK_DATA_DNS:
61      what = "dns";
62      break;
63    case CURL_LOCK_DATA_COOKIE:
64      what = "cookie";
65      break;
66    default:
67      fprintf(stderr, "lock: no such data: %d\n", (int)data);
68      return;
69  }
70  printf("lock:   %-6s [%s]: %d\n", what, user->text, user->counter);
71  user->counter++;
72}
73
74/* unlock callback */
75static void my_unlock(CURL *handle, curl_lock_data data, void *useptr )
76{
77  const char *what;
78  struct userdata *user = (struct userdata *)useptr;
79  (void)handle;
80  switch ( data ) {
81    case CURL_LOCK_DATA_SHARE:
82      what = "share";
83      break;
84    case CURL_LOCK_DATA_DNS:
85      what = "dns";
86      break;
87    case CURL_LOCK_DATA_COOKIE:
88      what = "cookie";
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
99/* build host entry */
100static struct curl_slist *sethost(struct curl_slist *headers)
101{
102  (void)headers;
103  return curl_slist_append(NULL, HOSTHEADER );
104}
105
106
107/* the dummy thread function */
108static void *fire(void *ptr)
109{
110  CURLcode code;
111  struct curl_slist *headers;
112  struct Tdata *tdata = (struct Tdata*)ptr;
113  CURL *curl;
114  int i=0;
115
116  if ((curl = curl_easy_init()) == NULL) {
117    fprintf(stderr, "curl_easy_init() failed\n");
118    return NULL;
119  }
120
121  headers = sethost(NULL);
122  curl_easy_setopt(curl, CURLOPT_VERBOSE,    1L);
123  curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
124  curl_easy_setopt(curl, CURLOPT_URL,        tdata->url);
125  printf( "CURLOPT_SHARE\n" );
126  curl_easy_setopt(curl, CURLOPT_SHARE, tdata->share);
127
128  printf( "PERFORM\n" );
129  code = curl_easy_perform(curl);
130  if( code != CURLE_OK ) {
131    fprintf(stderr, "perform url '%s' repeat %d failed, curlcode %d\n",
132            tdata->url, i, (int)code);
133  }
134
135  printf( "CLEANUP\n" );
136  curl_easy_cleanup(curl);
137  curl_slist_free_all(headers);
138
139  return NULL;
140}
141
142
143/* build request url */
144static char *suburl(const char *base, int i)
145{
146  return curl_maprintf("%s%.4d", base, i);
147}
148
149
150/* test function */
151int test(char *URL)
152{
153  int res;
154  CURLSHcode scode = CURLSHE_OK;
155  char *url;
156  struct Tdata tdata;
157  CURL *curl;
158  CURLSH *share;
159  struct curl_slist *headers;
160  int i;
161  struct userdata user;
162
163  user.text = (char *)"Pigs in space";
164  user.counter = 0;
165
166  printf( "GLOBAL_INIT\n" );
167  if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
168    fprintf(stderr, "curl_global_init() failed\n");
169    return TEST_ERR_MAJOR_BAD;
170  }
171
172  /* prepare share */
173  printf( "SHARE_INIT\n" );
174  if ((share = curl_share_init()) == NULL) {
175    fprintf(stderr, "curl_share_init() failed\n");
176    curl_global_cleanup();
177    return TEST_ERR_MAJOR_BAD;
178  }
179
180  if ( CURLSHE_OK == scode ) {
181    printf( "CURLSHOPT_LOCKFUNC\n" );
182    scode = curl_share_setopt( share, CURLSHOPT_LOCKFUNC, my_lock);
183  }
184  if ( CURLSHE_OK == scode ) {
185    printf( "CURLSHOPT_UNLOCKFUNC\n" );
186    scode = curl_share_setopt( share, CURLSHOPT_UNLOCKFUNC, my_unlock);
187  }
188  if ( CURLSHE_OK == scode ) {
189    printf( "CURLSHOPT_USERDATA\n" );
190    scode = curl_share_setopt( share, CURLSHOPT_USERDATA, &user);
191  }
192  if ( CURLSHE_OK == scode ) {
193    printf( "CURL_LOCK_DATA_COOKIE\n" );
194    scode = curl_share_setopt( share, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE);
195  }
196  if ( CURLSHE_OK == scode ) {
197    printf( "CURL_LOCK_DATA_DNS\n" );
198    scode = curl_share_setopt( share, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);
199  }
200
201  if ( CURLSHE_OK != scode ) {
202    fprintf(stderr, "curl_share_setopt() failed\n");
203    curl_share_cleanup(share);
204    curl_global_cleanup();
205    return TEST_ERR_MAJOR_BAD;
206  }
207
208
209  res = 0;
210
211  /* start treads */
212  for (i=1; i<=THREADS; i++ ) {
213
214    /* set thread data */
215    tdata.url   = suburl( URL, i ); /* must be curl_free()d */
216    tdata.share = share;
217
218    /* simulate thread, direct call of "thread" function */
219    printf( "*** run %d\n",i );
220    fire( &tdata );
221
222    curl_free( tdata.url );
223
224  }
225
226
227  /* fetch a another one and save cookies */
228  printf( "*** run %d\n", i );
229  if ((curl = curl_easy_init()) == NULL) {
230    fprintf(stderr, "curl_easy_init() failed\n");
231    curl_share_cleanup(share);
232    curl_global_cleanup();
233    return TEST_ERR_MAJOR_BAD;
234  }
235
236  url = suburl( URL, i );
237  headers = sethost( NULL );
238  test_setopt( curl, CURLOPT_HTTPHEADER, headers );
239  test_setopt( curl, CURLOPT_URL,        url );
240  printf( "CURLOPT_SHARE\n" );
241  test_setopt( curl, CURLOPT_SHARE,      share );
242  printf( "CURLOPT_COOKIEJAR\n" );
243  test_setopt( curl, CURLOPT_COOKIEJAR,  JAR );
244
245  printf( "PERFORM\n" );
246  curl_easy_perform( curl );
247
248  /* try to free share, expect to fail because share is in use*/
249  printf( "try SHARE_CLEANUP...\n" );
250  scode = curl_share_cleanup( share );
251  if ( scode==CURLSHE_OK )
252  {
253    fprintf(stderr, "curl_share_cleanup succeed but error expected\n");
254    share = NULL;
255  } else {
256    printf( "SHARE_CLEANUP failed, correct\n" );
257  }
258
259test_cleanup:
260
261  /* clean up last handle */
262  printf( "CLEANUP\n" );
263  curl_easy_cleanup( curl );
264  curl_slist_free_all( headers );
265
266  curl_free(url);
267
268  /* free share */
269  printf( "SHARE_CLEANUP\n" );
270  scode = curl_share_cleanup( share );
271  if ( scode!=CURLSHE_OK )
272    fprintf(stderr, "curl_share_cleanup failed, code errno %d\n",
273            (int)scode);
274
275  printf( "GLOBAL_CLEANUP\n" );
276  curl_global_cleanup();
277
278  return res;
279}
280
281