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