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
23#include "setup.h"
24#include <stdarg.h>
25#include <stdlib.h>
26#include <string.h>
27#include <curl/curl.h>
28#include "urldata.h"
29#include "share.h"
30#include "curl_memory.h"
31
32/* The last #include file should be: */
33#include "memdebug.h"
34
35CURLSH *
36curl_share_init(void)
37{
38  struct Curl_share *share = calloc(1, sizeof(struct Curl_share));
39  if(share)
40    share->specifier |= (1<<CURL_LOCK_DATA_SHARE);
41
42  return share;
43}
44
45#undef curl_share_setopt
46CURLSHcode
47curl_share_setopt(CURLSH *sh, CURLSHoption option, ...)
48{
49  struct Curl_share *share = (struct Curl_share *)sh;
50  va_list param;
51  int type;
52  curl_lock_function lockfunc;
53  curl_unlock_function unlockfunc;
54  void *ptr;
55
56  if(share->dirty)
57    /* don't allow setting options while one or more handles are already
58       using this share */
59    return CURLSHE_IN_USE;
60
61  va_start(param, option);
62
63  switch(option) {
64  case CURLSHOPT_SHARE:
65    /* this is a type this share will share */
66    type = va_arg(param, int);
67    share->specifier |= (1<<type);
68    switch( type ) {
69    case CURL_LOCK_DATA_DNS:
70      if(!share->hostcache) {
71        share->hostcache = Curl_mk_dnscache();
72        if(!share->hostcache)
73          return CURLSHE_NOMEM;
74      }
75      break;
76
77#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
78    case CURL_LOCK_DATA_COOKIE:
79      if(!share->cookies) {
80        share->cookies = Curl_cookie_init(NULL, NULL, NULL, TRUE );
81        if(!share->cookies)
82          return CURLSHE_NOMEM;
83      }
84      break;
85#endif   /* CURL_DISABLE_HTTP */
86
87    case CURL_LOCK_DATA_SSL_SESSION: /* not supported (yet) */
88    case CURL_LOCK_DATA_CONNECT:     /* not supported (yet) */
89
90    default:
91      return CURLSHE_BAD_OPTION;
92    }
93    break;
94
95  case CURLSHOPT_UNSHARE:
96    /* this is a type this share will no longer share */
97    type = va_arg(param, int);
98    share->specifier &= ~(1<<type);
99    switch( type ) {
100    case CURL_LOCK_DATA_DNS:
101      if(share->hostcache) {
102        Curl_hash_destroy(share->hostcache);
103        share->hostcache = NULL;
104      }
105      break;
106
107#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
108    case CURL_LOCK_DATA_COOKIE:
109      if(share->cookies) {
110        Curl_cookie_cleanup(share->cookies);
111        share->cookies = NULL;
112      }
113      break;
114#endif   /* CURL_DISABLE_HTTP */
115
116    case CURL_LOCK_DATA_SSL_SESSION:
117      break;
118
119    case CURL_LOCK_DATA_CONNECT:
120      break;
121
122    default:
123      return CURLSHE_BAD_OPTION;
124    }
125    break;
126
127  case CURLSHOPT_LOCKFUNC:
128    lockfunc = va_arg(param, curl_lock_function);
129    share->lockfunc = lockfunc;
130    break;
131
132  case CURLSHOPT_UNLOCKFUNC:
133    unlockfunc = va_arg(param, curl_unlock_function);
134    share->unlockfunc = unlockfunc;
135    break;
136
137  case CURLSHOPT_USERDATA:
138    ptr = va_arg(param, void *);
139    share->clientdata = ptr;
140    break;
141
142  default:
143    return CURLSHE_BAD_OPTION;
144  }
145
146  return CURLSHE_OK;
147}
148
149CURLSHcode
150curl_share_cleanup(CURLSH *sh)
151{
152  struct Curl_share *share = (struct Curl_share *)sh;
153
154  if(share == NULL)
155    return CURLSHE_INVALID;
156
157  if(share->lockfunc)
158    share->lockfunc(NULL, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE,
159                    share->clientdata);
160
161  if(share->dirty) {
162    if(share->unlockfunc)
163      share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata);
164    return CURLSHE_IN_USE;
165  }
166
167  if(share->hostcache) {
168    Curl_hash_destroy(share->hostcache);
169    share->hostcache = NULL;
170  }
171
172  if(share->cookies)
173    Curl_cookie_cleanup(share->cookies);
174
175  if(share->unlockfunc)
176    share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata);
177  free(share);
178
179  return CURLSHE_OK;
180}
181
182
183CURLSHcode
184Curl_share_lock(struct SessionHandle *data, curl_lock_data type,
185                curl_lock_access accesstype)
186{
187  struct Curl_share *share = data->share;
188
189  if(share == NULL)
190    return CURLSHE_INVALID;
191
192  if(share->specifier & (1<<type)) {
193    if(share->lockfunc) /* only call this if set! */
194      share->lockfunc(data, type, accesstype, share->clientdata);
195  }
196  /* else if we don't share this, pretend successful lock */
197
198  return CURLSHE_OK;
199}
200
201CURLSHcode
202Curl_share_unlock(struct SessionHandle *data, curl_lock_data type)
203{
204  struct Curl_share *share = data->share;
205
206  if(share == NULL)
207    return CURLSHE_INVALID;
208
209  if(share->specifier & (1<<type)) {
210    if(share->unlockfunc) /* only call this if set! */
211      share->unlockfunc (data, type, share->clientdata);
212  }
213
214  return CURLSHE_OK;
215}
216