1 /*-
2 * SSLsplit - transparent SSL/TLS interception
3 * https://www.roe.ch/SSLsplit
4 *
5 * Copyright (c) 2009-2019, Daniel Roethlisberger <daniel@roe.ch>.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "cache.h"
30
31 #include "log.h"
32 #include "khash.h"
33
34 #include <pthread.h>
35
36 /*
37 * Generic, thread-safe cache.
38 */
39
40 /*
41 * Create a new cache based on the initializer callback init_cb.
42 */
43 cache_t *
cache_new(cache_init_cb_t init_cb)44 cache_new(cache_init_cb_t init_cb)
45 {
46 cache_t *cache;
47
48 if (!(cache = malloc(sizeof(cache_t))))
49 return NULL;
50
51 if (pthread_mutex_init(&cache->mutex, NULL)) {
52 free(cache);
53 return NULL;
54 }
55
56 init_cb(cache);
57 return cache;
58 }
59
60 /*
61 * Reinitialize cache after fork(). Returns 0 on success, -1 on failure.
62 */
63 int
cache_reinit(cache_t * cache)64 cache_reinit(cache_t *cache)
65 {
66 return pthread_mutex_init(&cache->mutex, NULL) ? -1 : 0;
67 }
68
69 /*
70 * Free a cache and all associated resources.
71 * This function is not thread-safe.
72 */
73 void
cache_free(cache_t * cache)74 cache_free(cache_t *cache)
75 {
76 khiter_t it;
77
78 for (it = cache->begin_cb(); it != cache->end_cb(); it++) {
79 if (cache->exist_cb(it)) {
80 cache->free_key_cb(cache->get_key_cb(it));
81 cache->free_val_cb(cache->get_val_cb(it));
82 }
83 }
84 cache->fini_cb();
85 pthread_mutex_destroy(&cache->mutex);
86 free(cache);
87 }
88
89 void
cache_gc(cache_t * cache)90 cache_gc(cache_t *cache)
91 {
92 khiter_t it;
93 cache_val_t val;
94
95 pthread_mutex_lock(&cache->mutex);
96 for (it = cache->begin_cb(); it != cache->end_cb(); it++) {
97 if (cache->exist_cb(it)) {
98 val = cache->get_val_cb(it);
99 if (!cache->unpackverify_val_cb(val, 0)) {
100 cache->free_val_cb(val);
101 cache->free_key_cb(cache->get_key_cb(it));
102 cache->del_cb(it);
103 }
104 }
105 }
106 pthread_mutex_unlock(&cache->mutex);
107 }
108
109 cache_val_t
cache_get(cache_t * cache,cache_key_t key)110 cache_get(cache_t *cache, cache_key_t key)
111 {
112 cache_val_t rval = NULL;
113 khiter_t it;
114
115 if (!key)
116 return NULL;
117
118 pthread_mutex_lock(&cache->mutex);
119 it = cache->get_cb(key);
120 if (it != cache->end_cb()) {
121 cache_val_t val;
122 val = cache->get_val_cb(it);
123 if (!(rval = cache->unpackverify_val_cb(val, 1))) {
124 cache->free_val_cb(val);
125 cache->free_key_cb(cache->get_key_cb(it));
126 cache->del_cb(it);
127 }
128 }
129 cache->free_key_cb(key);
130 pthread_mutex_unlock(&cache->mutex);
131 return rval;
132 }
133
134 void
cache_set(cache_t * cache,cache_key_t key,cache_val_t val)135 cache_set(cache_t *cache, cache_key_t key, cache_val_t val)
136 {
137 khiter_t it;
138 int ret;
139
140 if (!key || !val)
141 return;
142
143 pthread_mutex_lock(&cache->mutex);
144 it = cache->put_cb(key, &ret);
145 if (!ret) {
146 cache->free_key_cb(key);
147 cache->free_val_cb(cache->get_val_cb(it));
148 }
149 cache->set_val_cb(it, val);
150 pthread_mutex_unlock(&cache->mutex);
151 }
152
153 void
cache_del(cache_t * cache,cache_key_t key)154 cache_del(cache_t *cache, cache_key_t key)
155 {
156 khiter_t it;
157
158 pthread_mutex_lock(&cache->mutex);
159 it = cache->get_cb(key);
160 if (it != cache->end_cb()) {
161 cache->free_val_cb(cache->get_val_cb(it));
162 cache->free_key_cb(cache->get_key_cb(it));
163 cache->del_cb(it);
164 }
165 cache->free_key_cb(key);
166 pthread_mutex_unlock(&cache->mutex);
167 }
168
169 /* vim: set noet ft=c: */
170