Mercurial > hg > nginx
comparison src/event/ngx_event_openssl.c @ 8078:5244d3b165ff
SSL: single allocation in session cache on 32-bit platforms.
Given the present typical SSL session sizes, on 32-bit platforms it is
now beneficial to store all data in a single allocation, since rbtree
node + session id + ASN1 representation of a session takes 256 bytes of
shared memory (36 + 32 + 150 = about 218 bytes plus SNI server name).
Storing all data in a single allocation is beneficial for SNI names up to
about 40 characters long and makes it possible to store about 4000 sessions
in one megabyte (instead of about 3000 sessions now). This also slightly
simplifies the code.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Wed, 12 Oct 2022 20:14:40 +0300 |
parents | ec1fa010c3a5 |
children | f106f4a68faf |
comparison
equal
deleted
inserted
replaced
8077:ec1fa010c3a5 | 8078:5244d3b165ff |
---|---|
3792 * The length of the session id is 16 bytes for SSLv2 sessions and | 3792 * The length of the session id is 16 bytes for SSLv2 sessions and |
3793 * between 1 and 32 bytes for SSLv3 and TLS, typically 32 bytes. | 3793 * between 1 and 32 bytes for SSLv3 and TLS, typically 32 bytes. |
3794 * Typical length of the external ASN1 representation of a session | 3794 * Typical length of the external ASN1 representation of a session |
3795 * is about 150 bytes plus SNI server name. | 3795 * is about 150 bytes plus SNI server name. |
3796 * | 3796 * |
3797 * On 32-bit platforms we allocate separately an rbtree node, | 3797 * On 32-bit platforms we allocate an rbtree node, a session id, and |
3798 * a session id, and an ASN1 representation, they take accordingly | 3798 * an ASN1 representation in a single allocation, it typically takes |
3799 * 64, 32, and 256 bytes. | 3799 * 256 bytes. |
3800 * | 3800 * |
3801 * On 64-bit platforms we allocate separately an rbtree node + session_id, | 3801 * On 64-bit platforms we allocate separately an rbtree node + session_id, |
3802 * and an ASN1 representation, they take accordingly 128 and 256 bytes. | 3802 * and an ASN1 representation, they take accordingly 128 and 256 bytes. |
3803 * | 3803 * |
3804 * OpenSSL's i2d_SSL_SESSION() and d2i_SSL_SESSION are slow, | 3804 * OpenSSL's i2d_SSL_SESSION() and d2i_SSL_SESSION are slow, |
3807 | 3807 |
3808 static int | 3808 static int |
3809 ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess) | 3809 ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess) |
3810 { | 3810 { |
3811 int len; | 3811 int len; |
3812 u_char *p, *id, *cached_sess, *session_id; | 3812 u_char *p, *session_id; |
3813 size_t n; | |
3813 uint32_t hash; | 3814 uint32_t hash; |
3814 SSL_CTX *ssl_ctx; | 3815 SSL_CTX *ssl_ctx; |
3815 unsigned int session_id_length; | 3816 unsigned int session_id_length; |
3816 ngx_shm_zone_t *shm_zone; | 3817 ngx_shm_zone_t *shm_zone; |
3817 ngx_connection_t *c; | 3818 ngx_connection_t *c; |
3867 ngx_shmtx_lock(&shpool->mutex); | 3868 ngx_shmtx_lock(&shpool->mutex); |
3868 | 3869 |
3869 /* drop one or two expired sessions */ | 3870 /* drop one or two expired sessions */ |
3870 ngx_ssl_expire_sessions(cache, shpool, 1); | 3871 ngx_ssl_expire_sessions(cache, shpool, 1); |
3871 | 3872 |
3872 cached_sess = ngx_slab_alloc_locked(shpool, len); | 3873 #if (NGX_PTR_SIZE == 8) |
3873 | 3874 n = sizeof(ngx_ssl_sess_id_t); |
3874 if (cached_sess == NULL) { | 3875 #else |
3876 n = offsetof(ngx_ssl_sess_id_t, session) + len; | |
3877 #endif | |
3878 | |
3879 sess_id = ngx_slab_alloc_locked(shpool, n); | |
3880 | |
3881 if (sess_id == NULL) { | |
3875 | 3882 |
3876 /* drop the oldest non-expired session and try once more */ | 3883 /* drop the oldest non-expired session and try once more */ |
3877 | 3884 |
3878 ngx_ssl_expire_sessions(cache, shpool, 0); | 3885 ngx_ssl_expire_sessions(cache, shpool, 0); |
3879 | 3886 |
3880 cached_sess = ngx_slab_alloc_locked(shpool, len); | 3887 sess_id = ngx_slab_alloc_locked(shpool, n); |
3881 | |
3882 if (cached_sess == NULL) { | |
3883 sess_id = NULL; | |
3884 goto failed; | |
3885 } | |
3886 } | |
3887 | |
3888 sess_id = ngx_slab_alloc_locked(shpool, sizeof(ngx_ssl_sess_id_t)); | |
3889 | |
3890 if (sess_id == NULL) { | |
3891 | |
3892 /* drop the oldest non-expired session and try once more */ | |
3893 | |
3894 ngx_ssl_expire_sessions(cache, shpool, 0); | |
3895 | |
3896 sess_id = ngx_slab_alloc_locked(shpool, sizeof(ngx_ssl_sess_id_t)); | |
3897 | 3888 |
3898 if (sess_id == NULL) { | 3889 if (sess_id == NULL) { |
3899 goto failed; | 3890 goto failed; |
3900 } | 3891 } |
3901 } | 3892 } |
3902 | 3893 |
3903 #if (NGX_PTR_SIZE == 8) | 3894 #if (NGX_PTR_SIZE == 8) |
3904 | 3895 |
3905 id = sess_id->sess_id; | 3896 sess_id->session = ngx_slab_alloc_locked(shpool, len); |
3906 | 3897 |
3907 #else | 3898 if (sess_id->session == NULL) { |
3908 | |
3909 id = ngx_slab_alloc_locked(shpool, session_id_length); | |
3910 | |
3911 if (id == NULL) { | |
3912 | 3899 |
3913 /* drop the oldest non-expired session and try once more */ | 3900 /* drop the oldest non-expired session and try once more */ |
3914 | 3901 |
3915 ngx_ssl_expire_sessions(cache, shpool, 0); | 3902 ngx_ssl_expire_sessions(cache, shpool, 0); |
3916 | 3903 |
3917 id = ngx_slab_alloc_locked(shpool, session_id_length); | 3904 sess_id->session = ngx_slab_alloc_locked(shpool, len); |
3918 | 3905 |
3919 if (id == NULL) { | 3906 if (sess_id->session == NULL) { |
3920 goto failed; | 3907 goto failed; |
3921 } | 3908 } |
3922 } | 3909 } |
3923 | 3910 |
3924 #endif | 3911 #endif |
3925 | 3912 |
3926 ngx_memcpy(cached_sess, buf, len); | 3913 ngx_memcpy(sess_id->session, buf, len); |
3927 | 3914 ngx_memcpy(sess_id->id, session_id, session_id_length); |
3928 ngx_memcpy(id, session_id, session_id_length); | |
3929 | 3915 |
3930 hash = ngx_crc32_short(session_id, session_id_length); | 3916 hash = ngx_crc32_short(session_id, session_id_length); |
3931 | 3917 |
3932 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | 3918 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, |
3933 "ssl new session: %08XD:%ud:%d", | 3919 "ssl new session: %08XD:%ud:%d", |
3934 hash, session_id_length, len); | 3920 hash, session_id_length, len); |
3935 | 3921 |
3936 sess_id->node.key = hash; | 3922 sess_id->node.key = hash; |
3937 sess_id->node.data = (u_char) session_id_length; | 3923 sess_id->node.data = (u_char) session_id_length; |
3938 sess_id->id = id; | |
3939 sess_id->len = len; | 3924 sess_id->len = len; |
3940 sess_id->session = cached_sess; | |
3941 | 3925 |
3942 sess_id->expire = ngx_time() + SSL_CTX_get_timeout(ssl_ctx); | 3926 sess_id->expire = ngx_time() + SSL_CTX_get_timeout(ssl_ctx); |
3943 | 3927 |
3944 ngx_queue_insert_head(&cache->expire_queue, &sess_id->queue); | 3928 ngx_queue_insert_head(&cache->expire_queue, &sess_id->queue); |
3945 | 3929 |
3948 ngx_shmtx_unlock(&shpool->mutex); | 3932 ngx_shmtx_unlock(&shpool->mutex); |
3949 | 3933 |
3950 return 0; | 3934 return 0; |
3951 | 3935 |
3952 failed: | 3936 failed: |
3953 | |
3954 if (cached_sess) { | |
3955 ngx_slab_free_locked(shpool, cached_sess); | |
3956 } | |
3957 | 3937 |
3958 if (sess_id) { | 3938 if (sess_id) { |
3959 ngx_slab_free_locked(shpool, sess_id); | 3939 ngx_slab_free_locked(shpool, sess_id); |
3960 } | 3940 } |
3961 | 3941 |
4049 | 4029 |
4050 ngx_queue_remove(&sess_id->queue); | 4030 ngx_queue_remove(&sess_id->queue); |
4051 | 4031 |
4052 ngx_rbtree_delete(&cache->session_rbtree, node); | 4032 ngx_rbtree_delete(&cache->session_rbtree, node); |
4053 | 4033 |
4034 #if (NGX_PTR_SIZE == 8) | |
4054 ngx_slab_free_locked(shpool, sess_id->session); | 4035 ngx_slab_free_locked(shpool, sess_id->session); |
4055 #if (NGX_PTR_SIZE == 4) | |
4056 ngx_slab_free_locked(shpool, sess_id->id); | |
4057 #endif | 4036 #endif |
4058 ngx_slab_free_locked(shpool, sess_id); | 4037 ngx_slab_free_locked(shpool, sess_id); |
4059 | 4038 |
4060 sess = NULL; | 4039 sess = NULL; |
4061 | 4040 |
4139 | 4118 |
4140 ngx_queue_remove(&sess_id->queue); | 4119 ngx_queue_remove(&sess_id->queue); |
4141 | 4120 |
4142 ngx_rbtree_delete(&cache->session_rbtree, node); | 4121 ngx_rbtree_delete(&cache->session_rbtree, node); |
4143 | 4122 |
4123 #if (NGX_PTR_SIZE == 8) | |
4144 ngx_slab_free_locked(shpool, sess_id->session); | 4124 ngx_slab_free_locked(shpool, sess_id->session); |
4145 #if (NGX_PTR_SIZE == 4) | |
4146 ngx_slab_free_locked(shpool, sess_id->id); | |
4147 #endif | 4125 #endif |
4148 ngx_slab_free_locked(shpool, sess_id); | 4126 ngx_slab_free_locked(shpool, sess_id); |
4149 | 4127 |
4150 goto done; | 4128 goto done; |
4151 } | 4129 } |
4188 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, | 4166 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, |
4189 "expire session: %08Xi", sess_id->node.key); | 4167 "expire session: %08Xi", sess_id->node.key); |
4190 | 4168 |
4191 ngx_rbtree_delete(&cache->session_rbtree, &sess_id->node); | 4169 ngx_rbtree_delete(&cache->session_rbtree, &sess_id->node); |
4192 | 4170 |
4171 #if (NGX_PTR_SIZE == 8) | |
4193 ngx_slab_free_locked(shpool, sess_id->session); | 4172 ngx_slab_free_locked(shpool, sess_id->session); |
4194 #if (NGX_PTR_SIZE == 4) | |
4195 ngx_slab_free_locked(shpool, sess_id->id); | |
4196 #endif | 4173 #endif |
4197 ngx_slab_free_locked(shpool, sess_id); | 4174 ngx_slab_free_locked(shpool, sess_id); |
4198 } | 4175 } |
4199 } | 4176 } |
4200 | 4177 |