1/***************************************************************************
2 *                                  _   _ ____  _
3 *  Project                     ___| | | |  _ \| |
4 *                             / __| | | | |_) | |
5 *                            | (__| |_| |  _ <| |___
6 *                             \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2013, 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 "curl_setup.h"
24
25#include <curl/curl.h>
26#include "urldata.h"
27#include "share.h"
28#include "vtls/vtls.h"
29#include "curl_memory.h"
30
31/* The last #include file should be: */
32#include "memdebug.h"
33
34CURLSH *
35curl_share_init(void)
36{
37  struct Curl_share *share = calloc(1, sizeof(struct Curl_share));
38  if(share)
39    share->specifier |= (1<<CURL_LOCK_DATA_SHARE);
40
41  return share;
42}
43
44#undef curl_share_setopt
45CURLSHcode
46curl_share_setopt(CURLSH *sh, CURLSHoption option, ...)
47{
48  struct Curl_share *share = (struct Curl_share *)sh;
49  va_list param;
50  int type;
51  curl_lock_function lockfunc;
52  curl_unlock_function unlockfunc;
53  void *ptr;
54  CURLSHcode res = CURLSHE_OK;
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          res = CURLSHE_NOMEM;
74      }
75      break;
76
77    case CURL_LOCK_DATA_COOKIE:
78#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
79      if(!share->cookies) {
80        share->cookies = Curl_cookie_init(NULL, NULL, NULL, TRUE );
81        if(!share->cookies)
82          res = CURLSHE_NOMEM;
83      }
84#else   /* CURL_DISABLE_HTTP */
85      res = CURLSHE_NOT_BUILT_IN;
86#endif
87      break;
88
89    case CURL_LOCK_DATA_SSL_SESSION:
90#ifdef USE_SSL
91      if(!share->sslsession) {
92        share->max_ssl_sessions = 8;
93        share->sslsession = calloc(share->max_ssl_sessions,
94                                   sizeof(struct curl_ssl_session));
95        share->sessionage = 0;
96        if(!share->sslsession)
97          res = CURLSHE_NOMEM;
98      }
99#else
100      res = CURLSHE_NOT_BUILT_IN;
101#endif
102      break;
103
104    case CURL_LOCK_DATA_CONNECT:     /* not supported (yet) */
105      break;
106
107    default:
108      res = CURLSHE_BAD_OPTION;
109    }
110    break;
111
112  case CURLSHOPT_UNSHARE:
113    /* this is a type this share will no longer share */
114    type = va_arg(param, int);
115    share->specifier &= ~(1<<type);
116    switch( type ) {
117    case CURL_LOCK_DATA_DNS:
118      if(share->hostcache) {
119        Curl_hash_destroy(share->hostcache);
120        share->hostcache = NULL;
121      }
122      break;
123
124    case CURL_LOCK_DATA_COOKIE:
125#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
126      if(share->cookies) {
127        Curl_cookie_cleanup(share->cookies);
128        share->cookies = NULL;
129      }
130#else   /* CURL_DISABLE_HTTP */
131      res = CURLSHE_NOT_BUILT_IN;
132#endif
133      break;
134
135    case CURL_LOCK_DATA_SSL_SESSION:
136#ifdef USE_SSL
137      Curl_safefree(share->sslsession);
138#else
139      res = CURLSHE_NOT_BUILT_IN;
140#endif
141      break;
142
143    case CURL_LOCK_DATA_CONNECT:
144      break;
145
146    default:
147      res = CURLSHE_BAD_OPTION;
148      break;
149    }
150    break;
151
152  case CURLSHOPT_LOCKFUNC:
153    lockfunc = va_arg(param, curl_lock_function);
154    share->lockfunc = lockfunc;
155    break;
156
157  case CURLSHOPT_UNLOCKFUNC:
158    unlockfunc = va_arg(param, curl_unlock_function);
159    share->unlockfunc = unlockfunc;
160    break;
161
162  case CURLSHOPT_USERDATA:
163    ptr = va_arg(param, void *);
164    share->clientdata = ptr;
165    break;
166
167  default:
168    res = CURLSHE_BAD_OPTION;
169    break;
170  }
171
172  va_end(param);
173
174  return res;
175}
176
177CURLSHcode
178curl_share_cleanup(CURLSH *sh)
179{
180  struct Curl_share *share = (struct Curl_share *)sh;
181
182  if(share == NULL)
183    return CURLSHE_INVALID;
184
185  if(share->lockfunc)
186    share->lockfunc(NULL, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE,
187                    share->clientdata);
188
189  if(share->dirty) {
190    if(share->unlockfunc)
191      share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata);
192    return CURLSHE_IN_USE;
193  }
194
195  if(share->hostcache) {
196    Curl_hash_destroy(share->hostcache);
197    share->hostcache = NULL;
198  }
199
200#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
201  if(share->cookies)
202    Curl_cookie_cleanup(share->cookies);
203#endif
204
205#ifdef USE_SSL
206  if(share->sslsession) {
207    size_t i;
208    for(i = 0; i < share->max_ssl_sessions; i++)
209      Curl_ssl_kill_session(&(share->sslsession[i]));
210    free(share->sslsession);
211  }
212#endif
213
214  if(share->unlockfunc)
215    share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata);
216  free(share);
217
218  return CURLSHE_OK;
219}
220
221
222CURLSHcode
223Curl_share_lock(struct SessionHandle *data, curl_lock_data type,
224                curl_lock_access accesstype)
225{
226  struct Curl_share *share = data->share;
227
228  if(share == NULL)
229    return CURLSHE_INVALID;
230
231  if(share->specifier & (1<<type)) {
232    if(share->lockfunc) /* only call this if set! */
233      share->lockfunc(data, type, accesstype, share->clientdata);
234  }
235  /* else if we don't share this, pretend successful lock */
236
237  return CURLSHE_OK;
238}
239
240CURLSHcode
241Curl_share_unlock(struct SessionHandle *data, curl_lock_data type)
242{
243  struct Curl_share *share = data->share;
244
245  if(share == NULL)
246    return CURLSHE_INVALID;
247
248  if(share->specifier & (1<<type)) {
249    if(share->unlockfunc) /* only call this if set! */
250      share->unlockfunc (data, type, share->clientdata);
251  }
252
253  return CURLSHE_OK;
254}
255