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