工具项目

SSLHelper.cpp 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675
  1. /*
  2. * Copyright: JessMA Open Source (ldcsaa@gmail.com)
  3. *
  4. * Author : Bruce Liang
  5. * Website : http://www.jessma.org
  6. * Project : https://github.com/ldcsaa
  7. * Blog : http://www.cnblogs.com/ldcsaa
  8. * Wiki : http://www.oschina.net/p/hp-socket
  9. * QQ Group : 75375912, 44636872
  10. *
  11. * Licensed under the Apache License, Version 2.0 (the "License");
  12. * you may not use this file except in compliance with the License.
  13. * You may obtain a copy of the License at
  14. *
  15. * http://www.apache.org/licenses/LICENSE-2.0
  16. *
  17. * Unless required by applicable law or agreed to in writing, software
  18. * distributed under the License is distributed on an "AS IS" BASIS,
  19. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  20. * See the License for the specific language governing permissions and
  21. * limitations under the License.
  22. */
  23. #include "stdafx.h"
  24. #include "SSLHelper.h"
  25. #include "SocketHelper.h"
  26. #ifdef _SSL_SUPPORT
  27. #include "openssl/ssl.h"
  28. #include "openssl/err.h"
  29. #include "openssl/engine.h"
  30. #include "openssl/x509v3.h"
  31. #include "../Common/Src/WaitFor.h"
  32. #include <atlpath.h>
  33. /*
  34. #if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_1_0
  35. #pragma comment(lib, "libeay32")
  36. #pragma comment(lib, "ssleay32")
  37. #else
  38. #pragma comment(lib, "libssl")
  39. #pragma comment(lib, "libcrypto")
  40. #pragma comment(lib, "crypt32")
  41. #endif
  42. */
  43. #if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_1_0
  44. int CSSLInitializer::sm_iLockNum = 0;
  45. CSimpleRWLock* CSSLInitializer::sm_pcsLocks = nullptr;
  46. #endif
  47. CSSLInitializer CSSLInitializer::sm_instance;
  48. const DWORD CSSLSessionPool::DEFAULT_ITEM_CAPACITY = CItemPool::DEFAULT_ITEM_CAPACITY;
  49. const DWORD CSSLSessionPool::DEFAULT_ITEM_POOL_SIZE = CItemPool::DEFAULT_POOL_SIZE;
  50. const DWORD CSSLSessionPool::DEFAULT_ITEM_POOL_HOLD = CItemPool::DEFAULT_POOL_HOLD;
  51. const DWORD CSSLSessionPool::DEFAULT_SESSION_LOCK_TIME = 10 * 1000;
  52. const DWORD CSSLSessionPool::DEFAULT_SESSION_POOL_SIZE = 150;
  53. const DWORD CSSLSessionPool::DEFAULT_SESSION_POOL_HOLD = 600;
  54. CSSLInitializer::CSSLInitializer()
  55. {
  56. #if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_1_0
  57. sm_iLockNum = CRYPTO_num_locks();
  58. if(sm_iLockNum > 0)
  59. sm_pcsLocks = new CSimpleRWLock[sm_iLockNum];
  60. /*
  61. #ifdef _DEBUG
  62. CRYPTO_malloc_debug_init();
  63. CRYPTO_dbg_set_options(V_CRYPTO_MDEBUG_ALL);
  64. CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
  65. #endif
  66. */
  67. CRYPTO_set_locking_callback (&ssl_lock_callback);
  68. CRYPTO_set_dynlock_create_callback (&ssl_lock_dyn_create_callback);
  69. CRYPTO_set_dynlock_destroy_callback (&ssl_lock_dyn_destroy_callback);
  70. CRYPTO_set_dynlock_lock_callback (&ssl_lock_dyn_callback);
  71. SSL_library_init();
  72. SSL_load_error_strings();
  73. OpenSSL_add_all_algorithms();
  74. #else
  75. OPENSSL_init_ssl(OPENSSL_INIT_SSL_DEFAULT, nullptr);
  76. #endif
  77. }
  78. CSSLInitializer::~CSSLInitializer()
  79. {
  80. CleanupThreadState();
  81. #if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_1_0
  82. CONF_modules_free();
  83. ENGINE_cleanup();
  84. EVP_cleanup();
  85. CRYPTO_cleanup_all_ex_data();
  86. ERR_free_strings();
  87. #if OPENSSL_VERSION_NUMBER >= OPENSSL_VERSION_1_0_2
  88. SSL_COMP_free_compression_methods();
  89. #endif
  90. CRYPTO_set_locking_callback (nullptr);
  91. CRYPTO_set_dynlock_create_callback (nullptr);
  92. CRYPTO_set_dynlock_destroy_callback (nullptr);
  93. CRYPTO_set_dynlock_lock_callback (nullptr);
  94. if(sm_iLockNum > 0)
  95. {
  96. delete[] sm_pcsLocks;
  97. sm_pcsLocks = nullptr;
  98. sm_iLockNum = 0;
  99. }
  100. #endif
  101. }
  102. void CSSLInitializer::CleanupThreadState(DWORD dwThreadID)
  103. {
  104. #if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_1_0
  105. CRYPTO_THREADID tid = {nullptr, dwThreadID};
  106. CRYPTO_THREADID_current(&tid);
  107. ERR_remove_thread_state(&tid);
  108. #else
  109. OPENSSL_thread_stop();
  110. #endif
  111. }
  112. #if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_1_0
  113. void CSSLInitializer::ssl_lock_callback(int mode, int n, const char *file, int line)
  114. {
  115. mode & CRYPTO_LOCK
  116. ? (mode & CRYPTO_READ
  117. ? sm_pcsLocks[n].WaitToRead()
  118. : sm_pcsLocks[n].WaitToWrite())
  119. : (mode & CRYPTO_READ
  120. ? sm_pcsLocks[n].ReadDone()
  121. : sm_pcsLocks[n].WriteDone());
  122. }
  123. CRYPTO_dynlock_value* CSSLInitializer::ssl_lock_dyn_create_callback(const char *file, int line)
  124. {
  125. return new DynamicLock;
  126. }
  127. void CSSLInitializer::ssl_lock_dyn_callback(int mode, CRYPTO_dynlock_value* l, const char *file, int line)
  128. {
  129. mode & CRYPTO_LOCK
  130. ? (mode & CRYPTO_READ
  131. ? l->cs.WaitToRead()
  132. : l->cs.WaitToWrite())
  133. : (mode & CRYPTO_READ
  134. ? l->cs.ReadDone()
  135. : l->cs.WriteDone());
  136. }
  137. void CSSLInitializer::ssl_lock_dyn_destroy_callback(CRYPTO_dynlock_value* l, const char *file, int line)
  138. {
  139. delete l;
  140. }
  141. #endif
  142. BOOL CSSLContext::Initialize(EnSSLSessionMode enSessionMode, int iVerifyMode, LPCTSTR lpszPemCertFile, LPCTSTR lpszPemKeyFile, LPCTSTR lpszKeyPasswod, LPCTSTR lpszCAPemCertFileOrPath, HP_Fn_SNI_ServerNameCallback fnServerNameCallback)
  143. {
  144. ASSERT(!IsValid());
  145. if(IsValid())
  146. {
  147. ::SetLastError(ERROR_INVALID_STATE);
  148. return FALSE;
  149. }
  150. m_enSessionMode = enSessionMode;
  151. if(AddContext(iVerifyMode, lpszPemCertFile, lpszPemKeyFile, lpszKeyPasswod, lpszCAPemCertFileOrPath) == 0)
  152. m_sslCtx = GetContext(0);
  153. else
  154. {
  155. Cleanup();
  156. return FALSE;
  157. }
  158. SetServerNameCallback(fnServerNameCallback);
  159. return TRUE;
  160. }
  161. int CSSLContext::AddServerContext(int iVerifyMode, LPCTSTR lpszPemCertFile, LPCTSTR lpszPemKeyFile, LPCTSTR lpszKeyPasswod, LPCTSTR lpszCAPemCertFileOrPath)
  162. {
  163. ASSERT(IsValid());
  164. if(!IsValid())
  165. {
  166. ::SetLastError(ERROR_INVALID_STATE);
  167. return FALSE;
  168. }
  169. if(m_enSessionMode != SSL_SM_SERVER)
  170. {
  171. ::SetLastError(ERROR_INVALID_OPERATION);
  172. return FALSE;
  173. }
  174. return AddContext(iVerifyMode, lpszPemCertFile, lpszPemKeyFile, lpszKeyPasswod, lpszCAPemCertFileOrPath);
  175. }
  176. int CSSLContext::AddContext(int iVerifyMode, LPCTSTR lpszPemCertFile, LPCTSTR lpszPemKeyFile, LPCTSTR lpszKeyPasswod, LPCTSTR lpszCAPemCertFileOrPath)
  177. {
  178. int iIndex = -1;
  179. SSL_CTX* sslCtx = SSL_CTX_new(SSLv23_method());
  180. SSL_CTX_set_quiet_shutdown(sslCtx, 1);
  181. SSL_CTX_set_verify(sslCtx, iVerifyMode, nullptr);
  182. SSL_CTX_set_cipher_list(sslCtx, "ALL:!aNULL:!eNULL");
  183. if(m_enSessionMode == SSL_SM_SERVER)
  184. {
  185. static volatile ULONG s_session_id_context = 0;
  186. ULONG session_id_context = ::InterlockedIncrement(&s_session_id_context);
  187. SSL_CTX_set_session_id_context(sslCtx, (BYTE*)&session_id_context, sizeof(session_id_context));
  188. }
  189. if(!LoadCertAndKey(sslCtx, iVerifyMode, lpszPemCertFile, lpszPemKeyFile, lpszKeyPasswod, lpszCAPemCertFileOrPath))
  190. SSL_CTX_free(sslCtx);
  191. else
  192. {
  193. iIndex = (int)m_lsSslCtxs.size();
  194. m_lsSslCtxs.push_back(sslCtx);
  195. }
  196. return iIndex;
  197. }
  198. BOOL CSSLContext::LoadCertAndKey(SSL_CTX* sslCtx, int iVerifyMode, LPCTSTR lpszPemCertFile, LPCTSTR lpszPemKeyFile, LPCTSTR lpszKeyPasswod, LPCTSTR lpszCAPemCertFileOrPath)
  199. {
  200. USES_CONVERSION;
  201. if(lpszCAPemCertFileOrPath != nullptr)
  202. {
  203. LPCTSTR lpszCAPemCertFile = nullptr;
  204. LPCTSTR lpszCAPemCertPath = nullptr;
  205. if(!ATLPath::FileExists(lpszCAPemCertFileOrPath))
  206. {
  207. ::SetLastError(ERROR_FILE_NOT_FOUND);
  208. return FALSE;
  209. }
  210. if(!ATLPath::IsDirectory(lpszCAPemCertFileOrPath))
  211. lpszCAPemCertFile = lpszCAPemCertFileOrPath;
  212. else
  213. lpszCAPemCertPath = lpszCAPemCertFileOrPath;
  214. if(!SSL_CTX_load_verify_locations(sslCtx, T2CA(lpszCAPemCertFile), T2CA(lpszCAPemCertPath)))
  215. {
  216. ::SetLastError(ERROR_INVALID_DATA);
  217. return FALSE;
  218. }
  219. if(!SSL_CTX_set_default_verify_paths(sslCtx))
  220. {
  221. ::SetLastError(ERROR_FUNCTION_FAILED);
  222. return FALSE;
  223. }
  224. if(m_enSessionMode == SSL_SM_SERVER && iVerifyMode & SSL_VM_PEER)
  225. {
  226. STACK_OF(X509_NAME)* caCertNames = SSL_load_client_CA_file(T2CA(lpszCAPemCertFileOrPath));
  227. if(caCertNames == nullptr)
  228. {
  229. ::SetLastError(ERROR_EMPTY);
  230. return FALSE;
  231. }
  232. SSL_CTX_set_client_CA_list(sslCtx, caCertNames);
  233. }
  234. }
  235. if(lpszPemCertFile != nullptr)
  236. {
  237. if( !ATLPath::FileExists(lpszPemCertFile) ||
  238. ATLPath::IsDirectory(lpszPemCertFile) )
  239. {
  240. ::SetLastError(ERROR_FILE_NOT_FOUND);
  241. return FALSE;
  242. }
  243. if( lpszPemKeyFile == nullptr ||
  244. !ATLPath::FileExists(lpszPemKeyFile) ||
  245. ATLPath::IsDirectory(lpszPemKeyFile) )
  246. {
  247. ::SetLastError(ERROR_FILE_NOT_FOUND);
  248. return FALSE;
  249. }
  250. if(lpszKeyPasswod != nullptr)
  251. SSL_CTX_set_default_passwd_cb_userdata(sslCtx, (void*)T2CA(lpszKeyPasswod));
  252. if(!SSL_CTX_use_PrivateKey_file(sslCtx, T2CA(lpszPemKeyFile), SSL_FILETYPE_PEM))
  253. {
  254. ::SetLastError(ERROR_INVALID_PASSWORD);
  255. return FALSE;
  256. }
  257. if(!SSL_CTX_use_certificate_chain_file(sslCtx, T2CA(lpszPemCertFile)))
  258. {
  259. ::SetLastError(ERROR_INVALID_DATA);
  260. return FALSE;
  261. }
  262. if(!SSL_CTX_check_private_key(sslCtx))
  263. {
  264. ::SetLastError(ERROR_INVALID_ACCESS);
  265. return FALSE;
  266. }
  267. }
  268. return TRUE;
  269. }
  270. void CSSLContext::Cleanup()
  271. {
  272. if(IsValid())
  273. {
  274. int iCount = (int)m_lsSslCtxs.size();
  275. for(int i = 0; i < iCount; i++)
  276. SSL_CTX_free(m_lsSslCtxs[i]);
  277. m_lsSslCtxs.clear();
  278. m_sslCtx = nullptr;
  279. }
  280. m_fnServerNameCallback = nullptr;
  281. RemoveThreadLocalState();
  282. }
  283. void CSSLContext::SetServerNameCallback(Fn_SNI_ServerNameCallback fn)
  284. {
  285. if(m_enSessionMode != SSL_SM_SERVER)
  286. return;
  287. m_fnServerNameCallback = fn;
  288. if(m_fnServerNameCallback == nullptr)
  289. return;
  290. VERIFY(SSL_CTX_set_tlsext_servername_callback(m_sslCtx, InternalServerNameCallback));
  291. VERIFY(SSL_CTX_set_tlsext_servername_arg(m_sslCtx, this));
  292. }
  293. int CALLBACK CSSLContext::InternalServerNameCallback(SSL* ssl, int* ad, void* arg)
  294. {
  295. USES_CONVERSION;
  296. CSSLContext* pThis = (CSSLContext*)arg;
  297. ASSERT(pThis->m_fnServerNameCallback != nullptr);
  298. const char* lpszServerName = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
  299. if(lpszServerName == nullptr)
  300. return SSL_TLSEXT_ERR_NOACK;
  301. int iIndex = pThis->m_fnServerNameCallback(A2CT(lpszServerName));
  302. if(iIndex == 0)
  303. return SSL_TLSEXT_ERR_OK;
  304. if(iIndex < 0)
  305. {
  306. ::SetLastError(ERROR_INVALID_NAME);
  307. return SSL_TLSEXT_ERR_ALERT_FATAL;
  308. }
  309. SSL_CTX* sslCtx = pThis->GetContext(iIndex);
  310. if(sslCtx == nullptr)
  311. {
  312. ::SetLastError(ERROR_INVALID_INDEX);
  313. return SSL_TLSEXT_ERR_ALERT_FATAL;
  314. }
  315. SSL_set_SSL_CTX(ssl, sslCtx);
  316. return SSL_TLSEXT_ERR_OK;
  317. }
  318. SSL_CTX* CSSLContext::GetContext(int i) const
  319. {
  320. SSL_CTX* sslCtx = nullptr;
  321. if(i >= 0 && i < (int)m_lsSslCtxs.size())
  322. sslCtx = m_lsSslCtxs[i];
  323. return sslCtx;
  324. }
  325. BOOL CSSLSession::WriteRecvChannel(const BYTE* pData, int iLength)
  326. {
  327. ASSERT(pData && iLength > 0);
  328. BOOL isOK = TRUE;
  329. int bytes = BIO_write(m_bioRecv, pData, iLength);
  330. if(bytes > 0)
  331. ASSERT(bytes == iLength);
  332. else if(!BIO_should_retry(m_bioRecv))
  333. isOK = FALSE;
  334. return isOK;
  335. }
  336. BOOL CSSLSession::ReadRecvChannel()
  337. {
  338. BOOL isOK = TRUE;
  339. int bytes = SSL_read(m_ssl, m_bufRecv.buf, m_pitRecv->Capacity());
  340. if(bytes > 0)
  341. m_bufRecv.len = bytes;
  342. else if(!IsFatalError(bytes))
  343. m_bufRecv.len = 0;
  344. else
  345. isOK = FALSE;
  346. if(isOK && m_enStatus == SSL_HSS_PROC && SSL_is_init_finished(m_ssl))
  347. m_enStatus = SSL_HSS_SUCC;
  348. return isOK;
  349. }
  350. BOOL CSSLSession::WriteSendChannel(const BYTE* pData, int iLength)
  351. {
  352. ASSERT(IsReady());
  353. ASSERT(pData && iLength > 0);
  354. BOOL isOK = TRUE;
  355. int bytes = SSL_write(m_ssl, pData, iLength);
  356. if(bytes > 0)
  357. ASSERT(bytes == iLength);
  358. else if(IsFatalError(bytes))
  359. isOK = FALSE;
  360. return isOK;
  361. }
  362. BOOL CSSLSession::WriteSendChannel(const WSABUF pBuffers[], int iCount)
  363. {
  364. ASSERT(pBuffers && iCount > 0);
  365. BOOL isOK = TRUE;
  366. for(int i = 0; i < iCount; i++)
  367. {
  368. const WSABUF& buffer = pBuffers[i];
  369. if(buffer.len > 0)
  370. {
  371. if(!WriteSendChannel((const BYTE*)buffer.buf, buffer.len))
  372. {
  373. isOK = FALSE;
  374. break;
  375. }
  376. }
  377. }
  378. return isOK;
  379. }
  380. BOOL CSSLSession::ReadSendChannel()
  381. {
  382. if(BIO_pending(m_bioSend) == 0)
  383. {
  384. m_bufSend.len = 0;
  385. return TRUE;
  386. }
  387. BOOL isOK = TRUE;
  388. int bytes = BIO_read(m_bioSend, m_bufSend.buf, m_pitSend->Capacity());
  389. if(bytes > 0)
  390. m_bufSend.len = bytes;
  391. else if(BIO_should_retry(m_bioSend))
  392. m_bufSend.len = 0;
  393. else
  394. isOK = FALSE;
  395. return isOK;
  396. }
  397. CSSLSession* CSSLSession::Renew(const CSSLContext& sslCtx, LPCSTR lpszHostName)
  398. {
  399. ASSERT(!IsValid());
  400. m_ssl = SSL_new(sslCtx.GetDefaultContext());
  401. m_bioSend = BIO_new(BIO_s_mem());
  402. m_bioRecv = BIO_new(BIO_s_mem());
  403. SSL_set_bio(m_ssl, m_bioRecv, m_bioSend);
  404. if(sslCtx.GetSessionMode() == SSL_SM_SERVER)
  405. SSL_accept(m_ssl);
  406. else
  407. {
  408. USES_CONVERSION;
  409. if(lpszHostName && lpszHostName[0] != 0 && !::IsIPAddress(A2CT(lpszHostName)))
  410. SSL_set_tlsext_host_name(m_ssl, lpszHostName);
  411. SSL_connect(m_ssl);
  412. }
  413. m_pitSend = m_itPool.PickFreeItem();
  414. m_pitRecv = m_itPool.PickFreeItem();
  415. m_bufSend.buf = (char*)m_pitSend->Ptr();
  416. m_bufRecv.buf = (char*)m_pitRecv->Ptr();
  417. m_enStatus = SSL_HSS_PROC;
  418. return this;
  419. }
  420. BOOL CSSLSession::Reset()
  421. {
  422. BOOL isOK = FALSE;
  423. if(IsValid())
  424. {
  425. CCriSecLock locallock(m_csSend);
  426. if(IsValid())
  427. {
  428. m_enStatus = SSL_HSS_INIT;
  429. SSL_shutdown(m_ssl);
  430. SSL_free(m_ssl);
  431. m_itPool.PutFreeItem(m_pitSend);
  432. m_itPool.PutFreeItem(m_pitRecv);
  433. m_pitSend = nullptr;
  434. m_pitRecv = nullptr;
  435. m_ssl = nullptr;
  436. m_bioSend = nullptr;
  437. m_bioRecv = nullptr;
  438. m_dwFreeTime= ::TimeGetTime();
  439. isOK = TRUE;
  440. }
  441. }
  442. ERR_clear_error();
  443. return isOK;
  444. }
  445. inline BOOL CSSLSession::IsFatalError(int iBytes)
  446. {
  447. int iErrorCode = SSL_get_error(m_ssl, iBytes);
  448. if( iErrorCode == SSL_ERROR_NONE ||
  449. iErrorCode == SSL_ERROR_WANT_READ ||
  450. iErrorCode == SSL_ERROR_WANT_WRITE ||
  451. iErrorCode == SSL_ERROR_WANT_CONNECT ||
  452. iErrorCode == SSL_ERROR_WANT_ACCEPT )
  453. return FALSE;
  454. #ifdef _DEBUG
  455. char szBuffer[512];
  456. #endif
  457. int i = 0;
  458. int iCode = iErrorCode;
  459. for(; iCode != SSL_ERROR_NONE; i++)
  460. {
  461. #ifdef _DEBUG
  462. ERR_error_string_n(iCode, szBuffer, sizeof(szBuffer));
  463. TRACE(" > SSL Error: %d - %s\n", iCode, szBuffer);
  464. #endif
  465. iCode = ERR_get_error();
  466. }
  467. if(iErrorCode == SSL_ERROR_SYSCALL && i == 1)
  468. {
  469. //ERR_clear_error();
  470. return FALSE;
  471. }
  472. return TRUE;
  473. }
  474. CSSLSession* CSSLSessionPool::PickFreeSession(LPCSTR lpszHostName)
  475. {
  476. DWORD dwIndex;
  477. CSSLSession* pSession = nullptr;
  478. if(m_lsFreeSession.TryLock(&pSession, dwIndex))
  479. {
  480. if(::GetTimeGap32(pSession->GetFreeTime()) >= m_dwSessionLockTime)
  481. VERIFY(m_lsFreeSession.ReleaseLock(nullptr, dwIndex));
  482. else
  483. {
  484. VERIFY(m_lsFreeSession.ReleaseLock(pSession, dwIndex));
  485. pSession = nullptr;
  486. }
  487. }
  488. if(!pSession) pSession = new CSSLSession(m_itPool);
  489. ASSERT(pSession);
  490. return pSession->Renew(m_sslCtx, lpszHostName);
  491. }
  492. void CSSLSessionPool::PutFreeSession(CSSLSession* pSession)
  493. {
  494. if(pSession->Reset())
  495. {
  496. if(!m_lsFreeSession.TryPut(pSession))
  497. {
  498. m_lsGCSession.PushBack(pSession);
  499. if(m_lsGCSession.Size() > m_dwSessionPoolSize)
  500. ReleaseGCSession();
  501. }
  502. }
  503. }
  504. void CSSLSessionPool::ReleaseGCSession(BOOL bForce)
  505. {
  506. CSSLSession* pSession = nullptr;
  507. DWORD now = ::TimeGetTime();
  508. while(m_lsGCSession.PopFront(&pSession))
  509. {
  510. if(bForce || (int)(now - pSession->GetFreeTime()) >= (int)m_dwSessionLockTime)
  511. delete pSession;
  512. else
  513. {
  514. m_lsGCSession.PushBack(pSession);
  515. break;
  516. }
  517. }
  518. }
  519. void CSSLSessionPool::Prepare()
  520. {
  521. m_itPool.Prepare();
  522. m_lsFreeSession.Reset(m_dwSessionPoolHold);
  523. }
  524. void CSSLSessionPool::Clear()
  525. {
  526. CSSLSession* pSession = nullptr;
  527. while(m_lsFreeSession.TryGet(&pSession))
  528. delete pSession;
  529. VERIFY(m_lsFreeSession.IsEmpty());
  530. m_lsFreeSession.Reset();
  531. ReleaseGCSession(TRUE);
  532. VERIFY(m_lsGCSession.IsEmpty());
  533. m_itPool.Clear();
  534. }
  535. #endif