"Fossies" - the Fresh Open Source Software Archive 
Member "stud-0.3/shctx.c" (2 Nov 2011, 8334 Bytes) of package /linux/privat/old/stud-0.3.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "shctx.c" see the
Fossies "Dox" file reference documentation.
1 /*
2 * shctx.c
3 *
4 * Copyright (C) 2011 EXCELIANCE
5 *
6 * Author: Emeric Brun - emeric@exceliance.fr
7 *
8 */
9 #include <sys/mman.h>
10 #ifdef USE_SYSCALL_FUTEX
11 #include <unistd.h>
12 #include <linux/futex.h>
13 #include <sys/syscall.h>
14 #else /* USE_SYSCALL_FUTEX */
15 #include <pthread.h>
16 #endif /* USE_SYSCALL_FUTEX */
17
18 #include "ebtree/ebmbtree.h"
19 #include "shctx.h"
20
21 #ifndef SHSESS_MAX_DATA_LEN
22 #define SHSESS_MAX_DATA_LEN 512
23 #endif
24
25 struct shared_session {
26 struct ebmb_node key;
27 unsigned char key_data[SSL_MAX_SSL_SESSION_ID_LENGTH];
28 int data_len;
29 unsigned char data[SHSESS_MAX_DATA_LEN];
30 struct shared_session *p;
31 struct shared_session *n;
32 };
33
34
35 struct shared_context {
36 #ifdef USE_SYSCALL_FUTEX
37 unsigned int waiters;
38 #else /* USE_SYSCALL_FUTEX */
39 pthread_mutex_t mutex;
40 #endif
41 struct shared_session active;
42 struct shared_session free;
43 };
44
45 /* Static shared context */
46 static struct shared_context *shctx = NULL;
47
48
49 /* Lock functions */
50 #ifdef USE_SYSCALL_FUTEX
51 static inline unsigned int xchg(unsigned int *ptr, unsigned int x)
52 {
53 __asm volatile("lock xchgl %0,%1"
54 : "=r" (x), "+m" (*ptr)
55 : "0" (x)
56 : "memory");
57 return x;
58 }
59
60 static inline unsigned int cmpxchg(unsigned int *ptr, unsigned int old, unsigned int new)
61 {
62 unsigned int ret;
63
64 __asm volatile("lock cmpxchgl %2,%1"
65 : "=a" (ret), "+m" (*ptr)
66 : "r" (new), "0" (old)
67 : "memory");
68 return ret;
69 }
70
71 static inline unsigned char atomic_inc(unsigned int *ptr)
72 {
73 unsigned char ret;
74 __asm volatile("lock incl %0\n"
75 "setne %1\n"
76 : "+m" (*ptr), "=qm" (ret)
77 :
78 : "memory");
79 return ret;
80 }
81
82 static inline unsigned char atomic_dec(unsigned int *ptr)
83 {
84 unsigned char ret;
85 __asm volatile("lock decl %0\n"
86 "setne %1\n"
87 : "+m" (*ptr), "=qm" (ret)
88 :
89 : "memory");
90 return ret;
91 }
92
93 static inline void shared_context_lock(void)
94 {
95 unsigned int x;
96
97 x = cmpxchg(&shctx->waiters, 0, 1);
98 if (x) {
99 if (x != 2)
100 x = xchg(&shctx->waiters, 2);
101
102 while (x) {
103 syscall(SYS_futex, &shctx->waiters, FUTEX_WAIT, 2, NULL, 0, 0);
104 x = xchg(&shctx->waiters, 2);
105 }
106 }
107 }
108
109 static inline void shared_context_unlock(void)
110 {
111 if (atomic_dec(&shctx->waiters)) {
112 shctx->waiters = 0;
113 syscall(SYS_futex, &shctx->waiters, FUTEX_WAKE, 1, NULL, 0, 0);
114 }
115 }
116
117 #else /* USE_SYSCALL_FUTEX */
118
119 #define shared_context_lock(v) pthread_mutex_lock(&shctx->mutex)
120 #define shared_context_unlock(v) pthread_mutex_unlock(&shctx->mutex)
121
122 #endif
123
124 /* List Macros */
125
126 #define shsess_unset(s) (s)->n->p = (s)->p; \
127 (s)->p->n = (s)->n;
128
129 #define shsess_set_free(s) shsess_unset(s) \
130 (s)->p = &shctx->free; \
131 (s)->n = shctx->free.n; \
132 shctx->free.n->p = s; \
133 shctx->free.n = s;
134
135
136 #define shsess_set_active(s) shsess_unset(s) \
137 (s)->p = &shctx->active; \
138 (s)->n = shctx->active.n; \
139 shctx->active.n->p = s; \
140 shctx->active.n = s;
141
142
143 #define shsess_get_next() (shctx->free.p == shctx->free.n) ? \
144 shctx->active.p : shctx->free.p;
145
146 /* Tree Macros */
147
148 #define shsess_tree_delete(s) ebmb_delete(&(s)->key);
149
150 #define shsess_tree_insert(s) (struct shared_session *)ebmb_insert(&shctx->active.key.node.branches, \
151 &(s)->key, SSL_MAX_SSL_SESSION_ID_LENGTH);
152
153 #define shsess_tree_lookup(k) (struct shared_session *)ebmb_lookup(&shctx->active.key.node.branches, \
154 (k), SSL_MAX_SSL_SESSION_ID_LENGTH);
155
156 /* Other Macros */
157
158 #define shsess_set_key(s,k,l) { memcpy((s)->key_data, (k), (l)); \
159 if ((l) < SSL_MAX_SSL_SESSION_ID_LENGTH) \
160 memset((s)->key_data+(l), 0, SSL_MAX_SSL_SESSION_ID_LENGTH-(l)); };
161
162
163 /* SSL context callbacks */
164
165 /* SSL callback used on new session creation */
166 int shctx_new_cb(SSL *ssl, SSL_SESSION *sess) {
167 (void)ssl;
168 struct shared_session *shsess;
169 unsigned char data[SHSESS_MAX_DATA_LEN],*p;
170 unsigned int data_len;
171
172 /* check if session reserved size in aligned buffer is large enougth for the ASN1 encode session */
173 data_len=i2d_SSL_SESSION(sess, NULL);
174 if(data_len > SHSESS_MAX_DATA_LEN)
175 return 1;
176
177 /* process ASN1 session encoding before the lock: lower cost */
178 p = data;
179 i2d_SSL_SESSION(sess, &p);
180
181 shared_context_lock();
182
183 shsess = shsess_get_next();
184
185 shsess_tree_delete(shsess);
186
187 shsess_set_key(shsess, sess->session_id, sess->session_id_length);
188
189 /* it returns the already existing node or current node if none, never returns null */
190 shsess = shsess_tree_insert(shsess);
191
192 /* store ASN1 encoded session into cache */
193 shsess->data_len = data_len;
194 memcpy(shsess->data, data, data_len);
195
196 shsess_set_active(shsess);
197
198 shared_context_unlock();
199
200 return 1; /* leave the session in local cache for reuse */
201 }
202
203 /* SSL callback used on lookup an existing session cause none found in internal cache */
204 SSL_SESSION *shctx_get_cb(SSL *ssl, unsigned char *key, int key_len, int *do_copy) {
205 (void)ssl;
206 struct shared_session *shsess;
207 unsigned char data[SHSESS_MAX_DATA_LEN], *p;
208 unsigned char tmpkey[SSL_MAX_SSL_SESSION_ID_LENGTH];
209 unsigned int data_len;
210 SSL_SESSION *sess;
211
212 /* allow the session to be freed automatically by openssl */
213 *do_copy = 0;
214
215 /* tree key is zeros padded sessionid */
216 if ( key_len < SSL_MAX_SSL_SESSION_ID_LENGTH ) {
217 memcpy(tmpkey, key, key_len);
218 memset(tmpkey+key_len, 0, SSL_MAX_SSL_SESSION_ID_LENGTH-key_len);
219 key = tmpkey;
220 }
221
222 /* lock cache */
223 shared_context_lock();
224
225 /* lookup for session */
226 shsess = shsess_tree_lookup(key);
227 if(!shsess) {
228 /* no session found: unlock cache and exit */
229 shared_context_unlock();
230 return NULL;
231 }
232
233 /* copy ASN1 session data to decode outside the lock */
234 data_len = shsess->data_len;
235 memcpy(data, shsess->data, shsess->data_len);
236
237 shsess_set_active(shsess);
238
239 shared_context_unlock();
240
241 /* decode ASN1 session */
242 p = data;
243 sess = d2i_SSL_SESSION(NULL, (const unsigned char **)&p, data_len);
244
245 return sess;
246 }
247
248 /* SSL callback used to signal session is no more used in internal cache */
249 void shctx_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess) {
250 (void)ctx;
251 struct shared_session *shsess;
252 unsigned char tmpkey[SSL_MAX_SSL_SESSION_ID_LENGTH];
253 unsigned char *key = sess->session_id;
254
255 /* tree key is zeros padded sessionid */
256 if ( sess->session_id_length < SSL_MAX_SSL_SESSION_ID_LENGTH ) {
257 memcpy(tmpkey, sess->session_id, sess->session_id_length);
258 memset(tmpkey+sess->session_id_length, 0, SSL_MAX_SSL_SESSION_ID_LENGTH-sess->session_id_length);
259 key = tmpkey;
260 }
261
262 shared_context_lock();
263
264 /* lookup for session */
265 shsess = shsess_tree_lookup(key);
266 if ( shsess ) {
267 shsess_set_free(shsess);
268 }
269
270 /* unlock cache */
271 shared_context_unlock();
272 }
273
274 /* Init shared memory context if not allocated and set SSL context callbacks
275 * size is the max number of stored session
276 * Returns: -1 on alloc failure, size if performs context alloc, and 0 if just perform
277 * callbacks registration */
278 int shared_context_init(SSL_CTX *ctx, int size)
279 {
280 int ret = 0;
281
282 if (!shctx) {
283 int i;
284
285 #ifndef USE_SYSCALL_FUTEX
286 pthread_mutexattr_t attr;
287 #endif /* USE_SYSCALL_FUTEX */
288 struct shared_session *prev,*cur;
289
290 shctx = (struct shared_context *)mmap(NULL, sizeof(struct shared_context)+(size*sizeof(struct shared_session)),
291 PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
292 if (!shctx)
293 return -1;
294
295 #ifdef USE_SYSCALL_FUTEX
296 shctx->waiters = 0;
297 #else
298 pthread_mutexattr_init(&attr);
299 pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
300 pthread_mutex_init(&shctx->mutex, &attr);
301 #endif
302 memset(&shctx->active.key, 0, sizeof(struct ebmb_node));
303 memset(&shctx->free.key, 0, sizeof(struct ebmb_node));
304
305 /* No duplicate authorized in tree: */
306 shctx->active.key.node.branches.b[1] = (void *)1;
307
308 cur = &shctx->active;
309 cur->n = cur->p = cur;
310
311 cur = &shctx->free;
312 for ( i = 0 ; i < size ; i++) {
313 prev = cur;
314 cur = (struct shared_session *)((char *)prev + sizeof(struct shared_session));
315 prev->n = cur;
316 cur->p = prev;
317 }
318 cur->n = &shctx->free;
319 shctx->free.p = cur;
320
321 ret = size;
322 }
323
324 /* set SSL internal cache size to external cache / 8 + 123 */
325 SSL_CTX_sess_set_cache_size(ctx, size >> 3 | 0x3ff);
326
327 /* Set callbacks */
328 SSL_CTX_sess_set_new_cb(ctx, shctx_new_cb);
329 SSL_CTX_sess_set_get_cb(ctx, shctx_get_cb);
330 SSL_CTX_sess_set_remove_cb(ctx, shctx_remove_cb);
331
332 return ret;
333 }
334