"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