32 using std::shared_ptr;
36 const uint32_t NUM_CACHE_BUCKETS = 16;
40 const int MIN_SESSION_ID_LENGTH = 16;
44 DEFINE_bool(dcache_unit_test,
false,
"All VIPs share one session cache");
57 : sessionCache(maxCacheSize, cacheCullSize) {
60 this, std::placeholders::_1,
61 std::placeholders::_2));
65 SSL_SESSION* session) {
66 VLOG(4) <<
"Free SSL session from local cache; id=" 68 SSL_SESSION_free(session);
78 maxCacheSize = (
uint32_t)(((
double)maxCacheSize) / n_buckets);
79 cacheCullSize = (
uint32_t)(((
double)cacheCullSize) / n_buckets);
80 if (maxCacheSize == 0) {
83 if (cacheCullSize == 0) {
87 caches_.push_back(std::unique_ptr<LocalSSLSessionCache>(
94 size_t bucket = hash(sessionId);
95 SSL_SESSION* session =
nullptr;
96 std::lock_guard<std::mutex>
g(caches_[bucket]->
lock);
98 auto itr = caches_[bucket]->sessionCache.find(sessionId);
100 session = itr->second;
104 SSL_SESSION_up_ref(session);
111 SSL_SESSION* session,
113 size_t bucket = hash(sessionId);
114 SSL_SESSION* oldSession =
nullptr;
115 std::lock_guard<std::mutex>
g(caches_[bucket]->
lock);
117 auto itr = caches_[bucket]->sessionCache.find(sessionId);
119 oldSession = itr->second;
125 SSL_SESSION_free(oldSession);
127 caches_[bucket]->removedSessions_ = 0;
128 caches_[bucket]->sessionCache.set(sessionId, session,
true);
135 size_t bucket = hash(sessionId);
136 std::lock_guard<std::mutex>
g(caches_[bucket]->
lock);
137 caches_[bucket]->sessionCache.erase(sessionId);
148 const std::shared_ptr<SSLCacheProvider>& externalCache):
151 externalCache_(externalCache) {
160 SSL_CTX_sess_set_remove_cb(sslCtx,
162 if (!FLAGS_dcache_unit_test && !context.empty()) {
167 SSL_CTX_set_session_cache_mode(sslCtx, SSL_SESS_CACHE_NO_INTERNAL
168 | SSL_SESS_CACHE_SERVER);
197 SSL_CTX* ctx = SSL_get_SSL_CTX(ssl);
200 if (manager ==
nullptr) {
201 LOG(
FATAL) <<
"Null SSLSessionCacheManager in callback";
208 unsigned int sessIdLen = 0;
209 const unsigned char* sessId = SSL_SESSION_get_id(session, &sessIdLen);
210 string sessionId((
char*) sessId, sessIdLen);
220 VLOG(4) <<
"New SSL session: send session to external cache; id=" <<
229 SSL_SESSION* session) {
233 if (manager ==
nullptr) {
234 LOG(
FATAL) <<
"Null SSLSessionCacheManager in callback";
240 SSL_SESSION* session) {
241 unsigned int sessIdLen = 0;
242 const unsigned char* sessId = SSL_SESSION_get_id(session, &sessIdLen);
243 string sessionId((
char*) sessId, sessIdLen);
263 SSL_CTX* ctx = SSL_get_SSL_CTX(ssl);
266 if (manager ==
nullptr) {
267 LOG(
FATAL) <<
"Null SSLSessionCacheManager in callback";
269 return manager->
getSession(ssl, (
unsigned char*)sess_id, id_len, copyflag);
274 unsigned char* session_id,
277 VLOG(7) <<
"SSL get session callback";
279 bool foreign =
false;
282 if (id_len < MIN_SESSION_ID_LENGTH) {
287 string sessionId((
char*)session_id, id_len);
291 assert(sslSocket !=
nullptr);
294 session.reset(
localCache_->lookupSession(sessionId));
295 #ifdef SSL_SESSION_CB_WOULD_BLOCK 299 if (!SSL_want_sess_cache_lookup(ssl)) {
300 missReason =
"reason: No async cache support;";
306 VLOG(4) <<
"Get SSL session [Pending]: Initiate Fetch; fd=" <<
310 *copyflag = SSL_SESSION_CB_WOULD_BLOCK;
313 missReason =
"reason: failed to send lookup request;";
318 if (pit->second.request_in_progress) {
320 VLOG(4) <<
"Get SSL session [Pending]: Request in progess: attach; " 321 "fd=" << sslSocket->
getFd() <<
" id=" <<
323 std::unique_ptr<DelayedDestruction::DestructorGuard> dg(
324 new DelayedDestruction::DestructorGuard(sslSocket));
325 pit->second.waiters.emplace_back(sslSocket,
std::move(dg));
326 *copyflag = SSL_SESSION_CB_WOULD_BLOCK;
331 pit->second.session);
333 SSL_SESSION_up_ref(session.get());
338 #elif FOLLY_OPENSSL_IS_110 345 }
catch (
const std::exception& e) {
346 missReason = folly::to<std::string>(
"reason: ", e.what(),
";");
351 SSL_SESSION_up_ref(session.get());
356 bool hit = (session !=
nullptr);
364 VLOG(4) <<
"Get SSL session [" << ((hit) ?
"Hit" :
"Miss")
365 <<
"]: " << ((foreign) ?
"external" :
"local") <<
" cache; " 366 << missReason <<
"fd=" << sslSocket->
getFd()
372 return session.release();
376 SSL_SESSION* session) {
378 uint32_t sessionLen = i2d_SSL_SESSION(session,
nullptr);
379 sessionString.resize(sessionLen);
381 i2d_SSL_SESSION(session, &cp);
384 std::chrono::seconds(expiration));
390 cacheCtx->sessionId = sessionId;
391 cacheCtx->session =
nullptr;
392 cacheCtx->sslSocket = sslSocket;
393 cacheCtx->guard.reset(
394 new DelayedDestruction::DestructorGuard(cacheCtx->sslSocket));
395 cacheCtx->manager =
this;
407 pit->second.request_in_progress =
false;
408 pit->second.session = cacheCtx->
session;
409 VLOG(7) <<
"Restart SSL accept";
411 for (
const auto& attachedLookup: pit->second.waiters) {
413 VLOG(4) <<
"Restart SSL accept (waiters) for fd=" <<
414 attachedLookup.first->getFd();
415 attachedLookup.first->restartSSLAccept();
424 cacheCtx->
session = d2i_SSL_SESSION(
nullptr, &data, length);
442 std::unique_ptr<folly::IOBuf> valueBuf) {
virtual ~SSLSessionCacheManager()
folly::AsyncSSLSocket * sslSocket
static int32_t sExDataIndex_
static SSL_SESSION * getSessionCallback(SSL *ssl, session_callback_arg_session_id_t session_id, int id_len, int *copyflag)
SSLSessionCacheManager(uint32_t maxCacheSize, uint32_t cacheCullSize, folly::SSLContext *ctx, const std::string &context, SSLStats *stats, const std::shared_ptr< SSLCacheProvider > &externalCache)
void restartSSLAccept(const SSLCacheProvider::CacheContext *cacheCtx)
constexpr detail::Map< Move > move
static void removeSessionCallback(SSL_CTX *ctx, SSL_SESSION *session)
void onGetFailure(SSLCacheProvider::CacheContext *cacheCtx)
const uint8_t * data() const
void pruneSessionCallback(const std::string &sessionId, SSL_SESSION *session)
int newSession(SSL *ssl, SSL_SESSION *session)
uint32_t removedSessions_
static std::shared_ptr< ShardedLocalSSLSessionCache > getLocalCache(uint32_t maxCacheSize, uint32_t cacheCullSize)
void setSessionIDResumed(bool resumed)
bool storeCacheRecord(const std::string &sessionId, SSL_SESSION *session)
ShardedLocalSSLSessionCache(uint32_t n_buckets, uint32_t maxCacheSize, uint32_t cacheCullSize)
static void getSSLCtxExIndex(int *pindex)
std::shared_ptr< FizzServerContext > ctx_
void removeSession(SSL_CTX *ctx, SSL_SESSION *session)
unsigned char * session_callback_arg_session_id_t
void onGetSuccess(SSLCacheProvider::CacheContext *cacheCtx, const std::string &value)
virtual void recordSSLSession(bool sessionNew, bool sessionHit, bool foreign) noexcept=0
LocalSSLSessionCache(uint32_t maxCacheSize, uint32_t cacheCullSize)
SSL_CTX * getSSLCtx() const
static std::shared_ptr< ShardedLocalSSLSessionCache > sCache_
SSL_SESSION * getSession(SSL *ssl, unsigned char *session_id, int id_len, int *copyflag)
std::size_t length() const
PendingLookupMap pendingLookups_
virtual int getFd() const
SSL_SESSION * lookupSession(const std::string &sessionId)
void storeSession(const std::string &sessionId, SSL_SESSION *session, SSLStats *stats)
virtual void recordSSLSessionRemove() noexcept=0
static std::mutex sCacheLock_
static const char *const value
void removeSession(const std::string &sessionId)
DEFINE_bool(dcache_unit_test, false,"All VIPs share one session cache")
static int newSessionCallback(SSL *ssl, SSL_SESSION *session)
std::shared_ptr< ShardedLocalSSLSessionCache > localCache_
void setSessionCacheContext(const std::string &context)
int bind(NetworkSocket s, const sockaddr *name, socklen_t namelen)
static std::string hexlify(const std::string &binary)
std::unique_ptr< SSL_SESSION, SSLSessionDeleter > SSLSessionUniquePtr
void restoreSession(SSLCacheProvider::CacheContext *cacheCtx, const uint8_t *data, size_t length)
std::shared_ptr< SSLCacheProvider > externalCache_
SSLSessionCacheMap sessionCache
virtual void recordSSLSessionFree(uint32_t freed) noexcept=0
bool lookupCacheRecord(const std::string &sessionId, folly::AsyncSSLSocket *sslSock)
static constexpr uint64_t data[1]
static AsyncSSLSocket * getFromSSL(const SSL *ssl)
void setPruneHook(PruneHookCall pruneHook)