blob: 59ac8b83162e9086441b4a5f23b55c2991cb4f4b [file] [log] [blame]
Emeric Brun3e541d12012-09-03 11:14:36 +02001/*
2 * shctx.c - shared context management functions for SSL
3 *
4 * Copyright (C) 2011-2012 EXCELIANCE
5 *
6 * Author: Emeric Brun - emeric@exceliance.fr
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 */
13
14#include <sys/mman.h>
Emeric Brunaf9619d2012-11-28 18:47:52 +010015#include <arpa/inet.h>
Willy Tarreauce3f9132014-05-28 16:47:01 +020016#include <ebmbtree.h>
William Lallemand24a7a752017-10-09 14:17:39 +020017#include <types/global.h>
William Lallemand4f45bb92017-10-30 20:08:51 +010018#include <common/mini-clist.h>
19#include "proto/shctx.h"
William Lallemanded0b5ad2017-10-30 19:36:36 +010020
William Lallemand24a7a752017-10-09 14:17:39 +020021#if !defined (USE_PRIVATE_CACHE)
William Lallemand4f45bb92017-10-30 20:08:51 +010022
William Lallemand24a7a752017-10-09 14:17:39 +020023int use_shared_mem = 0;
William Lallemand4f45bb92017-10-30 20:08:51 +010024
Emeric Brun9faf0712012-09-25 11:11:16 +020025#endif
Emeric Brun3e541d12012-09-03 11:14:36 +020026
William Lallemand4f45bb92017-10-30 20:08:51 +010027/*
28 * Reserve a row, put it in the hotlist, set the refcount to 1
29 *
30 * Reserve blocks in the avail list and put them in the hot list
31 * Return the first block put in the hot list or NULL if not enough blocks available
32 */
33struct shared_block *shctx_row_reserve_hot(struct shared_context *shctx, int data_len)
34{
35 struct shared_block *block, *sblock, *ret = NULL, *first;
36 int enough = 0;
37 int freed = 0;
38
39 /* not enough usable blocks */
40 if (data_len > shctx->nbav * shctx->block_size)
41 goto out;
Emeric Brun3e541d12012-09-03 11:14:36 +020042
William Lallemand4f45bb92017-10-30 20:08:51 +010043 while (!enough && !LIST_ISEMPTY(&shctx->avail)) {
44 int count = 0;
45 int first_count = 0, first_len = 0;
Emeric Brun3e541d12012-09-03 11:14:36 +020046
William Lallemand4f45bb92017-10-30 20:08:51 +010047 first = block = LIST_NEXT(&shctx->avail, struct shared_block *, list);
48 if (ret == NULL)
49 ret = first;
Emeric Brun3e541d12012-09-03 11:14:36 +020050
William Lallemand4f45bb92017-10-30 20:08:51 +010051 first_count = first->block_count;
52 first_len = first->len;
53 /*
54 Should never been set to 0.
55 if (first->block_count == 0)
56 first->block_count = 1;
57 */
Emeric Brun3e541d12012-09-03 11:14:36 +020058
William Lallemand4f45bb92017-10-30 20:08:51 +010059 list_for_each_entry_safe_from(block, sblock, &shctx->avail, list) {
60
61 /* release callback */
62 if (first_len && shctx->free_block)
63 shctx->free_block(first, block);
64
65 block->block_count = 1;
66 block->len = 0;
67
68 freed++;
69 data_len -= shctx->block_size;
70
71 if (data_len > 0)
72 shctx_block_set_hot(shctx, block);
73
74 if (data_len <= 0 && !enough) {
75 shctx_block_set_hot(shctx, block);
76 ret->block_count = freed;
77 ret->refcount = 1;
78 enough = 1;
79 }
80
81 count++;
82 if (count >= first_count)
83 break;
Emeric Brunaf9619d2012-11-28 18:47:52 +010084 }
Emeric Brunaf9619d2012-11-28 18:47:52 +010085 }
William Lallemand4f45bb92017-10-30 20:08:51 +010086
87out:
Emeric Brunaf9619d2012-11-28 18:47:52 +010088 return ret;
89}
Emeric Brun3e541d12012-09-03 11:14:36 +020090
William Lallemand4f45bb92017-10-30 20:08:51 +010091/*
92 * if the refcount is 0 move the row to the hot list. Increment the refcount
Emeric Brunaf9619d2012-11-28 18:47:52 +010093 */
William Lallemand4f45bb92017-10-30 20:08:51 +010094void shctx_row_inc_hot(struct shared_context *shctx, struct shared_block *first)
Emeric Brun3e541d12012-09-03 11:14:36 +020095{
William Lallemand4f45bb92017-10-30 20:08:51 +010096 struct shared_block *block, *sblock;
97 int count = 0;
Emeric Brunaf9619d2012-11-28 18:47:52 +010098
William Lallemand4f45bb92017-10-30 20:08:51 +010099 if (first->refcount <= 0) {
100
101 block = first;
102
103 list_for_each_entry_safe_from(block, sblock, &shctx->avail, list) {
104
105 shctx_block_set_hot(shctx, block);
106
107 count++;
108 if (count >= first->block_count)
109 break;
Emeric Brunaf9619d2012-11-28 18:47:52 +0100110 }
Emeric Brunaf9619d2012-11-28 18:47:52 +0100111 }
Emeric Brunaf9619d2012-11-28 18:47:52 +0100112
William Lallemand4f45bb92017-10-30 20:08:51 +0100113 first->refcount++;
Emeric Brunaf9619d2012-11-28 18:47:52 +0100114}
Emeric Brun3e541d12012-09-03 11:14:36 +0200115
William Lallemand4f45bb92017-10-30 20:08:51 +0100116/*
117 * decrement the refcount and move the row at the end of the avail list if it reaches 0.
Emeric Brunaf9619d2012-11-28 18:47:52 +0100118 */
William Lallemand4f45bb92017-10-30 20:08:51 +0100119void shctx_row_dec_hot(struct shared_context *shctx, struct shared_block *first)
Emeric Brunaf9619d2012-11-28 18:47:52 +0100120{
William Lallemand4f45bb92017-10-30 20:08:51 +0100121 struct shared_block *block, *sblock;
122 int count = 0;
Emeric Brunaf9619d2012-11-28 18:47:52 +0100123
William Lallemand4f45bb92017-10-30 20:08:51 +0100124 first->refcount--;
Emeric Brun3e541d12012-09-03 11:14:36 +0200125
William Lallemand4f45bb92017-10-30 20:08:51 +0100126 if (first->refcount <= 0) {
Emeric Brun3e541d12012-09-03 11:14:36 +0200127
William Lallemand4f45bb92017-10-30 20:08:51 +0100128 block = first;
Emeric Brun3e541d12012-09-03 11:14:36 +0200129
William Lallemand4f45bb92017-10-30 20:08:51 +0100130 list_for_each_entry_safe_from(block, sblock, &shctx->hot, list) {
Emeric Brun3e541d12012-09-03 11:14:36 +0200131
William Lallemand4f45bb92017-10-30 20:08:51 +0100132 shctx_block_set_avail(shctx, block);
Emeric Brun3e541d12012-09-03 11:14:36 +0200133
William Lallemand4f45bb92017-10-30 20:08:51 +0100134 count++;
135 if (count >= first->block_count)
Emeric Brunaf9619d2012-11-28 18:47:52 +0100136 break;
Emeric Brunaf9619d2012-11-28 18:47:52 +0100137 }
138 }
Emeric Brun3e541d12012-09-03 11:14:36 +0200139
William Lallemand4f45bb92017-10-30 20:08:51 +0100140}
141
142
143/*
144 * Append data in the row if there is enough space.
145 * The row should be in the hot list
146 *
147 * Return the amount of appended data if ret >= 0
148 * or how much more space it needs to contains the data if < 0.
149 */
150int shctx_row_data_append(struct shared_context *shctx, struct shared_block *first, unsigned char *data, int len)
151{
152 int remain, start;
153 int count = 0;
154 struct shared_block *block;
155
156
157 /* return -<len> needed to work */
158 if (len > first->block_count * shctx->block_size - first->len)
159 return (first->block_count * shctx->block_size - first->len) - len;
160
161 /* skipping full buffers, stop at the first buffer with remaining space */
162 block = first;
163 list_for_each_entry_from(block, &shctx->hot, list) {
164 count++;
165
166
167 /* break if there is not enough blocks */
168 if (count > first->block_count)
169 break;
170
171 /* end of copy */
172 if (len <= 0)
173 break;
174
175 /* skip full buffers */
176 if (count * shctx->block_size <= first->len)
177 continue;
178
179 /* remaining space in the current block which is not full */
180 remain = (shctx->block_size * count - first->len) % shctx->block_size;
181 /* if remain == 0, previous buffer are full, or first->len == 0 */
182 remain = remain ? remain : shctx->block_size;
183
184 /* start must be calculated before remain is modified */
185 start = shctx->block_size - remain;
186
187 /* must not try to copy more than len */
188 remain = MIN(remain, len);
189
190 memcpy(block->data + start, data, remain);
191 data += remain;
192 len -= remain;
193 first->len += remain; /* update len in the head of the row */
194 }
195
196 return len;
Emeric Brunaf9619d2012-11-28 18:47:52 +0100197}
Emeric Brun3e541d12012-09-03 11:14:36 +0200198
William Lallemand4f45bb92017-10-30 20:08:51 +0100199/*
200 * Copy <len> data from a row of blocks, return the remaining data to copy
201 * If 0 is returned, the full data has successfuly be copied
202 *
203 * The row should be in the hot list
204 */
205int shctx_row_data_get(struct shared_context *shctx, struct shared_block *first,
206 unsigned char *dst, int offset, int len)
207{
208 int count = 0, size = 0, start = -1;
209 struct shared_block *block;
210
William Lallemand7217c462017-10-31 20:21:46 +0100211 /* can't copy more */
212 if (len > first->len)
213 len = first->len;
214
William Lallemand4f45bb92017-10-30 20:08:51 +0100215 block = first;
216 count = 0;
217 /* Pass through the blocks to copy them */
218 list_for_each_entry_from(block, &shctx->hot, list) {
219 if (count >= first->block_count || len <= 0)
220 break;
221
222 count++;
223 /* continue until we are in right block
224 corresponding to the offset */
225 if (count < offset / shctx->block_size + 1)
226 continue;
227
228 /* on the first block, data won't possibly began at offset 0 */
229 if (start == -1)
230 start = offset - (count - 1) * shctx->block_size;
Emeric Brun3e541d12012-09-03 11:14:36 +0200231
William Lallemand4f45bb92017-10-30 20:08:51 +0100232 /* size can be lower than a block when copying the last block */
233 size = MIN(shctx->block_size - start, len);
234
235 memcpy(dst, block->data + start, size);
236 dst += size;
237 len -= size;
238 start = 0;
239 }
240 return len;
241}
Emeric Brun3e541d12012-09-03 11:14:36 +0200242
Emeric Brun3e541d12012-09-03 11:14:36 +0200243/* Allocate shared memory context.
William Lallemand4f45bb92017-10-30 20:08:51 +0100244 * <maxblocks> is maximum blocks.
245 * If <maxblocks> is set to less or equal to 0, ssl cache is disabled.
246 * Returns: -1 on alloc failure, <maxblocks> if it performs context alloc,
Emeric Brunaf9619d2012-11-28 18:47:52 +0100247 * and 0 if cache is already allocated.
248 */
William Lallemand4f45bb92017-10-30 20:08:51 +0100249int shctx_init(struct shared_context **orig_shctx, int maxblocks, int blocksize, int extra, int shared)
Emeric Brun3e541d12012-09-03 11:14:36 +0200250{
251 int i;
William Lallemand3f85c9a2017-10-09 16:30:50 +0200252 struct shared_context *shctx;
253 int ret;
Emeric Brun9faf0712012-09-25 11:11:16 +0200254#ifndef USE_PRIVATE_CACHE
Emeric Bruncd1a5262014-05-07 23:11:42 +0200255#ifdef USE_PTHREAD_PSHARED
Emeric Brun3e541d12012-09-03 11:14:36 +0200256 pthread_mutexattr_t attr;
Emeric Bruncd1a5262014-05-07 23:11:42 +0200257#endif
Emeric Brun9faf0712012-09-25 11:11:16 +0200258#endif
William Lallemand4f45bb92017-10-30 20:08:51 +0100259 void *cur;
Emeric Brun4b3091e2012-09-24 15:48:52 +0200260 int maptype = MAP_PRIVATE;
Emeric Brun3e541d12012-09-03 11:14:36 +0200261
William Lallemand4f45bb92017-10-30 20:08:51 +0100262 if (maxblocks <= 0)
Emeric Brun22890a12012-12-28 14:41:32 +0100263 return 0;
Emeric Brun3e541d12012-09-03 11:14:36 +0200264
Emeric Brun9faf0712012-09-25 11:11:16 +0200265#ifndef USE_PRIVATE_CACHE
Emeric Brun4b3091e2012-09-24 15:48:52 +0200266 if (shared)
267 maptype = MAP_SHARED;
Emeric Brun9faf0712012-09-25 11:11:16 +0200268#endif
Emeric Brun4b3091e2012-09-24 15:48:52 +0200269
William Lallemand4f45bb92017-10-30 20:08:51 +0100270 shctx = (struct shared_context *)mmap(NULL, sizeof(struct shared_context) + extra + (maxblocks * (sizeof(struct shared_block) + blocksize)),
Emeric Brun4b3091e2012-09-24 15:48:52 +0200271 PROT_READ | PROT_WRITE, maptype | MAP_ANON, -1, 0);
Emeric Brun3e541d12012-09-03 11:14:36 +0200272 if (!shctx || shctx == MAP_FAILED) {
273 shctx = NULL;
William Lallemand3f85c9a2017-10-09 16:30:50 +0200274 ret = SHCTX_E_ALLOC_CACHE;
275 goto err;
Emeric Brun3e541d12012-09-03 11:14:36 +0200276 }
277
William Lallemand4f45bb92017-10-30 20:08:51 +0100278 shctx->nbav = 0;
279
Emeric Brun9faf0712012-09-25 11:11:16 +0200280#ifndef USE_PRIVATE_CACHE
Emeric Bruncaa19cc2014-05-07 16:10:18 +0200281 if (maptype == MAP_SHARED) {
Emeric Bruncd1a5262014-05-07 23:11:42 +0200282#ifdef USE_PTHREAD_PSHARED
Emeric Bruncaa19cc2014-05-07 16:10:18 +0200283 if (pthread_mutexattr_init(&attr)) {
William Lallemand4f45bb92017-10-30 20:08:51 +0100284 munmap(shctx, sizeof(struct shared_context) + extra + (maxblocks * (sizeof(struct shared_block) + blocksize)));
Emeric Bruncaa19cc2014-05-07 16:10:18 +0200285 shctx = NULL;
William Lallemand3f85c9a2017-10-09 16:30:50 +0200286 ret = SHCTX_E_INIT_LOCK;
287 goto err;
Emeric Bruncaa19cc2014-05-07 16:10:18 +0200288 }
289
290 if (pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)) {
291 pthread_mutexattr_destroy(&attr);
William Lallemand4f45bb92017-10-30 20:08:51 +0100292 munmap(shctx, sizeof(struct shared_context) + extra + (maxblocks * (sizeof(struct shared_block) + blocksize)));
Emeric Bruncaa19cc2014-05-07 16:10:18 +0200293 shctx = NULL;
William Lallemand3f85c9a2017-10-09 16:30:50 +0200294 ret = SHCTX_E_INIT_LOCK;
295 goto err;
Emeric Bruncaa19cc2014-05-07 16:10:18 +0200296 }
297
298 if (pthread_mutex_init(&shctx->mutex, &attr)) {
299 pthread_mutexattr_destroy(&attr);
William Lallemand4f45bb92017-10-30 20:08:51 +0100300 munmap(shctx, sizeof(struct shared_context) + extra + (maxblocks * (sizeof(struct shared_block) + blocksize)));
Emeric Bruncaa19cc2014-05-07 16:10:18 +0200301 shctx = NULL;
William Lallemand3f85c9a2017-10-09 16:30:50 +0200302 ret = SHCTX_E_INIT_LOCK;
303 goto err;
Emeric Bruncaa19cc2014-05-07 16:10:18 +0200304 }
Emeric Bruncd1a5262014-05-07 23:11:42 +0200305#else
306 shctx->waiters = 0;
Emeric Brun3e541d12012-09-03 11:14:36 +0200307#endif
Emeric Brun4b3091e2012-09-24 15:48:52 +0200308 use_shared_mem = 1;
Emeric Bruncaa19cc2014-05-07 16:10:18 +0200309 }
Emeric Brun9faf0712012-09-25 11:11:16 +0200310#endif
Emeric Brun4b3091e2012-09-24 15:48:52 +0200311
William Lallemand4f45bb92017-10-30 20:08:51 +0100312 LIST_INIT(&shctx->avail);
313 LIST_INIT(&shctx->hot);
Emeric Brun3e541d12012-09-03 11:14:36 +0200314
William Lallemand4f45bb92017-10-30 20:08:51 +0100315 shctx->block_size = blocksize;
Emeric Brunaf9619d2012-11-28 18:47:52 +0100316
William Lallemand4f45bb92017-10-30 20:08:51 +0100317 /* init the free blocks after the shared context struct */
318 cur = (void *)shctx + sizeof(struct shared_context) + extra;
319 for (i = 0; i < maxblocks; i++) {
320 struct shared_block *cur_block = (struct shared_block *)cur;
321 cur_block->len = 0;
322 cur_block->refcount = 0;
323 cur_block->block_count = 1;
324 LIST_ADDQ(&shctx->avail, &cur_block->list);
325 shctx->nbav++;
326 cur += sizeof(struct shared_block) + blocksize;
Emeric Brun3e541d12012-09-03 11:14:36 +0200327 }
William Lallemand4f45bb92017-10-30 20:08:51 +0100328 ret = maxblocks;
William Lallemand3f85c9a2017-10-09 16:30:50 +0200329
330err:
331 *orig_shctx = shctx;
332 return ret;
Emeric Brun3e541d12012-09-03 11:14:36 +0200333}
334