├── LICENSE ├── README.md ├── cache_type ├── memcached │ ├── config │ └── ngx_ssl_session_memcached_module.c └── redis │ ├── config │ └── ngx_ssl_session_redis_module.c ├── config ├── nginx_1.12.0_ssl_session_cache.patch ├── ngx_http_ssl_session_cache_module.c ├── ngx_ssl_session_cache_module.c └── ngx_ssl_session_cache_module.h /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Nginx ngx_ssl_session_cache_module 2 | 3 | [![License](https://img.shields.io/badge/LICENSE-Apache2.0-ff69b4.svg)](http://www.apache.org/licenses/LICENSE-2.0.html) 4 | 5 | # Description 6 | 7 | This module provide a distributed session reuse function, support redis, memcached, support long connection and full asynchronous mode 8 | 9 | This module was developed based on openssl-1.0.2j early, Involved a large number of source code changes with openssl, due to the high cost of ops, then migrate to openssl-1.1.0e, using the high version of the asynchronous mode to complete the openssl code decoupling 10 | 11 | However, there is also need to make some changes to the nginx code, see patch 12 | 13 | # Prerequisite 14 | 15 | - Openssl >= 1.1.0 16 | - Nginx >= 1.9.14 17 | - Redis >= 2.0 18 | - Memcached >= 1.4.3 19 | 20 | # Directives 21 | 22 | ## remote_ssl_session_cache 23 | 24 | **Syntax:** *remote_ssl_session_cache [off] addr=address* 25 |     *[port=number] [type=redis | memcached] [interval=number]* 26 |     *[count=size] [timeout=number] [auth=password]* 27 | 28 | **Default:** *remote_ssl_session_cache* 29 |     *addr=uri [port=6379 type=redis interval=200 count=5000 timeout=1000]* 30 | 31 | **Context:** *http* 32 | 33 | * off 34 | 35 | * Disable the distributed session reuse function. 36 | 37 | * addr 38 | 39 | * Set the address of the cache system, support domain 40 | 41 | * port 42 | 43 | * Set the port of the cache system 44 | 45 | * type 46 | 47 | * Set the type of the cache system, redis or memcached 48 | 49 | * interval 50 | 51 | * Set the interval of keepalive check or reconnect 52 | 53 | * count 54 | 55 | * Set the queue size, enqueue when set or get, dequeue when cache system return, support unlimited 56 | 57 | * timeout 58 | 59 | * Set the read/write/connect timeout 60 | 61 | * auth 62 | 63 | * set the password for authentication 64 | 65 | # Compilation 66 | 67 | 1. patch –p0 < path-to-module/nginx_1.12.0_ssl_session_cache.patch 68 | 2. auto/configure --add-module=path-to-module --add-module=path-to-module/cache_type/memcached --add-module=path-to-module/cache_type/redis 69 | 70 | # Author 71 | 72 | * wywujianmiao@jd.com 73 | * jrliqing@jd.com 74 | * gengxiaotian@jd.com 75 | * jrwangshimeng@jd.com 76 | -------------------------------------------------------------------------------- /cache_type/memcached/config: -------------------------------------------------------------------------------- 1 | ngx_feature="compiler structure-packing pragma" 2 | ngx_feature_name="NGX_HAVE_PACK_PRAGMA" 3 | ngx_feature_run=yes 4 | ngx_feature_incs= 5 | ngx_feature_path= 6 | ngx_feature_libs= 7 | ngx_feature_test="#pragma pack(push, 1) 8 | struct test_s { 9 | char foo; 10 | int bar; 11 | }; 12 | #pragma pack(pop) 13 | 14 | if (sizeof(struct test_s) != (sizeof(char) + sizeof(int))) 15 | return 1;" 16 | . auto/feature 17 | 18 | ngx_addon_name=ngx_ssl_session_memcached_module 19 | HTTP_MODULES="$HTTP_MODULES ngx_ssl_session_memcached_module" 20 | NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_ssl_session_memcached_module.c" 21 | NGX_ADDON_DEPS="$NGX_ADDON_DEPS $ngx_addon_dir/../../ngx_ssl_session_cache_module.h" 22 | -------------------------------------------------------------------------------- /cache_type/memcached/ngx_ssl_session_memcached_module.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../../ngx_ssl_session_cache_module.h" 5 | 6 | 7 | #if (NGX_HAVE_PACK_PRAGMA) 8 | #pragma pack(push, 1) 9 | #elif (NGX_SOLARIS) 10 | #pragma pack(1) 11 | #else 12 | #error "ngx_ssl_session_memcached_module needs structure packing pragma support" 13 | #endif 14 | 15 | typedef struct { 16 | u_char magic; 17 | u_char opcode; 18 | uint16_t key_length; 19 | u_char extras_length; 20 | u_char data_type; 21 | union { 22 | uint16_t vbucket_id; 23 | uint16_t status; 24 | }v; 25 | uint32_t body_length; 26 | uint32_t opaque; 27 | uint64_t cas; 28 | } ngx_memcached_msg_head_t; 29 | 30 | typedef struct { 31 | uint32_t flags; 32 | uint32_t expiration; 33 | } ngx_memcached_msg_set_extras_t; 34 | 35 | #if (NGX_HAVE_PACK_PRAGMA) 36 | #pragma pack(pop) 37 | #elif (NGX_SOLARIS) 38 | #pragma pack() 39 | #else 40 | #error "ngx_ssl_session_memcached_module needs structure packing pragma support" 41 | #endif 42 | 43 | 44 | #define MEMCACHED_OPCODE_GET 0x00 45 | #define MEMCACHED_OPCODE_SET 0x01 46 | #define MEMCACHED_OPCODE_DEL 0x04 47 | #define MEMCACHED_OPCODE_CHK 0x0a 48 | #define MEMCACHED_OPCODE_ATH 0x21 49 | 50 | static ngx_ssl_session_cache_method_t * 51 | ngx_ssl_session_cache_int_module(ngx_pool_t *pool, ngx_uint_t *default_port); 52 | 53 | static ngx_ssl_session_cache_module_t ngx_ssl_session_memcached_module_ctx = { 54 | ngx_string("memcached"), 55 | ngx_ssl_session_cache_int_module 56 | }; 57 | 58 | ngx_module_t ngx_ssl_session_memcached_module = { 59 | NGX_MODULE_V1, 60 | &ngx_ssl_session_memcached_module_ctx, /* module context */ 61 | NULL, /* module directives */ 62 | NGX_RSSC_MODULE, /* module type */ 63 | NULL, /* init master */ 64 | NULL, /* init module */ 65 | NULL, /* init process */ 66 | NULL, /* init thread */ 67 | NULL, /* exit thread */ 68 | NULL, /* exit process */ 69 | NULL, /* exit master */ 70 | NGX_MODULE_V1_PADDING 71 | }; 72 | 73 | static ngx_buf_t * 74 | ngx_ssl_session_memcached_auth(ngx_ssl_session_cache_ctx_t *cache_ctx, const u_char *auth, int len) 75 | { 76 | ngx_buf_t *msg; 77 | ngx_memcached_msg_head_t *head; 78 | ngx_str_t key; 79 | 80 | ngx_str_set(&key, "PLAIN"); 81 | 82 | msg = ngx_ssl_session_cache_get_buf(cache_ctx, 83 | sizeof(ngx_memcached_msg_head_t) + len + key.len); 84 | if (msg == NULL) { 85 | return NULL; 86 | } 87 | 88 | head = (ngx_memcached_msg_head_t*)msg->start; 89 | 90 | ngx_memzero(head, sizeof(*head)); 91 | 92 | head->magic = 0x80; 93 | head->opcode = MEMCACHED_OPCODE_ATH; 94 | head->key_length = htons((uint16_t)key.len); 95 | head->body_length = htonl(len+key.len); 96 | 97 | 98 | msg->last = ngx_cpymem(msg->pos + sizeof(*head), key.data, key.len); 99 | msg->last = ngx_cpymem(msg->last, auth, len); 100 | 101 | return msg; 102 | } 103 | 104 | static ngx_buf_t * 105 | ngx_ssl_session_memcached_set(ngx_ssl_session_cache_ctx_t *cache_ctx, const u_char *key,int keylen, 106 | const u_char *session, int sesslen, unsigned int timeout) 107 | { 108 | ngx_buf_t *msg; 109 | ngx_memcached_msg_head_t *head; 110 | ngx_memcached_msg_set_extras_t *extras; 111 | 112 | msg = ngx_ssl_session_cache_get_buf(cache_ctx, 113 | sizeof(ngx_memcached_msg_head_t) + keylen + sesslen + 8); 114 | if (msg == NULL) { 115 | return NULL; 116 | } 117 | 118 | head = (ngx_memcached_msg_head_t*)msg->start; 119 | 120 | ngx_memzero(head, sizeof(*head)); 121 | 122 | head->magic = 0x80; 123 | head->opcode = MEMCACHED_OPCODE_SET; 124 | head->key_length = htons((uint16_t)keylen); 125 | head->extras_length = 0x08; 126 | head->body_length = htonl(keylen + sesslen + 8); 127 | 128 | 129 | extras = (ngx_memcached_msg_set_extras_t*) (msg->start + sizeof(*head)); 130 | 131 | extras->flags = 0x00; 132 | extras->expiration = htonl(timeout); 133 | 134 | msg->last = ngx_cpymem(msg->pos + sizeof(*head) + sizeof(*extras), key, keylen); 135 | 136 | msg->last = ngx_cpymem(msg->last, session, sesslen); 137 | 138 | return msg; 139 | } 140 | 141 | static ngx_buf_t * 142 | ngx_ssl_session_memcached_get(ngx_ssl_session_cache_ctx_t *cache_ctx, const u_char *key, int len) 143 | { 144 | ngx_buf_t *msg; 145 | ngx_memcached_msg_head_t *head; 146 | 147 | msg = ngx_ssl_session_cache_get_buf(cache_ctx, 148 | sizeof(ngx_memcached_msg_head_t) + len); 149 | if (msg == NULL) { 150 | return NULL; 151 | } 152 | 153 | head = (ngx_memcached_msg_head_t*)msg->start; 154 | 155 | ngx_memzero(head, sizeof(*head)); 156 | 157 | head->magic = 0x80; 158 | head->opcode = MEMCACHED_OPCODE_GET; 159 | head->key_length = htons((uint16_t)len); 160 | head->body_length = htonl(len); 161 | 162 | msg->last = ngx_cpymem(msg->pos + sizeof(*head), key, len); 163 | 164 | return msg; 165 | } 166 | 167 | static ngx_buf_t * 168 | ngx_ssl_session_memcached_delete(ngx_ssl_session_cache_ctx_t *cache_ctx, const u_char *key, int len) 169 | { 170 | ngx_buf_t *msg; 171 | ngx_memcached_msg_head_t *head; 172 | 173 | msg = ngx_ssl_session_cache_get_buf(cache_ctx, 174 | sizeof(ngx_memcached_msg_head_t) + len); 175 | if (msg == NULL) { 176 | return NULL; 177 | } 178 | 179 | head = (ngx_memcached_msg_head_t*)msg->start; 180 | 181 | ngx_memzero(head, sizeof(*head)); 182 | 183 | head->magic = 0x80; 184 | head->opcode = MEMCACHED_OPCODE_DEL; 185 | head->key_length = htons((uint16_t)len); 186 | head->body_length = htonl(len); 187 | 188 | msg->last = ngx_cpymem(msg->pos + sizeof(*head), key, len); 189 | 190 | return msg; 191 | } 192 | 193 | static ngx_buf_t * 194 | ngx_ssl_session_memcached_check(ngx_ssl_session_cache_ctx_t *cache_ctx) 195 | { 196 | ngx_buf_t *msg; 197 | ngx_memcached_msg_head_t *head; 198 | 199 | msg = ngx_ssl_session_cache_get_buf(cache_ctx, 200 | sizeof(ngx_memcached_msg_head_t)); 201 | if (msg == NULL) { 202 | return NULL; 203 | } 204 | 205 | head = (ngx_memcached_msg_head_t*)msg->start; 206 | 207 | ngx_memzero(head, sizeof(*head)); 208 | 209 | head->magic = 0x80; 210 | head->opcode = MEMCACHED_OPCODE_CHK; 211 | 212 | msg->last += sizeof(*head); 213 | 214 | return msg; 215 | } 216 | 217 | static ngx_int_t 218 | ngx_ssl_session_memcached_parse(ngx_buf_t *in, ngx_ssl_session_cache_node_t *node) 219 | { 220 | ngx_memcached_msg_head_t head; 221 | ngx_int_t status; 222 | 223 | if ((size_t)(in->last - in->pos) < sizeof(head)) { 224 | return NGX_SSL_SESSION_CACHE_PARSE_MSG_MORE_DATA; 225 | } 226 | 227 | ngx_memcpy(&head, in->pos, sizeof(head)); 228 | 229 | if (head.magic != 0x81) { 230 | return NGX_SSL_SESSION_CACHE_PARSE_MSG_PROTO_ERR; 231 | } 232 | 233 | head.v.status = ntohs(head.v.status); 234 | if (head.v.status != 0 ) { 235 | status = head.v.status; 236 | ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "ssl session memcached response status[%d]", status ); 237 | } 238 | 239 | head.key_length = ntohs(head.key_length); 240 | head.body_length = ntohl(head.body_length); 241 | 242 | switch (head.opcode) { 243 | 244 | case MEMCACHED_OPCODE_GET: 245 | 246 | if (node->msg_type != NGX_SSL_SESSION_CACHE_MSG_TYPE_GET) { 247 | return NGX_SSL_SESSION_CACHE_PARSE_MSG_TYPE_ERR; 248 | } 249 | 250 | if ((size_t)(in->last - in->pos) < sizeof(head) + head.body_length) { 251 | return NGX_SSL_SESSION_CACHE_PARSE_MSG_MORE_DATA; 252 | } 253 | 254 | in->pos += sizeof(head); 255 | 256 | if (head.v.status == 0 ) { 257 | node->session.data = in->pos + head.extras_length; 258 | node->session.len = head.body_length - head.extras_length; 259 | } 260 | 261 | in->pos += head.body_length; 262 | 263 | return NGX_SSL_SESSION_CACHE_PARSE_MSG_OK; 264 | 265 | case MEMCACHED_OPCODE_SET: 266 | 267 | if (node->msg_type != NGX_SSL_SESSION_CACHE_MSG_TYPE_SET) { 268 | return NGX_SSL_SESSION_CACHE_PARSE_MSG_TYPE_ERR; 269 | } 270 | 271 | in->pos += sizeof(head) + head.body_length; 272 | 273 | return NGX_SSL_SESSION_CACHE_PARSE_MSG_OK; 274 | 275 | case MEMCACHED_OPCODE_DEL: 276 | 277 | if (node->msg_type != NGX_SSL_SESSION_CACHE_MSG_TYPE_DEL) { 278 | return NGX_SSL_SESSION_CACHE_PARSE_MSG_TYPE_ERR; 279 | } 280 | 281 | in->pos += sizeof(head) + head.body_length; 282 | 283 | return NGX_SSL_SESSION_CACHE_PARSE_MSG_OK; 284 | 285 | case MEMCACHED_OPCODE_CHK: 286 | 287 | if (node->msg_type != NGX_SSL_SESSION_CACHE_MSG_TYPE_CHECK) { 288 | return NGX_SSL_SESSION_CACHE_PARSE_MSG_TYPE_ERR; 289 | } 290 | 291 | in->pos += sizeof(head) + head.body_length; 292 | 293 | return NGX_SSL_SESSION_CACHE_PARSE_MSG_OK; 294 | 295 | case MEMCACHED_OPCODE_ATH: 296 | 297 | if (node->msg_type != NGX_SSL_SESSION_CACHE_MSG_TYPE_AUTH) { 298 | return NGX_SSL_SESSION_CACHE_PARSE_MSG_TYPE_ERR; 299 | } 300 | 301 | if (head.v.status != 0) { 302 | ngx_str_t auth_error; 303 | 304 | auth_error.data = in->pos + sizeof(head); 305 | auth_error.len = head.body_length; 306 | ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "ssl session memcached response status[%V]", &auth_error); 307 | return NGX_SSL_SESSION_CACHE_PARSE_MSG_STATUS_ERR; 308 | } 309 | 310 | 311 | in->pos += sizeof(head) + head.body_length; 312 | 313 | return NGX_SSL_SESSION_CACHE_PARSE_MSG_OK; 314 | 315 | default: 316 | return NGX_SSL_SESSION_CACHE_PARSE_MSG_TYPE_ERR; 317 | } 318 | } 319 | 320 | static ngx_ssl_session_cache_method_t * 321 | ngx_ssl_session_cache_int_module(ngx_pool_t *pool, ngx_uint_t *default_port) 322 | { 323 | ngx_ssl_session_cache_method_t *method; 324 | 325 | method = ngx_pcalloc(pool, sizeof(*method)); 326 | if (method == NULL) { 327 | return NULL; 328 | } 329 | 330 | method->auth = ngx_ssl_session_memcached_auth; 331 | method->set = ngx_ssl_session_memcached_set; 332 | method->get = ngx_ssl_session_memcached_get; 333 | method->delete = ngx_ssl_session_memcached_delete; 334 | method->check = ngx_ssl_session_memcached_check; 335 | method->parse = ngx_ssl_session_memcached_parse; 336 | 337 | *default_port = 11211; 338 | 339 | return method; 340 | } 341 | -------------------------------------------------------------------------------- /cache_type/redis/config: -------------------------------------------------------------------------------- 1 | ngx_addon_name=ngx_ssl_session_redis_module 2 | HTTP_MODULES="$HTTP_MODULES ngx_ssl_session_redis_module" 3 | NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_ssl_session_redis_module.c" 4 | NGX_ADDON_DEPS="$NGX_ADDON_DEPS $ngx_addon_dir/../../ngx_ssl_session_cache_module.h" 5 | -------------------------------------------------------------------------------- /cache_type/redis/ngx_ssl_session_redis_module.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../../ngx_ssl_session_cache_module.h" 5 | 6 | 7 | static ngx_ssl_session_cache_method_t * 8 | ngx_ssl_session_redis_int_module(ngx_pool_t *pool, ngx_uint_t *default_port); 9 | 10 | static ngx_ssl_session_cache_module_t ngx_ssl_session_redis_module_ctx = { 11 | ngx_string("redis"), 12 | ngx_ssl_session_redis_int_module 13 | }; 14 | 15 | ngx_module_t ngx_ssl_session_redis_module = { 16 | NGX_MODULE_V1, 17 | &ngx_ssl_session_redis_module_ctx, /* module context */ 18 | NULL, /* module directives */ 19 | NGX_RSSC_MODULE, /* module type */ 20 | NULL, /* init master */ 21 | NULL, /* init module */ 22 | NULL, /* init process */ 23 | NULL, /* init thread */ 24 | NULL, /* exit thread */ 25 | NULL, /* exit process */ 26 | NULL, /* exit master */ 27 | NGX_MODULE_V1_PADDING 28 | }; 29 | 30 | static ngx_buf_t * 31 | ngx_ssl_session_redis_auth(ngx_ssl_session_cache_ctx_t *cache_ctx, const u_char *auth, int len) 32 | { 33 | ngx_buf_t *msg; 34 | ngx_str_t redis_string; 35 | ngx_uint_t redis_string_len; 36 | 37 | ngx_str_set(&redis_string, "*2\r\n" 38 | "$4\r\n" 39 | "AUTH\r\n" 40 | "$%d\r\n" 41 | "%s\r\n"); 42 | 43 | redis_string_len = redis_string.len + NGX_INT32_LEN - 2 + len - 2; 44 | 45 | msg = ngx_ssl_session_cache_get_buf(cache_ctx, redis_string_len); 46 | if (msg == NULL) { 47 | return NULL; 48 | } 49 | 50 | msg->last = ngx_snprintf(msg->last, redis_string_len, (char*)redis_string.data, len, auth); 51 | 52 | return msg; 53 | } 54 | 55 | static ngx_buf_t * 56 | ngx_ssl_session_redis_set(ngx_ssl_session_cache_ctx_t *cache_ctx, const u_char *key,int keylen, 57 | const u_char *session, int sesslen, unsigned int timeout) 58 | { 59 | ngx_buf_t *msg; 60 | ngx_str_t redis_string; 61 | ngx_uint_t redis_string_len; 62 | 63 | 64 | ngx_str_set(&redis_string, "*5\r\n" 65 | "$3\r\n" 66 | "SET\r\n" 67 | "$%d\r\n" 68 | "%s\r\n" 69 | "$%d\r\n" 70 | "%s\r\n" 71 | "$2\r\n" 72 | "EX\r\n" 73 | "$%d\r\n" 74 | "%ud\r\n"); 75 | 76 | 77 | redis_string_len = redis_string.len + ngx_ssl_session_cache_get_size_len(keylen) - 2 + keylen - 2 + \ 78 | ngx_ssl_session_cache_get_size_len(sesslen) - 2 + sesslen - 2 + \ 79 | ngx_ssl_session_cache_get_size_len(timeout)*2 - 5; 80 | 81 | msg = ngx_ssl_session_cache_get_buf(cache_ctx, redis_string_len); 82 | if (msg == NULL) { 83 | return NULL; 84 | } 85 | 86 | msg->last[0] = '*'; msg->last[1] = '5'; msg->last[2] = '\r'; msg->last[3] = '\n'; 87 | msg->last[4] = '$'; msg->last[5] = '3'; msg->last[6] = '\r'; msg->last[7] = '\n'; 88 | msg->last[8] = 'S'; msg->last[9] = 'E'; msg->last[10] = 'T'; msg->last[11] = '\r'; msg->last[12] = '\n'; 89 | 90 | msg->last += 13; 91 | 92 | msg->last = ngx_snprintf(msg->last, msg->end - msg->last, "$%d", keylen); 93 | *msg->last++ = '\r'; 94 | *msg->last++ = '\n'; 95 | 96 | msg->last = ngx_cpymem(msg->last, key, keylen); 97 | *msg->last++ = '\r'; 98 | *msg->last++ = '\n'; 99 | 100 | 101 | msg->last = ngx_snprintf(msg->last, msg->end - msg->last, "$%d", sesslen); 102 | *msg->last++ = '\r'; 103 | *msg->last++ = '\n'; 104 | 105 | msg->last = ngx_cpymem(msg->last, session, sesslen); 106 | 107 | msg->last[0] = '\r'; msg->last[1] = '\n'; 108 | 109 | msg->last[2] = '$'; msg->last[3] = '2'; msg->last[4] = '\r'; msg->last[5] = '\n'; 110 | msg->last[6] = 'E'; msg->last[7] = 'X'; msg->last[8] = '\r'; msg->last[9] = '\n'; 111 | 112 | msg->last += 10; 113 | 114 | msg->last = ngx_snprintf(msg->last, msg->end - msg->last, "$%d\r\n%ud\r\n", ngx_ssl_session_cache_get_size_len(timeout), timeout); 115 | 116 | return msg; 117 | } 118 | 119 | static ngx_buf_t * 120 | ngx_ssl_session_redis_get(ngx_ssl_session_cache_ctx_t *cache_ctx, const u_char *key, int len) 121 | { 122 | ngx_buf_t *msg; 123 | ngx_str_t redis_string; 124 | ngx_uint_t redis_string_len; 125 | 126 | ngx_str_set(&redis_string, "*2\r\n" 127 | "$3\r\n" 128 | "GET\r\n" 129 | "$%d\r\n" 130 | "%s\r\n"); 131 | 132 | redis_string_len = redis_string.len + NGX_INT32_LEN - 2 + len - 2; 133 | 134 | msg = ngx_ssl_session_cache_get_buf(cache_ctx, redis_string_len); 135 | if (msg == NULL) { 136 | return NULL; 137 | } 138 | 139 | ngx_str_set(&redis_string, "*2\r\n" 140 | "$3\r\n" 141 | "GET\r\n" 142 | "$%d\r\n"); 143 | 144 | msg->last = ngx_snprintf(msg->last, msg->end - msg->last, (char*)redis_string.data, len); 145 | 146 | msg->last = ngx_cpymem(msg->last, key, len); 147 | *msg->last++ = '\r'; 148 | *msg->last++ = '\n'; 149 | 150 | return msg; 151 | } 152 | 153 | static ngx_buf_t * 154 | ngx_ssl_session_redis_delete(ngx_ssl_session_cache_ctx_t *cache_ctx, const u_char *key, int len) 155 | { 156 | ngx_buf_t *msg; 157 | ngx_str_t redis_string; 158 | ngx_uint_t redis_string_len; 159 | 160 | ngx_str_set(&redis_string, "*2\r\n" 161 | "$3\r\n" 162 | "DEL\r\n" 163 | "$%d\r\n" 164 | "%s\r\n"); 165 | 166 | redis_string_len = redis_string.len + NGX_INT32_LEN - 2 + len - 2; 167 | 168 | msg = ngx_ssl_session_cache_get_buf(cache_ctx, redis_string_len); 169 | if (msg == NULL) { 170 | return NULL; 171 | } 172 | 173 | ngx_str_set(&redis_string, "*2\r\n" 174 | "$3\r\n" 175 | "DEL\r\n" 176 | "$%d\r\n"); 177 | 178 | msg->last = ngx_snprintf(msg->last, msg->end - msg->last, (char*)redis_string.data, len); 179 | 180 | msg->last = ngx_cpymem(msg->last, key, len); 181 | *msg->last++ = '\r'; 182 | *msg->last++ = '\n'; 183 | 184 | return msg; 185 | 186 | } 187 | 188 | static ngx_buf_t * 189 | ngx_ssl_session_redis_check(ngx_ssl_session_cache_ctx_t *cache_ctx) 190 | { 191 | ngx_buf_t *msg; 192 | ngx_str_t redis_string; 193 | ngx_uint_t redis_string_len; 194 | 195 | ngx_str_set(&redis_string, "*1\r\n" 196 | "$4\r\n" 197 | "PING\r\n"); 198 | 199 | redis_string_len = redis_string.len; 200 | 201 | msg = ngx_ssl_session_cache_get_buf(cache_ctx, redis_string_len); 202 | if (msg == NULL) { 203 | return NULL; 204 | } 205 | 206 | msg->last = ngx_cpymem(msg->last, redis_string.data, redis_string.len); 207 | 208 | return msg; 209 | } 210 | 211 | static ngx_int_t 212 | ngx_ssl_session_redis_parse(ngx_buf_t *in, ngx_ssl_session_cache_node_t *node) 213 | { 214 | u_char *pos; 215 | u_char *str_cr; 216 | ngx_int_t len; 217 | 218 | str_cr = ngx_strlchr(in->pos, in->last, '\r'); 219 | if (str_cr == NULL || str_cr + 1 == in->last) { 220 | return NGX_SSL_SESSION_CACHE_PARSE_MSG_MORE_DATA; 221 | } 222 | 223 | pos = in->pos; 224 | 225 | switch (*pos) { 226 | 227 | case '+': 228 | 229 | if (str_cr - pos == 3 && pos[1] == 'O' && pos[2] == 'K' && 230 | (node->msg_type == NGX_SSL_SESSION_CACHE_MSG_TYPE_SET || 231 | node->msg_type == NGX_SSL_SESSION_CACHE_MSG_TYPE_AUTH)) { 232 | in->pos += 5; 233 | return NGX_SSL_SESSION_CACHE_PARSE_MSG_OK; 234 | } 235 | 236 | 237 | if (str_cr - pos == 5 && 238 | pos[1] == 'P' && pos[2] == 'O' && pos[3] == 'N' && pos[4] == 'G' && 239 | node->msg_type == NGX_SSL_SESSION_CACHE_MSG_TYPE_CHECK) { 240 | in->pos += 7; 241 | return NGX_SSL_SESSION_CACHE_PARSE_MSG_OK; 242 | } 243 | 244 | return NGX_SSL_SESSION_CACHE_PARSE_MSG_TYPE_ERR; 245 | 246 | case '-': 247 | 248 | *str_cr = '\0'; 249 | ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "ssl session redis response msg[%s]", pos + 1 ); 250 | return NGX_SSL_SESSION_CACHE_PARSE_MSG_STATUS_ERR; 251 | 252 | case '$': 253 | 254 | pos++; 255 | 256 | if (node->msg_type != NGX_SSL_SESSION_CACHE_MSG_TYPE_GET) { 257 | return NGX_SSL_SESSION_CACHE_PARSE_MSG_TYPE_ERR; 258 | } 259 | 260 | if (pos[0] == '-' && pos[1] == '1') { 261 | node->session.data = NULL; 262 | 263 | in->pos += 5; 264 | return NGX_SSL_SESSION_CACHE_PARSE_MSG_OK; 265 | } 266 | 267 | len = ngx_atoi(pos, str_cr - pos); 268 | if (len == NGX_ERROR) { 269 | return NGX_SSL_SESSION_CACHE_PARSE_MSG_PROTO_ERR; 270 | } 271 | 272 | if (in->last - str_cr - 4 < len) { 273 | return NGX_SSL_SESSION_CACHE_PARSE_MSG_MORE_DATA; 274 | } 275 | 276 | node->session.data = str_cr + 2; 277 | node->session.len = len; 278 | 279 | in->pos = str_cr + 2 + len + 2; 280 | 281 | return NGX_SSL_SESSION_CACHE_PARSE_MSG_OK; 282 | 283 | case ':': 284 | 285 | if (node->msg_type != NGX_SSL_SESSION_CACHE_MSG_TYPE_DEL) { 286 | return NGX_SSL_SESSION_CACHE_PARSE_MSG_TYPE_ERR; 287 | } 288 | 289 | in->pos = str_cr + 2; 290 | 291 | return NGX_SSL_SESSION_CACHE_PARSE_MSG_OK; 292 | 293 | default: 294 | return NGX_SSL_SESSION_CACHE_PARSE_MSG_PROTO_ERR; 295 | } 296 | } 297 | 298 | static ngx_ssl_session_cache_method_t * 299 | ngx_ssl_session_redis_int_module(ngx_pool_t *pool, ngx_uint_t *default_port) 300 | { 301 | ngx_ssl_session_cache_method_t *method; 302 | 303 | method = ngx_pcalloc(pool, sizeof(*method)); 304 | if (method == NULL) { 305 | return NULL; 306 | } 307 | 308 | method->auth = ngx_ssl_session_redis_auth; 309 | method->set = ngx_ssl_session_redis_set; 310 | method->get = ngx_ssl_session_redis_get; 311 | method->delete = ngx_ssl_session_redis_delete; 312 | method->check = ngx_ssl_session_redis_check; 313 | method->parse = ngx_ssl_session_redis_parse; 314 | 315 | *default_port = 6379; 316 | 317 | return method; 318 | } 319 | -------------------------------------------------------------------------------- /config: -------------------------------------------------------------------------------- 1 | ngx_addon_name=ngx_http_ssl_session_cache_module 2 | HTTP_MODULES="$HTTP_MODULES ngx_http_ssl_session_cache_module" 3 | NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_ssl_session_cache_module.c 4 | $ngx_addon_dir/ngx_ssl_session_cache_module.c" 5 | 6 | NGX_ADDON_DEPS="$NGX_ADDON_DEPS $ngx_addon_dir/ngx_ssl_session_cache_module.h" 7 | 8 | -------------------------------------------------------------------------------- /nginx_1.12.0_ssl_session_cache.patch: -------------------------------------------------------------------------------- 1 | diff -ru src/event/ngx_event_openssl.c src2/event/ngx_event_openssl.c 2 | --- src/event/ngx_event_openssl.c 2017-07-31 14:41:47.204433207 -0400 3 | +++ src2/event/ngx_event_openssl.c 2017-07-31 14:44:27.810431433 -0400 4 | @@ -1338,6 +1338,14 @@ 5 | return NGX_AGAIN; 6 | } 7 | 8 | + if (sslerr == SSL_ERROR_WANT_ASYNC) 9 | + { 10 | + c->read->handler = ngx_ssl_handshake_handler; 11 | + c->write->handler = ngx_ssl_handshake_handler; 12 | + c->read->ready = 0; 13 | + return NGX_AGAIN; 14 | + } 15 | + 16 | err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0; 17 | 18 | c->ssl->no_wait_shutdown = 1; 19 | -------------------------------------------------------------------------------- /ngx_http_ssl_session_cache_module.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "ngx_ssl_session_cache_module.h" 6 | 7 | static ngx_int_t 8 | ngx_http_ssl_session_cache_init_process(ngx_cycle_t *cycle); 9 | static void 10 | ngx_http_ssl_session_cache_exit_process(ngx_cycle_t *cycle); 11 | static void* 12 | ngx_http_ssl_session_cache_create_srv_conf(ngx_conf_t *cf); 13 | static char* 14 | ngx_http_ssl_session_cache_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child); 15 | static char* 16 | ngx_http_ssl_cache_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); 17 | 18 | static int ngx_http_ssl_session_cache_conf_index = -1; 19 | 20 | static ngx_command_t ngx_http_ssl_session_cache_commands[] = { 21 | { 22 | /* only in http main. 23 | new request order: find_server -> new_session 24 | request with session id order: get_session -> find_server */ 25 | ngx_string("remote_ssl_session_cache"), 26 | NGX_HTTP_MAIN_CONF | NGX_CONF_1MORE, 27 | ngx_http_ssl_cache_conf, 28 | NGX_HTTP_SRV_CONF_OFFSET, 29 | 0, 30 | NULL 31 | }, 32 | 33 | ngx_null_command 34 | }; 35 | 36 | static ngx_http_module_t ngx_http_ssl_session_cache_module_ctx = { 37 | NULL, /* preconfiguration */ 38 | NULL, /* postconfiguration */ 39 | 40 | NULL, /* create main configuration */ 41 | NULL, /* init main configuration */ 42 | 43 | ngx_http_ssl_session_cache_create_srv_conf, /* create server configuration */ 44 | ngx_http_ssl_session_cache_merge_srv_conf, /* merge server configuration */ 45 | 46 | NULL, /* create location configuration */ 47 | NULL /* merge location configuration */ 48 | }; 49 | 50 | ngx_module_t ngx_http_ssl_session_cache_module = { 51 | NGX_MODULE_V1, 52 | &ngx_http_ssl_session_cache_module_ctx, /* module context */ 53 | ngx_http_ssl_session_cache_commands, /* module directives */ 54 | NGX_HTTP_MODULE, /* module type */ 55 | NULL, /* init master */ 56 | NULL, /* init module */ 57 | ngx_http_ssl_session_cache_init_process, /* init process */ 58 | NULL, /* init thread */ 59 | NULL, /* exit thread */ 60 | ngx_http_ssl_session_cache_exit_process, /* exit process */ 61 | NULL, /* exit master */ 62 | NGX_MODULE_V1_PADDING 63 | }; 64 | 65 | static ngx_ssl_session_cache_ctx_t * 66 | ngx_http_ssl_session_cache_get_ctx(ngx_ssl_conn_t *ssl_conn) 67 | { 68 | ngx_ssl_session_cache_conf_t *sccf; 69 | SSL_CTX *ssl_ctx; 70 | 71 | ssl_ctx = SSL_get_SSL_CTX(ssl_conn); 72 | 73 | sccf = SSL_CTX_get_ex_data(ssl_ctx, ngx_http_ssl_session_cache_conf_index); 74 | if (sccf == NULL) { 75 | return 0; 76 | } 77 | 78 | return sccf->cache_ctx; 79 | } 80 | 81 | static int 82 | ngx_http_ssl_session_cache_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess) 83 | { 84 | ngx_ssl_session_cache_ctx_t *cache_ctx; 85 | 86 | cache_ctx = ngx_http_ssl_session_cache_get_ctx(ssl_conn); 87 | if (cache_ctx == NULL) { 88 | return 0; 89 | } 90 | 91 | return ngx_ssl_session_cache_new_session(cache_ctx, ssl_conn, sess); 92 | } 93 | 94 | static ngx_ssl_session_t * 95 | ngx_http_ssl_session_cache_get_session(ngx_ssl_conn_t *ssl_conn, const u_char *id, 96 | int len, int *copy) 97 | { 98 | ngx_ssl_session_cache_ctx_t *cache_ctx; 99 | 100 | *copy = 0; 101 | 102 | cache_ctx = ngx_http_ssl_session_cache_get_ctx(ssl_conn); 103 | if (cache_ctx == NULL) { 104 | return NULL; 105 | } 106 | 107 | return ngx_ssl_session_cache_get_session(cache_ctx, ssl_conn, id, len, copy); 108 | } 109 | 110 | static void 111 | ngx_http_ssl_session_cache_remove_session(SSL_CTX *ssl_ctx, ngx_ssl_session_t *sess) 112 | { 113 | ngx_ssl_session_cache_conf_t *sccf; 114 | 115 | sccf = SSL_CTX_get_ex_data(ssl_ctx, ngx_http_ssl_session_cache_conf_index); 116 | if (sccf == NULL || sccf->cache_ctx == NULL) { 117 | return; 118 | } 119 | 120 | return ngx_ssl_session_cache_remove_session(sccf->cache_ctx, sess); 121 | } 122 | 123 | static int 124 | ngx_http_ssl_session_cache_set_openssl_cb(SSL_CTX *ssl_ctx) 125 | { 126 | SSL_CTX_sess_set_new_cb(ssl_ctx, ngx_http_ssl_session_cache_new_session); 127 | SSL_CTX_sess_set_get_cb(ssl_ctx, ngx_http_ssl_session_cache_get_session); 128 | SSL_CTX_sess_set_remove_cb(ssl_ctx, ngx_http_ssl_session_cache_remove_session); 129 | 130 | return 1; 131 | } 132 | 133 | static ngx_int_t 134 | ngx_http_ssl_session_cache_init_process(ngx_cycle_t *cycle) 135 | { 136 | ngx_http_core_main_conf_t *cmcf; 137 | ngx_http_core_srv_conf_t **cscf; 138 | ngx_ssl_session_cache_conf_t *sccf; 139 | ngx_uint_t i; 140 | 141 | cmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_core_module); 142 | if (cmcf == NULL) { 143 | return NGX_ERROR; 144 | } 145 | 146 | cscf = cmcf->servers.elts; 147 | for (i=0; iservers.nelts; i++) { 148 | sccf = cscf[i]->ctx->srv_conf[ngx_http_ssl_session_cache_module.ctx_index]; 149 | if (sccf == NULL || sccf->cache_ctx == NULL || sccf->cache_ctx->pool) { 150 | continue; 151 | } 152 | 153 | if (ngx_ssl_session_cache_add_timers(cycle, sccf) != NGX_OK) { 154 | ngx_http_ssl_session_cache_exit_process(cycle); 155 | return NGX_ERROR; 156 | } 157 | } 158 | 159 | return NGX_OK; 160 | } 161 | 162 | static void 163 | ngx_http_ssl_session_cache_exit_process(ngx_cycle_t *cycle) 164 | { 165 | ngx_pool_t *p; 166 | ngx_http_core_main_conf_t *cmcf; 167 | ngx_http_core_srv_conf_t **cscf; 168 | ngx_ssl_session_cache_conf_t *sccf; 169 | ngx_uint_t i; 170 | 171 | cmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_core_module); 172 | if (cmcf == NULL) { 173 | return ; 174 | } 175 | 176 | cscf = cmcf->servers.elts; 177 | for (i=0; iservers.nelts; i++) { 178 | sccf = cscf[i]->ctx->srv_conf[ngx_http_ssl_session_cache_module.ctx_index]; 179 | if (sccf == NULL || sccf->cache_ctx == NULL || sccf->cache_ctx->pool == NULL) { 180 | continue; 181 | } 182 | 183 | p = sccf->cache_ctx->pool; 184 | 185 | ngx_destroy_pool(p); 186 | 187 | sccf->cache_ctx->pool = NULL; 188 | } 189 | } 190 | 191 | static void* 192 | ngx_http_ssl_session_cache_create_srv_conf(ngx_conf_t *cf) 193 | { 194 | ngx_ssl_session_cache_conf_t *sccf; 195 | 196 | sccf = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_session_cache_conf_t)); 197 | if (sccf == NULL) { 198 | return NULL; 199 | } 200 | 201 | sccf->onoff = NGX_CONF_UNSET; 202 | sccf->proc_timeout = NGX_CONF_UNSET_MSEC; 203 | sccf->interval = NGX_CONF_UNSET_MSEC; 204 | sccf->queue_depth = NGX_CONF_UNSET; 205 | sccf->cache_method = NGX_CONF_UNSET_PTR; 206 | sccf->cache_ctx = NULL; 207 | 208 | ngx_str_null(&sccf->auth); 209 | 210 | return sccf; 211 | } 212 | 213 | static int 214 | ngx_http_ssl_session_cache_listen_ssl(ngx_conf_t *cf) 215 | { 216 | ngx_http_core_srv_conf_t *cscf; 217 | ngx_http_core_main_conf_t *cmcf; 218 | ngx_http_conf_port_t *port; 219 | ngx_http_conf_addr_t *addr; 220 | ngx_http_core_srv_conf_t **server; 221 | ngx_uint_t i, j, k; 222 | int on = 0; 223 | 224 | cscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_core_module); 225 | cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); 226 | 227 | port = cmcf->ports->elts; 228 | for (i=0; i < cmcf->ports->nelts; i++) { 229 | 230 | addr = port[i].addrs.elts; 231 | for (j=0; j < port[i].addrs.nelts; j++) { 232 | 233 | server = addr[j].servers.elts; 234 | for (k=0; k < addr[j].servers.nelts; k++) { 235 | if (server[k] != cscf) { 236 | continue; 237 | } 238 | 239 | if (addr[j].opt.ssl) { 240 | on = 1; 241 | } 242 | } 243 | } 244 | } 245 | 246 | return on; 247 | } 248 | 249 | static char* 250 | ngx_http_ssl_session_cache_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) 251 | { 252 | ngx_ssl_session_cache_conf_t *prev = parent; 253 | ngx_ssl_session_cache_conf_t *conf = child; 254 | ngx_http_ssl_srv_conf_t *sscf; 255 | long cache_mode; 256 | 257 | sscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_ssl_module); 258 | 259 | if (!sscf->enable && !ngx_http_ssl_session_cache_listen_ssl(cf)) { 260 | conf->cache_ctx = NULL; 261 | conf->onoff = NGX_SSL_SESSION_CACHE_OFF; 262 | 263 | return NGX_CONF_OK; 264 | } 265 | 266 | if (conf->onoff == NGX_SSL_SESSION_CACHE_OFF || sscf->ssl.ctx == NULL) { 267 | conf->cache_ctx = NULL; 268 | 269 | return NGX_CONF_OK; 270 | } 271 | 272 | if (prev->onoff == NGX_CONF_UNSET && conf->onoff == NGX_CONF_UNSET) { 273 | conf->cache_ctx = NULL; 274 | conf->onoff = NGX_SSL_SESSION_CACHE_OFF; 275 | 276 | return NGX_CONF_OK; 277 | } 278 | 279 | cache_mode = SSL_SESS_CACHE_NO_INTERNAL | SSL_SESS_CACHE_SERVER; 280 | 281 | SSL_CTX_set_mode(sscf->ssl.ctx, SSL_MODE_ASYNC); 282 | SSL_CTX_set_session_cache_mode(sscf->ssl.ctx, cache_mode); 283 | 284 | if (ngx_http_ssl_session_cache_conf_index == -1) { 285 | ngx_http_ssl_session_cache_conf_index = 286 | SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, NULL); 287 | if (ngx_http_ssl_session_cache_conf_index == -1) { 288 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "SSL_get_ex_new_index() failed"); 289 | return NGX_CONF_ERROR; 290 | } 291 | } 292 | 293 | if (SSL_CTX_set_ex_data(sscf->ssl.ctx, ngx_http_ssl_session_cache_conf_index, 294 | conf) == 0) { 295 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "SSL_CTX_set_ex_data() failed"); 296 | return NGX_CONF_ERROR; 297 | } 298 | 299 | ngx_http_ssl_session_cache_set_openssl_cb(sscf->ssl.ctx); 300 | 301 | conf->session_timeout = sscf->session_timeout; 302 | 303 | if (conf->onoff == NGX_SSL_SESSION_CACHE_ON) { 304 | return NGX_CONF_OK; 305 | } 306 | 307 | conf->onoff = prev->onoff; 308 | conf->queue_depth = prev->queue_depth; 309 | conf->proc_timeout = prev->proc_timeout; 310 | conf->interval = prev->interval; 311 | conf->cache_ctx = prev->cache_ctx; 312 | conf->cache_method = prev->cache_method; 313 | conf->url = prev->url; 314 | conf->auth = prev->auth; 315 | 316 | return NGX_CONF_OK; 317 | } 318 | 319 | static char* 320 | ngx_http_ssl_cache_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 321 | { 322 | ngx_ssl_session_cache_conf_t *sccf; 323 | 324 | sccf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_ssl_session_cache_module); 325 | 326 | return ngx_ssl_session_cache_conf(sccf, cf, cmd, conf); 327 | } 328 | -------------------------------------------------------------------------------- /ngx_ssl_session_cache_module.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "ngx_ssl_session_cache_module.h" 5 | 6 | #define CACHE_CONNECTED 1 7 | #define CACHE_NOT_CONNECTED 2 8 | 9 | static void 10 | ngx_ssl_session_cache_write_data(); 11 | static void 12 | ngx_ssl_session_cache_rehandshake(ngx_connection_t *c); 13 | 14 | #define NGX_CACHE_UNLIMITED -2 15 | 16 | #define NGX_CACHE_BUF_MIN_SIZE 256 17 | 18 | #define ngx_ssl_session_cache_free_node(ctx, n) do { \ 19 | (n)->out = (ngx_buf_t*)(ctx)->free_node; \ 20 | (ctx)->free_node = (n); } while(0); 21 | 22 | #define ngx_ssl_session_cache_free_buf(ctx, n) do { \ 23 | (n)->out->pos = (u_char*)(ctx)->free_out_buf; \ 24 | (ctx)->free_out_buf = (n)->out; } while(0); 25 | 26 | ngx_uint_t 27 | ngx_ssl_session_cache_get_size_len(ngx_uint_t size) 28 | { 29 | ngx_uint_t count = 0; 30 | while(size){ 31 | count++; 32 | size/=10; 33 | } 34 | return count; 35 | } 36 | 37 | ngx_buf_t * 38 | ngx_ssl_session_cache_get_buf(ngx_ssl_session_cache_ctx_t *cache_ctx, size_t size) 39 | { 40 | ngx_buf_t *b; 41 | ngx_buf_t **buf; 42 | 43 | if (size < NGX_CACHE_BUF_MIN_SIZE ) { 44 | size = NGX_CACHE_BUF_MIN_SIZE; 45 | } 46 | 47 | for (buf = &cache_ctx->free_out_buf; *buf; buf = (ngx_buf_t**)&b->pos) { 48 | b = *buf; 49 | if (size <= (size_t)(b->end - b->start)){ 50 | 51 | *buf =(ngx_buf_t*) b->pos; 52 | 53 | b->pos = b->start; 54 | b->last = b->start; 55 | 56 | return b; 57 | } 58 | } 59 | 60 | b = ngx_create_temp_buf(cache_ctx->pool, size); 61 | if (!b) { 62 | ngx_log_error(NGX_LOG_CRIT, cache_ctx->log, 0, "[remote ssl session cache] malloc buf(%d) fail", size); 63 | return NULL; 64 | } 65 | 66 | return b; 67 | } 68 | 69 | ngx_ssl_session_cache_node_t * 70 | ngx_ssl_session_cache_get_node(ngx_ssl_session_cache_ctx_t *cache_ctx) 71 | { 72 | ngx_ssl_session_cache_node_t *n; 73 | 74 | if (cache_ctx->free_node != NULL) { 75 | n = cache_ctx->free_node; 76 | cache_ctx->free_node = (ngx_ssl_session_cache_node_t*)n->out; 77 | 78 | return n; 79 | } 80 | 81 | n = ngx_pcalloc(cache_ctx->pool, sizeof(ngx_ssl_session_cache_node_t)); 82 | if (!n) { 83 | ngx_log_error(NGX_LOG_CRIT, cache_ctx->log, 0, "[remote ssl session cache] malloc node fail"); 84 | return NULL; 85 | } 86 | 87 | return n; 88 | } 89 | 90 | static ngx_int_t 91 | ngx_ssl_session_cache_auth(ngx_ssl_session_cache_ctx_t *cache_ctx, const u_char *auth, int len) 92 | { 93 | ngx_ssl_session_cache_node_t *node; 94 | 95 | node = ngx_ssl_session_cache_get_node(cache_ctx); 96 | if (node == NULL) { 97 | return NGX_ERROR; 98 | } 99 | 100 | node->out = cache_ctx->conf->cache_method->auth(cache_ctx, auth, len); 101 | if (node->out == NULL) { 102 | ngx_ssl_session_cache_free_node(cache_ctx, node); 103 | return NGX_ERROR; 104 | } 105 | 106 | node->msg_type = NGX_SSL_SESSION_CACHE_MSG_TYPE_AUTH; 107 | node->c = NULL; 108 | node->seq = 0; 109 | cache_ctx->queue_num++; 110 | 111 | ngx_queue_insert_tail(&cache_ctx->write_queue, &node->queue); 112 | 113 | ngx_ssl_session_cache_write_data(cache_ctx); 114 | 115 | return NGX_OK; 116 | } 117 | 118 | static ngx_int_t 119 | ngx_ssl_session_cache_get(ngx_ssl_session_cache_ctx_t *cache_ctx, ngx_connection_t *c, const u_char *id, int id_len) 120 | { 121 | ngx_ssl_session_cache_node_t *node; 122 | 123 | if (cache_ctx->conf->queue_depth != NGX_CACHE_UNLIMITED && cache_ctx->queue_num >= cache_ctx->conf->queue_depth) { 124 | ngx_log_debug(NGX_LOG_DEBUG_HTTP, cache_ctx->log, 0, 125 | "[remote ssl session cache] queue size exceed max size %d", cache_ctx->conf->queue_depth); 126 | return NGX_ERROR; 127 | } 128 | 129 | node = ngx_ssl_session_cache_get_node(cache_ctx); 130 | if (node == NULL) { 131 | return NGX_ERROR; 132 | } 133 | 134 | node->out = cache_ctx->conf->cache_method->get(cache_ctx, id, id_len); 135 | if (node->out == NULL){ 136 | ngx_ssl_session_cache_free_node(cache_ctx, node); 137 | 138 | return NGX_ERROR; 139 | } 140 | 141 | node->msg_type = NGX_SSL_SESSION_CACHE_MSG_TYPE_GET; 142 | node->c = c; 143 | node->seq = c->number; 144 | node->session.data = NULL; 145 | node->session.len = 0; 146 | 147 | cache_ctx->queue_num++; 148 | 149 | ngx_queue_insert_tail(&cache_ctx->write_queue, &node->queue); 150 | 151 | ngx_ssl_session_cache_write_data(cache_ctx); 152 | 153 | return NGX_OK; 154 | } 155 | 156 | ngx_int_t 157 | ngx_ssl_session_cache_set(ngx_ssl_session_cache_ctx_t *cache_ctx, ngx_connection_t *c, 158 | const u_char *id, int id_len, const u_char *sess, int sess_len) 159 | { 160 | ngx_ssl_session_cache_node_t *node = NULL; 161 | 162 | if (cache_ctx->conf->queue_depth != NGX_CACHE_UNLIMITED && cache_ctx->queue_num >= cache_ctx->conf->queue_depth) { 163 | ngx_log_debug(NGX_LOG_DEBUG_HTTP, cache_ctx->log, 0, 164 | "[remote ssl session cache] queue size exceed max size %d", cache_ctx->conf->queue_depth); 165 | return NGX_ERROR; 166 | } 167 | 168 | node = ngx_ssl_session_cache_get_node(cache_ctx); 169 | if (node == NULL) { 170 | return NGX_ERROR; 171 | } 172 | 173 | node->out = cache_ctx->conf->cache_method->set(cache_ctx, id, id_len, sess, 174 | sess_len, cache_ctx->conf->session_timeout); 175 | if (node->out == NULL ){ 176 | ngx_ssl_session_cache_free_node(cache_ctx, node); 177 | 178 | return NGX_ERROR; 179 | } 180 | 181 | node->msg_type = NGX_SSL_SESSION_CACHE_MSG_TYPE_SET; 182 | node->c = c; 183 | node->seq = c->number; 184 | cache_ctx->queue_num++; 185 | 186 | ngx_queue_insert_tail(&cache_ctx->write_queue, &node->queue); 187 | 188 | ngx_ssl_session_cache_write_data(cache_ctx); 189 | 190 | return NGX_OK; 191 | } 192 | 193 | static void 194 | ngx_ssl_session_cache_check(ngx_ssl_session_cache_ctx_t *cache_ctx) 195 | { 196 | ngx_ssl_session_cache_node_t *node; 197 | 198 | node = ngx_ssl_session_cache_get_node(cache_ctx); 199 | if (node == NULL) { 200 | return; 201 | } 202 | 203 | node->out = cache_ctx->conf->cache_method->check(cache_ctx); 204 | if (node->out == NULL) { 205 | ngx_ssl_session_cache_free_node(cache_ctx, node); 206 | return; 207 | } 208 | 209 | node->msg_type = NGX_SSL_SESSION_CACHE_MSG_TYPE_CHECK; 210 | 211 | cache_ctx->queue_num++; 212 | ngx_queue_insert_tail(&cache_ctx->write_queue, &node->queue); 213 | 214 | ngx_ssl_session_cache_write_data(cache_ctx); 215 | 216 | return; 217 | } 218 | 219 | static void 220 | ngx_ssl_session_cache_delete(ngx_ssl_session_cache_ctx_t *cache_ctx, const u_char *key, int len) 221 | { 222 | ngx_ssl_session_cache_node_t *node; 223 | 224 | node = ngx_ssl_session_cache_get_node(cache_ctx); 225 | if (node == NULL) { 226 | return; 227 | } 228 | 229 | node->out = cache_ctx->conf->cache_method->delete(cache_ctx, key, len); 230 | if (node->out == NULL) { 231 | ngx_ssl_session_cache_free_node(cache_ctx, node); 232 | return; 233 | } 234 | 235 | node->msg_type = NGX_SSL_SESSION_CACHE_MSG_TYPE_DEL; 236 | node->c = NULL; 237 | node->seq = 0; 238 | 239 | cache_ctx->queue_num++; 240 | ngx_queue_insert_tail(&cache_ctx->write_queue, &node->queue); 241 | 242 | ngx_ssl_session_cache_write_data(cache_ctx); 243 | 244 | return; 245 | } 246 | 247 | static void 248 | ngx_ssl_session_cache_clear_resource(ngx_ssl_session_cache_ctx_t *cache_ctx) 249 | { 250 | ngx_queue_t *q; 251 | ngx_ssl_session_cache_node_t *node; 252 | 253 | cache_ctx->is_connected = CACHE_NOT_CONNECTED; 254 | 255 | if (cache_ctx->pc.connection) { 256 | ngx_close_connection(cache_ctx->pc.connection); 257 | cache_ctx->pc.connection = NULL; 258 | } 259 | 260 | if (cache_ctx->ev.timer_set) { 261 | ngx_del_timer(&cache_ctx->ev); 262 | } 263 | 264 | q = ngx_queue_head(&cache_ctx->write_queue); 265 | 266 | while (q != ngx_queue_sentinel(&cache_ctx->write_queue)) { 267 | 268 | node = ngx_queue_data(q, ngx_ssl_session_cache_node_t, queue); 269 | ngx_ssl_session_cache_free_buf(cache_ctx, node); 270 | 271 | q = ngx_queue_next(q); 272 | } 273 | 274 | if (!ngx_queue_empty(&cache_ctx->write_queue)) { 275 | 276 | ngx_queue_add(&cache_ctx->read_queue, &cache_ctx->write_queue); 277 | } 278 | 279 | while (1) { 280 | q = ngx_queue_head(&cache_ctx->read_queue); 281 | if (q == ngx_queue_sentinel(&cache_ctx->read_queue)) { 282 | break; 283 | } 284 | 285 | node = ngx_queue_data(q, ngx_ssl_session_cache_node_t, queue); 286 | 287 | if (node->msg_type == NGX_SSL_SESSION_CACHE_MSG_TYPE_GET && node->c->number == node->seq && 288 | node->c->fd != -1) { 289 | ngx_ssl_session_cache_rehandshake(node->c); 290 | } 291 | 292 | ngx_queue_remove(&node->queue); 293 | 294 | ngx_ssl_session_cache_free_node(cache_ctx, node); 295 | } 296 | 297 | cache_ctx->queue_num = 0; 298 | ngx_queue_init(&cache_ctx->read_queue); 299 | ngx_queue_init(&cache_ctx->write_queue); 300 | 301 | cache_ctx->in.pos = cache_ctx->in.start; 302 | cache_ctx->in.last = cache_ctx->in.start; 303 | 304 | ngx_log_error(NGX_LOG_CRIT, cache_ctx->log, 0, "[remote ssl session cache] : close connection, clear resource"); 305 | } 306 | 307 | static void 308 | ngx_ssl_session_cache_clear_resource_add_timer(ngx_ssl_session_cache_ctx_t *cache_ctx) 309 | { 310 | ngx_ssl_session_cache_clear_resource(cache_ctx); 311 | 312 | ngx_add_timer(&cache_ctx->ev, cache_ctx->conf->interval); 313 | } 314 | 315 | static ngx_int_t 316 | ngx_ssl_session_cache_check_need_exit(ngx_ssl_session_cache_ctx_t *cache_ctx) 317 | { 318 | if (ngx_terminate || ngx_exiting || ngx_quit) { 319 | ngx_ssl_session_cache_clear_resource(cache_ctx); 320 | return 1; 321 | } 322 | return 0; 323 | } 324 | 325 | static ngx_int_t 326 | ngx_ssl_session_cache_process_buffer(ngx_ssl_session_cache_ctx_t *cache_ctx) 327 | { 328 | ngx_queue_t *q; 329 | ngx_ssl_session_cache_node_t *node; 330 | ngx_int_t rc; 331 | 332 | if (ngx_queue_empty(&cache_ctx->read_queue)) { 333 | return NGX_SSL_SESSION_CACHE_PARSE_MSG_PROTO_ERR; 334 | } 335 | 336 | while (1) { 337 | 338 | q = ngx_queue_head(&cache_ctx->read_queue); 339 | if (q == ngx_queue_sentinel(&cache_ctx->read_queue)) { 340 | return NGX_OK; 341 | } 342 | 343 | node = ngx_queue_data(q, ngx_ssl_session_cache_node_t, queue); 344 | 345 | rc = cache_ctx->conf->cache_method->parse(&cache_ctx->in, node); 346 | if (rc == NGX_SSL_SESSION_CACHE_PARSE_MSG_MORE_DATA) { 347 | return NGX_AGAIN; 348 | } else if(rc < 0 ) { 349 | return NGX_ERROR; 350 | } 351 | 352 | if (node->msg_type == NGX_SSL_SESSION_CACHE_MSG_TYPE_GET && 353 | node->c->number == node->seq && node->c->fd != -1) { 354 | ngx_ssl_session_cache_rehandshake(node->c); 355 | } 356 | 357 | ngx_queue_remove(&node->queue); 358 | cache_ctx->queue_num--; 359 | ngx_ssl_session_cache_free_node(cache_ctx, node); 360 | } 361 | } 362 | 363 | static void 364 | ngx_ssl_session_cache_read_handler(ngx_event_t *event) 365 | { 366 | ngx_ssl_session_cache_ctx_t *cache_ctx; 367 | ngx_connection_t *c; 368 | ngx_uint_t n, remain; 369 | ssize_t size; 370 | 371 | c = event->data; 372 | cache_ctx = c->data; 373 | 374 | if (ngx_ssl_session_cache_check_need_exit(cache_ctx)) { 375 | return; 376 | } 377 | 378 | if (event->timedout) { 379 | goto failed; 380 | } 381 | 382 | if (event->timer_set) { 383 | ngx_del_timer(event); 384 | } 385 | 386 | while (1) { 387 | n = cache_ctx->in.end - cache_ctx->in.last; 388 | 389 | if (n == 0) { 390 | if (cache_ctx->in.pos != cache_ctx->in.start) { 391 | 392 | remain = cache_ctx->in.last - cache_ctx->in.pos; 393 | ngx_memcpy(cache_ctx->in.start, cache_ctx->in.pos, remain); 394 | cache_ctx->in.pos = cache_ctx->in.start; 395 | cache_ctx->in.last = cache_ctx->in.pos + remain; 396 | n = cache_ctx->in.end - cache_ctx->in.last; 397 | } else { 398 | 399 | if( ngx_ssl_session_cache_process_buffer(cache_ctx) == NGX_ERROR) { 400 | goto failed; 401 | } 402 | } 403 | } 404 | 405 | size = c->recv(c, cache_ctx->in.last, n); 406 | 407 | if (size == NGX_AGAIN) { 408 | 409 | if (!ngx_queue_empty(&cache_ctx->read_queue)) { 410 | ngx_add_timer(event, cache_ctx->conf->proc_timeout); 411 | } 412 | 413 | return; 414 | } else if(size < 1){ 415 | 416 | goto failed; 417 | } 418 | 419 | cache_ctx->in.last += size; 420 | 421 | if (ngx_ssl_session_cache_process_buffer(cache_ctx) == NGX_ERROR) { 422 | goto failed; 423 | } 424 | } 425 | 426 | failed: 427 | ngx_ssl_session_cache_clear_resource_add_timer(cache_ctx); 428 | } 429 | 430 | static void 431 | ngx_ssl_session_cache_write_data(ngx_ssl_session_cache_ctx_t *cache_ctx) 432 | { 433 | ngx_queue_t *q; 434 | ngx_ssl_session_cache_node_t *node; 435 | ssize_t size; 436 | ngx_connection_t *c; 437 | 438 | c = cache_ctx->pc.connection; 439 | 440 | if (ngx_queue_empty(&cache_ctx->write_queue)) { 441 | if (ngx_handle_write_event(c->write, 0) != NGX_OK) { 442 | ngx_ssl_session_cache_clear_resource_add_timer(cache_ctx); 443 | } 444 | 445 | return; 446 | } 447 | 448 | while (1) { 449 | 450 | q = ngx_queue_head(&cache_ctx->write_queue); 451 | 452 | if (q == ngx_queue_sentinel(&cache_ctx->write_queue)) { 453 | 454 | if (ngx_handle_write_event(c->write, 0) != NGX_OK) { 455 | ngx_ssl_session_cache_clear_resource_add_timer(cache_ctx); 456 | return; 457 | } 458 | 459 | goto DONE; 460 | } 461 | 462 | node = ngx_queue_data(q, ngx_ssl_session_cache_node_t, queue); 463 | 464 | while (node->out->pos < node->out->last) { 465 | size = c->send(c, node->out->pos, node->out->last - node->out->pos); 466 | 467 | if (size >= 0) { 468 | node->out->pos += size; 469 | } else if (size == NGX_AGAIN) { 470 | 471 | ngx_add_timer(c->write, cache_ctx->conf->proc_timeout); 472 | 473 | if (ngx_handle_write_event(c->write, 0) != NGX_OK) { 474 | ngx_ssl_session_cache_clear_resource_add_timer(cache_ctx); 475 | return; 476 | } 477 | 478 | goto DONE; 479 | } else { 480 | return ngx_ssl_session_cache_clear_resource_add_timer(cache_ctx); 481 | } 482 | } 483 | 484 | ngx_ssl_session_cache_free_buf(cache_ctx, node); 485 | 486 | ngx_queue_remove(&node->queue); 487 | ngx_queue_insert_tail(&cache_ctx->read_queue, &node->queue); 488 | } 489 | 490 | DONE: 491 | 492 | if (!c->read->timer_set) { 493 | ngx_add_timer(c->read, cache_ctx->conf->proc_timeout); 494 | } 495 | 496 | return; 497 | } 498 | 499 | static void 500 | ngx_ssl_session_cache_write_handler(ngx_event_t *event) 501 | { 502 | ngx_ssl_session_cache_ctx_t *cache_ctx; 503 | 504 | cache_ctx = ((ngx_connection_t*)event->data)->data; 505 | 506 | if (ngx_ssl_session_cache_check_need_exit(cache_ctx)) { 507 | return; 508 | } 509 | 510 | if (event->timedout) { 511 | ngx_ssl_session_cache_clear_resource_add_timer(cache_ctx); 512 | return; 513 | } 514 | 515 | cache_ctx->is_connected = CACHE_CONNECTED; 516 | 517 | if (event->timer_set) { 518 | ngx_del_timer(event); 519 | } 520 | 521 | ngx_ssl_session_cache_write_data(cache_ctx); 522 | } 523 | 524 | static void 525 | ngx_ssl_session_cache_auth_handler(ngx_event_t *event) 526 | { 527 | ngx_ssl_session_cache_ctx_t *cache_ctx; 528 | 529 | cache_ctx = ((ngx_connection_t*)event->data)->data; 530 | 531 | if (ngx_ssl_session_cache_check_need_exit(cache_ctx)) { 532 | return; 533 | } 534 | 535 | if (event->timedout) { 536 | ngx_ssl_session_cache_clear_resource_add_timer(cache_ctx); 537 | return; 538 | } 539 | 540 | cache_ctx->is_connected = CACHE_CONNECTED; 541 | 542 | if (event->timer_set) { 543 | ngx_del_timer(event); 544 | } 545 | 546 | event->handler = ngx_ssl_session_cache_write_handler; 547 | 548 | if (ngx_ssl_session_cache_auth(cache_ctx, cache_ctx->conf->auth.data, cache_ctx->conf->auth.len) != NGX_OK) { 549 | ngx_ssl_session_cache_clear_resource_add_timer(cache_ctx); 550 | return; 551 | } 552 | 553 | return; 554 | } 555 | 556 | static void 557 | ngx_ssl_session_cache_connect(ngx_event_t *ev) 558 | { 559 | ngx_ssl_session_cache_ctx_t *cache_ctx; 560 | ngx_int_t rc; 561 | ngx_uint_t i; 562 | ngx_connection_t *c; 563 | 564 | cache_ctx = ev->data; 565 | 566 | for (i = 0; i < cache_ctx->conf->url.naddrs; i++) { 567 | 568 | cache_ctx->pc.name = &cache_ctx->conf->url.addrs[i].name; 569 | cache_ctx->pc.sockaddr = cache_ctx->conf->url.addrs[i].sockaddr; 570 | cache_ctx->pc.socklen = cache_ctx->conf->url.addrs[i].socklen; 571 | 572 | rc = ngx_event_connect_peer(&cache_ctx->pc); 573 | 574 | if (rc == NGX_ERROR || rc == NGX_DECLINED || rc == NGX_BUSY) { 575 | continue; 576 | } 577 | 578 | c = cache_ctx->pc.connection; 579 | c->data = cache_ctx; 580 | c->log = ev->log; 581 | c->read->log = ev->log; 582 | c->write->log = ev->log; 583 | c->write->handler = ngx_ssl_session_cache_write_handler; 584 | c->read->handler = ngx_ssl_session_cache_read_handler; 585 | 586 | if (cache_ctx->conf->auth.len != 0) { 587 | c->write->handler = ngx_ssl_session_cache_auth_handler; 588 | } 589 | 590 | if (rc == NGX_AGAIN) { 591 | ngx_add_timer(c->write, cache_ctx->conf->proc_timeout); 592 | return; 593 | } 594 | 595 | if (rc == NGX_OK) { 596 | c->write->handler(ev); 597 | return; 598 | } 599 | 600 | break; 601 | } 602 | } 603 | 604 | static void 605 | ngx_ssl_session_cache_time_handler(ngx_event_t *ev) 606 | { 607 | ngx_ssl_session_cache_ctx_t *cache_ctx; 608 | 609 | cache_ctx = ev->data; 610 | 611 | ngx_add_timer(&cache_ctx->ev, cache_ctx->conf->interval); 612 | 613 | if (cache_ctx->is_connected == CACHE_NOT_CONNECTED && 614 | cache_ctx->pc.connection == NULL) { 615 | return ngx_ssl_session_cache_connect(ev); 616 | } 617 | 618 | if (cache_ctx->queue_num == 0 && 619 | cache_ctx->pc.connection != NULL) { 620 | return ngx_ssl_session_cache_check(cache_ctx); 621 | } 622 | } 623 | 624 | int 625 | ngx_ssl_session_cache_new_session(ngx_ssl_session_cache_ctx_t *cache_ctx, 626 | ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess) 627 | { 628 | ngx_connection_t *c; 629 | u_char buf[NGX_SSL_MAX_SESSION_SIZE]; 630 | unsigned int session_id_length; 631 | int len; 632 | u_char *p, *session_id; 633 | 634 | if (cache_ctx->is_connected == CACHE_NOT_CONNECTED) { 635 | ngx_log_debug0(NGX_LOG_DEBUG_CORE, cache_ctx->log, 0, 636 | "[remote ssl session cache] new session when cache is not connected"); 637 | return 0; 638 | } 639 | 640 | len = i2d_SSL_SESSION(sess, NULL); 641 | 642 | /* do not cache too big session */ 643 | if (len > (int) NGX_SSL_MAX_SESSION_SIZE) { 644 | return 0; 645 | } 646 | 647 | p = buf; 648 | i2d_SSL_SESSION(sess, &p); 649 | 650 | c = ngx_ssl_get_connection(ssl_conn); 651 | 652 | #if OPENSSL_VERSION_NUMBER >= 0x0090800fL 653 | session_id = (u_char *) SSL_SESSION_get_id(sess, &session_id_length); 654 | #else 655 | session_id = sess->session_id; 656 | session_id_length = sess->session_id_length; 657 | #endif 658 | 659 | ngx_ssl_session_cache_set(cache_ctx, c, session_id, session_id_length, buf, len); 660 | 661 | return 0; 662 | } 663 | 664 | static void 665 | ngx_ssl_session_cache_rehandshake(ngx_connection_t *c) 666 | { 667 | ngx_int_t rc; 668 | 669 | rc = ngx_ssl_handshake(c); 670 | 671 | if (rc == NGX_AGAIN) { 672 | ngx_reusable_connection(c, 0); 673 | return; 674 | } 675 | 676 | c->ssl->handler(c); 677 | 678 | return; 679 | } 680 | 681 | ngx_ssl_session_t * 682 | ngx_ssl_session_cache_get_session(ngx_ssl_session_cache_ctx_t *cache_ctx, 683 | ngx_ssl_conn_t *ssl_conn, const u_char *id, int len, int *copy) 684 | { 685 | ngx_connection_t *c = NULL; 686 | ngx_ssl_session_t *sess; 687 | ngx_ssl_session_cache_node_t *node; 688 | ngx_queue_t *q; 689 | ngx_int_t rc; 690 | 691 | if (cache_ctx->is_connected == CACHE_NOT_CONNECTED) { 692 | ngx_log_debug0(NGX_LOG_DEBUG_CORE, cache_ctx->log, 0, 693 | "[remote ssl session cache] get session when cache is not connected"); 694 | return NULL; 695 | } 696 | 697 | do { 698 | *copy = 0; 699 | 700 | sess = NULL; 701 | 702 | c = ngx_ssl_get_connection(ssl_conn); 703 | 704 | q = ngx_queue_head(&cache_ctx->read_queue); 705 | if (q == ngx_queue_sentinel(&cache_ctx->read_queue)) { 706 | goto GET; 707 | } 708 | 709 | node = ngx_queue_data(q, ngx_ssl_session_cache_node_t, queue); 710 | 711 | 712 | if (node->c != c || node->seq != c->number) { 713 | GET: 714 | rc = ngx_ssl_session_cache_get(cache_ctx, c, id, len); 715 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cache_ctx->log, 0, "[remote ssl session cache] : first get session, async get done, result [%i]", rc); 716 | 717 | if (rc == NGX_ERROR) { 718 | 719 | return NULL; /*failed, new session*/ 720 | } else { 721 | 722 | ASYNC_pause_job(); 723 | } 724 | } else { 725 | 726 | if (node->session.len == 0 || node->session.data == NULL) { 727 | return NULL; 728 | } 729 | 730 | sess = d2i_SSL_SESSION(NULL, (const unsigned char**)&node->session.data, node->session.len); 731 | 732 | ngx_log_debug(NGX_LOG_DEBUG_HTTP, cache_ctx->log, 0, "[remote ssl session cache] : second get session done"); 733 | 734 | return sess; 735 | } 736 | }while(1); 737 | 738 | } 739 | 740 | void 741 | ngx_ssl_session_cache_remove_session(ngx_ssl_session_cache_ctx_t *cache_ctx, 742 | ngx_ssl_session_t *sess) 743 | { 744 | u_char *session_id; 745 | unsigned int id_len; 746 | 747 | if (cache_ctx->is_connected == CACHE_NOT_CONNECTED) { 748 | ngx_log_debug0(NGX_LOG_DEBUG_CORE, cache_ctx->log, 0, 749 | "[remote ssl session cache] delete session when cache is not connected"); 750 | return ; 751 | } 752 | 753 | #if OPENSSL_VERSION_NUMBER >= 0x0090800fL 754 | session_id = (u_char *) SSL_SESSION_get_id(sess, &id_len); 755 | #else 756 | session_id = sess->session_id; 757 | id_len = sess->session_id_length; 758 | #endif 759 | 760 | ngx_ssl_session_cache_delete(cache_ctx, session_id, id_len); 761 | 762 | ngx_log_debug(NGX_LOG_DEBUG_HTTP, cache_ctx->log, 0, "[remote ssl session cache] : in ngx_ssl_session_cache_remove_session"); 763 | return; 764 | } 765 | 766 | ngx_int_t 767 | ngx_ssl_session_cache_add_timers(ngx_cycle_t *cycle, ngx_ssl_session_cache_conf_t *sccf) 768 | { 769 | ngx_ssl_session_cache_ctx_t *cache_ctx; 770 | 771 | if (sccf->onoff != NGX_SSL_SESSION_CACHE_ON) { 772 | ngx_log_debug(NGX_LOG_DEBUG_HTTP, cycle->log, 0, "[remote ssl session cache] : store_sess off"); 773 | return NGX_OK; 774 | } 775 | 776 | if (sccf->cache_ctx->pool != NULL) { 777 | return NGX_OK; 778 | } 779 | 780 | cache_ctx = sccf->cache_ctx; 781 | 782 | cache_ctx->conf = sccf; 783 | 784 | cache_ctx->pool = ngx_create_pool(128 * 1024, cycle->log); 785 | if (cache_ctx->pool == NULL) { 786 | return NGX_ERROR; 787 | } 788 | 789 | cache_ctx->in.start = ngx_palloc(cache_ctx->pool, 32 * 1024); 790 | if (cache_ctx->in.start == NULL ) { 791 | return NGX_ERROR; 792 | } 793 | 794 | cache_ctx->in.pos = cache_ctx->in.start; 795 | cache_ctx->in.last = cache_ctx->in.start; 796 | cache_ctx->in.end = cache_ctx->in.start + 32 * 1024; 797 | 798 | cache_ctx->pc.get = ngx_event_get_peer; 799 | cache_ctx->pc.log = cycle->log; 800 | cache_ctx->pc.log_error = NGX_ERROR_ERR; 801 | cache_ctx->is_connected = CACHE_NOT_CONNECTED; 802 | cache_ctx->ev.handler = ngx_ssl_session_cache_time_handler; 803 | cache_ctx->ev.log = cycle->log; 804 | cache_ctx->ev.data = cache_ctx; 805 | cache_ctx->log = cycle->log; 806 | cache_ctx->queue_num = 0; 807 | 808 | ngx_queue_init(&cache_ctx->read_queue); 809 | ngx_queue_init(&cache_ctx->write_queue); 810 | 811 | ngx_add_timer(&cache_ctx->ev, sccf->interval); 812 | 813 | return NGX_OK; 814 | } 815 | 816 | static ngx_ssl_session_cache_method_t * 817 | ngx_ssl_session_cache_type(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t *default_port) 818 | { 819 | int i; 820 | ngx_module_t **module; 821 | ngx_ssl_session_cache_module_t *module_ctx; 822 | 823 | module = cf->cycle->modules; 824 | 825 | *default_port = 0; 826 | 827 | for (i = 0 ;module[i]; i++) { 828 | if (module[i]->type != NGX_RSSC_MODULE) { 829 | continue; 830 | } 831 | 832 | module_ctx = module[i]->ctx; 833 | 834 | if (module_ctx->name.len != name->len || 835 | ngx_strncmp(module_ctx->name.data, name->data, name->len)) { 836 | continue; 837 | } 838 | 839 | return module_ctx->init(cf->pool, default_port); 840 | } 841 | 842 | return NULL; 843 | } 844 | 845 | char* 846 | ngx_ssl_session_cache_conf(ngx_ssl_session_cache_conf_t *sccf, ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 847 | { 848 | ngx_str_t *value, s, addr = ngx_null_string, type; 849 | ngx_uint_t i, port, default_port, interval; 850 | ngx_msec_t timeout; 851 | ngx_int_t count, onoff; 852 | 853 | value = cf->args->elts; 854 | onoff = NGX_SSL_SESSION_CACHE_ON; 855 | 856 | port = 0; 857 | timeout = 1000; 858 | interval = 200; 859 | count = 5000; 860 | 861 | ngx_str_set(&type, "redis"); 862 | 863 | if (sccf->onoff != NGX_CONF_UNSET) { 864 | return "is duplicate"; 865 | } 866 | 867 | for (i = 1; i < cf->args->nelts; ++i) { 868 | if (ngx_strncmp(value[i].data, "addr=", 5) == 0) { 869 | addr.len = value[i].len - 5; 870 | addr.data = value[i].data + 5; 871 | continue; 872 | } 873 | 874 | if (ngx_strncmp(value[i].data, "port=", 5) == 0) { 875 | s.len = value[i].len - 5; 876 | s.data = value[i].data + 5; 877 | port = ngx_atoi(s.data, s.len); 878 | if (port == 0) { 879 | goto invalid_param; 880 | } 881 | continue; 882 | } 883 | 884 | if (ngx_strncmp(value[i].data, "auth=", 5) == 0) { 885 | sccf->auth.len = value[i].len - 5; 886 | sccf->auth.data = value[i].data + 5; 887 | continue; 888 | } 889 | 890 | if (ngx_strncmp(value[i].data, "timeout=", 8) == 0) { 891 | s.len = value[i].len - 8; 892 | s.data = value[i].data + 8; 893 | timeout = ngx_atoi(s.data, s.len); 894 | if (timeout == 0) { 895 | goto invalid_param; 896 | } 897 | continue; 898 | } 899 | 900 | if (ngx_strncmp(value[i].data, "interval=", 9) == 0) { 901 | s.len = value[i].len - 9; 902 | s.data = value[i].data + 9; 903 | interval = ngx_atoi(s.data, s.len); 904 | if (interval == 0) { 905 | goto invalid_param; 906 | } 907 | continue; 908 | } 909 | 910 | if (ngx_strncmp(value[i].data, "count=", 6) == 0) { 911 | s.len = value[i].len - 6; 912 | s.data = value[i].data + 6; 913 | 914 | if (ngx_strlen("unlimited") == s.len && ngx_strncmp(s.data, "unlimited", s.len) == 0) { 915 | count = NGX_CACHE_UNLIMITED; 916 | } else { 917 | count = ngx_atoi(s.data, s.len); 918 | if (count <= 0) { 919 | goto invalid_param; 920 | } 921 | } 922 | continue; 923 | } 924 | 925 | if (value[i].len == 3 && ngx_strncmp(value[i].data, "off", 3) == 0) { 926 | onoff = NGX_SSL_SESSION_CACHE_OFF; 927 | continue; 928 | } 929 | 930 | if (ngx_strncmp(value[i].data, "type=", 5) == 0) { 931 | type.len = value[i].len - 5; 932 | type.data = value[i].data + 5; 933 | continue; 934 | } 935 | 936 | goto invalid_param; 937 | } 938 | 939 | if (onoff == NGX_SSL_SESSION_CACHE_OFF ) { 940 | sccf->onoff = NGX_SSL_SESSION_CACHE_OFF; 941 | return NGX_CONF_OK; 942 | } 943 | 944 | sccf->cache_method = ngx_ssl_session_cache_type(cf, &type, &default_port); 945 | if (sccf->cache_method == NULL) { 946 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 947 | "remote_ssl_session_cache init cache type[%V] fail", &type); 948 | return NGX_CONF_ERROR; 949 | } 950 | 951 | if (addr.len == 0 || addr.data == NULL) { 952 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 953 | "invalid ssl session cache param, remote_ssl_session_cache url empty"); 954 | return NGX_CONF_ERROR; 955 | } 956 | 957 | if (port == 0 ) { 958 | port = default_port; 959 | } 960 | 961 | sccf->url.host = addr; 962 | sccf->url.port = port; 963 | sccf->proc_timeout = timeout; 964 | sccf->interval = interval; 965 | sccf->queue_depth = count; 966 | sccf->onoff = onoff; 967 | 968 | sccf->cache_ctx = ngx_pcalloc(cf->pool, sizeof(*sccf->cache_ctx)); 969 | if (sccf->cache_ctx == NULL) { 970 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 971 | "remote_ssl_session_cache alloc memory fail"); 972 | return NGX_CONF_ERROR; 973 | } 974 | 975 | if (ngx_inet_resolve_host(cf->pool, &sccf->url) != NGX_OK) { 976 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 977 | "parse addr failed, url: \"%V\"", &addr); 978 | return NGX_CONF_ERROR; 979 | } 980 | 981 | return NGX_CONF_OK; 982 | 983 | invalid_param: 984 | 985 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 986 | "invalid remote_ssl_session_cache param \"%V\"", &value[i]); 987 | 988 | return NGX_CONF_ERROR; 989 | } 990 | -------------------------------------------------------------------------------- /ngx_ssl_session_cache_module.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #ifndef _NGX_SSL_SESSION_CACHE_MODULE_H_ 7 | #define _NGX_SSL_SESSION_CACHE_MODULE_H_ 8 | 9 | #define NGX_RSSC_MODULE 0x52535343 /* "RSSC" */ 10 | 11 | #define NGX_SSL_SESSION_CACHE_MSG_TYPE_SET 1 12 | #define NGX_SSL_SESSION_CACHE_MSG_TYPE_GET 2 13 | #define NGX_SSL_SESSION_CACHE_MSG_TYPE_DEL 3 14 | #define NGX_SSL_SESSION_CACHE_MSG_TYPE_AUTH 4 15 | #define NGX_SSL_SESSION_CACHE_MSG_TYPE_CHECK 5 16 | 17 | #define NGX_SSL_SESSION_CACHE_PARSE_MSG_OK 0 18 | #define NGX_SSL_SESSION_CACHE_PARSE_MSG_MORE_DATA -1 19 | #define NGX_SSL_SESSION_CACHE_PARSE_MSG_PROTO_ERR -2 20 | #define NGX_SSL_SESSION_CACHE_PARSE_MSG_TYPE_ERR -3 21 | #define NGX_SSL_SESSION_CACHE_PARSE_MSG_DATA_LARGE -4 22 | #define NGX_SSL_SESSION_CACHE_PARSE_MSG_STATUS_ERR -5 23 | 24 | #define NGX_SSL_SESSION_CACHE_OFF 0 25 | #define NGX_SSL_SESSION_CACHE_ON 1 26 | 27 | struct ngx_ssl_session_cache_ctx_s; 28 | typedef struct ngx_ssl_session_cache_ctx_s ngx_ssl_session_cache_ctx_t; 29 | 30 | typedef struct { 31 | ngx_int_t msg_type; 32 | ngx_connection_t *c; 33 | ngx_buf_t *out; 34 | ngx_uint_t seq; 35 | ngx_queue_t queue; 36 | ngx_str_t session; 37 | } ngx_ssl_session_cache_node_t; 38 | 39 | typedef struct { 40 | ngx_buf_t *(*auth)(ngx_ssl_session_cache_ctx_t *ctx, const u_char *auth, int len); 41 | 42 | ngx_buf_t *(*set)(ngx_ssl_session_cache_ctx_t *ctx, const u_char *key,int keylen, 43 | const u_char *session, int sesslen, unsigned int timeout); 44 | 45 | ngx_buf_t *(*get)(ngx_ssl_session_cache_ctx_t *ctx, const u_char *key, int len); 46 | ngx_buf_t *(*delete)(ngx_ssl_session_cache_ctx_t *ctx, const u_char *key, int len); 47 | ngx_buf_t *(*check)(ngx_ssl_session_cache_ctx_t *ctx); 48 | ngx_int_t (*parse)(ngx_buf_t *in, ngx_ssl_session_cache_node_t *node); 49 | } ngx_ssl_session_cache_method_t; 50 | 51 | typedef struct { 52 | ngx_url_t url; 53 | ngx_int_t queue_depth; 54 | ngx_msec_t proc_timeout; 55 | ngx_msec_t interval; 56 | ngx_msec_t session_timeout; 57 | ngx_int_t onoff; 58 | ngx_str_t auth; 59 | ngx_ssl_session_cache_ctx_t *cache_ctx; 60 | ngx_ssl_session_cache_method_t *cache_method; 61 | } ngx_ssl_session_cache_conf_t; 62 | 63 | 64 | 65 | struct ngx_ssl_session_cache_ctx_s { 66 | ngx_pool_t *pool; 67 | ngx_event_t ev; 68 | ngx_buf_t in; 69 | ngx_buf_t *free_out_buf; 70 | ngx_ssl_session_cache_node_t *free_node; 71 | ngx_log_t *log; 72 | ngx_queue_t write_queue; 73 | ngx_queue_t read_queue; 74 | ngx_peer_connection_t pc; 75 | ngx_ssl_session_cache_conf_t *conf; 76 | ngx_int_t is_connected; 77 | ngx_int_t queue_num; 78 | }; 79 | 80 | 81 | typedef struct { 82 | ngx_str_t name; 83 | ngx_ssl_session_cache_method_t *(*init)(ngx_pool_t *pool, ngx_uint_t *default_port); 84 | }ngx_ssl_session_cache_module_t; 85 | 86 | ngx_uint_t 87 | ngx_ssl_session_cache_get_size_len(ngx_uint_t size); 88 | 89 | ngx_buf_t * 90 | ngx_ssl_session_cache_get_buf(ngx_ssl_session_cache_ctx_t *cache_ctx, size_t size); 91 | 92 | ngx_int_t 93 | ngx_ssl_session_cache_add_timers(ngx_cycle_t *cycle, ngx_ssl_session_cache_conf_t *sscf); 94 | 95 | int 96 | ngx_ssl_session_cache_new_session(ngx_ssl_session_cache_ctx_t *cache_ctx, 97 | ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess); 98 | 99 | ngx_ssl_session_t * 100 | ngx_ssl_session_cache_get_session(ngx_ssl_session_cache_ctx_t *cache_ctx, 101 | ngx_ssl_conn_t *ssl_conn, const u_char *id, int len, int *copy); 102 | 103 | void 104 | ngx_ssl_session_cache_remove_session(ngx_ssl_session_cache_ctx_t *cache_ctx, 105 | ngx_ssl_session_t *sess); 106 | 107 | char* 108 | ngx_ssl_session_cache_conf(ngx_ssl_session_cache_conf_t *sccf, 109 | ngx_conf_t *cf, ngx_command_t *cmd, void *conf); 110 | 111 | #endif 112 | --------------------------------------------------------------------------------