source: mod_gnutls/src/gnutls_cache.c @ 6e0bfd6

debian/masterdebian/stretch-backportsjessie-backportsmsvaupstream
Last change on this file since 6e0bfd6 was 6e0bfd6, checked in by Paul Querna <chip@…>, 14 years ago
  • make memcahe optional
  • update for 2.1.x branch changes.
  • some mucking around with the conf stuff
  • Property mode set to 100644
File size: 7.2 KB
Line 
1/* ====================================================================
2 *  Copyright 2004 Paul Querna
3 *
4 *  Licensed under the Apache License, Version 2.0 (the "License");
5 *  you may not use this file except in compliance with the License.
6 *  You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 *
16 */
17
18#include "mod_gnutls.h"
19
20#if HAVE_APR_MEMCACHE
21#include "apr_memcache.h"
22#endif
23
24#include "ap_mpm.h"
25
26#define GNUTLS_SESSION_ID_STRING_LEN \
27    ((GNUTLS_MAX_SESSION_ID + 1) * 2)
28#define MC_TAG "mod_gnutls:"
29#define MC_TAG_LEN \
30    (sizeof(MC_TAG))
31#define STR_SESSION_LEN (GNUTLS_SESSION_ID_STRING_LEN + MC_TAG_LEN)
32
33static char *gnutls_session_id2sz(unsigned char *id, int idlen,
34                        char *str, int strsize)
35{
36    char *cp;
37    int n;
38 
39    cp = apr_cpystrn(str, MC_TAG, MC_TAG_LEN);
40    for (n = 0; n < idlen && n < GNUTLS_MAX_SESSION_ID; n++) {
41        apr_snprintf(cp, strsize - (cp-str), "%02X", id[n]);
42        cp += 2;
43    }
44    *cp = '\0';
45    return str;
46}
47
48
49#if HAVE_APR_MEMCACHE
50
51/**
52 * GnuTLS Session Cache using libmemcached
53 *
54 */
55
56/* The underlying apr_memcache system is thread safe... woohoo */
57static apr_memcache_t* mc;
58
59int mc_cache_child_init(apr_pool_t *p, server_rec *s, 
60                                mod_gnutls_srvconf_rec *sc)
61{
62    apr_status_t rv = APR_SUCCESS;
63    int thread_limit = 0;
64    int nservers = 0;
65    char* cache_config;
66    char* split;
67    char* tok;
68
69    ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
70
71    /* Find all the servers in the first run to get a total count */
72    cache_config = apr_pstrdup(p, sc->cache_config);
73    split = apr_strtok(cache_config, " ", &tok);
74    while (split) {
75        nservers++;
76        split = apr_strtok(NULL," ", &tok);
77    }
78
79    rv = apr_memcache_create(p, nservers, 0, &mc);
80    if (rv != APR_SUCCESS) {
81        ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
82                        "[gnutls_cache] Failed to create Memcache Object of '%d' size.", 
83                         nservers);
84        return rv;
85    }
86
87    /* Now add each server to the memcache */
88    cache_config = apr_pstrdup(p, sc->cache_config);
89    split = apr_strtok(cache_config, " ", &tok);
90    while (split) {
91        apr_memcache_server_t* st;
92        char* host_str;
93        char* scope_id;
94        apr_port_t port;
95
96        rv = apr_parse_addr_port(&host_str, &scope_id, &port, split, p);
97        if(rv != APR_SUCCESS) {
98            ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
99                         "[gnutls_cache] Failed to Parse Server: '%s'", split);
100            return rv;
101        }
102
103        if(host_str == NULL) {
104            ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
105                         "[gnutls_cache] Failed to Parse Server, "
106                         "no hostname specified: '%s'", split);
107            return rv;
108        }
109
110        if (port == 0) {
111            port = 11211; /* default port */
112        }
113
114        /* Should Max Conns be (thread_limit / nservers) ? */
115        rv = apr_memcache_server_create(p,
116                                        host_str, port,
117                                        0,
118                                        1,
119                                        thread_limit, 
120                                        600,
121                                        &st);
122        if(rv != APR_SUCCESS) {
123            ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
124                         "[gnutls_cache] Failed to Create Server: %s:%d", 
125                         host_str, port);
126            return rv;
127        }
128
129        rv = apr_memcache_add_server(mc, st);
130        if(rv != APR_SUCCESS) {
131            ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
132                         "[gnutls_cache] Failed to Add Server: %s:%d", 
133                         host_str, port);
134            return rv;
135        }
136
137        split = apr_strtok(NULL," ", &tok);
138    }
139    return rv;
140}
141
142static int mc_cache_store(void* baton, gnutls_datum_t key, 
143                          gnutls_datum_t data)
144{
145    apr_status_t rv = APR_SUCCESS;
146    mod_gnutls_handle_t *ctxt = baton;
147    char buf[STR_SESSION_LEN];
148    char* strkey = NULL;
149    apr_uint32_t timeout;
150
151    strkey = gnutls_session_id2sz(key.data, key.size, buf, sizeof(buf));
152    if(!strkey)
153        return -1;
154
155    timeout = 3600;
156
157    rv = apr_memcache_set(mc,  strkey, data.data, data.size, timeout, 0);
158
159    if(rv != APR_SUCCESS) {
160        ap_log_error(APLOG_MARK, APLOG_CRIT, rv,
161                     ctxt->c->base_server,
162                     "[gnutls_cache] error setting key '%s' "
163                     "with %d bytes of data", strkey, data.size);
164        return -1;
165    }
166
167    return 0;
168}
169
170static gnutls_datum_t mc_cache_fetch(void* baton, gnutls_datum_t key)
171{
172    apr_status_t rv = APR_SUCCESS;
173    mod_gnutls_handle_t *ctxt = baton;
174    char buf[STR_SESSION_LEN];
175    char* strkey = NULL;
176    char* value;
177    apr_size_t value_len;
178    gnutls_datum_t data = { NULL, 0 };
179
180    strkey = gnutls_session_id2sz(key.data, key.size, buf, sizeof(buf));
181    if(!strkey) {
182        return data;
183    }
184
185    rv = apr_memcache_getp(mc, ctxt->c->pool, strkey,
186                           &value, &value_len, NULL);
187
188    if(rv != APR_SUCCESS) {
189        ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
190                     ctxt->c->base_server,
191                     "[gnutls_cache] error fetching key '%s' ",
192                     strkey);
193
194        data.size = 0;
195        data.data = NULL;
196        return data;
197    }
198
199    /* TODO: Eliminate this memcpy. gnutls-- */
200    data.data = gnutls_malloc(value_len);
201    if (data.data == NULL)
202        return data;
203
204    data.size = value_len;
205    memcpy(data.data, value, value_len);
206
207    return data;
208}
209
210static int mc_cache_delete(void* baton, gnutls_datum_t key)
211{
212    apr_status_t rv = APR_SUCCESS;
213    mod_gnutls_handle_t *ctxt = baton;
214    char buf[STR_SESSION_LEN];
215    char* strkey = NULL;
216
217    strkey = gnutls_session_id2sz(key.data, key.size, buf, sizeof(buf));
218    if(!strkey)
219        return -1;
220
221    rv = apr_memcache_delete(mc, strkey, 0);
222
223    if(rv != APR_SUCCESS) {
224        ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
225                     ctxt->c->base_server,
226                     "[gnutls_cache] error deleting key '%s' ",
227                      strkey);
228        return -1;
229    }
230
231    return 0;
232}
233
234#endif /* have_apr_memcache */
235
236int mod_gnutls_cache_child_init(apr_pool_t *p, server_rec *s, 
237                                mod_gnutls_srvconf_rec *sc)
238{
239#if HAVE_APR_MEMCACHE
240    return mc_cache_child_init(p, s, sc);
241#else
242    return 0;
243#endif
244}
245
246int mod_gnutls_cache_session_init(mod_gnutls_handle_t *ctxt)
247{
248#if HAVE_APR_MEMCACHE
249    gnutls_db_set_retrieve_function(ctxt->session, mc_cache_fetch);
250    gnutls_db_set_remove_function(ctxt->session, mc_cache_delete);
251    gnutls_db_set_store_function(ctxt->session, mc_cache_store);
252    gnutls_db_set_ptr(ctxt->session, ctxt);
253#else
254    /* TODO: Alternative Cache Backends */
255#endif
256    return 0;
257}
Note: See TracBrowser for help on using the repository browser.