1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * _ __ ___ ___ __| | ___ ___| | mod_ssl
19 * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
20 * | | | | | | (_) | (_| | \__ \__ \ |
21 * |_| |_| |_|\___/ \__,_|___|___/___/_|
24 * Session Cache via Shared Memory (Hash Table Variant)
30 * Wrapper functions for table library which resemble malloc(3) & Co
31 * but use the variants from the MM shared memory library.
34 static void *ssl_scache_shmht_malloc(void *opt_param, size_t size)
36 SSLModConfigRec *mc = myModConfig((server_rec *)opt_param);
38 apr_rmm_off_t off = apr_rmm_calloc(mc->pSessionCacheDataRMM, size);
39 return apr_rmm_addr_get(mc->pSessionCacheDataRMM, off);
42 static void *ssl_scache_shmht_calloc(void *opt_param,
43 size_t number, size_t size)
45 SSLModConfigRec *mc = myModConfig((server_rec *)opt_param);
47 apr_rmm_off_t off = apr_rmm_calloc(mc->pSessionCacheDataRMM, (number*size));
49 return apr_rmm_addr_get(mc->pSessionCacheDataRMM, off);
52 static void *ssl_scache_shmht_realloc(void *opt_param, void *ptr, size_t size)
54 SSLModConfigRec *mc = myModConfig((server_rec *)opt_param);
56 apr_rmm_off_t off = apr_rmm_realloc(mc->pSessionCacheDataRMM, ptr, size);
57 return apr_rmm_addr_get(mc->pSessionCacheDataRMM, off);
60 static void ssl_scache_shmht_free(void *opt_param, void *ptr)
62 SSLModConfigRec *mc = myModConfig((server_rec *)opt_param);
64 apr_rmm_off_t off = apr_rmm_offset_get(mc->pSessionCacheDataRMM, ptr);
65 apr_rmm_free(mc->pSessionCacheDataRMM, off);
70 * Now the actual session cache implementation
71 * based on a hash table inside a shared memory segment.
74 void ssl_scache_shmht_init(server_rec *s, apr_pool_t *p)
76 SSLModConfigRec *mc = myModConfig(s);
84 * Create shared memory segment
86 if (mc->szSessionCacheDataFile == NULL) {
87 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
88 "SSLSessionCache required");
92 if ((rv = apr_shm_create(&(mc->pSessionCacheDataMM),
93 mc->nSessionCacheDataSize,
94 mc->szSessionCacheDataFile, mc->pPool)) != APR_SUCCESS) {
95 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
96 "Cannot allocate shared memory");
100 if ((rv = apr_rmm_init(&(mc->pSessionCacheDataRMM), NULL,
101 apr_shm_baseaddr_get(mc->pSessionCacheDataMM),
102 mc->nSessionCacheDataSize, mc->pPool)) != APR_SUCCESS) {
103 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
104 "Cannot initialize rmm");
107 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
108 "initialize MM %pp RMM %pp",
109 mc->pSessionCacheDataMM, mc->pSessionCacheDataRMM);
112 * Create hash table in shared memory segment
114 avail = mc->nSessionCacheDataSize;
115 n = (avail/2) / 1024;
119 * Passing server_rec as opt_param to table_alloc so that we can do
120 * logging if required ssl_util_table. Otherwise, mc is sufficient.
122 if ((ta = table_alloc(n, &ta_errno,
123 ssl_scache_shmht_malloc,
124 ssl_scache_shmht_calloc,
125 ssl_scache_shmht_realloc,
126 ssl_scache_shmht_free, s )) == NULL) {
127 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
128 "Cannot allocate hash table in shared memory: %s",
129 table_strerror(ta_errno));
133 table_attr(ta, TABLE_FLAG_AUTO_ADJUST|TABLE_FLAG_ADJUST_DOWN);
134 table_set_data_alignment(ta, sizeof(char *));
136 mc->tSessionCacheDataTable = ta;
141 ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
142 "Init: Created hash-table (%d buckets) "
143 "in shared memory (%" APR_SIZE_T_FMT
144 " bytes) for SSL session cache",
149 void ssl_scache_shmht_kill(server_rec *s)
151 SSLModConfigRec *mc = myModConfig(s);
153 if (mc->pSessionCacheDataRMM != NULL) {
154 apr_rmm_destroy(mc->pSessionCacheDataRMM);
155 mc->pSessionCacheDataRMM = NULL;
158 if (mc->pSessionCacheDataMM != NULL) {
159 apr_shm_destroy(mc->pSessionCacheDataMM);
160 mc->pSessionCacheDataMM = NULL;
165 BOOL ssl_scache_shmht_store(server_rec *s, UCHAR *id, int idlen, time_t expiry, SSL_SESSION *sess)
167 SSLModConfigRec *mc = myModConfig(s);
169 UCHAR ucaData[SSL_SESSION_MAX_DER];
173 /* streamline session data */
174 if ((nData = i2d_SSL_SESSION(sess, NULL)) > sizeof(ucaData))
177 i2d_SSL_SESSION(sess, &ucp);
180 if (table_insert_kd(mc->tSessionCacheDataTable,
181 id, idlen, NULL, sizeof(time_t)+nData,
182 NULL, &vp, 1) != TABLE_ERROR_NONE) {
186 memcpy(vp, &expiry, sizeof(time_t));
187 memcpy((char *)vp+sizeof(time_t), ucaData, nData);
190 /* allow the regular expiring to occur */
191 ssl_scache_shmht_expire(s);
196 SSL_SESSION *ssl_scache_shmht_retrieve(server_rec *s, UCHAR *id, int idlen)
198 SSLModConfigRec *mc = myModConfig(s);
200 SSL_SESSION *sess = NULL;
201 MODSSL_D2I_SSL_SESSION_CONST UCHAR *ucpData;
207 /* allow the regular expiring to occur */
208 ssl_scache_shmht_expire(s);
210 /* lookup key in table */
212 if (table_retrieve(mc->tSessionCacheDataTable,
213 id, idlen, &vp, &n) != TABLE_ERROR_NONE) {
218 /* copy over the information to the SCI */
219 nData = n-sizeof(time_t);
220 ucpData = (UCHAR *)malloc(nData);
221 if (ucpData == NULL) {
225 memcpy(&expiry, vp, sizeof(time_t));
226 memcpy((void *)ucpData, (char *)vp+sizeof(time_t), nData);
229 /* make sure the stuff is still not expired */
232 ssl_scache_shmht_remove(s, id, idlen);
236 /* unstreamed SSL_SESSION */
237 sess = d2i_SSL_SESSION(NULL, &ucpData, nData);
242 void ssl_scache_shmht_remove(server_rec *s, UCHAR *id, int idlen)
244 SSLModConfigRec *mc = myModConfig(s);
246 /* remove value under key in table */
248 table_delete(mc->tSessionCacheDataTable, id, idlen, NULL, NULL);
253 void ssl_scache_shmht_expire(server_rec *s)
255 SSLModConfigRec *mc = myModConfig(s);
256 SSLSrvConfigRec *sc = mySrvConfig(s);
257 static time_t tLast = 0;
258 table_linear_t iterator;
273 * make sure the expiration for still not-accessed session
274 * cache entries is done only from time to time
277 if (tNow < tLast+sc->session_cache_timeout)
282 if (table_first_r(mc->tSessionCacheDataTable, &iterator,
283 &vpKey, &nKey, &vpData, &nData) == TABLE_ERROR_NONE) {
287 if (nData < sizeof(time_t) || vpData == NULL)
290 memcpy(&tExpiresAt, vpData, sizeof(time_t));
292 * XXX : Force the record to be cleaned up. TBD (Madhu)
295 if (tExpiresAt <= tNow)
300 rc = table_next_r(mc->tSessionCacheDataTable, &iterator,
301 &vpKey, &nKey, &vpData, &nData);
303 table_delete(mc->tSessionCacheDataTable,
304 vpKeyThis, nKeyThis, NULL, NULL);
307 } while (rc == TABLE_ERROR_NONE);
308 /* (vpKeyThis != vpKey) && (nKeyThis != nKey) */
311 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
312 "Inter-Process Session Cache (SHMHT) Expiry: "
313 "old: %d, new: %d, removed: %d",
314 nElements, nElements-nDeleted, nDeleted);
318 void ssl_scache_shmht_status(server_rec *s, apr_pool_t *p, void (*func)(char *, void *), void *arg)
320 SSLModConfigRec *mc = myModConfig(s);
332 if (table_first(mc->tSessionCacheDataTable,
333 &vpKey, &nKey, &vpData, &nData) == TABLE_ERROR_NONE) {
335 if (vpKey == NULL || vpData == NULL)
339 } while (table_next(mc->tSessionCacheDataTable,
340 &vpKey, &nKey, &vpData, &nData) == TABLE_ERROR_NONE);
343 if (nSize > 0 && nElem > 0)
344 nAverage = nSize / nElem;
347 func(apr_psprintf(p, "cache type: <b>SHMHT</b>, maximum size: <b>%d</b> bytes<br>", mc->nSessionCacheDataSize), arg);
348 func(apr_psprintf(p, "current sessions: <b>%d</b>, current size: <b>%d</b> bytes<br>", nElem, nSize), arg);
349 func(apr_psprintf(p, "average session size: <b>%d</b> bytes<br>", nAverage), arg);