From 5793bc370c794a10e6ed014cb535a47672842ae6 Mon Sep 17 00:00:00 2001 From: Alejandro Alvarez Date: Tue, 20 Sep 2011 17:43:54 +0200 Subject: SSL session sharing support added With locking, plus test, plus documentation --- lib/share.c | 24 +++++++++++++++++++++++- lib/share.h | 4 ++++ lib/sslgen.c | 49 ++++++++++++++++++++++++++++++++++++++++++------- lib/sslgen.h | 2 ++ lib/url.c | 9 +++++++++ 5 files changed, 80 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/share.c b/lib/share.c index a3db4ded9..a3eae1639 100644 --- a/lib/share.c +++ b/lib/share.c @@ -25,6 +25,7 @@ #include #include "urldata.h" #include "share.h" +#include "sslgen.h" #include "curl_memory.h" /* The last #include file should be: */ @@ -82,7 +83,16 @@ curl_share_setopt(CURLSH *sh, CURLSHoption option, ...) 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: @@ -112,6 +122,11 @@ curl_share_setopt(CURLSH *sh, CURLSHoption option, ...) #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: @@ -148,6 +163,7 @@ CURLSHcode curl_share_cleanup(CURLSH *sh) { struct Curl_share *share = (struct Curl_share *)sh; + unsigned int i; if(share == NULL) return CURLSHE_INVALID; @@ -170,6 +186,12 @@ curl_share_cleanup(CURLSH *sh) 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); diff --git a/lib/share.h b/lib/share.h index ea8e233d2..cf200008f 100644 --- a/lib/share.h +++ b/lib/share.h @@ -26,6 +26,7 @@ #include "setup.h" #include #include "cookie.h" +#include "urldata.h" /* SalfordC says "A structure member may not be volatile". Hence: */ @@ -46,6 +47,9 @@ struct Curl_share { struct curl_hash *hostcache; struct CookieInfo *cookies; + + struct curl_ssl_session *sslsession; + unsigned int nsslsession; }; CURLSHcode Curl_share_lock (struct SessionHandle *, curl_lock_data, diff --git a/lib/sslgen.c b/lib/sslgen.c index 005d82ef3..77c641b24 100644 --- a/lib/sslgen.c +++ b/lib/sslgen.c @@ -62,6 +62,7 @@ #include "url.h" #include "curl_memory.h" #include "progress.h" +#include "share.h" /* The last #include file should be: */ #include "memdebug.h" @@ -236,6 +237,10 @@ int Curl_ssl_getsessionid(struct connectdata *conn, /* 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) @@ -254,13 +259,19 @@ int Curl_ssl_getsessionid(struct connectdata *conn, } } *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 */ @@ -288,14 +299,23 @@ static int kill_session(struct curl_ssl_session *session) 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); } /* @@ -325,6 +345,10 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, /* 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; (iset.ssl.numsessions) && data->state.session[i].sessionid; i++) { @@ -335,7 +359,7 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, } 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 */ @@ -349,6 +373,11 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, 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); @@ -363,14 +392,20 @@ void Curl_ssl_close_all(struct SessionHandle *data) { 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); diff --git a/lib/sslgen.h b/lib/sslgen.h index ec8fe50bb..73164fd23 100644 --- a/lib/sslgen.h +++ b/lib/sslgen.h @@ -64,6 +64,8 @@ int Curl_ssl_getsessionid(struct connectdata *conn, CURLcode Curl_ssl_addsessionid(struct connectdata *conn, void *ssl_sessionid, size_t idsize); +/* Kill a single session ID entry in the cache */ +int Curl_ssl_kill_session(struct curl_ssl_session *session); /* delete a session from the cache */ void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid); diff --git a/lib/url.c b/lib/url.c index 086091485..c9135a6b3 100644 --- a/lib/url.c +++ b/lib/url.c @@ -2083,6 +2083,11 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, if(data->share->cookies == data->cookies) data->cookies = NULL; + if(data->share->sslsession == data->state.session) { + data->state.session = NULL; + data->set.ssl.numsessions = 0; + } + data->share->dirty--; Curl_share_unlock(data, CURL_LOCK_DATA_SHARE); @@ -2114,6 +2119,10 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, data->cookies = data->share->cookies; } #endif /* CURL_DISABLE_HTTP */ + if(data->share->sslsession) { + data->set.ssl.numsessions = data->share->nsslsession; + data->state.session = data->share->sslsession; + } Curl_share_unlock(data, CURL_LOCK_DATA_SHARE); } -- cgit v1.2.3