blob: 151b68a49321128d6b7f79b044cc13dcb29bdbbb [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 Brun3e541d12012-09-03 11:14:36 +020016#ifdef USE_SYSCALL_FUTEX
17#include <unistd.h>
Willy Tarreau18b20592012-09-04 12:26:26 +020018#ifndef u32
19#define u32 unsigned int
20#endif
Emeric Brun3e541d12012-09-03 11:14:36 +020021#include <linux/futex.h>
22#include <sys/syscall.h>
23#else /* USE_SYSCALL_FUTEX */
24#include <pthread.h>
25#endif /* USE_SYSCALL_FUTEX */
Emeric Brun9faf0712012-09-25 11:11:16 +020026#endif
Emeric Brunaf9619d2012-11-28 18:47:52 +010027#include <arpa/inet.h>
Emeric Brun3e541d12012-09-03 11:14:36 +020028#include "ebmbtree.h"
29#include "proto/shctx.h"
30
Emeric Brunaf9619d2012-11-28 18:47:52 +010031struct shsess_packet_hdr {
32 unsigned int eol;
33 unsigned char final:1;
34 unsigned char seq:7;
35 unsigned char id[SSL_MAX_SSL_SESSION_ID_LENGTH];
36};
37
38struct shsess_packet {
39 unsigned char version;
40 unsigned char sig[SHA_DIGEST_LENGTH];
41 struct shsess_packet_hdr hdr;
42 unsigned char data[0];
43};
44
Emeric Brun3e541d12012-09-03 11:14:36 +020045struct shared_session {
46 struct ebmb_node key;
47 unsigned char key_data[SSL_MAX_SSL_SESSION_ID_LENGTH];
Emeric Brunaf9619d2012-11-28 18:47:52 +010048 unsigned char data[SHSESS_BLOCK_MIN_SIZE];
Emeric Brun3e541d12012-09-03 11:14:36 +020049};
50
Emeric Brunaf9619d2012-11-28 18:47:52 +010051struct shared_block {
52 union {
53 struct shared_session session;
54 unsigned char data[sizeof(struct shared_session)];
55 } data;
56 short int data_len;
57 struct shared_block *p;
58 struct shared_block *n;
59};
Emeric Brun3e541d12012-09-03 11:14:36 +020060
61struct shared_context {
Emeric Brun9faf0712012-09-25 11:11:16 +020062#ifndef USE_PRIVATE_CACHE
Emeric Brun3e541d12012-09-03 11:14:36 +020063#ifdef USE_SYSCALL_FUTEX
64 unsigned int waiters;
65#else /* USE_SYSCALL_FUTEX */
66 pthread_mutex_t mutex;
67#endif
Emeric Brun9faf0712012-09-25 11:11:16 +020068#endif
Emeric Brunaf9619d2012-11-28 18:47:52 +010069 struct shsess_packet_hdr upd;
70 unsigned char data[SHSESS_MAX_DATA_LEN];
71 short int data_len;
72 struct shared_block active;
73 struct shared_block free;
Emeric Brun3e541d12012-09-03 11:14:36 +020074};
75
76/* Static shared context */
77static struct shared_context *shctx = NULL;
Emeric Brun9faf0712012-09-25 11:11:16 +020078#ifndef USE_PRIVATE_CACHE
Emeric Brun4b3091e2012-09-24 15:48:52 +020079static int use_shared_mem = 0;
Emeric Brun9faf0712012-09-25 11:11:16 +020080#endif
Emeric Brun3e541d12012-09-03 11:14:36 +020081
Emeric Brun3e541d12012-09-03 11:14:36 +020082/* Lock functions */
Emeric Brun9faf0712012-09-25 11:11:16 +020083#ifdef USE_PRIVATE_CACHE
Willy Tarreau338a4fc2012-10-18 15:11:52 +020084#define shared_context_lock()
85#define shared_context_unlock()
Emeric Brun9faf0712012-09-25 11:11:16 +020086
87#else
Emeric Brun3e541d12012-09-03 11:14:36 +020088#ifdef USE_SYSCALL_FUTEX
Emeric Brunce08baa2012-10-04 17:28:25 +020089#if defined (__i486__) || defined (__i586__) || defined (__i686__) || defined (__x86_64__)
Emeric Brun3e541d12012-09-03 11:14:36 +020090static inline unsigned int xchg(unsigned int *ptr, unsigned int x)
91{
92 __asm volatile("lock xchgl %0,%1"
93 : "=r" (x), "+m" (*ptr)
94 : "0" (x)
95 : "memory");
96 return x;
97}
98
99static inline unsigned int cmpxchg(unsigned int *ptr, unsigned int old, unsigned int new)
100{
101 unsigned int ret;
102
103 __asm volatile("lock cmpxchgl %2,%1"
104 : "=a" (ret), "+m" (*ptr)
105 : "r" (new), "0" (old)
106 : "memory");
107 return ret;
108}
109
110static inline unsigned char atomic_dec(unsigned int *ptr)
111{
112 unsigned char ret;
113 __asm volatile("lock decl %0\n"
114 "setne %1\n"
115 : "+m" (*ptr), "=qm" (ret)
116 :
117 : "memory");
118 return ret;
119}
120
121#else /* if no x86_64 or i586 arch: use less optimized gcc >= 4.1 built-ins */
122static inline unsigned int xchg(unsigned int *ptr, unsigned int x)
123{
124 return __sync_lock_test_and_set(ptr, x);
125}
126
127static inline unsigned int cmpxchg(unsigned int *ptr, unsigned int old, unsigned int new)
128{
129 return __sync_val_compare_and_swap(ptr, old, new);
130}
131
132static inline unsigned char atomic_dec(unsigned int *ptr)
133{
134 return __sync_sub_and_fetch(ptr, 1) ? 1 : 0;
135}
136
137#endif
138
Emeric Brun4b3091e2012-09-24 15:48:52 +0200139static inline void _shared_context_lock(void)
Emeric Brun3e541d12012-09-03 11:14:36 +0200140{
141 unsigned int x;
142
143 x = cmpxchg(&shctx->waiters, 0, 1);
144 if (x) {
145 if (x != 2)
146 x = xchg(&shctx->waiters, 2);
147
148 while (x) {
149 syscall(SYS_futex, &shctx->waiters, FUTEX_WAIT, 2, NULL, 0, 0);
150 x = xchg(&shctx->waiters, 2);
151 }
152 }
153}
154
Emeric Brun4b3091e2012-09-24 15:48:52 +0200155static inline void _shared_context_unlock(void)
Emeric Brun3e541d12012-09-03 11:14:36 +0200156{
157 if (atomic_dec(&shctx->waiters)) {
158 shctx->waiters = 0;
159 syscall(SYS_futex, &shctx->waiters, FUTEX_WAKE, 1, NULL, 0, 0);
160 }
161}
162
Willy Tarreau338a4fc2012-10-18 15:11:52 +0200163#define shared_context_lock() if (use_shared_mem) _shared_context_lock()
Emeric Brun4b3091e2012-09-24 15:48:52 +0200164
Willy Tarreau338a4fc2012-10-18 15:11:52 +0200165#define shared_context_unlock() if (use_shared_mem) _shared_context_unlock()
Emeric Brun4b3091e2012-09-24 15:48:52 +0200166
Emeric Brun3e541d12012-09-03 11:14:36 +0200167#else /* USE_SYSCALL_FUTEX */
168
Willy Tarreau338a4fc2012-10-18 15:11:52 +0200169#define shared_context_lock() if (use_shared_mem) pthread_mutex_lock(&shctx->mutex)
Emeric Brun4b3091e2012-09-24 15:48:52 +0200170
Willy Tarreau338a4fc2012-10-18 15:11:52 +0200171#define shared_context_unlock() if (use_shared_mem) pthread_mutex_unlock(&shctx->mutex)
Emeric Brun3e541d12012-09-03 11:14:36 +0200172
173#endif
Emeric Brun9faf0712012-09-25 11:11:16 +0200174#endif
Emeric Brun3e541d12012-09-03 11:14:36 +0200175
176/* List Macros */
177
Emeric Brunaf9619d2012-11-28 18:47:52 +0100178#define shblock_unset(s) (s)->n->p = (s)->p; \
Emeric Brun3e541d12012-09-03 11:14:36 +0200179 (s)->p->n = (s)->n;
180
Emeric Brunaf9619d2012-11-28 18:47:52 +0100181#define shblock_set_free(s) shblock_unset(s) \
182 (s)->n = &shctx->free; \
183 (s)->p = shctx->free.p; \
184 shctx->free.p->n = s; \
185 shctx->free.p = s;
Emeric Brun3e541d12012-09-03 11:14:36 +0200186
187
Emeric Brunaf9619d2012-11-28 18:47:52 +0100188#define shblock_set_active(s) shblock_unset(s) \
189 (s)->n = &shctx->active; \
190 (s)->p = shctx->active.p; \
191 shctx->active.p->n = s; \
192 shctx->active.p = s;
Emeric Brun3e541d12012-09-03 11:14:36 +0200193
194
Emeric Brun3e541d12012-09-03 11:14:36 +0200195/* Tree Macros */
196
197#define shsess_tree_delete(s) ebmb_delete(&(s)->key);
198
Emeric Brunaf9619d2012-11-28 18:47:52 +0100199#define shsess_tree_insert(s) (struct shared_session *)ebmb_insert(&shctx->active.data.session.key.node.branches, \
Emeric Brun3e541d12012-09-03 11:14:36 +0200200 &(s)->key, SSL_MAX_SSL_SESSION_ID_LENGTH);
201
Emeric Brunaf9619d2012-11-28 18:47:52 +0100202#define shsess_tree_lookup(k) (struct shared_session *)ebmb_lookup(&shctx->active.data.session.key.node.branches, \
Emeric Brun3e541d12012-09-03 11:14:36 +0200203 (k), SSL_MAX_SSL_SESSION_ID_LENGTH);
204
Emeric Brunaf9619d2012-11-28 18:47:52 +0100205/* shared session functions */
Emeric Brun3e541d12012-09-03 11:14:36 +0200206
Emeric Brunaf9619d2012-11-28 18:47:52 +0100207/* Free session blocks, returns number of freed blocks */
208static int shsess_free(struct shared_session *shsess)
209{
210 struct shared_block *block;
211 int ret = 1;
Emeric Brun3e541d12012-09-03 11:14:36 +0200212
Emeric Brunaf9619d2012-11-28 18:47:52 +0100213 if (((struct shared_block *)shsess)->data_len <= sizeof(shsess->data)) {
214 shblock_set_free((struct shared_block *)shsess);
215 return ret;
216 }
217 block = ((struct shared_block *)shsess)->n;
218 shblock_set_free((struct shared_block *)shsess);
219 while (1) {
220 struct shared_block *next;
Emeric Brun3e541d12012-09-03 11:14:36 +0200221
Emeric Brunaf9619d2012-11-28 18:47:52 +0100222 if (block->data_len <= sizeof(block->data)) {
223 /* last block */
224 shblock_set_free(block);
225 ret++;
226 break;
227 }
228 next = block->n;
229 shblock_set_free(block);
230 ret++;
231 block = next;
232 }
233 return ret;
234}
Emeric Brun3e541d12012-09-03 11:14:36 +0200235
Emeric Brunaf9619d2012-11-28 18:47:52 +0100236/* This function frees enough blocks to store a new session of data_len.
237 * Returns a ptr on a free block if it succeeds, or NULL if there are not
238 * enough blocks to store that session.
239 */
240static struct shared_session *shsess_get_next(int data_len)
Emeric Brun3e541d12012-09-03 11:14:36 +0200241{
Emeric Brunaf9619d2012-11-28 18:47:52 +0100242 int head = 0;
243 struct shared_block *b;
244
245 b = shctx->free.n;
246 while (b != &shctx->free) {
247 if (!head) {
248 data_len -= sizeof(b->data.session.data);
249 head = 1;
250 }
251 else
252 data_len -= sizeof(b->data.data);
253 if (data_len <= 0)
254 return &shctx->free.n->data.session;
255 b = b->n;
256 }
257 b = shctx->active.n;
258 while (b != &shctx->active) {
259 int freed;
260
261 shsess_tree_delete(&b->data.session);
262 freed = shsess_free(&b->data.session);
263 if (!head)
264 data_len -= sizeof(b->data.session.data) + (freed-1)*sizeof(b->data.data);
265 else
266 data_len -= freed*sizeof(b->data.data);
267 if (data_len <= 0)
268 return &shctx->free.n->data.session;
269 b = shctx->active.n;
270 }
271 return NULL;
272}
Emeric Brun3e541d12012-09-03 11:14:36 +0200273
Emeric Brunaf9619d2012-11-28 18:47:52 +0100274/* store a session into the cache
275 * s_id : session id padded with zero to SSL_MAX_SSL_SESSION_ID_LENGTH
276 * data: asn1 encoded session
277 * data_len: asn1 encoded session length
278 * Returns 1 id session was stored (else 0)
279 */
280static int shsess_store(unsigned char *s_id, unsigned char *data, int data_len)
281{
282 struct shared_session *shsess, *oldshsess;
283
284 shsess = shsess_get_next(data_len);
285 if (!shsess) {
286 /* Could not retrieve enough free blocks to store that session */
Emeric Brun3e541d12012-09-03 11:14:36 +0200287 return 0;
Emeric Brunaf9619d2012-11-28 18:47:52 +0100288 }
Emeric Brun3e541d12012-09-03 11:14:36 +0200289
Emeric Brunaf9619d2012-11-28 18:47:52 +0100290 /* prepare key */
291 memcpy(shsess->key_data, s_id, SSL_MAX_SSL_SESSION_ID_LENGTH);
Emeric Brun3e541d12012-09-03 11:14:36 +0200292
Emeric Brunaf9619d2012-11-28 18:47:52 +0100293 /* it returns the already existing node
294 or current node if none, never returns null */
295 oldshsess = shsess_tree_insert(shsess);
296 if (oldshsess != shsess) {
297 /* free all blocks used by old node */
298 shsess_free(oldshsess);
299 shsess = oldshsess;
300 }
Emeric Brun3e541d12012-09-03 11:14:36 +0200301
Emeric Brunaf9619d2012-11-28 18:47:52 +0100302 ((struct shared_block *)shsess)->data_len = data_len;
303 if (data_len <= sizeof(shsess->data)) {
304 /* Store on a single block */
305 memcpy(shsess->data, data, data_len);
306 shblock_set_active((struct shared_block *)shsess);
307 }
308 else {
309 unsigned char *p;
310 /* Store on multiple blocks */
311 int cur_len;
Emeric Brun3e541d12012-09-03 11:14:36 +0200312
Emeric Brunaf9619d2012-11-28 18:47:52 +0100313 memcpy(shsess->data, data, sizeof(shsess->data));
314 p = data + sizeof(shsess->data);
315 cur_len = data_len - sizeof(shsess->data);
316 shblock_set_active((struct shared_block *)shsess);
317 while (1) {
318 /* Store next data on free block.
319 * shsess_get_next guarantees that there are enough
320 * free blocks in queue.
321 */
322 struct shared_block *block;
Emeric Brun3e541d12012-09-03 11:14:36 +0200323
Emeric Brunaf9619d2012-11-28 18:47:52 +0100324 block = shctx->free.n;
325 if (cur_len <= sizeof(block->data)) {
326 /* This is the last block */
327 block->data_len = cur_len;
328 memcpy(block->data.data, p, cur_len);
329 shblock_set_active(block);
330 break;
331 }
332 /* Intermediate block */
333 block->data_len = cur_len;
334 memcpy(block->data.data, p, sizeof(block->data));
335 p += sizeof(block->data.data);
336 cur_len -= sizeof(block->data.data);
337 shblock_set_active(block);
338 }
339 }
Emeric Brun3e541d12012-09-03 11:14:36 +0200340
Emeric Brunaf9619d2012-11-28 18:47:52 +0100341 return 1;
342}
Emeric Brun3e541d12012-09-03 11:14:36 +0200343
Emeric Brun3e541d12012-09-03 11:14:36 +0200344
Emeric Brunaf9619d2012-11-28 18:47:52 +0100345/* SSL context callbacks */
Emeric Brun3e541d12012-09-03 11:14:36 +0200346
Emeric Brunaf9619d2012-11-28 18:47:52 +0100347/* SSL callback used on new session creation */
348int shctx_new_cb(SSL *ssl, SSL_SESSION *sess)
349{
350 unsigned char encsess[sizeof(struct shsess_packet)+SHSESS_MAX_DATA_LEN];
351 struct shsess_packet *packet = (struct shsess_packet *)encsess;
352 unsigned char *p;
353 int data_len, sid_length;
Emeric Brun3e541d12012-09-03 11:14:36 +0200354
Emeric Brun3e541d12012-09-03 11:14:36 +0200355
Emeric Brunaf9619d2012-11-28 18:47:52 +0100356 /* Session id is already stored in to key and session id is known
357 * so we dont store it to keep size.
358 */
359 sid_length = sess->session_id_length;
360 sess->session_id_length = 0;
361 sess->sid_ctx_length = 0;
Emeric Brun3e541d12012-09-03 11:14:36 +0200362
Emeric Brunaf9619d2012-11-28 18:47:52 +0100363 /* check if buffer is large enough for the ASN1 encoded session */
364 data_len = i2d_SSL_SESSION(sess, NULL);
365 if (data_len > SHSESS_MAX_DATA_LEN)
366 goto err;
367
368 /* process ASN1 session encoding before the lock */
369 p = packet->data;
370 i2d_SSL_SESSION(sess, &p);
371
372 memcpy(packet->hdr.id, sess->session_id, sid_length);
373 if (sid_length < SSL_MAX_SSL_SESSION_ID_LENGTH)
374 memset(&packet->hdr.id[sid_length], 0, SSL_MAX_SSL_SESSION_ID_LENGTH-sid_length);
375
376 shared_context_lock();
377
378 /* store to cache */
379 shsess_store(packet->hdr.id, packet->data, data_len);
380
381 shared_context_unlock();
382
383err:
384 /* reset original length values */
385 sess->sid_ctx_length = ssl->sid_ctx_length;
386 sess->session_id_length = sid_length;
Emeric Brun3e541d12012-09-03 11:14:36 +0200387
388 return 0; /* do not increment session reference count */
389}
390
391/* SSL callback used on lookup an existing session cause none found in internal cache */
392SSL_SESSION *shctx_get_cb(SSL *ssl, unsigned char *key, int key_len, int *do_copy)
393{
394 struct shared_session *shsess;
395 unsigned char data[SHSESS_MAX_DATA_LEN], *p;
396 unsigned char tmpkey[SSL_MAX_SSL_SESSION_ID_LENGTH];
Emeric Brunaf9619d2012-11-28 18:47:52 +0100397 int data_len;
Emeric Brun3e541d12012-09-03 11:14:36 +0200398 SSL_SESSION *sess;
Emeric Brun3e541d12012-09-03 11:14:36 +0200399
400 /* allow the session to be freed automatically by openssl */
401 *do_copy = 0;
402
403 /* tree key is zeros padded sessionid */
404 if (key_len < SSL_MAX_SSL_SESSION_ID_LENGTH) {
405 memcpy(tmpkey, key, key_len);
406 memset(tmpkey + key_len, 0, SSL_MAX_SSL_SESSION_ID_LENGTH - key_len);
407 key = tmpkey;
408 }
409
410 /* lock cache */
411 shared_context_lock();
412
413 /* lookup for session */
414 shsess = shsess_tree_lookup(key);
415 if (!shsess) {
416 /* no session found: unlock cache and exit */
417 shared_context_unlock();
418 return NULL;
419 }
420
Emeric Brunaf9619d2012-11-28 18:47:52 +0100421 data_len = ((struct shared_block *)shsess)->data_len;
422 if (data_len <= sizeof(shsess->data)) {
423 /* Session stored on single block */
424 memcpy(data, shsess->data, data_len);
425 shblock_set_active((struct shared_block *)shsess);
426 }
427 else {
428 /* Session stored on multiple blocks */
429 struct shared_block *block;
Emeric Brun3e541d12012-09-03 11:14:36 +0200430
Emeric Brunaf9619d2012-11-28 18:47:52 +0100431 memcpy(data, shsess->data, sizeof(shsess->data));
432 p = data + sizeof(shsess->data);
433 block = ((struct shared_block *)shsess)->n;
434 shblock_set_active((struct shared_block *)shsess);
435 while (1) {
436 /* Retrieve data from next block */
437 struct shared_block *next;
Emeric Brun3e541d12012-09-03 11:14:36 +0200438
Emeric Brunaf9619d2012-11-28 18:47:52 +0100439 if (block->data_len <= sizeof(block->data.data)) {
440 /* This is the last block */
441 memcpy(p, block->data.data, block->data_len);
442 p += block->data_len;
443 shblock_set_active(block);
444 break;
445 }
446 /* Intermediate block */
447 memcpy(p, block->data.data, sizeof(block->data.data));
448 p += sizeof(block->data.data);
449 next = block->n;
450 shblock_set_active(block);
451 block = next;
452 }
453 }
Emeric Brun3e541d12012-09-03 11:14:36 +0200454
455 shared_context_unlock();
456
457 /* decode ASN1 session */
458 p = data;
459 sess = d2i_SSL_SESSION(NULL, (const unsigned char **)&p, data_len);
Emeric Brunaf9619d2012-11-28 18:47:52 +0100460 /* Reset session id and session id contenxt */
461 if (sess) {
462 memcpy(sess->session_id, key, key_len);
463 sess->session_id_length = key_len;
464 memcpy(sess->sid_ctx, ssl->sid_ctx, ssl->sid_ctx_length);
465 sess->sid_ctx_length = ssl->sid_ctx_length;
466 }
Emeric Brun3e541d12012-09-03 11:14:36 +0200467
468 return sess;
469}
470
471/* SSL callback used to signal session is no more used in internal cache */
472void shctx_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess)
473{
474 struct shared_session *shsess;
475 unsigned char tmpkey[SSL_MAX_SSL_SESSION_ID_LENGTH];
476 unsigned char *key = sess->session_id;
477 (void)ctx;
478
479 /* tree key is zeros padded sessionid */
480 if (sess->session_id_length < SSL_MAX_SSL_SESSION_ID_LENGTH) {
481 memcpy(tmpkey, sess->session_id, sess->session_id_length);
482 memset(tmpkey+sess->session_id_length, 0, SSL_MAX_SSL_SESSION_ID_LENGTH - sess->session_id_length);
483 key = tmpkey;
484 }
485
486 shared_context_lock();
487
488 /* lookup for session */
489 shsess = shsess_tree_lookup(key);
490 if (shsess) {
Emeric Brunaf9619d2012-11-28 18:47:52 +0100491 /* free session */
492 shsess_tree_delete(shsess);
493 shsess_free(shsess);
Emeric Brun3e541d12012-09-03 11:14:36 +0200494 }
495
496 /* unlock cache */
497 shared_context_unlock();
498}
499
Emeric Brun3e541d12012-09-03 11:14:36 +0200500/* Allocate shared memory context.
Emeric Brunaf9619d2012-11-28 18:47:52 +0100501 * <size> is maximum cached sessions.
Emeric Brun22890a12012-12-28 14:41:32 +0100502 * If <size> is set to less or equal to 0, ssl cache is disabled.
Emeric Brunaf9619d2012-11-28 18:47:52 +0100503 * Returns: -1 on alloc failure, <size> if it performs context alloc,
504 * and 0 if cache is already allocated.
505 */
Emeric Brun4b3091e2012-09-24 15:48:52 +0200506int shared_context_init(int size, int shared)
Emeric Brun3e541d12012-09-03 11:14:36 +0200507{
508 int i;
Emeric Brun9faf0712012-09-25 11:11:16 +0200509#ifndef USE_PRIVATE_CACHE
Emeric Brun3e541d12012-09-03 11:14:36 +0200510#ifndef USE_SYSCALL_FUTEX
511 pthread_mutexattr_t attr;
512#endif /* USE_SYSCALL_FUTEX */
Emeric Brun9faf0712012-09-25 11:11:16 +0200513#endif
Emeric Brunaf9619d2012-11-28 18:47:52 +0100514 struct shared_block *prev,*cur;
Emeric Brun4b3091e2012-09-24 15:48:52 +0200515 int maptype = MAP_PRIVATE;
Emeric Brun3e541d12012-09-03 11:14:36 +0200516
517 if (shctx)
518 return 0;
519
520 if (size<=0)
Emeric Brun22890a12012-12-28 14:41:32 +0100521 return 0;
Emeric Brun3e541d12012-09-03 11:14:36 +0200522
Emeric Brunaf9619d2012-11-28 18:47:52 +0100523 /* Increate size by one to reserve one node for lookup */
524 size++;
Emeric Brun9faf0712012-09-25 11:11:16 +0200525#ifndef USE_PRIVATE_CACHE
Emeric Brun4b3091e2012-09-24 15:48:52 +0200526 if (shared)
527 maptype = MAP_SHARED;
Emeric Brun9faf0712012-09-25 11:11:16 +0200528#endif
Emeric Brun4b3091e2012-09-24 15:48:52 +0200529
Emeric Brunaf9619d2012-11-28 18:47:52 +0100530 shctx = (struct shared_context *)mmap(NULL, sizeof(struct shared_context)+(size*sizeof(struct shared_block)),
Emeric Brun4b3091e2012-09-24 15:48:52 +0200531 PROT_READ | PROT_WRITE, maptype | MAP_ANON, -1, 0);
Emeric Brun3e541d12012-09-03 11:14:36 +0200532 if (!shctx || shctx == MAP_FAILED) {
533 shctx = NULL;
534 return -1;
535 }
536
Emeric Brun9faf0712012-09-25 11:11:16 +0200537#ifndef USE_PRIVATE_CACHE
Emeric Brun3e541d12012-09-03 11:14:36 +0200538#ifdef USE_SYSCALL_FUTEX
539 shctx->waiters = 0;
540#else
541 pthread_mutexattr_init(&attr);
542 pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
543 pthread_mutex_init(&shctx->mutex, &attr);
544#endif
Emeric Brun4b3091e2012-09-24 15:48:52 +0200545 if (maptype == MAP_SHARED)
546 use_shared_mem = 1;
Emeric Brun9faf0712012-09-25 11:11:16 +0200547#endif
Emeric Brun4b3091e2012-09-24 15:48:52 +0200548
Emeric Brunaf9619d2012-11-28 18:47:52 +0100549 memset(&shctx->active.data.session.key, 0, sizeof(struct ebmb_node));
550 memset(&shctx->free.data.session.key, 0, sizeof(struct ebmb_node));
Emeric Brun3e541d12012-09-03 11:14:36 +0200551
552 /* No duplicate authorized in tree: */
Emeric Brunaf9619d2012-11-28 18:47:52 +0100553 shctx->active.data.session.key.node.branches = EB_ROOT_UNIQUE;
554
555 /* Init remote update cache */
556 shctx->upd.eol = 0;
557 shctx->upd.seq = 0;
558 shctx->data_len = 0;
Emeric Brun3e541d12012-09-03 11:14:36 +0200559
560 cur = &shctx->active;
561 cur->n = cur->p = cur;
562
563 cur = &shctx->free;
564 for (i = 0 ; i < size ; i++) {
565 prev = cur;
Emeric Brunaf9619d2012-11-28 18:47:52 +0100566 cur = (struct shared_block *)((char *)prev + sizeof(struct shared_block));
Emeric Brun3e541d12012-09-03 11:14:36 +0200567 prev->n = cur;
568 cur->p = prev;
569 }
570 cur->n = &shctx->free;
571 shctx->free.p = cur;
572
573 return size;
574}
575
576
577/* Set session cache mode to server and disable openssl internal cache.
578 * Set shared cache callbacks on an ssl context.
579 * Shared context MUST be firstly initialized */
580void shared_context_set_cache(SSL_CTX *ctx)
581{
Emeric Brun786991e2012-11-26 18:37:12 +0100582 SSL_CTX_set_session_id_context(ctx, (const unsigned char *)SHCTX_APPNAME, strlen(SHCTX_APPNAME));
583
Emeric Brun22890a12012-12-28 14:41:32 +0100584 if (!shctx) {
585 SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
Emeric Brun3e541d12012-09-03 11:14:36 +0200586 return;
Emeric Brun22890a12012-12-28 14:41:32 +0100587 }
588
589 SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER |
590 SSL_SESS_CACHE_NO_INTERNAL |
591 SSL_SESS_CACHE_NO_AUTO_CLEAR);
Emeric Brun3e541d12012-09-03 11:14:36 +0200592
593 /* Set callbacks */
594 SSL_CTX_sess_set_new_cb(ctx, shctx_new_cb);
595 SSL_CTX_sess_set_get_cb(ctx, shctx_get_cb);
596 SSL_CTX_sess_set_remove_cb(ctx, shctx_remove_cb);
597}