blob: f33b7ca8ed155af4ee970459818812b1471bdf0f [file] [log] [blame]
Emeric Brun3e541d12012-09-03 11:14:36 +02001/*
2 * shctx.c - shared context management functions for SSL
3 *
4 * Copyright (C) 2011-2012 EXCELIANCE
5 *
6 * Author: Emeric Brun - emeric@exceliance.fr
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 */
13
14#include <sys/mman.h>
Emeric Brun9faf0712012-09-25 11:11:16 +020015#ifndef USE_PRIVATE_CACHE
Emeric Bruncd1a5262014-05-07 23:11:42 +020016#ifdef USE_PTHREAD_PSHARED
17#include <pthread.h>
18#else
Emeric Brun3e541d12012-09-03 11:14:36 +020019#ifdef USE_SYSCALL_FUTEX
20#include <unistd.h>
Willy Tarreau18b20592012-09-04 12:26:26 +020021#ifndef u32
22#define u32 unsigned int
23#endif
Emeric Brun3e541d12012-09-03 11:14:36 +020024#include <linux/futex.h>
25#include <sys/syscall.h>
Emeric Bruncd1a5262014-05-07 23:11:42 +020026#endif
27#endif
Emeric Brun9faf0712012-09-25 11:11:16 +020028#endif
Emeric Brunaf9619d2012-11-28 18:47:52 +010029#include <arpa/inet.h>
Emeric Brun3e541d12012-09-03 11:14:36 +020030#include "ebmbtree.h"
31#include "proto/shctx.h"
32
Emeric Brunaf9619d2012-11-28 18:47:52 +010033struct shsess_packet_hdr {
34 unsigned int eol;
35 unsigned char final:1;
36 unsigned char seq:7;
37 unsigned char id[SSL_MAX_SSL_SESSION_ID_LENGTH];
38};
39
40struct shsess_packet {
41 unsigned char version;
42 unsigned char sig[SHA_DIGEST_LENGTH];
43 struct shsess_packet_hdr hdr;
44 unsigned char data[0];
45};
46
Emeric Brun3e541d12012-09-03 11:14:36 +020047struct shared_session {
48 struct ebmb_node key;
49 unsigned char key_data[SSL_MAX_SSL_SESSION_ID_LENGTH];
Emeric Brunaf9619d2012-11-28 18:47:52 +010050 unsigned char data[SHSESS_BLOCK_MIN_SIZE];
Emeric Brun3e541d12012-09-03 11:14:36 +020051};
52
Emeric Brunaf9619d2012-11-28 18:47:52 +010053struct shared_block {
54 union {
55 struct shared_session session;
56 unsigned char data[sizeof(struct shared_session)];
57 } data;
58 short int data_len;
59 struct shared_block *p;
60 struct shared_block *n;
61};
Emeric Brun3e541d12012-09-03 11:14:36 +020062
63struct shared_context {
Emeric Brun9faf0712012-09-25 11:11:16 +020064#ifndef USE_PRIVATE_CACHE
Emeric Bruncd1a5262014-05-07 23:11:42 +020065#ifdef USE_PTHREAD_PSHARED
Emeric Brun3e541d12012-09-03 11:14:36 +020066 pthread_mutex_t mutex;
Emeric Bruncd1a5262014-05-07 23:11:42 +020067#else
68 unsigned int waiters;
Emeric Brun3e541d12012-09-03 11:14:36 +020069#endif
Emeric Brun9faf0712012-09-25 11:11:16 +020070#endif
Emeric Brunaf9619d2012-11-28 18:47:52 +010071 struct shsess_packet_hdr upd;
72 unsigned char data[SHSESS_MAX_DATA_LEN];
73 short int data_len;
74 struct shared_block active;
75 struct shared_block free;
Emeric Brun3e541d12012-09-03 11:14:36 +020076};
77
78/* Static shared context */
79static struct shared_context *shctx = NULL;
80
Emeric Brun3e541d12012-09-03 11:14:36 +020081/* Lock functions */
Emeric Bruncd1a5262014-05-07 23:11:42 +020082
83#if defined (USE_PRIVATE_CACHE)
84
Willy Tarreau338a4fc2012-10-18 15:11:52 +020085#define shared_context_lock()
86#define shared_context_unlock()
Emeric Brun9faf0712012-09-25 11:11:16 +020087
Emeric Bruncd1a5262014-05-07 23:11:42 +020088#elif defined (USE_PTHREAD_PSHARED)
89static int use_shared_mem = 0;
90
91#define shared_context_lock() if (use_shared_mem) pthread_mutex_lock(&shctx->mutex)
92#define shared_context_unlock() if (use_shared_mem) pthread_mutex_unlock(&shctx->mutex)
93
Emeric Brun9faf0712012-09-25 11:11:16 +020094#else
Emeric Bruncd1a5262014-05-07 23:11:42 +020095static int use_shared_mem = 0;
96
Emeric Brun3e541d12012-09-03 11:14:36 +020097#ifdef USE_SYSCALL_FUTEX
Emeric Bruncd1a5262014-05-07 23:11:42 +020098static inline void _shared_context_wait4lock(unsigned int *count, unsigned int *uaddr, int value)
99{
100 syscall(SYS_futex, uaddr, FUTEX_WAIT, value, NULL, 0, 0);
101}
102
103static inline void _shared_context_awakelocker(unsigned int *uaddr)
104{
105 syscall(SYS_futex, uaddr, FUTEX_WAKE, 1, NULL, 0, 0);
106}
107
108#else /* internal spin lock */
109
110#if defined (__i486__) || defined (__i586__) || defined (__i686__) || defined (__x86_64__)
111static inline void relax()
112{
113 __asm volatile("rep;nop\n" ::: "memory");
114}
115#else /* if no x86_64 or i586 arch: use less optimized but generic asm */
116static inline void relax()
117{
118 __asm volatile("" ::: "memory");
119}
120#endif
121
122static inline void _shared_context_wait4lock(unsigned int *count, unsigned int *uaddr, int value)
123{
124 int i;
125
126 for (i = 0; i < *count; i++) {
127 relax();
128 relax();
129 }
130 *count = *count << 1;
131}
132
133#define _shared_context_awakelocker(a)
134
135#endif
136
Emeric Brunce08baa2012-10-04 17:28:25 +0200137#if defined (__i486__) || defined (__i586__) || defined (__i686__) || defined (__x86_64__)
Emeric Brun3e541d12012-09-03 11:14:36 +0200138static inline unsigned int xchg(unsigned int *ptr, unsigned int x)
139{
140 __asm volatile("lock xchgl %0,%1"
141 : "=r" (x), "+m" (*ptr)
142 : "0" (x)
143 : "memory");
144 return x;
145}
146
147static inline unsigned int cmpxchg(unsigned int *ptr, unsigned int old, unsigned int new)
148{
149 unsigned int ret;
150
151 __asm volatile("lock cmpxchgl %2,%1"
152 : "=a" (ret), "+m" (*ptr)
153 : "r" (new), "0" (old)
154 : "memory");
155 return ret;
156}
157
158static inline unsigned char atomic_dec(unsigned int *ptr)
159{
160 unsigned char ret;
161 __asm volatile("lock decl %0\n"
162 "setne %1\n"
163 : "+m" (*ptr), "=qm" (ret)
164 :
165 : "memory");
166 return ret;
167}
168
169#else /* if no x86_64 or i586 arch: use less optimized gcc >= 4.1 built-ins */
170static inline unsigned int xchg(unsigned int *ptr, unsigned int x)
171{
172 return __sync_lock_test_and_set(ptr, x);
173}
174
175static inline unsigned int cmpxchg(unsigned int *ptr, unsigned int old, unsigned int new)
176{
177 return __sync_val_compare_and_swap(ptr, old, new);
178}
179
180static inline unsigned char atomic_dec(unsigned int *ptr)
181{
182 return __sync_sub_and_fetch(ptr, 1) ? 1 : 0;
183}
184
185#endif
186
Emeric Brun4b3091e2012-09-24 15:48:52 +0200187static inline void _shared_context_lock(void)
Emeric Brun3e541d12012-09-03 11:14:36 +0200188{
189 unsigned int x;
Emeric Bruncd1a5262014-05-07 23:11:42 +0200190 unsigned int count = 4;
Emeric Brun3e541d12012-09-03 11:14:36 +0200191
192 x = cmpxchg(&shctx->waiters, 0, 1);
193 if (x) {
194 if (x != 2)
195 x = xchg(&shctx->waiters, 2);
196
197 while (x) {
Emeric Bruncd1a5262014-05-07 23:11:42 +0200198 _shared_context_wait4lock(&count, &shctx->waiters, 2);
Emeric Brun3e541d12012-09-03 11:14:36 +0200199 x = xchg(&shctx->waiters, 2);
200 }
201 }
202}
203
Emeric Brun4b3091e2012-09-24 15:48:52 +0200204static inline void _shared_context_unlock(void)
Emeric Brun3e541d12012-09-03 11:14:36 +0200205{
206 if (atomic_dec(&shctx->waiters)) {
207 shctx->waiters = 0;
Emeric Bruncd1a5262014-05-07 23:11:42 +0200208 _shared_context_awakelocker(&shctx->waiters);
Emeric Brun3e541d12012-09-03 11:14:36 +0200209 }
210}
211
Willy Tarreau338a4fc2012-10-18 15:11:52 +0200212#define shared_context_lock() if (use_shared_mem) _shared_context_lock()
Emeric Brun4b3091e2012-09-24 15:48:52 +0200213
Willy Tarreau338a4fc2012-10-18 15:11:52 +0200214#define shared_context_unlock() if (use_shared_mem) _shared_context_unlock()
Emeric Brun4b3091e2012-09-24 15:48:52 +0200215
Emeric Brun9faf0712012-09-25 11:11:16 +0200216#endif
Emeric Brun3e541d12012-09-03 11:14:36 +0200217
218/* List Macros */
219
Emeric Brunaf9619d2012-11-28 18:47:52 +0100220#define shblock_unset(s) (s)->n->p = (s)->p; \
Emeric Brun3e541d12012-09-03 11:14:36 +0200221 (s)->p->n = (s)->n;
222
Emeric Brunaf9619d2012-11-28 18:47:52 +0100223#define shblock_set_free(s) shblock_unset(s) \
224 (s)->n = &shctx->free; \
225 (s)->p = shctx->free.p; \
226 shctx->free.p->n = s; \
227 shctx->free.p = s;
Emeric Brun3e541d12012-09-03 11:14:36 +0200228
229
Emeric Brunaf9619d2012-11-28 18:47:52 +0100230#define shblock_set_active(s) shblock_unset(s) \
231 (s)->n = &shctx->active; \
232 (s)->p = shctx->active.p; \
233 shctx->active.p->n = s; \
234 shctx->active.p = s;
Emeric Brun3e541d12012-09-03 11:14:36 +0200235
236
Emeric Brun3e541d12012-09-03 11:14:36 +0200237/* Tree Macros */
238
239#define shsess_tree_delete(s) ebmb_delete(&(s)->key);
240
Emeric Brunaf9619d2012-11-28 18:47:52 +0100241#define shsess_tree_insert(s) (struct shared_session *)ebmb_insert(&shctx->active.data.session.key.node.branches, \
Emeric Brun3e541d12012-09-03 11:14:36 +0200242 &(s)->key, SSL_MAX_SSL_SESSION_ID_LENGTH);
243
Emeric Brunaf9619d2012-11-28 18:47:52 +0100244#define shsess_tree_lookup(k) (struct shared_session *)ebmb_lookup(&shctx->active.data.session.key.node.branches, \
Emeric Brun3e541d12012-09-03 11:14:36 +0200245 (k), SSL_MAX_SSL_SESSION_ID_LENGTH);
246
Emeric Brunaf9619d2012-11-28 18:47:52 +0100247/* shared session functions */
Emeric Brun3e541d12012-09-03 11:14:36 +0200248
Emeric Brunaf9619d2012-11-28 18:47:52 +0100249/* Free session blocks, returns number of freed blocks */
250static int shsess_free(struct shared_session *shsess)
251{
252 struct shared_block *block;
253 int ret = 1;
Emeric Brun3e541d12012-09-03 11:14:36 +0200254
Emeric Brunaf9619d2012-11-28 18:47:52 +0100255 if (((struct shared_block *)shsess)->data_len <= sizeof(shsess->data)) {
256 shblock_set_free((struct shared_block *)shsess);
257 return ret;
258 }
259 block = ((struct shared_block *)shsess)->n;
260 shblock_set_free((struct shared_block *)shsess);
261 while (1) {
262 struct shared_block *next;
Emeric Brun3e541d12012-09-03 11:14:36 +0200263
Emeric Brunaf9619d2012-11-28 18:47:52 +0100264 if (block->data_len <= sizeof(block->data)) {
265 /* last block */
266 shblock_set_free(block);
267 ret++;
268 break;
269 }
270 next = block->n;
271 shblock_set_free(block);
272 ret++;
273 block = next;
274 }
275 return ret;
276}
Emeric Brun3e541d12012-09-03 11:14:36 +0200277
Emeric Brunaf9619d2012-11-28 18:47:52 +0100278/* This function frees enough blocks to store a new session of data_len.
279 * Returns a ptr on a free block if it succeeds, or NULL if there are not
280 * enough blocks to store that session.
281 */
282static struct shared_session *shsess_get_next(int data_len)
Emeric Brun3e541d12012-09-03 11:14:36 +0200283{
Emeric Brunaf9619d2012-11-28 18:47:52 +0100284 int head = 0;
285 struct shared_block *b;
286
287 b = shctx->free.n;
288 while (b != &shctx->free) {
289 if (!head) {
290 data_len -= sizeof(b->data.session.data);
291 head = 1;
292 }
293 else
294 data_len -= sizeof(b->data.data);
295 if (data_len <= 0)
296 return &shctx->free.n->data.session;
297 b = b->n;
298 }
299 b = shctx->active.n;
300 while (b != &shctx->active) {
301 int freed;
302
303 shsess_tree_delete(&b->data.session);
304 freed = shsess_free(&b->data.session);
305 if (!head)
306 data_len -= sizeof(b->data.session.data) + (freed-1)*sizeof(b->data.data);
307 else
308 data_len -= freed*sizeof(b->data.data);
309 if (data_len <= 0)
310 return &shctx->free.n->data.session;
311 b = shctx->active.n;
312 }
313 return NULL;
314}
Emeric Brun3e541d12012-09-03 11:14:36 +0200315
Emeric Brunaf9619d2012-11-28 18:47:52 +0100316/* store a session into the cache
317 * s_id : session id padded with zero to SSL_MAX_SSL_SESSION_ID_LENGTH
318 * data: asn1 encoded session
319 * data_len: asn1 encoded session length
320 * Returns 1 id session was stored (else 0)
321 */
322static int shsess_store(unsigned char *s_id, unsigned char *data, int data_len)
323{
324 struct shared_session *shsess, *oldshsess;
325
326 shsess = shsess_get_next(data_len);
327 if (!shsess) {
328 /* Could not retrieve enough free blocks to store that session */
Emeric Brun3e541d12012-09-03 11:14:36 +0200329 return 0;
Emeric Brunaf9619d2012-11-28 18:47:52 +0100330 }
Emeric Brun3e541d12012-09-03 11:14:36 +0200331
Emeric Brunaf9619d2012-11-28 18:47:52 +0100332 /* prepare key */
333 memcpy(shsess->key_data, s_id, SSL_MAX_SSL_SESSION_ID_LENGTH);
Emeric Brun3e541d12012-09-03 11:14:36 +0200334
Emeric Brunaf9619d2012-11-28 18:47:52 +0100335 /* it returns the already existing node
336 or current node if none, never returns null */
337 oldshsess = shsess_tree_insert(shsess);
338 if (oldshsess != shsess) {
339 /* free all blocks used by old node */
340 shsess_free(oldshsess);
341 shsess = oldshsess;
342 }
Emeric Brun3e541d12012-09-03 11:14:36 +0200343
Emeric Brunaf9619d2012-11-28 18:47:52 +0100344 ((struct shared_block *)shsess)->data_len = data_len;
345 if (data_len <= sizeof(shsess->data)) {
346 /* Store on a single block */
347 memcpy(shsess->data, data, data_len);
348 shblock_set_active((struct shared_block *)shsess);
349 }
350 else {
351 unsigned char *p;
352 /* Store on multiple blocks */
353 int cur_len;
Emeric Brun3e541d12012-09-03 11:14:36 +0200354
Emeric Brunaf9619d2012-11-28 18:47:52 +0100355 memcpy(shsess->data, data, sizeof(shsess->data));
356 p = data + sizeof(shsess->data);
357 cur_len = data_len - sizeof(shsess->data);
358 shblock_set_active((struct shared_block *)shsess);
359 while (1) {
360 /* Store next data on free block.
361 * shsess_get_next guarantees that there are enough
362 * free blocks in queue.
363 */
364 struct shared_block *block;
Emeric Brun3e541d12012-09-03 11:14:36 +0200365
Emeric Brunaf9619d2012-11-28 18:47:52 +0100366 block = shctx->free.n;
367 if (cur_len <= sizeof(block->data)) {
368 /* This is the last block */
369 block->data_len = cur_len;
370 memcpy(block->data.data, p, cur_len);
371 shblock_set_active(block);
372 break;
373 }
374 /* Intermediate block */
375 block->data_len = cur_len;
376 memcpy(block->data.data, p, sizeof(block->data));
377 p += sizeof(block->data.data);
378 cur_len -= sizeof(block->data.data);
379 shblock_set_active(block);
380 }
381 }
Emeric Brun3e541d12012-09-03 11:14:36 +0200382
Emeric Brunaf9619d2012-11-28 18:47:52 +0100383 return 1;
384}
Emeric Brun3e541d12012-09-03 11:14:36 +0200385
Emeric Brun3e541d12012-09-03 11:14:36 +0200386
Emeric Brunaf9619d2012-11-28 18:47:52 +0100387/* SSL context callbacks */
Emeric Brun3e541d12012-09-03 11:14:36 +0200388
Emeric Brunaf9619d2012-11-28 18:47:52 +0100389/* SSL callback used on new session creation */
390int shctx_new_cb(SSL *ssl, SSL_SESSION *sess)
391{
392 unsigned char encsess[sizeof(struct shsess_packet)+SHSESS_MAX_DATA_LEN];
393 struct shsess_packet *packet = (struct shsess_packet *)encsess;
394 unsigned char *p;
Emeric Brunf27af0d2013-04-26 18:56:49 +0200395 int data_len, sid_length, sid_ctx_length;
Emeric Brun3e541d12012-09-03 11:14:36 +0200396
Emeric Brun3e541d12012-09-03 11:14:36 +0200397
Emeric Brunaf9619d2012-11-28 18:47:52 +0100398 /* Session id is already stored in to key and session id is known
399 * so we dont store it to keep size.
400 */
401 sid_length = sess->session_id_length;
402 sess->session_id_length = 0;
Emeric Brunf27af0d2013-04-26 18:56:49 +0200403 sid_ctx_length = sess->sid_ctx_length;
Emeric Brunaf9619d2012-11-28 18:47:52 +0100404 sess->sid_ctx_length = 0;
Emeric Brun3e541d12012-09-03 11:14:36 +0200405
Emeric Brunaf9619d2012-11-28 18:47:52 +0100406 /* check if buffer is large enough for the ASN1 encoded session */
407 data_len = i2d_SSL_SESSION(sess, NULL);
408 if (data_len > SHSESS_MAX_DATA_LEN)
409 goto err;
410
411 /* process ASN1 session encoding before the lock */
412 p = packet->data;
413 i2d_SSL_SESSION(sess, &p);
414
415 memcpy(packet->hdr.id, sess->session_id, sid_length);
416 if (sid_length < SSL_MAX_SSL_SESSION_ID_LENGTH)
417 memset(&packet->hdr.id[sid_length], 0, SSL_MAX_SSL_SESSION_ID_LENGTH-sid_length);
418
419 shared_context_lock();
420
421 /* store to cache */
422 shsess_store(packet->hdr.id, packet->data, data_len);
423
424 shared_context_unlock();
425
426err:
427 /* reset original length values */
Emeric Brunaf9619d2012-11-28 18:47:52 +0100428 sess->session_id_length = sid_length;
Emeric Brunf27af0d2013-04-26 18:56:49 +0200429 sess->sid_ctx_length = sid_ctx_length;
Emeric Brun3e541d12012-09-03 11:14:36 +0200430
431 return 0; /* do not increment session reference count */
432}
433
434/* SSL callback used on lookup an existing session cause none found in internal cache */
435SSL_SESSION *shctx_get_cb(SSL *ssl, unsigned char *key, int key_len, int *do_copy)
436{
437 struct shared_session *shsess;
438 unsigned char data[SHSESS_MAX_DATA_LEN], *p;
439 unsigned char tmpkey[SSL_MAX_SSL_SESSION_ID_LENGTH];
Emeric Brunaf9619d2012-11-28 18:47:52 +0100440 int data_len;
Emeric Brun3e541d12012-09-03 11:14:36 +0200441 SSL_SESSION *sess;
Emeric Brun3e541d12012-09-03 11:14:36 +0200442
443 /* allow the session to be freed automatically by openssl */
444 *do_copy = 0;
445
446 /* tree key is zeros padded sessionid */
447 if (key_len < SSL_MAX_SSL_SESSION_ID_LENGTH) {
448 memcpy(tmpkey, key, key_len);
449 memset(tmpkey + key_len, 0, SSL_MAX_SSL_SESSION_ID_LENGTH - key_len);
450 key = tmpkey;
451 }
452
453 /* lock cache */
454 shared_context_lock();
455
456 /* lookup for session */
457 shsess = shsess_tree_lookup(key);
458 if (!shsess) {
459 /* no session found: unlock cache and exit */
460 shared_context_unlock();
461 return NULL;
462 }
463
Emeric Brunaf9619d2012-11-28 18:47:52 +0100464 data_len = ((struct shared_block *)shsess)->data_len;
465 if (data_len <= sizeof(shsess->data)) {
466 /* Session stored on single block */
467 memcpy(data, shsess->data, data_len);
468 shblock_set_active((struct shared_block *)shsess);
469 }
470 else {
471 /* Session stored on multiple blocks */
472 struct shared_block *block;
Emeric Brun3e541d12012-09-03 11:14:36 +0200473
Emeric Brunaf9619d2012-11-28 18:47:52 +0100474 memcpy(data, shsess->data, sizeof(shsess->data));
475 p = data + sizeof(shsess->data);
476 block = ((struct shared_block *)shsess)->n;
477 shblock_set_active((struct shared_block *)shsess);
478 while (1) {
479 /* Retrieve data from next block */
480 struct shared_block *next;
Emeric Brun3e541d12012-09-03 11:14:36 +0200481
Emeric Brunaf9619d2012-11-28 18:47:52 +0100482 if (block->data_len <= sizeof(block->data.data)) {
483 /* This is the last block */
484 memcpy(p, block->data.data, block->data_len);
485 p += block->data_len;
486 shblock_set_active(block);
487 break;
488 }
489 /* Intermediate block */
490 memcpy(p, block->data.data, sizeof(block->data.data));
491 p += sizeof(block->data.data);
492 next = block->n;
493 shblock_set_active(block);
494 block = next;
495 }
496 }
Emeric Brun3e541d12012-09-03 11:14:36 +0200497
498 shared_context_unlock();
499
500 /* decode ASN1 session */
501 p = data;
502 sess = d2i_SSL_SESSION(NULL, (const unsigned char **)&p, data_len);
Emeric Brunaf9619d2012-11-28 18:47:52 +0100503 /* Reset session id and session id contenxt */
504 if (sess) {
505 memcpy(sess->session_id, key, key_len);
506 sess->session_id_length = key_len;
Emeric Brunf27af0d2013-04-26 18:56:49 +0200507 memcpy(sess->sid_ctx, (const unsigned char *)SHCTX_APPNAME, strlen(SHCTX_APPNAME));
Emeric Brunaf9619d2012-11-28 18:47:52 +0100508 sess->sid_ctx_length = ssl->sid_ctx_length;
509 }
Emeric Brun3e541d12012-09-03 11:14:36 +0200510
511 return sess;
512}
513
514/* SSL callback used to signal session is no more used in internal cache */
515void shctx_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess)
516{
517 struct shared_session *shsess;
518 unsigned char tmpkey[SSL_MAX_SSL_SESSION_ID_LENGTH];
519 unsigned char *key = sess->session_id;
520 (void)ctx;
521
522 /* tree key is zeros padded sessionid */
523 if (sess->session_id_length < SSL_MAX_SSL_SESSION_ID_LENGTH) {
524 memcpy(tmpkey, sess->session_id, sess->session_id_length);
525 memset(tmpkey+sess->session_id_length, 0, SSL_MAX_SSL_SESSION_ID_LENGTH - sess->session_id_length);
526 key = tmpkey;
527 }
528
529 shared_context_lock();
530
531 /* lookup for session */
532 shsess = shsess_tree_lookup(key);
533 if (shsess) {
Emeric Brunaf9619d2012-11-28 18:47:52 +0100534 /* free session */
535 shsess_tree_delete(shsess);
536 shsess_free(shsess);
Emeric Brun3e541d12012-09-03 11:14:36 +0200537 }
538
539 /* unlock cache */
540 shared_context_unlock();
541}
542
Emeric Brun3e541d12012-09-03 11:14:36 +0200543/* Allocate shared memory context.
Emeric Brunaf9619d2012-11-28 18:47:52 +0100544 * <size> is maximum cached sessions.
Emeric Brun22890a12012-12-28 14:41:32 +0100545 * If <size> is set to less or equal to 0, ssl cache is disabled.
Emeric Brunaf9619d2012-11-28 18:47:52 +0100546 * Returns: -1 on alloc failure, <size> if it performs context alloc,
547 * and 0 if cache is already allocated.
548 */
Emeric Brun4b3091e2012-09-24 15:48:52 +0200549int shared_context_init(int size, int shared)
Emeric Brun3e541d12012-09-03 11:14:36 +0200550{
551 int i;
Emeric Brun9faf0712012-09-25 11:11:16 +0200552#ifndef USE_PRIVATE_CACHE
Emeric Bruncd1a5262014-05-07 23:11:42 +0200553#ifdef USE_PTHREAD_PSHARED
Emeric Brun3e541d12012-09-03 11:14:36 +0200554 pthread_mutexattr_t attr;
Emeric Bruncd1a5262014-05-07 23:11:42 +0200555#endif
Emeric Brun9faf0712012-09-25 11:11:16 +0200556#endif
Emeric Brunaf9619d2012-11-28 18:47:52 +0100557 struct shared_block *prev,*cur;
Emeric Brun4b3091e2012-09-24 15:48:52 +0200558 int maptype = MAP_PRIVATE;
Emeric Brun3e541d12012-09-03 11:14:36 +0200559
560 if (shctx)
561 return 0;
562
563 if (size<=0)
Emeric Brun22890a12012-12-28 14:41:32 +0100564 return 0;
Emeric Brun3e541d12012-09-03 11:14:36 +0200565
Emeric Brunaf9619d2012-11-28 18:47:52 +0100566 /* Increate size by one to reserve one node for lookup */
567 size++;
Emeric Brun9faf0712012-09-25 11:11:16 +0200568#ifndef USE_PRIVATE_CACHE
Emeric Brun4b3091e2012-09-24 15:48:52 +0200569 if (shared)
570 maptype = MAP_SHARED;
Emeric Brun9faf0712012-09-25 11:11:16 +0200571#endif
Emeric Brun4b3091e2012-09-24 15:48:52 +0200572
Emeric Brunaf9619d2012-11-28 18:47:52 +0100573 shctx = (struct shared_context *)mmap(NULL, sizeof(struct shared_context)+(size*sizeof(struct shared_block)),
Emeric Brun4b3091e2012-09-24 15:48:52 +0200574 PROT_READ | PROT_WRITE, maptype | MAP_ANON, -1, 0);
Emeric Brun3e541d12012-09-03 11:14:36 +0200575 if (!shctx || shctx == MAP_FAILED) {
576 shctx = NULL;
Emeric Bruncaa19cc2014-05-07 16:10:18 +0200577 return SHCTX_E_ALLOC_CACHE;
Emeric Brun3e541d12012-09-03 11:14:36 +0200578 }
579
Emeric Brun9faf0712012-09-25 11:11:16 +0200580#ifndef USE_PRIVATE_CACHE
Emeric Bruncaa19cc2014-05-07 16:10:18 +0200581 if (maptype == MAP_SHARED) {
Emeric Bruncd1a5262014-05-07 23:11:42 +0200582#ifdef USE_PTHREAD_PSHARED
Emeric Bruncaa19cc2014-05-07 16:10:18 +0200583 if (pthread_mutexattr_init(&attr)) {
584 munmap(shctx, sizeof(struct shared_context)+(size*sizeof(struct shared_block)));
585 shctx = NULL;
586 return SHCTX_E_INIT_LOCK;
587 }
588
589 if (pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)) {
590 pthread_mutexattr_destroy(&attr);
591 munmap(shctx, sizeof(struct shared_context)+(size*sizeof(struct shared_block)));
592 shctx = NULL;
593 return SHCTX_E_INIT_LOCK;
594 }
595
596 if (pthread_mutex_init(&shctx->mutex, &attr)) {
597 pthread_mutexattr_destroy(&attr);
598 munmap(shctx, sizeof(struct shared_context)+(size*sizeof(struct shared_block)));
599 shctx = NULL;
600 return SHCTX_E_INIT_LOCK;
601 }
Emeric Bruncd1a5262014-05-07 23:11:42 +0200602#else
603 shctx->waiters = 0;
Emeric Brun3e541d12012-09-03 11:14:36 +0200604#endif
Emeric Brun4b3091e2012-09-24 15:48:52 +0200605 use_shared_mem = 1;
Emeric Bruncaa19cc2014-05-07 16:10:18 +0200606 }
Emeric Brun9faf0712012-09-25 11:11:16 +0200607#endif
Emeric Brun4b3091e2012-09-24 15:48:52 +0200608
Emeric Brunaf9619d2012-11-28 18:47:52 +0100609 memset(&shctx->active.data.session.key, 0, sizeof(struct ebmb_node));
610 memset(&shctx->free.data.session.key, 0, sizeof(struct ebmb_node));
Emeric Brun3e541d12012-09-03 11:14:36 +0200611
612 /* No duplicate authorized in tree: */
Emeric Brunaf9619d2012-11-28 18:47:52 +0100613 shctx->active.data.session.key.node.branches = EB_ROOT_UNIQUE;
614
615 /* Init remote update cache */
616 shctx->upd.eol = 0;
617 shctx->upd.seq = 0;
618 shctx->data_len = 0;
Emeric Brun3e541d12012-09-03 11:14:36 +0200619
620 cur = &shctx->active;
621 cur->n = cur->p = cur;
622
623 cur = &shctx->free;
624 for (i = 0 ; i < size ; i++) {
625 prev = cur;
Emeric Brunaf9619d2012-11-28 18:47:52 +0100626 cur = (struct shared_block *)((char *)prev + sizeof(struct shared_block));
Emeric Brun3e541d12012-09-03 11:14:36 +0200627 prev->n = cur;
628 cur->p = prev;
629 }
630 cur->n = &shctx->free;
631 shctx->free.p = cur;
632
633 return size;
634}
635
636
637/* Set session cache mode to server and disable openssl internal cache.
638 * Set shared cache callbacks on an ssl context.
639 * Shared context MUST be firstly initialized */
640void shared_context_set_cache(SSL_CTX *ctx)
641{
Emeric Brun786991e2012-11-26 18:37:12 +0100642 SSL_CTX_set_session_id_context(ctx, (const unsigned char *)SHCTX_APPNAME, strlen(SHCTX_APPNAME));
643
Emeric Brun22890a12012-12-28 14:41:32 +0100644 if (!shctx) {
645 SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
Emeric Brun3e541d12012-09-03 11:14:36 +0200646 return;
Emeric Brun22890a12012-12-28 14:41:32 +0100647 }
648
649 SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER |
650 SSL_SESS_CACHE_NO_INTERNAL |
651 SSL_SESS_CACHE_NO_AUTO_CLEAR);
Emeric Brun3e541d12012-09-03 11:14:36 +0200652
653 /* Set callbacks */
654 SSL_CTX_sess_set_new_cb(ctx, shctx_new_cb);
655 SSL_CTX_sess_set_get_cb(ctx, shctx_get_cb);
656 SSL_CTX_sess_set_remove_cb(ctx, shctx_remove_cb);
657}