diff src/event/ngx_event_openssl.c @ 274:052a7b1d40e5 NGINX_0_5_7

nginx 0.5.7 *) Feature: the ssl_session_cache storage optimization. *) Bugfixes in the "ssl_session_cache" and "limit_zone" directives. *) Bugfix: the segmentation fault was occurred on start or while reconfiguration if the "ssl_session_cache" or "limit_zone" directives were used on 64-bit platforms. *) Bugfix: a segmentation fault occurred if the "add_before_body" or "add_after_body" directives were used and there was no "Content-Type" header line in response. *) Bugfix: the OpenSSL library was always built with the threads support. Thanks to Den Ivanov. *) Bugfix: the PCRE-6.5+ library and the icc compiler compatibility.
author Igor Sysoev <http://sysoev.ru>
date Mon, 15 Jan 2007 00:00:00 +0300
parents 29a6403156b0
children c5c2b2883984
line wrap: on
line diff
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -32,6 +32,8 @@ static ngx_ssl_session_t *ngx_ssl_get_ca
 static void ngx_ssl_remove_session(SSL_CTX *ssl, ngx_ssl_session_t *sess);
 static void ngx_ssl_expire_sessions(ngx_ssl_session_cache_t *cache,
     ngx_slab_pool_t *shpool, ngx_uint_t n);
+static void ngx_ssl_session_rbtree_insert_value(ngx_rbtree_node_t *temp,
+    ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
 
 static void *ngx_openssl_create_conf(ngx_cycle_t *cycle);
 static char *ngx_openssl_init_conf(ngx_cycle_t *cycle, void *conf);
@@ -1160,10 +1162,10 @@ ngx_ssl_session_cache(ngx_ssl_t *ssl, ng
         if (builtin_session_cache != NGX_SSL_DFLT_BUILTIN_SCACHE) {
             SSL_CTX_sess_set_cache_size(ssl->ctx, builtin_session_cache);
         }
-
-        SSL_CTX_set_timeout(ssl->ctx, timeout);
     }
 
+    SSL_CTX_set_timeout(ssl->ctx, timeout);
+
     if (shm_zone) {
         shm_zone->init = ngx_ssl_session_cache_init;
 
@@ -1223,7 +1225,7 @@ ngx_ssl_session_cache_init(ngx_shm_zone_
 
     cache->session_rbtree->root = sentinel;
     cache->session_rbtree->sentinel = sentinel;
-    cache->session_rbtree->insert = ngx_rbtree_insert_value;
+    cache->session_rbtree->insert = ngx_ssl_session_rbtree_insert_value;
 
     shm_zone->data = cache;
 
@@ -1232,6 +1234,18 @@ ngx_ssl_session_cache_init(ngx_shm_zone_
 
 
 /*
+ * The length of the session id is 16 bytes for SSLv2 sessions and
+ * between 1 and 32 bytes for SSLv3/TLSv1, typically 32 bytes.
+ * It seems that the typical length of the external ASN1 representation
+ * of a session is 118 or 119 bytes for SSLv3/TSLv1.
+ *
+ * Thus on 32-bit platforms we allocate separately an rbtree node,
+ * a session id, and an ASN1 representation, they take accordingly
+ * 64, 32, and 128 bytes.
+ *
+ * On 64-bit platforms we allocate separately an rbtree node + session_id,
+ * and an ASN1 representation, they take accordingly 128 and 128 bytes.
+ *
  * OpenSSL's i2d_SSL_SESSION() and d2i_SSL_SESSION are slow,
  * so they are outside the code locked by shared pool mutex
  */
@@ -1240,7 +1254,7 @@ static int
 ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess)
 {
     int                       len;
-    u_char                   *p, *id;
+    u_char                   *p, *id, *cached_sess;
     uint32_t                  hash;
     SSL_CTX                  *ssl_ctx;
     ngx_time_t               *tp;
@@ -1248,7 +1262,6 @@ ngx_ssl_new_session(ngx_ssl_conn_t *ssl_
     ngx_connection_t         *c;
     ngx_slab_pool_t          *shpool;
     ngx_ssl_sess_id_t        *sess_id;
-    ngx_ssl_cached_sess_t    *cached_sess;
     ngx_ssl_session_cache_t  *cache;
     u_char                    buf[NGX_SSL_MAX_SESSION_SIZE];
 
@@ -1276,8 +1289,7 @@ ngx_ssl_new_session(ngx_ssl_conn_t *ssl_
     /* drop one or two expired sessions */
     ngx_ssl_expire_sessions(cache, shpool, 1);
 
-    cached_sess = ngx_slab_alloc_locked(shpool,
-                                  offsetof(ngx_ssl_cached_sess_t, asn1) + len);
+    cached_sess = ngx_slab_alloc_locked(shpool, len);
 
     if (cached_sess == NULL) {
 
@@ -1285,26 +1297,33 @@ ngx_ssl_new_session(ngx_ssl_conn_t *ssl_
 
         ngx_ssl_expire_sessions(cache, shpool, 0);
 
-        cached_sess = ngx_slab_alloc_locked(shpool,
-                                  offsetof(ngx_ssl_cached_sess_t, asn1) + len);
+        cached_sess = ngx_slab_alloc_locked(shpool, len);
 
         if (cached_sess == NULL) {
-            id = NULL;
+            sess_id = NULL;
             goto failed;
         }
     }
 
-    id = ngx_slab_alloc_locked(shpool, sess->session_id_length);
-    if (id == NULL) {
-        goto failed;
-    }
-
     sess_id = ngx_slab_alloc_locked(shpool, sizeof(ngx_ssl_sess_id_t));
     if (sess_id == NULL) {
         goto failed;
     }
 
-    ngx_memcpy(&cached_sess->asn1[0], buf, len);
+#if (NGX_PTR_SIZE == 8)
+
+    id = sess_id->sess_id;
+
+#else
+
+    id = ngx_slab_alloc_locked(shpool, sess->session_id_length);
+    if (id == NULL) {
+        goto failed;
+    }
+
+#endif
+
+    ngx_memcpy(cached_sess, buf, len);
 
     ngx_memcpy(id, sess->session_id, sess->session_id_length);
 
@@ -1314,21 +1333,20 @@ ngx_ssl_new_session(ngx_ssl_conn_t *ssl_
                    "http ssl new session: %08XD:%d:%d",
                    hash, sess->session_id_length, len);
 
+    tp = ngx_timeofday();
+
     sess_id->node.key = hash;
     sess_id->node.data = (u_char) sess->session_id_length;
     sess_id->id = id;
     sess_id->len = len;
     sess_id->session = cached_sess;
 
-    tp = ngx_timeofday();
-
-    cached_sess->expire = tp->sec + SSL_CTX_get_timeout(ssl_ctx);
-    cached_sess->sess_id = sess_id;
-
-    cached_sess->next = cache->session_cache_head.next;
-    cached_sess->next->prev = cached_sess;
-    cached_sess->prev = &cache->session_cache_head;
-    cache->session_cache_head.next = cached_sess;
+    sess_id->expire = tp->sec + SSL_CTX_get_timeout(ssl_ctx);
+
+    sess_id->next = cache->session_cache_head.next;
+    sess_id->next->prev = sess_id;
+    sess_id->prev = &cache->session_cache_head;
+    cache->session_cache_head.next = sess_id;
 
     ngx_rbtree_insert(cache->session_rbtree, &sess_id->node);
 
@@ -1342,8 +1360,8 @@ failed:
         ngx_slab_free_locked(shpool, cached_sess);
     }
 
-    if (id) {
-        ngx_slab_free_locked(shpool, id);
+    if (sess_id) {
+        ngx_slab_free_locked(shpool, sess_id);
     }
 
     ngx_shmtx_unlock(&shpool->mutex);
@@ -1364,6 +1382,7 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_
 #endif
     u_char                   *p;
     uint32_t                  hash;
+    ngx_int_t                 rc;
     ngx_time_t               *tp;
     ngx_shm_zone_t           *shm_zone;
     ngx_slab_pool_t          *shpool;
@@ -1371,13 +1390,12 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_
     ngx_rbtree_node_t        *node, *sentinel;
     ngx_ssl_session_t        *sess;
     ngx_ssl_sess_id_t        *sess_id;
-    ngx_ssl_cached_sess_t    *cached_sess;
     ngx_ssl_session_cache_t  *cache;
     u_char                    buf[NGX_SSL_MAX_SESSION_SIZE];
 
     c = ngx_ssl_get_connection(ssl_conn);
 
-    hash = ngx_crc32_short(id, len);
+    hash = ngx_crc32_short(id, (size_t) len);
     *copy = 0;
 
     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
@@ -1413,17 +1431,19 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_
             continue;
         }
 
-        if (hash == node->key && (u_char) len == node->data) {
+        /* hash == node->key */
+
+        do {
             sess_id = (ngx_ssl_sess_id_t *) node;
 
-            if (ngx_strncmp(id, sess_id->id, len) == 0) {
-
-                cached_sess = sess_id->session;
+            rc = ngx_memn2cmp(id, sess_id->id,
+                              (size_t) len, (size_t) node->data);
+            if (rc == 0) {
 
                 tp = ngx_timeofday();
 
-                if (cached_sess->expire > tp->sec) {
-                    ngx_memcpy(buf, &cached_sess->asn1[0], sess_id->len);
+                if (sess_id->expire > tp->sec) {
+                    ngx_memcpy(buf, sess_id->session, sess_id->len);
 
                     ngx_shmtx_unlock(&shpool->mutex);
 
@@ -1433,24 +1453,31 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_
                     return sess;
                 }
 
-                cached_sess->next->prev = cached_sess->prev;
-                cached_sess->prev->next = cached_sess->next;
+                sess_id->next->prev = sess_id->prev;
+                sess_id->prev->next = sess_id->next;
 
                 ngx_rbtree_delete(cache->session_rbtree, node);
 
-                ngx_slab_free_locked(shpool, cached_sess);
+                ngx_slab_free_locked(shpool, sess_id->session);
+#if (NGX_PTR_SIZE == 4)
                 ngx_slab_free_locked(shpool, sess_id->id);
+#endif
                 ngx_slab_free_locked(shpool, sess_id);
 
                 sess = NULL;
 
-                break;
+                goto done;
             }
-        }
-
-        node = node->right;
+
+            node = (rc < 0) ? node->left : node->right;
+
+        } while (node != sentinel && hash == node->key);
+
+        break;
     }
 
+done:
+
     ngx_shmtx_unlock(&shpool->mutex);
 
     return sess;
@@ -1460,13 +1487,14 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_
 static void
 ngx_ssl_remove_session(SSL_CTX *ssl, ngx_ssl_session_t *sess)
 {
-    u_char                   *id, len;
+    size_t                    len;
+    u_char                   *id;
     uint32_t                  hash;
+    ngx_int_t                 rc;
     ngx_shm_zone_t           *shm_zone;
     ngx_slab_pool_t          *shpool;
     ngx_rbtree_node_t        *node, *sentinel;
     ngx_ssl_sess_id_t        *sess_id;
-    ngx_ssl_cached_sess_t    *cached_sess;
     ngx_ssl_session_cache_t  *cache;
 
     shm_zone = SSL_CTX_get_ex_data(ssl, ngx_ssl_session_cache_index);
@@ -1474,12 +1502,12 @@ ngx_ssl_remove_session(SSL_CTX *ssl, ngx
     cache = shm_zone->data;
 
     id = sess->session_id;
-    len = (u_char) sess->session_id_length;
-
-    hash = ngx_crc32_short(id, (size_t) len);
+    len = (size_t) sess->session_id_length;
+
+    hash = ngx_crc32_short(id, len);
 
     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0,
-                   "http ssl remove session: %08XD:%d", hash, len);
+                   "http ssl remove session: %08XD:%uz", hash, len);
 
     shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
 
@@ -1500,29 +1528,37 @@ ngx_ssl_remove_session(SSL_CTX *ssl, ngx
             continue;
         }
 
-        if (hash == node->key && len == node->data) {
+        /* hash == node->key */
+
+        do {
             sess_id = (ngx_ssl_sess_id_t *) node;
 
-            if (ngx_strncmp(id, sess_id->id, (size_t) len) == 0) {
-
-                cached_sess = sess_id->session;
-
-                cached_sess->next->prev = cached_sess->prev;
-                cached_sess->prev->next = cached_sess->next;
+            rc = ngx_memn2cmp(id, sess_id->id, len, (size_t) node->data);
+
+            if (rc == 0) {
+                sess_id->next->prev = sess_id->prev;
+                sess_id->prev->next = sess_id->next;
 
                 ngx_rbtree_delete(cache->session_rbtree, node);
 
-                ngx_slab_free_locked(shpool, cached_sess);
+                ngx_slab_free_locked(shpool, sess_id->session);
+#if (NGX_PTR_SIZE == 4)
                 ngx_slab_free_locked(shpool, sess_id->id);
+#endif
                 ngx_slab_free_locked(shpool, sess_id);
 
-                break;
+                goto done;
             }
-        }
-
-        node = node->right;
+
+            node = (rc < 0) ? node->left : node->right;
+
+        } while (node != sentinel && hash == node->key);
+
+        break;
     }
 
+done:
+
     ngx_shmtx_unlock(&shpool->mutex);
 }
 
@@ -1531,41 +1567,101 @@ static void
 ngx_ssl_expire_sessions(ngx_ssl_session_cache_t *cache,
     ngx_slab_pool_t *shpool, ngx_uint_t n)
 {
-    ngx_time_t                  *tp;
-    ngx_ssl_sess_id_t      *sess_id;
-    ngx_ssl_cached_sess_t  *sess;
+    ngx_time_t         *tp;
+    ngx_ssl_sess_id_t  *sess_id;
 
     tp = ngx_timeofday();
 
     while (n < 3) {
 
-        sess = cache->session_cache_tail.prev;
-
-        if (sess == &cache->session_cache_head) {
+        sess_id = cache->session_cache_tail.prev;
+
+        if (sess_id == &cache->session_cache_head) {
             return;
         }
 
-        if (n++ != 0 && sess->expire > tp->sec) {
+        if (n++ != 0 && sess_id->expire > tp->sec) {
             break;
         }
 
-        sess->next->prev = sess->prev;
-        sess->prev->next = sess->next;
-
-        sess_id = sess->sess_id;
+        sess_id->next->prev = sess_id->prev;
+        sess_id->prev->next = sess_id->next;
 
         ngx_rbtree_delete(cache->session_rbtree, &sess_id->node);
 
         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0,
                        "expire session: %08Xi", sess_id->node.key);
 
-        ngx_slab_free_locked(shpool, sess);
+        ngx_slab_free_locked(shpool, sess_id->session);
+#if (NGX_PTR_SIZE == 4)
         ngx_slab_free_locked(shpool, sess_id->id);
+#endif
         ngx_slab_free_locked(shpool, sess_id);
     }
 }
 
 
+static void
+ngx_ssl_session_rbtree_insert_value(ngx_rbtree_node_t *temp,
+    ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
+{
+    ngx_ssl_sess_id_t  *sess_id, *sess_id_temp;
+
+    for ( ;; ) {
+
+        if (node->key < temp->key) {
+
+            if (temp->left == sentinel) {
+                temp->left = node;
+                break;
+            }
+
+            temp = temp->left;
+
+        } else if (node->key > temp->key) {
+
+            if (temp->right == sentinel) { 
+                temp->right = node;
+                break;
+            }
+
+            temp = temp->right;
+
+        } else { /* node->key == temp->key */
+
+            sess_id = (ngx_ssl_sess_id_t *) node;
+            sess_id_temp = (ngx_ssl_sess_id_t *) temp;
+
+            if (ngx_memn2cmp(sess_id->id, sess_id_temp->id,
+                             (size_t) node->data, (size_t) temp->data)
+                < 0)
+            {
+                if (temp->left == sentinel) {
+                    temp->left = node;
+                    break;
+                }
+
+                temp = temp->left;
+    
+            } else {
+    
+                if (temp->right == sentinel) {
+                    temp->right = node;
+                    break;
+                }
+
+                temp = temp->right;
+            }
+        }
+    }
+
+    node->parent = temp;
+    node->left = sentinel;
+    node->right = sentinel;
+    ngx_rbt_red(node);
+}   
+
+
 void
 ngx_ssl_cleanup_ctx(void *data)
 {