blob: 61fd12d3d61823d4cecf0305e1e9069f14d473e3 [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"
20#include <proto/openssl-compat.h>
William Lallemanded0b5ad2017-10-30 19:36:36 +010021
William Lallemand24a7a752017-10-09 14:17:39 +020022#if !defined (USE_PRIVATE_CACHE)
William Lallemand4f45bb92017-10-30 20:08:51 +010023
William Lallemand24a7a752017-10-09 14:17:39 +020024int use_shared_mem = 0;
William Lallemand4f45bb92017-10-30 20:08:51 +010025
Emeric Brun9faf0712012-09-25 11:11:16 +020026#endif
Emeric Brun3e541d12012-09-03 11:14:36 +020027
William Lallemand4f45bb92017-10-30 20:08:51 +010028/*
29 * Reserve a row, put it in the hotlist, set the refcount to 1
30 *
31 * Reserve blocks in the avail list and put them in the hot list
32 * Return the first block put in the hot list or NULL if not enough blocks available
33 */
34struct shared_block *shctx_row_reserve_hot(struct shared_context *shctx, int data_len)
35{
36 struct shared_block *block, *sblock, *ret = NULL, *first;
37 int enough = 0;
38 int freed = 0;
39
40 /* not enough usable blocks */
41 if (data_len > shctx->nbav * shctx->block_size)
42 goto out;
Emeric Brun3e541d12012-09-03 11:14:36 +020043
William Lallemand4f45bb92017-10-30 20:08:51 +010044 while (!enough && !LIST_ISEMPTY(&shctx->avail)) {
45 int count = 0;
46 int first_count = 0, first_len = 0;
Emeric Brun3e541d12012-09-03 11:14:36 +020047
William Lallemand4f45bb92017-10-30 20:08:51 +010048 first = block = LIST_NEXT(&shctx->avail, struct shared_block *, list);
49 if (ret == NULL)
50 ret = first;
Emeric Brun3e541d12012-09-03 11:14:36 +020051
William Lallemand4f45bb92017-10-30 20:08:51 +010052 first_count = first->block_count;
53 first_len = first->len;
54 /*
55 Should never been set to 0.
56 if (first->block_count == 0)
57 first->block_count = 1;
58 */
Emeric Brun3e541d12012-09-03 11:14:36 +020059
William Lallemand4f45bb92017-10-30 20:08:51 +010060 list_for_each_entry_safe_from(block, sblock, &shctx->avail, list) {
61
62 /* release callback */
63 if (first_len && shctx->free_block)
64 shctx->free_block(first, block);
65
66 block->block_count = 1;
67 block->len = 0;
68
69 freed++;
70 data_len -= shctx->block_size;
71
72 if (data_len > 0)
73 shctx_block_set_hot(shctx, block);
74
75 if (data_len <= 0 && !enough) {
76 shctx_block_set_hot(shctx, block);
77 ret->block_count = freed;
78 ret->refcount = 1;
79 enough = 1;
80 }
81
82 count++;
83 if (count >= first_count)
84 break;
Emeric Brunaf9619d2012-11-28 18:47:52 +010085 }
Emeric Brunaf9619d2012-11-28 18:47:52 +010086 }
William Lallemand4f45bb92017-10-30 20:08:51 +010087
88out:
Emeric Brunaf9619d2012-11-28 18:47:52 +010089 return ret;
90}
Emeric Brun3e541d12012-09-03 11:14:36 +020091
William Lallemand4f45bb92017-10-30 20:08:51 +010092/*
93 * if the refcount is 0 move the row to the hot list. Increment the refcount
Emeric Brunaf9619d2012-11-28 18:47:52 +010094 */
William Lallemand4f45bb92017-10-30 20:08:51 +010095void shctx_row_inc_hot(struct shared_context *shctx, struct shared_block *first)
Emeric Brun3e541d12012-09-03 11:14:36 +020096{
William Lallemand4f45bb92017-10-30 20:08:51 +010097 struct shared_block *block, *sblock;
98 int count = 0;
Emeric Brunaf9619d2012-11-28 18:47:52 +010099
William Lallemand4f45bb92017-10-30 20:08:51 +0100100 if (first->refcount <= 0) {
101
102 block = first;
103
104 list_for_each_entry_safe_from(block, sblock, &shctx->avail, list) {
105
106 shctx_block_set_hot(shctx, block);
107
108 count++;
109 if (count >= first->block_count)
110 break;
Emeric Brunaf9619d2012-11-28 18:47:52 +0100111 }
Emeric Brunaf9619d2012-11-28 18:47:52 +0100112 }
Emeric Brunaf9619d2012-11-28 18:47:52 +0100113
William Lallemand4f45bb92017-10-30 20:08:51 +0100114 first->refcount++;
Emeric Brunaf9619d2012-11-28 18:47:52 +0100115}
Emeric Brun3e541d12012-09-03 11:14:36 +0200116
William Lallemand4f45bb92017-10-30 20:08:51 +0100117/*
118 * 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 +0100119 */
William Lallemand4f45bb92017-10-30 20:08:51 +0100120void shctx_row_dec_hot(struct shared_context *shctx, struct shared_block *first)
Emeric Brunaf9619d2012-11-28 18:47:52 +0100121{
William Lallemand4f45bb92017-10-30 20:08:51 +0100122 struct shared_block *block, *sblock;
123 int count = 0;
Emeric Brunaf9619d2012-11-28 18:47:52 +0100124
William Lallemand4f45bb92017-10-30 20:08:51 +0100125 first->refcount--;
Emeric Brun3e541d12012-09-03 11:14:36 +0200126
William Lallemand4f45bb92017-10-30 20:08:51 +0100127 if (first->refcount <= 0) {
Emeric Brun3e541d12012-09-03 11:14:36 +0200128
William Lallemand4f45bb92017-10-30 20:08:51 +0100129 block = first;
Emeric Brun3e541d12012-09-03 11:14:36 +0200130
William Lallemand4f45bb92017-10-30 20:08:51 +0100131 list_for_each_entry_safe_from(block, sblock, &shctx->hot, list) {
Emeric Brun3e541d12012-09-03 11:14:36 +0200132
William Lallemand4f45bb92017-10-30 20:08:51 +0100133 shctx_block_set_avail(shctx, block);
Emeric Brun3e541d12012-09-03 11:14:36 +0200134
William Lallemand4f45bb92017-10-30 20:08:51 +0100135 count++;
136 if (count >= first->block_count)
Emeric Brunaf9619d2012-11-28 18:47:52 +0100137 break;
Emeric Brunaf9619d2012-11-28 18:47:52 +0100138 }
139 }
Emeric Brun3e541d12012-09-03 11:14:36 +0200140
William Lallemand4f45bb92017-10-30 20:08:51 +0100141}
142
143
144/*
145 * Append data in the row if there is enough space.
146 * The row should be in the hot list
147 *
148 * Return the amount of appended data if ret >= 0
149 * or how much more space it needs to contains the data if < 0.
150 */
151int shctx_row_data_append(struct shared_context *shctx, struct shared_block *first, unsigned char *data, int len)
152{
153 int remain, start;
154 int count = 0;
155 struct shared_block *block;
156
157
158 /* return -<len> needed to work */
159 if (len > first->block_count * shctx->block_size - first->len)
160 return (first->block_count * shctx->block_size - first->len) - len;
161
162 /* skipping full buffers, stop at the first buffer with remaining space */
163 block = first;
164 list_for_each_entry_from(block, &shctx->hot, list) {
165 count++;
166
167
168 /* break if there is not enough blocks */
169 if (count > first->block_count)
170 break;
171
172 /* end of copy */
173 if (len <= 0)
174 break;
175
176 /* skip full buffers */
177 if (count * shctx->block_size <= first->len)
178 continue;
179
180 /* remaining space in the current block which is not full */
181 remain = (shctx->block_size * count - first->len) % shctx->block_size;
182 /* if remain == 0, previous buffer are full, or first->len == 0 */
183 remain = remain ? remain : shctx->block_size;
184
185 /* start must be calculated before remain is modified */
186 start = shctx->block_size - remain;
187
188 /* must not try to copy more than len */
189 remain = MIN(remain, len);
190
191 memcpy(block->data + start, data, remain);
192 data += remain;
193 len -= remain;
194 first->len += remain; /* update len in the head of the row */
195 }
196
197 return len;
Emeric Brunaf9619d2012-11-28 18:47:52 +0100198}
Emeric Brun3e541d12012-09-03 11:14:36 +0200199
William Lallemand4f45bb92017-10-30 20:08:51 +0100200/*
201 * Copy <len> data from a row of blocks, return the remaining data to copy
202 * If 0 is returned, the full data has successfuly be copied
203 *
204 * The row should be in the hot list
205 */
206int shctx_row_data_get(struct shared_context *shctx, struct shared_block *first,
207 unsigned char *dst, int offset, int len)
208{
209 int count = 0, size = 0, start = -1;
210 struct shared_block *block;
211
William Lallemand7217c462017-10-31 20:21:46 +0100212 /* can't copy more */
213 if (len > first->len)
214 len = first->len;
215
William Lallemand4f45bb92017-10-30 20:08:51 +0100216 block = first;
217 count = 0;
218 /* Pass through the blocks to copy them */
219 list_for_each_entry_from(block, &shctx->hot, list) {
220 if (count >= first->block_count || len <= 0)
221 break;
222
223 count++;
224 /* continue until we are in right block
225 corresponding to the offset */
226 if (count < offset / shctx->block_size + 1)
227 continue;
228
229 /* on the first block, data won't possibly began at offset 0 */
230 if (start == -1)
231 start = offset - (count - 1) * shctx->block_size;
Emeric Brun3e541d12012-09-03 11:14:36 +0200232
William Lallemand4f45bb92017-10-30 20:08:51 +0100233 /* size can be lower than a block when copying the last block */
234 size = MIN(shctx->block_size - start, len);
235
236 memcpy(dst, block->data + start, size);
237 dst += size;
238 len -= size;
239 start = 0;
240 }
241 return len;
242}
Emeric Brun3e541d12012-09-03 11:14:36 +0200243
Emeric Brun3e541d12012-09-03 11:14:36 +0200244/* Allocate shared memory context.
William Lallemand4f45bb92017-10-30 20:08:51 +0100245 * <maxblocks> is maximum blocks.
246 * If <maxblocks> is set to less or equal to 0, ssl cache is disabled.
247 * Returns: -1 on alloc failure, <maxblocks> if it performs context alloc,
Emeric Brunaf9619d2012-11-28 18:47:52 +0100248 * and 0 if cache is already allocated.
249 */
William Lallemand4f45bb92017-10-30 20:08:51 +0100250int shctx_init(struct shared_context **orig_shctx, int maxblocks, int blocksize, int extra, int shared)
Emeric Brun3e541d12012-09-03 11:14:36 +0200251{
252 int i;
William Lallemand3f85c9a2017-10-09 16:30:50 +0200253 struct shared_context *shctx;
254 int ret;
Emeric Brun9faf0712012-09-25 11:11:16 +0200255#ifndef USE_PRIVATE_CACHE
Emeric Bruncd1a5262014-05-07 23:11:42 +0200256#ifdef USE_PTHREAD_PSHARED
Emeric Brun3e541d12012-09-03 11:14:36 +0200257 pthread_mutexattr_t attr;
Emeric Bruncd1a5262014-05-07 23:11:42 +0200258#endif
Emeric Brun9faf0712012-09-25 11:11:16 +0200259#endif
William Lallemand4f45bb92017-10-30 20:08:51 +0100260 void *cur;
Emeric Brun4b3091e2012-09-24 15:48:52 +0200261 int maptype = MAP_PRIVATE;
Emeric Brun3e541d12012-09-03 11:14:36 +0200262
William Lallemand4f45bb92017-10-30 20:08:51 +0100263 if (maxblocks <= 0)
Emeric Brun22890a12012-12-28 14:41:32 +0100264 return 0;
Emeric Brun3e541d12012-09-03 11:14:36 +0200265
Emeric Brun9faf0712012-09-25 11:11:16 +0200266#ifndef USE_PRIVATE_CACHE
Emeric Brun4b3091e2012-09-24 15:48:52 +0200267 if (shared)
268 maptype = MAP_SHARED;
Emeric Brun9faf0712012-09-25 11:11:16 +0200269#endif
Emeric Brun4b3091e2012-09-24 15:48:52 +0200270
William Lallemand4f45bb92017-10-30 20:08:51 +0100271 shctx = (struct shared_context *)mmap(NULL, sizeof(struct shared_context) + extra + (maxblocks * (sizeof(struct shared_block) + blocksize)),
Emeric Brun4b3091e2012-09-24 15:48:52 +0200272 PROT_READ | PROT_WRITE, maptype | MAP_ANON, -1, 0);
Emeric Brun3e541d12012-09-03 11:14:36 +0200273 if (!shctx || shctx == MAP_FAILED) {
274 shctx = NULL;
William Lallemand3f85c9a2017-10-09 16:30:50 +0200275 ret = SHCTX_E_ALLOC_CACHE;
276 goto err;
Emeric Brun3e541d12012-09-03 11:14:36 +0200277 }
278
William Lallemand4f45bb92017-10-30 20:08:51 +0100279 shctx->nbav = 0;
280
Emeric Brun9faf0712012-09-25 11:11:16 +0200281#ifndef USE_PRIVATE_CACHE
Emeric Bruncaa19cc2014-05-07 16:10:18 +0200282 if (maptype == MAP_SHARED) {
Emeric Bruncd1a5262014-05-07 23:11:42 +0200283#ifdef USE_PTHREAD_PSHARED
Emeric Bruncaa19cc2014-05-07 16:10:18 +0200284 if (pthread_mutexattr_init(&attr)) {
William Lallemand4f45bb92017-10-30 20:08:51 +0100285 munmap(shctx, sizeof(struct shared_context) + extra + (maxblocks * (sizeof(struct shared_block) + blocksize)));
Emeric Bruncaa19cc2014-05-07 16:10:18 +0200286 shctx = NULL;
William Lallemand3f85c9a2017-10-09 16:30:50 +0200287 ret = SHCTX_E_INIT_LOCK;
288 goto err;
Emeric Bruncaa19cc2014-05-07 16:10:18 +0200289 }
290
291 if (pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)) {
292 pthread_mutexattr_destroy(&attr);
William Lallemand4f45bb92017-10-30 20:08:51 +0100293 munmap(shctx, sizeof(struct shared_context) + extra + (maxblocks * (sizeof(struct shared_block) + blocksize)));
Emeric Bruncaa19cc2014-05-07 16:10:18 +0200294 shctx = NULL;
William Lallemand3f85c9a2017-10-09 16:30:50 +0200295 ret = SHCTX_E_INIT_LOCK;
296 goto err;
Emeric Bruncaa19cc2014-05-07 16:10:18 +0200297 }
298
299 if (pthread_mutex_init(&shctx->mutex, &attr)) {
300 pthread_mutexattr_destroy(&attr);
William Lallemand4f45bb92017-10-30 20:08:51 +0100301 munmap(shctx, sizeof(struct shared_context) + extra + (maxblocks * (sizeof(struct shared_block) + blocksize)));
Emeric Bruncaa19cc2014-05-07 16:10:18 +0200302 shctx = NULL;
William Lallemand3f85c9a2017-10-09 16:30:50 +0200303 ret = SHCTX_E_INIT_LOCK;
304 goto err;
Emeric Bruncaa19cc2014-05-07 16:10:18 +0200305 }
Emeric Bruncd1a5262014-05-07 23:11:42 +0200306#else
307 shctx->waiters = 0;
Emeric Brun3e541d12012-09-03 11:14:36 +0200308#endif
Emeric Brun4b3091e2012-09-24 15:48:52 +0200309 use_shared_mem = 1;
Emeric Bruncaa19cc2014-05-07 16:10:18 +0200310 }
Emeric Brun9faf0712012-09-25 11:11:16 +0200311#endif
Emeric Brun4b3091e2012-09-24 15:48:52 +0200312
William Lallemand4f45bb92017-10-30 20:08:51 +0100313 LIST_INIT(&shctx->avail);
314 LIST_INIT(&shctx->hot);
Emeric Brun3e541d12012-09-03 11:14:36 +0200315
William Lallemand4f45bb92017-10-30 20:08:51 +0100316 shctx->block_size = blocksize;
Emeric Brunaf9619d2012-11-28 18:47:52 +0100317
William Lallemand4f45bb92017-10-30 20:08:51 +0100318 /* init the free blocks after the shared context struct */
319 cur = (void *)shctx + sizeof(struct shared_context) + extra;
320 for (i = 0; i < maxblocks; i++) {
321 struct shared_block *cur_block = (struct shared_block *)cur;
322 cur_block->len = 0;
323 cur_block->refcount = 0;
324 cur_block->block_count = 1;
325 LIST_ADDQ(&shctx->avail, &cur_block->list);
326 shctx->nbav++;
327 cur += sizeof(struct shared_block) + blocksize;
Emeric Brun3e541d12012-09-03 11:14:36 +0200328 }
William Lallemand4f45bb92017-10-30 20:08:51 +0100329 ret = maxblocks;
William Lallemand3f85c9a2017-10-09 16:30:50 +0200330
331err:
332 *orig_shctx = shctx;
333 return ret;
Emeric Brun3e541d12012-09-03 11:14:36 +0200334}
335