djbdnscurve6 45
djbdnscurve6
Loading...
Searching...
No Matches
sipcache.c
Go to the documentation of this file.
1#include "alloc.h"
2#include "byte.h"
3#include "tai.h"
4#include "dns.h"
5#include "exit.h"
6#include "uint_t.h"
7#include "siphash.h"
8#include "sipcache.h"
9
10uint64 cache_motion = 0;
11static unsigned char siphash_key[16];
12
13static char *x = 0;
14static uint32 size;
15static uint32 hsize;
16static uint32 writer;
17static uint32 oldest;
18static uint32 unused;
19
20/*
21100 <= size <= 1000000000.
224 <= hsize <= size/16.
23hsize is a power of 2.
24hsize <= writer <= oldest <= unused <= size.
25If oldest == unused then unused == size.
26x is a hash table with the following structure:
27x[0...hsize-1]: hsize/4 head links.
28x[hsize...writer-1]: consecutive entries, newest entry on the right.
29x[writer...oldest-1]: free space for new entries.
30x[oldest...unused-1]: consecutive entries, oldest entry on the left.
31x[unused...size-1]: unused.
32Each hash bucket is a linked list containing the following items:
33the head link, the newest entry, the second-newest entry, etc.
34Each link is a 4-byte number giving the xor of
35the positions of the adjacent items in the list.
36Entries are always inserted immediately after the head and removed at the tail.
37Each entry contains the following information:
384-byte link; 4-byte keylen; 4-byte datalen; 8-byte expire time; key; data.
39*/
40
41#define MAXKEYLEN 1000
42#define MAXDATALEN 1000000
43
44static void cache_impossible(void)
45{
46 _exit(111);
47}
48
49static void set4(uint32 pos,uint32 u)
50{
51 if (pos > size - 4) cache_impossible();
52 uint32_pack(x + pos,u);
53}
54
55static uint32 get4(uint32 pos)
56{
57 uint32 result = 0;
58
59 if (pos > size - 4) cache_impossible();
60 uint32_unpack (x + pos,&result);
61
62 return result;
63}
64
65static unsigned int hash (const char *key,unsigned int keylen)
66{
67 uint64 h;
68 siphash24((unsigned char *)&h,(const unsigned char *)key,keylen,siphash_key);
69
70 return ((uint32)h) & (hsize - 4);
71}
72
73char *cache_get(const char *key,unsigned int keylen,unsigned int *datalen,uint32 *ttl)
74{
75 struct tai now;
76 struct tai expire;
77
78 uint32 u = 0, pos = 0;
79 uint32 prevpos = 0, nextpos = 0;
80
81 double d = 0.0;
82 unsigned int loop = 0;
83
84 if (!x) return 0;
85 if (keylen > MAXKEYLEN) return 0;
86
87 prevpos = hash (key, keylen);
88 pos = get4 (prevpos);
89
90 while (pos) {
91 if (get4(pos + 4) == keylen) {
92 if (pos + 20 + keylen > size) cache_impossible();
93 if (byte_equal(key, keylen, x + pos + 20)) {
94 tai_unpack (x + pos + 12,&expire);
95 tai_now (&now);
96 if (tai_less (&expire,&now)) return 0;
97
98 tai_sub (&expire,&expire,&now);
99 d = tai_approx (&expire);
100 if (d > 604800) d = 604800;
101 *ttl = d;
102
103 u = get4 (pos + 8);
104 if (u > size - pos - 20 - keylen) cache_impossible();
105 *datalen = u;
106
107 return x + pos + 20 + keylen;
108 }
109 }
110 nextpos = prevpos ^ get4 (pos);
111 prevpos = pos;
112 pos = nextpos;
113 if (++loop > 100) return 0; /* to protect against hash flooding */
114 }
115
116 return 0;
117}
118
119void cache_set(const char *key,unsigned int keylen,const char *data,unsigned int datalen, uint32 ttl)
120{
121 uint32 pos = 0;
122 struct tai now;
123 struct tai expire;
124
125 unsigned int keyhash = 0;
126 unsigned int entrylen = 0;
127
128 if (!x) return;
129 if (keylen > MAXKEYLEN) return;
130 if (datalen > MAXDATALEN) return;
131
132 if (!ttl) return;
133 if (ttl > 604800) ttl = 604800;
134
135 entrylen = keylen + datalen + 20;
136
137 while (writer + entrylen > oldest) {
138 if (oldest == unused) {
139 if (writer <= hsize) return;
140 unused = writer;
141 oldest = hsize;
142 writer = hsize;
143 }
144 pos = get4(oldest);
145 set4 (pos,get4(pos) ^ oldest);
146
147 oldest += get4(oldest + 4) + get4(oldest + 8) + 20;
148 if (oldest > unused) cache_impossible();
149 if (oldest == unused) {
150 unused = size;
151 oldest = size;
152 }
153 }
154
155 keyhash = hash (key,keylen);
156
157 tai_now(&now);
158 tai_uint(&expire,ttl);
159 tai_add(&expire,&expire,&now);
160
161 pos = get4(keyhash);
162 if (pos)
163 set4(pos,get4(pos) ^ keyhash ^ writer);
164
165 set4(writer,pos ^ keyhash);
166 set4(writer + 4,keylen);
167 set4(writer + 8,datalen);
168 tai_pack (x + writer + 12,&expire);
169 byte_copy (x + writer + 20,keylen,key);
170 byte_copy (x + writer + 20 + keylen,datalen,data);
171
172 set4(keyhash,writer);
173 writer += entrylen;
174 cache_motion += entrylen;
175}
176
177int cache_init (unsigned int cachesize)
178{
179 unsigned int i = 0U;
180
181 do {
182 siphash_key[i] = (unsigned char) dns_random(0x100);
183 } while (++i < sizeof(siphash_key));
184
185 if (x) { alloc_free (x); x = 0; }
186
187 if (cachesize > 1000000000) cachesize = 1000000000;
188 if (cachesize < 100) cachesize = 100;
189 size = cachesize;
190
191 hsize = 4;
192 while (hsize <= (size >> 5)) hsize <<= 1;
193
194 x = alloc(size);
195 if (!x) return 0;
196 byte_zero(x,size);
197
198 writer = hsize;
199 oldest = size;
200 unused = size;
201
202 return 1;
203}
char data[32767]
Definition: axfrdns.c:130
struct tai now
Definition: axfrdns.c:129
unsigned int dns_random(unsigned int n)
Definition: dns_random.c:56
struct line * x
void h(const char *home, int uid, int gid, int mode)
void d(const char *home, const char *subdir, int uid, int gid, int mode)
int cache_init(unsigned int cachesize)
Definition: sipcache.c:177
#define MAXKEYLEN
Definition: sipcache.c:41
void cache_set(const char *key, unsigned int keylen, const char *data, unsigned int datalen, uint32 ttl)
Definition: sipcache.c:119
uint64 cache_motion
Definition: sipcache.c:10
char * cache_get(const char *key, unsigned int keylen, unsigned int *datalen, uint32 *ttl)
Definition: sipcache.c:73
#define MAXDATALEN
Definition: sipcache.c:42
int siphash24(unsigned char *out, const unsigned char *in, unsigned long long inlen, const unsigned char *k)
Definition: siphash.c:57
unsigned long u
Definition: utime.c:10