Commit 5793bc37 authored by Alejandro Alvarez's avatar Alejandro Alvarez Committed by Daniel Stenberg
Browse files

SSL session sharing support added

With locking, plus test, plus documentation
parent ff5ba6e4
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -64,6 +64,11 @@ Cached DNS hosts will be shared across the easy handles using this shared
object. Note that when you use the multi interface, all easy handles added to
the same multi handle will share DNS cache by default without this having to
be used!
.IP CURL_LOCK_DATA_SSL_SESSION
SSL session IDs will be shared accross the easy handles using this shared
object. This will reduce the time spent in the SSL handshake when reconnecting
to the same server. Note SSL session IDs are reused within the same easy handle
by default.
.RE
.IP CURLSHOPT_UNSHARE
This option does the opposite of \fICURLSHOPT_SHARE\fP. It specifies that
+23 −1
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include <curl/curl.h>
#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);
+4 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include "setup.h"
#include <curl/curl.h>
#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,
+42 −7
Original line number Diff line number Diff line
@@ -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; (i<data->set.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);
+2 −0
Original line number Diff line number Diff line
@@ -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);

Loading