I thought you were going to format to our style guidelines before committing?
On Oct 8, 2014, at 11:34 AM, bri...@apache.org wrote: > Repository: trafficserver > Updated Branches: > refs/heads/master 195259b16 -> f1bedb41e > > > TS-3080: Optimized SSL Session Cache > > > Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo > Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/53bf5d1e > Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/53bf5d1e > Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/53bf5d1e > > Branch: refs/heads/master > Commit: 53bf5d1e7618ae38b0a8b49263a047282eec68d1 > Parents: 72b7c05 > Author: Brian Geffon <bri...@apache.org> > Authored: Tue Oct 7 18:51:34 2014 -0700 > Committer: Brian Geffon <bri...@apache.org> > Committed: Tue Oct 7 18:52:34 2014 -0700 > > ---------------------------------------------------------------------- > iocore/net/Makefile.am | 1 + > iocore/net/P_SSLConfig.h | 12 +- > iocore/net/P_SSLUtils.h | 4 + > iocore/net/SSLConfig.cc | 19 ++- > iocore/net/SSLSessionCache.cc | 246 +++++++++++++++++++++++++++++++++++++ > iocore/net/SSLSessionCache.h | 149 ++++++++++++++++++++++ > iocore/net/SSLUtils.cc | 98 ++++++++++++++- > lib/ts/ink_mutex.h | 29 +++++ > mgmt/RecordsConfig.cc | 8 +- > proxy/Makefile.am | 2 +- > 10 files changed, 559 insertions(+), 9 deletions(-) > ---------------------------------------------------------------------- > > > http://git-wip-us.apache.org/repos/asf/trafficserver/blob/53bf5d1e/iocore/net/Makefile.am > ---------------------------------------------------------------------- > diff --git a/iocore/net/Makefile.am b/iocore/net/Makefile.am > index 0120528..da7a476 100644 > --- a/iocore/net/Makefile.am > +++ b/iocore/net/Makefile.am > @@ -88,6 +88,7 @@ libinknet_a_SOURCES = \ > P_UnixUDPConnection.h \ > Socks.cc \ > SSLCertLookup.cc \ > + SSLSessionCache.cc \ > SSLConfig.cc \ > SSLNetAccept.cc \ > SSLNetProcessor.cc \ > > http://git-wip-us.apache.org/repos/asf/trafficserver/blob/53bf5d1e/iocore/net/P_SSLConfig.h > ---------------------------------------------------------------------- > diff --git a/iocore/net/P_SSLConfig.h b/iocore/net/P_SSLConfig.h > index aa4926f..0cad7d9 100644 > --- a/iocore/net/P_SSLConfig.h > +++ b/iocore/net/P_SSLConfig.h > @@ -32,6 +32,7 @@ > #define __P_SSLCONFIG_H__ > > #include "ProxyConfig.h" > +#include "SSLSessionCache.h" > > struct SSLCertLookup; > > @@ -51,7 +52,8 @@ struct SSLConfigParams : public ConfigInfo > enum SSL_SESSION_CACHE_MODE > { > SSL_SESSION_CACHE_MODE_OFF = 0, > - SSL_SESSION_CACHE_MODE_SERVER = 1 > + SSL_SESSION_CACHE_MODE_SERVER_OPENSSL_IMPL = 1, > + SSL_SESSION_CACHE_MODE_SERVER_ATS_IMPL = 2 > }; > > SSLConfigParams(); > @@ -69,6 +71,8 @@ struct SSLConfigParams : public ConfigInfo > int verify_depth; > int ssl_session_cache; // SSL_SESSION_CACHE_MODE > int ssl_session_cache_size; > + int ssl_session_cache_num_buckets; > + int ssl_session_cache_skip_on_contention; > int ssl_session_cache_timeout; > > char * clientCertPath; > @@ -88,6 +92,10 @@ struct SSLConfigParams : public ConfigInfo > static int ssl_ocsp_request_timeout; > static int ssl_ocsp_update_period; > > + static size_t session_cache_number_buckets; > + static size_t session_cache_max_bucket_size; > + static bool session_cache_skip_on_lock_contention; > + > static init_ssl_ctx_func init_ssl_ctx_cb; > > void initialize(); > @@ -126,4 +134,6 @@ private: > static int configid; > }; > > +extern SSLSessionCache *session_cache; > + > #endif > > http://git-wip-us.apache.org/repos/asf/trafficserver/blob/53bf5d1e/iocore/net/P_SSLUtils.h > ---------------------------------------------------------------------- > diff --git a/iocore/net/P_SSLUtils.h b/iocore/net/P_SSLUtils.h > index 3cf0c20..1c9f0b8 100644 > --- a/iocore/net/P_SSLUtils.h > +++ b/iocore/net/P_SSLUtils.h > @@ -70,6 +70,10 @@ enum SSL_Stats > ssl_total_tickets_verified_stat, > ssl_total_tickets_not_found_stat, > ssl_total_tickets_renewed_stat, > + ssl_session_cache_hit, > + ssl_session_cache_miss, > + ssl_session_cache_eviction, > + ssl_session_cache_lock_contention, > > /* error stats */ > ssl_error_want_write, > > http://git-wip-us.apache.org/repos/asf/trafficserver/blob/53bf5d1e/iocore/net/SSLConfig.cc > ---------------------------------------------------------------------- > diff --git a/iocore/net/SSLConfig.cc b/iocore/net/SSLConfig.cc > index 402664a..3aaddc1 100644 > --- a/iocore/net/SSLConfig.cc > +++ b/iocore/net/SSLConfig.cc > @@ -37,6 +37,7 @@ > #include "P_SSLConfig.h" > #include "P_SSLUtils.h" > #include "P_SSLCertLookup.h" > +#include "SSLSessionCache.h" > #include <records/I_RecHttp.h> > > int SSLConfig::configid = 0; > @@ -47,6 +48,10 @@ bool SSLConfigParams::ssl_ocsp_enabled = false; > int SSLConfigParams::ssl_ocsp_cache_timeout = 3600; > int SSLConfigParams::ssl_ocsp_request_timeout = 10; > int SSLConfigParams::ssl_ocsp_update_period = 60; > +size_t SSLConfigParams::session_cache_number_buckets = 1024; > +bool SSLConfigParams::session_cache_skip_on_lock_contention = false; > +size_t SSLConfigParams::session_cache_max_bucket_size = 100; > + > init_ssl_ctx_func SSLConfigParams::init_ssl_ctx_cb = NULL; > > static ConfigUpdateHandler<SSLCertificateConfig> * sslCertUpdate; > @@ -70,8 +75,10 @@ SSLConfigParams::SSLConfigParams() > > ssl_ctx_options = 0; > ssl_client_ctx_protocols = 0; > - ssl_session_cache = SSL_SESSION_CACHE_MODE_SERVER; > - ssl_session_cache_size = 1024*20; > + ssl_session_cache = SSL_SESSION_CACHE_MODE_SERVER_ATS_IMPL; > + ssl_session_cache_size = 1024*100; > + ssl_session_cache_num_buckets = 1024; // Sessions per bucket is > ceil(ssl_session_cache_size / ssl_session_cache_num_buckets) > + ssl_session_cache_skip_on_contention = 0; > ssl_session_cache_timeout = 0; > } > > @@ -248,8 +255,16 @@ SSLConfigParams::initialize() > // SSL session cache configurations > REC_ReadConfigInteger(ssl_session_cache, "proxy.config.ssl.session_cache"); > REC_ReadConfigInteger(ssl_session_cache_size, > "proxy.config.ssl.session_cache.size"); > + REC_ReadConfigInteger(ssl_session_cache_num_buckets, > "proxy.config.ssl.session_cache.num_buckets"); > + REC_ReadConfigInteger(ssl_session_cache_skip_on_contention, > "proxy.config.ssl.session_cache.skip_cache_on_bucket_contention"); > REC_ReadConfigInteger(ssl_session_cache_timeout, > "proxy.config.ssl.session_cache.timeout"); > > + SSLConfigParams::session_cache_max_bucket_size = > ceil(ssl_session_cache_size/ssl_session_cache_num_buckets ); > + SSLConfigParams::session_cache_skip_on_lock_contention = > ssl_session_cache_skip_on_contention; > + SSLConfigParams::session_cache_number_buckets = > ssl_session_cache_num_buckets; > + > + session_cache = new SSLSessionCache(); > + > // SSL record size > REC_EstablishStaticConfigInt32(ssl_maxrecord, > "proxy.config.ssl.max_record_size"); > > > http://git-wip-us.apache.org/repos/asf/trafficserver/blob/53bf5d1e/iocore/net/SSLSessionCache.cc > ---------------------------------------------------------------------- > diff --git a/iocore/net/SSLSessionCache.cc b/iocore/net/SSLSessionCache.cc > new file mode 100644 > index 0000000..c936ee7 > --- /dev/null > +++ b/iocore/net/SSLSessionCache.cc > @@ -0,0 +1,246 @@ > +/** @file > + > + @section license License > + > + Licensed to the Apache Software Foundation (ASF) under one > + or more contributor license agreements. See the NOTICE file > + distributed with this work for additional information > + regarding copyright ownership. The ASF licenses this file > + to you under the Apache License, Version 2.0 (the > + "License"); you may not use this file except in compliance > + with the License. You may obtain a copy of the License at > + > + http://www.apache.org/licenses/LICENSE-2.0 > + > + Unless required by applicable law or agreed to in writing, software > + distributed under the License is distributed on an "AS IS" BASIS, > + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. > + See the License for the specific language governing permissions and > + limitations under the License. > + */ > + > +#include <cstring> > +#include <deque> > +#include "P_SSLConfig.h" > +#include "SSLSessionCache.h" > + > +#define SSLSESSIONCACHE_STRINGIFY0(x) #x > +#define SSLSESSIONCACHE_STRINGIFY(x) SSLSESSIONCACHE_STRINGIFY0(x) > +#define SSLSESSIONCACHE_LINENO SSLSESSIONCACHE_STRINGIFY(__LINE__) > + > +#ifdef DEBUG > +#define PRINT_BUCKET(x) this->print(x " at " __FILE__ ":" > SSLSESSIONCACHE_LINENO); > +#else > +#define PRINT_BUCKET(x) > +#endif > + > +using ts::detail::RBNode; > + > +/* Session Cache */ > +SSLSessionCache::SSLSessionCache() > + : session_bucket(NULL) { > + Debug("ssl.session_cache", "Created new ssl session cache %p with %ld > buckets each with size max size %ld", this, > SSLConfigParams::session_cache_number_buckets, > SSLConfigParams::session_cache_max_bucket_size); > + > + session_bucket = new > SSLSessionBucket[SSLConfigParams::session_cache_number_buckets]; > +} > + > +SSLSessionCache::~SSLSessionCache() { > + delete []session_bucket; > +} > + > +bool SSLSessionCache::getSession(const SSLSessionID &sid, const char > *sni_name, SSL_SESSION **sess) { > + uint64_t hash = sid.hash(); > + uint64_t target_bucket = hash % > SSLConfigParams::session_cache_number_buckets; > + SSLSessionBucket *bucket = &session_bucket[target_bucket]; > + bool ret = false; > + > + if (is_debug_tag_set("ssl.session_cache")) { > + char buf[sid.len * 2 + 1]; > + sid.toString(buf, sizeof(buf)); > + Debug("ssl.session_cache.get", "SessionCache looking in bucket %" > PRId64 " (%p) for session '%s' (hash: %" PRIX64 ").", target_bucket, bucket, > buf, hash); > + } > + > + ret = bucket->getSession(sid, sni_name, sess); > + > + if (ret) > + SSL_INCREMENT_DYN_STAT(ssl_session_cache_hit); > + else > + SSL_INCREMENT_DYN_STAT(ssl_session_cache_miss); > + > + return ret; > +} > + > +void SSLSessionCache::removeSession(const SSLSessionID &sid) { > + uint64_t hash = sid.hash(); > + uint64_t target_bucket = hash % > SSLConfigParams::session_cache_number_buckets; > + SSLSessionBucket *bucket = &session_bucket[target_bucket]; > + > + if (is_debug_tag_set("ssl.session_cache")) { > + char buf[sid.len * 2 + 1]; > + sid.toString(buf, sizeof(buf)); > + Debug("ssl.session_cache.remove", "SessionCache using bucket %" PRId64 > " (%p): Removing session '%s' (hash: %" PRIX64 ").", target_bucket, bucket, > buf, hash); > + } > + > + SSL_INCREMENT_DYN_STAT(ssl_session_cache_eviction); > + bucket->removeSession(sid); > +} > + > +void SSLSessionCache::insertSession(const SSLSessionID &sid, const char > *sni_name, SSL_SESSION *sess) { > + uint64_t hash = sid.hash(); > + uint64_t target_bucket = hash % > SSLConfigParams::session_cache_number_buckets; > + SSLSessionBucket *bucket = &session_bucket[target_bucket]; > + > + if (is_debug_tag_set("ssl.session_cache")) { > + char buf[sid.len * 2 + 1]; > + sid.toString(buf, sizeof(buf)); > + Debug("ssl.session_cache.insert", "SessionCache using bucket %" PRId64 > " (%p): Inserting session '%s' (hash: %" PRIX64 ").", target_bucket, bucket, > buf, hash); > + } > + > + bucket->insertSession(sid, sni_name, sess); > +} > + > +void SSLSessionBucket::insertSession(const SSLSessionID &id, const char > *sni_name, SSL_SESSION *sess) { > + size_t len = i2d_SSL_SESSION(sess, NULL); // make sure we're not going to > need more than SSL_MAX_SESSION_SIZE bytes > + /* do not cache a session that's too big. */ > + if (len > (size_t) SSL_MAX_SESSION_SIZE) { > + Debug("ssl.session_cache", "Unable to save SSL session because size of > %" PRId64 " exceeds the max of %d", len, SSL_MAX_SESSION_SIZE); > + return; > + } > + > + if (is_debug_tag_set("ssl.session_cache")) { > + char buf[id.len * 2 + 1]; > + id.toString(buf, sizeof(buf)); > + Debug("ssl.session_cache", "Inserting session '%s' to bucket %p with sni > name '%s'", buf, this, sni_name); > + } > + > + Ptr<IOBufferData> buf; > + buf = new_IOBufferData(buffer_size_to_index(len, MAX_BUFFER_SIZE_INDEX), > MEMALIGNED); > + ink_release_assert(static_cast<size_t>(buf->block_size()) >= len); > + unsigned char *loc = reinterpret_cast<unsigned char *>(buf->data()); > + i2d_SSL_SESSION(sess, &loc); > + > + SSLSession *ssl_session = new SSLSession(id, sni_name, buf, len); > + > + ink_scoped_try_mutex scoped_mutex(mutex); > + if (!scoped_mutex.hasLock()) { > + SSL_INCREMENT_DYN_STAT(ssl_session_cache_lock_contention); > + if (SSLConfigParams::session_cache_skip_on_lock_contention) > + return; > + > + scoped_mutex.lock(); > + } > + > + PRINT_BUCKET("insertSession before") > + if (queue.size >= > static_cast<int>(SSLConfigParams::session_cache_max_bucket_size)) { > + removeOldestSession(); > + } > + > + /* do the actual insert */ > + queue.enqueue(ssl_session); > + > + PRINT_BUCKET("insertSession after") > +} > + > + > + > +bool SSLSessionBucket::getSession(const SSLSessionID &id, const char > *sni_name, SSL_SESSION **sess) { > + char buf[id.len * 2 + 1]; > + if (is_debug_tag_set("ssl.session_cache")) { > + id.toString(buf, sizeof(buf)); > + } > + > + Debug("ssl.session_cache", "Looking for session with id '%s' in bucket %p > with sni name '%s'", buf, this, sni_name); > + > + ink_scoped_try_mutex scoped_mutex(mutex); > + if (!scoped_mutex.hasLock()) { > + SSL_INCREMENT_DYN_STAT(ssl_session_cache_lock_contention); > + if (SSLConfigParams::session_cache_skip_on_lock_contention) > + return false; > + scoped_mutex.lock(); > + } > + > + PRINT_BUCKET("getSession") > + > + // We work backwards because that's the most likely place we'll find our > session... > + SSLSession *node = queue.tail; > + while (node) { > + if (node->session_id == id) > + { > + if ((node->sni_name == NULL && sni_name == NULL) /* this session > doesn't have an associated SNI name */|| > + (node->sni_name && sni_name && strcmp(node->sni_name, sni_name) == > 0)) { /* the session does have an associated SNI name */ > + Debug("ssl.session_cache", "Found session with id '%s' in bucket %p > with sni name '%s'.", buf, this, sni_name); > + > + const unsigned char *loc = reinterpret_cast<const unsigned char > *>(node->asn1_data->data()); > + *sess = d2i_SSL_SESSION(NULL, &loc, node->len_asn1_data); > + > + return true; > + } else { > + Debug("ssl.session_cache", "Found session with id '%s' in bucket %p > but sni names didn't match! '%s' != '%s'.", buf, this, node->sni_name, > sni_name); > + return false; > + } > + } > + > + node = node->link.prev; > + } > + > + Debug("ssl.session_cache", "Session with id '%s' not found in bucket %p.", > buf, this); > + return false; > +} > + > +void inline SSLSessionBucket::print(const char *ref_str) const { > + /* NOTE: This method assumes you're already holding the bucket lock */ > + if (!is_debug_tag_set("ssl.session_cache.bucket")) { > + return; > + } > + > + fprintf(stderr, "-------------- BUCKET %p (%s) ----------------\n", this, > ref_str); > + fprintf(stderr, "Current Size: %d, Max Size: %" PRId64 "\n", queue.size, > SSLConfigParams::session_cache_max_bucket_size); > + fprintf(stderr, "Queue: \n"); > + > + SSLSession *node = queue.head; > + while(node) { > + char s_buf[2 * node->session_id.len + 1]; > + node->session_id.toString(s_buf, sizeof(s_buf)); > + fprintf(stderr, " %s\n", s_buf); > + node = node->link.next; > + } > +} > + > +void inline SSLSessionBucket::removeOldestSession() { > + PRINT_BUCKET("removeOldestSession before") > + while (queue.head && queue.size >= > static_cast<int>(SSLConfigParams::session_cache_max_bucket_size)) { > + SSLSession *old_head = queue.pop(); > + if (is_debug_tag_set("ssl.session_cache")) { > + char buf[old_head->session_id.len * 2 + 1]; > + old_head->session_id.toString(buf, sizeof(buf)); > + Debug("ssl.session_cache", "Removing session '%s' from bucket %p > because the bucket has size %d and max %" PRId64, buf, this, (queue.size + > 1), SSLConfigParams::session_cache_max_bucket_size); > + } > + delete old_head; > + } > + PRINT_BUCKET("removeOldestSession after") > +} > + > +void SSLSessionBucket::removeSession(const SSLSessionID &id) { > + ink_scoped_mutex scoped_mutex(mutex); // We can't bail on contention here > because this session MUST be removed. > + SSLSession *node = queue.head; > + while (node) { > + if (node->session_id == id) > + { > + queue.remove(node); > + delete node; > + return; > + } > + } > +} > + > +/* Session Bucket */ > +SSLSessionBucket::SSLSessionBucket() : root(NULL) { > + Debug("ssl.session_cache", "Created new bucket %p with max size %ld", > this, SSLConfigParams::session_cache_max_bucket_size); > + ink_mutex_init(&mutex, "session_bucket"); > +} > + > +SSLSessionBucket::~SSLSessionBucket() { > + ink_mutex_destroy(&mutex); > +} > + > + > > http://git-wip-us.apache.org/repos/asf/trafficserver/blob/53bf5d1e/iocore/net/SSLSessionCache.h > ---------------------------------------------------------------------- > diff --git a/iocore/net/SSLSessionCache.h b/iocore/net/SSLSessionCache.h > new file mode 100644 > index 0000000..283438a > --- /dev/null > +++ b/iocore/net/SSLSessionCache.h > @@ -0,0 +1,149 @@ > +/** @file > + > + @section license License > + > + Licensed to the Apache Software Foundation (ASF) under one > + or more contributor license agreements. See the NOTICE file > + distributed with this work for additional information > + regarding copyright ownership. The ASF licenses this file > + to you under the Apache License, Version 2.0 (the > + "License"); you may not use this file except in compliance > + with the License. You may obtain a copy of the License at > + > + http://www.apache.org/licenses/LICENSE-2.0 > + > + Unless required by applicable law or agreed to in writing, software > + distributed under the License is distributed on an "AS IS" BASIS, > + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. > + See the License for the specific language governing permissions and > + limitations under the License. > + */ > + > +#ifndef SSL_SESSION_CACHE_ > +#define SSL_SESSION_CACHE_ > +#include "Map.h" > +#include "List.h" > +#include "ink_mutex.h" > +#include "P_EventSystem.h" > +#include "P_AIO.h" > +#include "I_RecProcess.h" > +#include "libts.h" > +#include "P_SSLUtils.h" > +#include "RbTree.h" > +#include <openssl/ssl.h> > + > +#define SSL_MAX_SESSION_SIZE 2048 > + > +struct SSLSessionID { > + char bytes[SSL_MAX_SSL_SESSION_ID_LENGTH]; > + size_t len; > + > + SSLSessionID(const unsigned char *s, size_t l) : len(l) { > + ink_release_assert(l <= sizeof(bytes)); > + memcpy(bytes, s, l); > + } > + > + SSLSessionID(const SSLSessionID& other) { > + if (other.len) > + memcpy(bytes, other.bytes, other.len); > + > + len = other.len; > + } > + > + bool operator<(const SSLSessionID &other) const { > + if (len != other.len) > + return len < other.len; > + > + return (memcmp(bytes, other.bytes, len) < 0); > + } > + > + SSLSessionID& operator=(const SSLSessionID& other) { > + if (other.len) > + memcpy(bytes, other.bytes, other.len); > + > + len = other.len; > + return *this; > + } > + > + bool operator==(const SSLSessionID &other) const { > + if (len != other.len) > + return false; > + > + // memcmp returns 0 on equal > + return (memcmp(bytes, other.bytes, len) == 0); > + } > + > + const char *toString(char *buf, size_t buflen) const { > + char *cur_pos = buf; > + for (size_t i = 0; i < len && buflen > 0; ++i) { > + if (buflen > 2) { // we have enough space for 3 bytes, 2 hex and 1 > null terminator > + snprintf(cur_pos, 3 /* including a null terminator */, "%02hhX", > static_cast<unsigned char>(bytes[i])); > + cur_pos += 2; > + buflen -= 2; > + } else { // not enough space for any more hex bytes, just null > terminate > + *cur_pos = '\0'; > + break; > + } > + } > + return buf; > + } > + > + uint64_t hash() const { > + // because the session ids should be uniformly random let's just use the > upper 64 bits as the hash. > + if (len >= sizeof(uint64_t)) > + return *reinterpret_cast<uint64_t *>(const_cast<char *>(bytes)); > + else if (len) > + return static_cast<uint64_t>(bytes[0]); > + else > + return 0; > + } > + > +}; > + > +class SSLSession { > +public: > + SSLSessionID session_id; > + const char *sni_name; > + Ptr<IOBufferData> asn1_data; /* this is the ASN1 representation of the > SSL_CTX */ > + size_t len_asn1_data; > + > + SSLSession(const SSLSessionID &id, const char *name, Ptr<IOBufferData> > ssl_asn1_data, size_t len_asn1) > + : session_id(id), sni_name(name), asn1_data(ssl_asn1_data), > len_asn1_data(len_asn1) > + { } > + > + LINK(SSLSession, link); > +}; > + > +class SSLSessionBucket { > +public: > + SSLSessionBucket(); > + ~SSLSessionBucket(); > + void removeOldestSession(); > + void insertSession(const SSLSessionID &, const char *sni_name, SSL_SESSION > *ctx); > + bool getSession(const SSLSessionID &, const char *sni_name, SSL_SESSION > **ctx); > + void removeSession(const SSLSessionID &); > + > +private: > + /* these method must be used while hold the lock */ > + void print(const char *) const; > + > + mutable ink_mutex mutex; > + CountQueue<SSLSession> queue; > + SSLSession *root; > +}; > + > +class SSLSessionCache { > +public: > + bool getSession(const SSLSessionID &sid, const char *sni_name, > SSL_SESSION **sess); > + void insertSession(const SSLSessionID &sid, const char *sni_name, > SSL_SESSION *sess); > + void removeSession(const SSLSessionID &sid); > + SSLSessionCache(); > + ~SSLSessionCache(); > + > + private: > + SSLSessionBucket *session_bucket; > +}; > + > +#endif > + > + > > http://git-wip-us.apache.org/repos/asf/trafficserver/blob/53bf5d1e/iocore/net/SSLUtils.cc > ---------------------------------------------------------------------- > diff --git a/iocore/net/SSLUtils.cc b/iocore/net/SSLUtils.cc > index 3bf90d7..7fede11 100644 > --- a/iocore/net/SSLUtils.cc > +++ b/iocore/net/SSLUtils.cc > @@ -26,6 +26,7 @@ > #include "P_Net.h" > #include "ink_cap.h" > #include "P_OCSPStapling.h" > +#include "SSLSessionCache.h" > > #include <string> > #include <openssl/err.h> > @@ -106,6 +107,7 @@ struct ssl_user_config > > #define HAVE_OPENSSL_SESSION_TICKETS 1 > > +SSLSessionCache *session_cache; // declared extern in P_SSLConfig.h > static void session_ticket_free(void *, void *, CRYPTO_EX_DATA *, int, long, > void *); > static int ssl_callback_session_ticket(SSL *, unsigned char *, unsigned char > *, EVP_CIPHER_CTX *, HMAC_CTX *, int); > #endif /* SSL_CTX_set_tlsext_ticket_key_cb */ > @@ -176,6 +178,61 @@ SSL_CTX_add_extra_chain_cert_file(SSL_CTX * ctx, const > char * chainfile) > return true; > } > > + > +static SSL_SESSION* ssl_get_cached_session(SSL *ssl, unsigned char *id, int > len, int *copy) { > + const char *servername = SSL_get_servername(ssl, > TLSEXT_NAMETYPE_host_name); > + *copy = 0; > + > + SSLSessionID sid(id, len); > + if (diags->tag_activated("ssl.session_cache")) { > + char printable_buf[(len * 2) + 1]; > + sid.toString(printable_buf, sizeof(printable_buf)); > + Debug("ssl.session_cache.get", "ssl_get_cached_session cached session > '%s' on name '%s'", printable_buf, servername); > + } > + > + SSL_SESSION *session = NULL; > + if(session_cache->getSession(sid, servername, &session)) > + return session; > + else > + return NULL; > + > +} > + > +static int ssl_new_cached_session(SSL *ssl, SSL_SESSION *sess) { > + unsigned int len = 0; > + const unsigned char *id = SSL_SESSION_get_id(sess, &len); > + const char *servername = SSL_get_servername(ssl, > TLSEXT_NAMETYPE_host_name); > + > + SSLSessionID sid(id, len); > + if (diags->tag_activated("ssl.session_cache")) { > + char printable_buf[(len * 2) + 1]; > + sid.toString(printable_buf, sizeof(printable_buf)); > + Debug("ssl.session_cache.insert", "ssl_new_cached_session session '%s' > on name '%s'", printable_buf, servername); > + } > + > + session_cache->insertSession(sid, servername, sess); > + > + return 0; > +} > + > +static void ssl_rm_cached_session(SSL_CTX *ctx, SSL_SESSION *sess) { > + SSL_CTX_remove_session(ctx, sess); > + > + unsigned int len = 0; > + const unsigned char *id = SSL_SESSION_get_id(sess, &len); > + > + SSLSessionID sid(id, len); > + if (diags->tag_activated("ssl.session_cache")) { > + char printable_buf[(len * 2) + 1]; > + sid.toString(printable_buf, sizeof(printable_buf)); > + Debug("ssl.session_cache.remove", "ssl_rm_cached_session cached session > '%s'", printable_buf); > + } > + > + session_cache->removeSession(sid); > +} > + > + > + > #if TS_USE_TLS_SNI > > static int > @@ -691,6 +748,22 @@ SSLInitializeStatistics() > RECD_INT, RECP_PERSISTENT, (int) > ssl_total_tickets_renewed_stat, > RecRawStatSyncCount); > > + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, > "proxy.process.ssl.ssl_session_cache_hit", > + RECD_INT, RECP_PERSISTENT, (int) ssl_session_cache_hit, > + RecRawStatSyncCount); > + > + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, > "proxy.process.ssl.ssl_session_cache_miss", > + RECD_INT, RECP_PERSISTENT, (int) ssl_session_cache_miss, > + RecRawStatSyncCount); > + > + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, > "proxy.process.ssl.ssl_session_cache_eviction", > + RECD_INT, RECP_PERSISTENT, (int) > ssl_session_cache_eviction, > + RecRawStatSyncCount); > + > + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, > "proxy.process.ssl.ssl_session_cache_lock_contention", > + RECD_INT, RECP_PERSISTENT, (int) > ssl_session_cache_lock_contention, > + RecRawStatSyncCount); > + > /* error stats */ > RecRegisterRawStat(ssl_rsb, RECT_PROCESS, > "proxy.process.ssl.ssl_error_want_write", > RECD_INT, RECP_PERSISTENT, (int) ssl_error_want_write, > @@ -993,18 +1066,37 @@ SSLInitServerContext( > // disable selected protocols > SSL_CTX_set_options(ctx, params->ssl_ctx_options); > > + Debug("ssl.session_cache", "ssl context=%p: using session cache options, > enabled=%d, size=%d, num_buckets=%d, skip_on_contention=%d, timeout=%d", > + ctx, params->ssl_session_cache, > params->ssl_session_cache_size, params->ssl_session_cache_num_buckets, > + params->ssl_session_cache_skip_on_contention, > params->ssl_session_cache_timeout); > + > if (params->ssl_session_cache_timeout) { > - SSL_CTX_set_timeout(ctx, params->ssl_session_cache_timeout); > + SSL_CTX_set_timeout(ctx, params->ssl_session_cache_timeout); > } > > switch (params->ssl_session_cache) { > case SSLConfigParams::SSL_SESSION_CACHE_MODE_OFF: > - SSL_CTX_set_session_cache_mode(ctx, > SSL_SESS_CACHE_OFF|SSL_SESS_CACHE_NO_INTERNAL); > + Debug("ssl.session_cache", "disabling SSL session cache"); > + > + SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF | > SSL_SESS_CACHE_NO_INTERNAL); > break; > - case SSLConfigParams::SSL_SESSION_CACHE_MODE_SERVER: > + case SSLConfigParams::SSL_SESSION_CACHE_MODE_SERVER_OPENSSL_IMPL: > + Debug("ssl.session_cache", "enabling SSL session cache with OpenSSL > implementation"); > + > SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER); > SSL_CTX_sess_set_cache_size(ctx, params->ssl_session_cache_size); > break; > + case SSLConfigParams::SSL_SESSION_CACHE_MODE_SERVER_ATS_IMPL: { > + Debug("ssl.session_cache", "enabling SSL session cache with ATS > implementation"); > + /* Add all the OpenSSL callbacks */ > + SSL_CTX_sess_set_new_cb(ctx, ssl_new_cached_session); > + SSL_CTX_sess_set_remove_cb(ctx, ssl_rm_cached_session); > + SSL_CTX_sess_set_get_cb(ctx, ssl_get_cached_session); > + > + SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER | > SSL_SESS_CACHE_NO_INTERNAL); > + > + break; > + } > } > > #ifdef SSL_MODE_RELEASE_BUFFERS > > http://git-wip-us.apache.org/repos/asf/trafficserver/blob/53bf5d1e/lib/ts/ink_mutex.h > ---------------------------------------------------------------------- > diff --git a/lib/ts/ink_mutex.h b/lib/ts/ink_mutex.h > index 326d6bb..1de3e9a 100644 > --- a/lib/ts/ink_mutex.h > +++ b/lib/ts/ink_mutex.h > @@ -127,4 +127,33 @@ private: > ink_mutex& mtx; > }; > > +struct ink_scoped_try_mutex > +{ > + explicit ink_scoped_try_mutex(ink_mutex& m) : mtx(m), has_lock(false) { > + if(ink_mutex_try_acquire(&mtx)) { > + has_lock = true; > + } > + } > + > + void lock() { > + if (!has_lock) > + ink_mutex_acquire(&mtx); > + has_lock = true; > + } > + > + bool hasLock() const { > + return has_lock; > + } > + > + ~ink_scoped_try_mutex() { > + if (has_lock) > + ink_mutex_release(&mtx); > + } > + > +private: > + ink_mutex& mtx; > + bool has_lock; > +}; > + > + > #endif /* _ink_mutex_h_ */ > > http://git-wip-us.apache.org/repos/asf/trafficserver/blob/53bf5d1e/mgmt/RecordsConfig.cc > ---------------------------------------------------------------------- > diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc > index 6455831..f042037 100644 > --- a/mgmt/RecordsConfig.cc > +++ b/mgmt/RecordsConfig.cc > @@ -1286,9 +1286,13 @@ RecordElement RecordsConfig[] = { > , > {RECT_CONFIG, "proxy.config.ssl.client.CA.cert.path", RECD_STRING, > TS_BUILD_SYSCONFDIR, RECU_RESTART_TS, RR_NULL, RECC_NULL, NULL, RECA_NULL} > , > - {RECT_CONFIG, "proxy.config.ssl.session_cache", RECD_INT, "1", > RECU_RESTART_TS, RR_NULL, RECC_NULL, NULL, RECA_NULL} > + {RECT_CONFIG, "proxy.config.ssl.session_cache", RECD_INT, "2", > RECU_RESTART_TS, RR_NULL, RECC_NULL, NULL, RECA_NULL} > , > - {RECT_CONFIG, "proxy.config.ssl.session_cache.size", RECD_INT, "20480", > RECU_RESTART_TS, RR_NULL, RECC_NULL, NULL, RECA_NULL} > + {RECT_CONFIG, "proxy.config.ssl.session_cache.size", RECD_INT, "102400", > RECU_RESTART_TS, RR_NULL, RECC_NULL, NULL, RECA_NULL} > + , > + {RECT_CONFIG, "proxy.config.ssl.session_cache.num_buckets", RECD_INT, > "256", RECU_RESTART_TS, RR_NULL, RECC_NULL, NULL, RECA_NULL} > + , > + {RECT_CONFIG, > "proxy.config.ssl.session_cache.skip_cache_on_bucket_contention", RECD_INT, > "0", RECU_RESTART_TS, RR_NULL, RECC_NULL, NULL, RECA_NULL} > , > {RECT_CONFIG, "proxy.config.ssl.max_record_size", RECD_INT, "0", > RECU_DYNAMIC, RR_NULL, RECC_NULL, NULL, RECA_NULL} > , > > http://git-wip-us.apache.org/repos/asf/trafficserver/blob/53bf5d1e/proxy/Makefile.am > ---------------------------------------------------------------------- > diff --git a/proxy/Makefile.am b/proxy/Makefile.am > index dc5c2a3..6a659b1 100644 > --- a/proxy/Makefile.am > +++ b/proxy/Makefile.am > @@ -213,11 +213,11 @@ traffic_server_LDADD = \ > $(top_builddir)/iocore/cluster/libinkcluster.a \ > $(top_builddir)/iocore/cache/libinkcache.a \ > $(top_builddir)/iocore/aio/libinkaio.a \ > + $(top_builddir)/lib/ts/libtsutil.la \ > $(top_builddir)/iocore/net/libinknet.a \ > $(top_builddir)/iocore/eventsystem/libinkevent.a \ > $(top_builddir)/lib/records/librecords_p.a \ > $(top_builddir)/iocore/eventsystem/libinkevent.a \ > - $(top_builddir)/lib/ts/libtsutil.la \ > @HWLOC_LIBS@ \ > @LIBPCRE@ \ > @OPENSSL_LIBS@ \ >