#include <curl/curl.h>
#include "urldata.h"
#include "share.h"
+#include "sslgen.h"
#include "curl_memory.h"
/* The last #include file should be: */
break;
#endif /* CURL_DISABLE_HTTP */
- case CURL_LOCK_DATA_SSL_SESSION: /* not supported (yet) */
+ case CURL_LOCK_DATA_SSL_SESSION:
+ if(!share->sslsession) {
+ share->nsslsession = 8;
+ share->sslsession = calloc(share->nsslsession,
+ sizeof(struct curl_ssl_session));
+ if(!share->sslsession)
+ return CURLSHE_NOMEM;
+ }
+ break;
+
case CURL_LOCK_DATA_CONNECT: /* not supported (yet) */
default:
#endif /* CURL_DISABLE_HTTP */
case CURL_LOCK_DATA_SSL_SESSION:
+ if(share->sslsession) {
+ free(share->sslsession);
+ share->sslsession = NULL;
+ share->nsslsession = 0;
+ }
break;
case CURL_LOCK_DATA_CONNECT:
curl_share_cleanup(CURLSH *sh)
{
struct Curl_share *share = (struct Curl_share *)sh;
+ unsigned int i;
if(share == NULL)
return CURLSHE_INVALID;
if(share->cookies)
Curl_cookie_cleanup(share->cookies);
+ if(share->sslsession) {
+ for(i = 0; i < share->nsslsession; ++i)
+ Curl_ssl_kill_session(&(share->sslsession[i]));
+ free(share->sslsession);
+ }
+
if(share->unlockfunc)
share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata);
free(share);
#include "url.h"
#include "curl_memory.h"
#include "progress.h"
+#include "share.h"
/* The last #include file should be: */
#include "memdebug.h"
/* session ID re-use is disabled */
return TRUE;
+ /* Lock for reading if shared */
+ if(data->share && data->share->sslsession == data->state.session)
+ Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SHARED);
+
for(i=0; i< data->set.ssl.numsessions; i++) {
check = &data->state.session[i];
if(!check->sessionid)
}
}
*ssl_sessionid = NULL;
+
+ /* Unlock for reading */
+ if(data->share && data->share->sslsession == data->state.session)
+ Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION);
+
+
return TRUE;
}
/*
* Kill a single session ID entry in the cache.
*/
-static int kill_session(struct curl_ssl_session *session)
+int Curl_ssl_kill_session(struct curl_ssl_session *session)
{
if(session->sessionid) {
/* defensive check */
void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid)
{
int i;
- for(i=0; i< conn->data->set.ssl.numsessions; i++) {
- struct curl_ssl_session *check = &conn->data->state.session[i];
+ struct SessionHandle *data=conn->data;
+
+ if(data->share && data->share->sslsession == data->state.session)
+ Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION,
+ CURL_LOCK_ACCESS_SINGLE);
+
+ for(i=0; i< data->set.ssl.numsessions; i++) {
+ struct curl_ssl_session *check = &data->state.session[i];
if(check->sessionid == ssl_sessionid) {
- kill_session(check);
+ Curl_ssl_kill_session(check);
break;
}
}
+
+ if(data->share && data->share->sslsession == data->state.session)
+ Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION);
}
/*
/* Now we should add the session ID and the host name to the cache, (remove
the oldest if necessary) */
+ /* If using shared SSL session, lock! */
+ if(data->share && data->share->sslsession == data->state.session)
+ Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE);
+
/* find an empty slot for us, or find the oldest */
for(i=1; (i<data->set.ssl.numsessions) &&
data->state.session[i].sessionid; i++) {
}
if(i == data->set.ssl.numsessions)
/* cache is full, we must "kill" the oldest entry! */
- kill_session(store);
+ Curl_ssl_kill_session(store);
else
store = &data->state.session[i]; /* use this slot */
store->name = clone_host; /* clone host name */
store->remote_port = conn->remote_port; /* port number */
+
+ /* Unlock */
+ if(data->share && data->share->sslsession == data->state.session)
+ Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION);
+
if(!Curl_clone_ssl_config(&conn->ssl_config, &store->ssl_config)) {
store->sessionid = NULL; /* let caller free sessionid */
free(clone_host);
{
long i;
/* kill the session ID cache */
- if(data->state.session) {
+ if(data->state.session &&
+ !(data->share && data->share->sslsession == data->state.session)) {
+
+ Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE);
+
for(i=0; i< data->set.ssl.numsessions; i++)
/* the single-killer function handles empty table slots */
- kill_session(&data->state.session[i]);
+ Curl_ssl_kill_session(&data->state.session[i]);
/* free the cache data */
free(data->state.session);
data->state.session = NULL;
+
+ Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION);
}
curlssl_close_all(data);
--- /dev/null
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "test.h"
+
+#include <curl/mprintf.h>
+
+#include "memdebug.h"
+
+#define THREADS 2
+
+/* struct containing data of a thread */
+struct Tdata {
+ CURLSH *share;
+ char *url;
+};
+
+struct userdata {
+ char *text;
+ int counter;
+};
+
+/* lock callback */
+static void my_lock(CURL *handle, curl_lock_data data, curl_lock_access laccess,
+ void *useptr )
+{
+ const char *what;
+ struct userdata *user = (struct userdata *)useptr;
+
+ (void)handle;
+ (void)laccess;
+
+ switch ( data ) {
+ case CURL_LOCK_DATA_SHARE:
+ what = "share";
+ break;
+ case CURL_LOCK_DATA_DNS:
+ what = "dns";
+ break;
+ case CURL_LOCK_DATA_COOKIE:
+ what = "cookie";
+ break;
+ case CURL_LOCK_DATA_SSL_SESSION:
+ what = "ssl_session";
+ break;
+ default:
+ fprintf(stderr, "lock: no such data: %d\n", (int)data);
+ return;
+ }
+ printf("lock: %-6s [%s]: %d\n", what, user->text, user->counter);
+ user->counter++;
+}
+
+/* unlock callback */
+static void my_unlock(CURL *handle, curl_lock_data data, void *useptr )
+{
+ const char *what;
+ struct userdata *user = (struct userdata *)useptr;
+ (void)handle;
+ switch ( data ) {
+ case CURL_LOCK_DATA_SHARE:
+ what = "share";
+ break;
+ case CURL_LOCK_DATA_DNS:
+ what = "dns";
+ break;
+ case CURL_LOCK_DATA_COOKIE:
+ what = "cookie";
+ break;
+ case CURL_LOCK_DATA_SSL_SESSION:
+ what = "ssl_session";
+ break;
+ default:
+ fprintf(stderr, "unlock: no such data: %d\n", (int)data);
+ return;
+ }
+ printf("unlock: %-6s [%s]: %d\n", what, user->text, user->counter);
+ user->counter++;
+}
+
+/* the dummy thread function */
+static void *fire(void *ptr)
+{
+ CURLcode code;
+ struct Tdata *tdata = (struct Tdata*)ptr;
+ CURL *curl;
+ int i=0;
+
+ if ((curl = curl_easy_init()) == NULL) {
+ fprintf(stderr, "curl_easy_init() failed\n");
+ return NULL;
+ }
+
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
+ curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
+ curl_easy_setopt(curl, CURLOPT_URL, tdata->url);
+ printf( "CURLOPT_SHARE\n" );
+ curl_easy_setopt(curl, CURLOPT_SHARE, tdata->share);
+
+ printf( "PERFORM\n" );
+ code = curl_easy_perform(curl);
+ if( code != CURLE_OK ) {
+ fprintf(stderr, "perform url '%s' repeat %d failed, curlcode %d\n",
+ tdata->url, i, (int)code);
+ }
+
+ printf( "CLEANUP\n" );
+ curl_easy_cleanup(curl);
+
+ return NULL;
+}
+
+/* test function */
+int test(char *URL)
+{
+ int res;
+ CURLSHcode scode = CURLSHE_OK;
+ char *url;
+ struct Tdata tdata;
+ CURL *curl;
+ CURLSH *share;
+ int i;
+ struct userdata user;
+
+ user.text = (char *)"Pigs in space";
+ user.counter = 0;
+
+ printf( "GLOBAL_INIT\n" );
+ if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
+ fprintf(stderr, "curl_global_init() failed\n");
+ return TEST_ERR_MAJOR_BAD;
+ }
+
+ /* prepare share */
+ printf( "SHARE_INIT\n" );
+ if ((share = curl_share_init()) == NULL) {
+ fprintf(stderr, "curl_share_init() failed\n");
+ curl_global_cleanup();
+ return TEST_ERR_MAJOR_BAD;
+ }
+
+ if ( CURLSHE_OK == scode ) {
+ printf( "CURLSHOPT_LOCKFUNC\n" );
+ scode = curl_share_setopt( share, CURLSHOPT_LOCKFUNC, my_lock);
+ }
+ if ( CURLSHE_OK == scode ) {
+ printf( "CURLSHOPT_UNLOCKFUNC\n" );
+ scode = curl_share_setopt( share, CURLSHOPT_UNLOCKFUNC, my_unlock);
+ }
+ if ( CURLSHE_OK == scode ) {
+ printf( "CURLSHOPT_USERDATA\n" );
+ scode = curl_share_setopt( share, CURLSHOPT_USERDATA, &user);
+ }
+ if ( CURLSHE_OK == scode ) {
+ printf( "CURL_LOCK_DATA_SSL_SESSION\n" );
+ scode = curl_share_setopt( share, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION);
+ }
+
+ if ( CURLSHE_OK != scode ) {
+ fprintf(stderr, "curl_share_setopt() failed\n");
+ curl_share_cleanup(share);
+ curl_global_cleanup();
+ return TEST_ERR_MAJOR_BAD;
+ }
+
+
+ res = 0;
+
+ /* start treads */
+ for (i=1; i<=THREADS; i++ ) {
+
+ /* set thread data */
+ tdata.url = URL;
+ tdata.share = share;
+
+ /* simulate thread, direct call of "thread" function */
+ printf( "*** run %d\n",i );
+ fire( &tdata );
+ }
+
+
+ /* fetch a another one */
+ printf( "*** run %d\n", i );
+ if ((curl = curl_easy_init()) == NULL) {
+ fprintf(stderr, "curl_easy_init() failed\n");
+ curl_share_cleanup(share);
+ curl_global_cleanup();
+ return TEST_ERR_MAJOR_BAD;
+ }
+
+ url = URL;
+ test_setopt( curl, CURLOPT_URL, url );
+ printf( "CURLOPT_SHARE\n" );
+ test_setopt( curl, CURLOPT_SHARE, share );
+
+ printf( "PERFORM\n" );
+ curl_easy_perform( curl );
+
+ /* try to free share, expect to fail because share is in use*/
+ printf( "try SHARE_CLEANUP...\n" );
+ scode = curl_share_cleanup( share );
+ if ( scode==CURLSHE_OK )
+ {
+ fprintf(stderr, "curl_share_cleanup succeed but error expected\n");
+ share = NULL;
+ } else {
+ printf( "SHARE_CLEANUP failed, correct\n" );
+ }
+
+test_cleanup:
+
+ /* clean up last handle */
+ printf( "CLEANUP\n" );
+ curl_easy_cleanup( curl );
+
+ /* free share */
+ printf( "SHARE_CLEANUP\n" );
+ scode = curl_share_cleanup( share );
+ if ( scode!=CURLSHE_OK )
+ fprintf(stderr, "curl_share_cleanup failed, code errno %d\n",
+ (int)scode);
+
+ printf( "GLOBAL_CLEANUP\n" );
+ curl_global_cleanup();
+
+ return res;
+}
+