| | varnish-cache/bin/varnishd/cache/cache_ban.c |
0 |
|
/*- |
1 |
|
* Copyright (c) 2006 Verdens Gang AS |
2 |
|
* Copyright (c) 2006-2015 Varnish Software AS |
3 |
|
* All rights reserved. |
4 |
|
* |
5 |
|
* Author: Poul-Henning Kamp <phk@phk.freebsd.dk> |
6 |
|
* |
7 |
|
* SPDX-License-Identifier: BSD-2-Clause |
8 |
|
* |
9 |
|
* Redistribution and use in source and binary forms, with or without |
10 |
|
* modification, are permitted provided that the following conditions |
11 |
|
* are met: |
12 |
|
* 1. Redistributions of source code must retain the above copyright |
13 |
|
* notice, this list of conditions and the following disclaimer. |
14 |
|
* 2. Redistributions in binary form must reproduce the above copyright |
15 |
|
* notice, this list of conditions and the following disclaimer in the |
16 |
|
* documentation and/or other materials provided with the distribution. |
17 |
|
* |
18 |
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
19 |
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
20 |
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
21 |
|
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE |
22 |
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
23 |
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
24 |
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
25 |
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
26 |
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
27 |
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
28 |
|
* SUCH DAMAGE. |
29 |
|
* |
30 |
|
*/ |
31 |
|
|
32 |
|
#include "config.h" |
33 |
|
|
34 |
|
#include <stdlib.h> |
35 |
|
#include <stdio.h> |
36 |
|
|
37 |
|
#include "cache_varnishd.h" |
38 |
|
#include "cache_ban.h" |
39 |
|
#include "cache_objhead.h" |
40 |
|
|
41 |
|
#include "vcli_serve.h" |
42 |
|
#include "vend.h" |
43 |
|
#include "vmb.h" |
44 |
|
|
45 |
|
/* cache_ban_build.c */ |
46 |
|
void BAN_Build_Init(void); |
47 |
|
void BAN_Build_Fini(void); |
48 |
|
|
49 |
|
struct lock ban_mtx; |
50 |
|
int ban_shutdown; |
51 |
|
struct banhead_s ban_head = VTAILQ_HEAD_INITIALIZER(ban_head); |
52 |
|
struct ban * volatile ban_start; |
53 |
|
|
54 |
|
static pthread_t ban_thread; |
55 |
|
static int ban_holds; |
56 |
|
uint64_t bans_persisted_bytes; |
57 |
|
uint64_t bans_persisted_fragmentation; |
58 |
|
|
59 |
|
struct ban_test { |
60 |
|
uint8_t oper; |
61 |
|
uint8_t arg1; |
62 |
|
const char *arg1_spec; |
63 |
|
const char *arg2; |
64 |
|
double arg2_double; |
65 |
|
const void *arg2_spec; |
66 |
|
}; |
67 |
|
|
68 |
|
static const char * const arg_name[BAN_ARGARRSZ + 1] = { |
69 |
|
#define PVAR(a, b, c) [BAN_ARGIDX(c)] = (a), |
70 |
|
#include "tbl/ban_vars.h" |
71 |
|
[BAN_ARGARRSZ] = NULL |
72 |
|
}; |
73 |
|
|
74 |
|
/*-------------------------------------------------------------------- |
75 |
|
* Storage handling of bans |
76 |
|
*/ |
77 |
|
|
78 |
|
static struct ban * |
79 |
1040 |
ban_alloc(void) |
80 |
|
{ |
81 |
|
struct ban *b; |
82 |
|
|
83 |
1040 |
ALLOC_OBJ(b, BAN_MAGIC); |
84 |
1040 |
if (b != NULL) |
85 |
1040 |
VTAILQ_INIT(&b->objcore); |
86 |
1040 |
return (b); |
87 |
|
} |
88 |
|
|
89 |
|
void |
90 |
2800 |
BAN_Free(struct ban *b) |
91 |
|
{ |
92 |
|
|
93 |
2800 |
CHECK_OBJ_NOTNULL(b, BAN_MAGIC); |
94 |
2800 |
AZ(b->refcount); |
95 |
2800 |
assert(VTAILQ_EMPTY(&b->objcore)); |
96 |
|
|
97 |
2800 |
if (b->spec != NULL) |
98 |
2800 |
free(b->spec); |
99 |
2800 |
FREE_OBJ(b); |
100 |
2800 |
} |
101 |
|
|
102 |
|
/*-------------------------------------------------------------------- |
103 |
|
* Get/release holds which prevent the ban_lurker from starting. |
104 |
|
* Holds are held while stevedores load zombie objects. |
105 |
|
*/ |
106 |
|
|
107 |
|
void |
108 |
1520 |
BAN_Hold(void) |
109 |
|
{ |
110 |
|
|
111 |
1520 |
Lck_Lock(&ban_mtx); |
112 |
|
/* Once holds are released, we allow no more */ |
113 |
1520 |
assert(ban_holds > 0); |
114 |
1520 |
ban_holds++; |
115 |
1520 |
Lck_Unlock(&ban_mtx); |
116 |
1520 |
} |
117 |
|
|
118 |
|
void |
119 |
38060 |
BAN_Release(void) |
120 |
|
{ |
121 |
|
|
122 |
38060 |
Lck_Lock(&ban_mtx); |
123 |
38060 |
assert(ban_holds > 0); |
124 |
38060 |
ban_holds--; |
125 |
38060 |
Lck_Unlock(&ban_mtx); |
126 |
38060 |
if (ban_holds == 0) |
127 |
36540 |
WRK_BgThread(&ban_thread, "ban-lurker", ban_lurker, NULL); |
128 |
38060 |
} |
129 |
|
|
130 |
|
/*-------------------------------------------------------------------- |
131 |
|
* Extract time and length from ban-spec |
132 |
|
*/ |
133 |
|
|
134 |
|
vtim_real |
135 |
33040 |
ban_time(const uint8_t *banspec) |
136 |
|
{ |
137 |
|
vtim_real t; |
138 |
|
uint64_t u; |
139 |
|
|
140 |
33040 |
assert(sizeof t == sizeof u); |
141 |
33040 |
assert(sizeof t == (BANS_LENGTH - BANS_TIMESTAMP)); |
142 |
33040 |
u = vbe64dec(banspec + BANS_TIMESTAMP); |
143 |
33040 |
memcpy(&t, &u, sizeof t); |
144 |
33040 |
return (t); |
145 |
|
} |
146 |
|
|
147 |
|
unsigned |
148 |
229882 |
ban_len(const uint8_t *banspec) |
149 |
|
{ |
150 |
|
unsigned u; |
151 |
|
|
152 |
229882 |
u = vbe32dec(banspec + BANS_LENGTH); |
153 |
229882 |
return (u); |
154 |
|
} |
155 |
|
|
156 |
|
int |
157 |
8840 |
ban_equal(const uint8_t *bs1, const uint8_t *bs2) |
158 |
|
{ |
159 |
|
unsigned u; |
160 |
|
|
161 |
|
/* |
162 |
|
* Compare two ban-strings. |
163 |
|
*/ |
164 |
8840 |
u = ban_len(bs1); |
165 |
8840 |
if (u != ban_len(bs2)) |
166 |
1960 |
return (0); |
167 |
6880 |
if (bs1[BANS_FLAGS] & BANS_FLAG_NODEDUP) |
168 |
200 |
return (0); |
169 |
|
|
170 |
6680 |
return (!memcmp(bs1 + BANS_LENGTH, bs2 + BANS_LENGTH, u - BANS_LENGTH)); |
171 |
8840 |
} |
172 |
|
|
173 |
|
void |
174 |
38501 |
ban_mark_completed(struct ban *b) |
175 |
|
{ |
176 |
|
unsigned ln; |
177 |
|
|
178 |
38501 |
CHECK_OBJ_NOTNULL(b, BAN_MAGIC); |
179 |
38501 |
Lck_AssertHeld(&ban_mtx); |
180 |
|
|
181 |
38501 |
AN(b->spec); |
182 |
38501 |
if (!(b->flags & BANS_FLAG_COMPLETED)) { |
183 |
38501 |
ln = ban_len(b->spec); |
184 |
38501 |
b->flags |= BANS_FLAG_COMPLETED; |
185 |
38501 |
b->spec[BANS_FLAGS] |= BANS_FLAG_COMPLETED; |
186 |
38501 |
VWMB(); |
187 |
38501 |
vbe32enc(b->spec + BANS_LENGTH, BANS_HEAD_LEN); |
188 |
38501 |
VSC_C_main->bans_completed++; |
189 |
38501 |
bans_persisted_fragmentation += ln - ban_len(b->spec); |
190 |
38501 |
VSC_C_main->bans_persisted_fragmentation = |
191 |
38501 |
bans_persisted_fragmentation; |
192 |
38501 |
} |
193 |
38501 |
} |
194 |
|
|
195 |
|
/*-------------------------------------------------------------------- |
196 |
|
* Access a lump of bytes in a ban test spec |
197 |
|
*/ |
198 |
|
|
199 |
|
static const void * |
200 |
14200 |
ban_get_lump(const uint8_t **bs) |
201 |
|
{ |
202 |
|
const void *r; |
203 |
|
unsigned ln; |
204 |
|
|
205 |
86280 |
while (**bs == 0xff) |
206 |
72080 |
*bs += 1; |
207 |
14200 |
ln = vbe32dec(*bs); |
208 |
14200 |
*bs += PRNDUP(sizeof(uint32_t)); |
209 |
14200 |
assert(PAOK(*bs)); |
210 |
14200 |
r = (const void*)*bs; |
211 |
14200 |
*bs += ln; |
212 |
14200 |
return (r); |
213 |
|
} |
214 |
|
|
215 |
|
/*-------------------------------------------------------------------- |
216 |
|
* Pick a test apart from a spec string |
217 |
|
*/ |
218 |
|
|
219 |
|
static void |
220 |
12200 |
ban_iter(const uint8_t **bs, struct ban_test *bt) |
221 |
|
{ |
222 |
|
uint64_t dtmp; |
223 |
|
|
224 |
12200 |
memset(bt, 0, sizeof *bt); |
225 |
12200 |
bt->arg2_double = nan(""); |
226 |
12200 |
bt->arg1 = *(*bs)++; |
227 |
12200 |
if (BANS_HAS_ARG1_SPEC(bt->arg1)) { |
228 |
3880 |
bt->arg1_spec = (const char *)*bs; |
229 |
3880 |
(*bs) += (*bs)[0] + 2; |
230 |
3880 |
} |
231 |
12200 |
if (BANS_HAS_ARG2_DOUBLE(bt->arg1)) { |
232 |
5080 |
dtmp = vbe64dec(ban_get_lump(bs)); |
233 |
5080 |
bt->oper = *(*bs)++; |
234 |
|
|
235 |
5080 |
memcpy(&bt->arg2_double, &dtmp, sizeof dtmp); |
236 |
5080 |
return; |
237 |
|
} |
238 |
7120 |
bt->arg2 = ban_get_lump(bs); |
239 |
7120 |
bt->oper = *(*bs)++; |
240 |
7120 |
if (BANS_HAS_ARG2_SPEC(bt->oper)) |
241 |
2000 |
bt->arg2_spec = ban_get_lump(bs); |
242 |
12200 |
} |
243 |
|
|
244 |
|
/*-------------------------------------------------------------------- |
245 |
|
* A new object is created, grab a reference to the newest ban |
246 |
|
*/ |
247 |
|
|
248 |
|
void |
249 |
55359 |
BAN_NewObjCore(struct objcore *oc) |
250 |
|
{ |
251 |
|
|
252 |
55359 |
CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC); |
253 |
55359 |
AZ(oc->ban); |
254 |
55359 |
AN(oc->objhead); |
255 |
55359 |
Lck_Lock(&ban_mtx); |
256 |
55359 |
oc->ban = ban_start; |
257 |
55359 |
ban_start->refcount++; |
258 |
55359 |
VTAILQ_INSERT_TAIL(&ban_start->objcore, oc, ban_list); |
259 |
55359 |
Lck_Unlock(&ban_mtx); |
260 |
55359 |
} |
261 |
|
|
262 |
|
/*-------------------------------------------------------------------- |
263 |
|
* An object is destroyed, release its ban reference |
264 |
|
*/ |
265 |
|
|
266 |
|
void |
267 |
72973 |
BAN_DestroyObj(struct objcore *oc) |
268 |
|
{ |
269 |
|
|
270 |
72973 |
CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC); |
271 |
72973 |
if (oc->ban == NULL) |
272 |
58430 |
return; |
273 |
14543 |
Lck_Lock(&ban_mtx); |
274 |
14543 |
CHECK_OBJ_ORNULL(oc->ban, BAN_MAGIC); |
275 |
14543 |
if (oc->ban != NULL) { |
276 |
14543 |
assert(oc->ban->refcount > 0); |
277 |
14543 |
oc->ban->refcount--; |
278 |
14543 |
VTAILQ_REMOVE(&oc->ban->objcore, oc, ban_list); |
279 |
14543 |
oc->ban = NULL; |
280 |
14543 |
} |
281 |
14543 |
Lck_Unlock(&ban_mtx); |
282 |
72973 |
} |
283 |
|
|
284 |
|
/*-------------------------------------------------------------------- |
285 |
|
* Find a ban based on a timestamp. |
286 |
|
* Assume we have a BAN_Hold, so list traversal is safe. |
287 |
|
*/ |
288 |
|
|
289 |
|
struct ban * |
290 |
680 |
BAN_FindBan(vtim_real t0) |
291 |
|
{ |
292 |
|
struct ban *b; |
293 |
|
vtim_real t1; |
294 |
|
|
295 |
680 |
assert(ban_holds > 0); |
296 |
1840 |
VTAILQ_FOREACH(b, &ban_head, list) { |
297 |
1840 |
t1 = ban_time(b->spec); |
298 |
1840 |
if (t1 == t0) |
299 |
680 |
return (b); |
300 |
1160 |
if (t1 < t0) |
301 |
0 |
break; |
302 |
1160 |
} |
303 |
0 |
return (NULL); |
304 |
680 |
} |
305 |
|
|
306 |
|
/*-------------------------------------------------------------------- |
307 |
|
* Grab a reference to a ban and associate the objcore with that ban. |
308 |
|
* Assume we have a BAN_Hold, so list traversal is safe. |
309 |
|
*/ |
310 |
|
|
311 |
|
void |
312 |
680 |
BAN_RefBan(struct objcore *oc, struct ban *b) |
313 |
|
{ |
314 |
|
|
315 |
680 |
Lck_Lock(&ban_mtx); |
316 |
680 |
CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC); |
317 |
680 |
AZ(oc->ban); |
318 |
680 |
CHECK_OBJ_NOTNULL(b, BAN_MAGIC); |
319 |
680 |
assert(ban_holds > 0); |
320 |
680 |
b->refcount++; |
321 |
680 |
VTAILQ_INSERT_TAIL(&b->objcore, oc, ban_list); |
322 |
680 |
oc->ban = b; |
323 |
680 |
Lck_Unlock(&ban_mtx); |
324 |
680 |
} |
325 |
|
|
326 |
|
/*-------------------------------------------------------------------- |
327 |
|
* Compile a full ban list and export this area to the stevedores for |
328 |
|
* persistence. |
329 |
|
*/ |
330 |
|
|
331 |
|
static void |
332 |
72660 |
ban_export(void) |
333 |
|
{ |
334 |
|
struct ban *b; |
335 |
|
struct vsb *vsb; |
336 |
|
unsigned ln; |
337 |
|
|
338 |
72660 |
Lck_AssertHeld(&ban_mtx); |
339 |
72660 |
ln = bans_persisted_bytes - bans_persisted_fragmentation; |
340 |
72660 |
vsb = VSB_new_auto(); |
341 |
72660 |
AN(vsb); |
342 |
148400 |
VTAILQ_FOREACH_REVERSE(b, &ban_head, banhead_s, list) |
343 |
75740 |
AZ(VSB_bcat(vsb, b->spec, ban_len(b->spec))); |
344 |
72660 |
AZ(VSB_finish(vsb)); |
345 |
72660 |
assert(VSB_len(vsb) == ln); |
346 |
72660 |
STV_BanExport((const uint8_t *)VSB_data(vsb), VSB_len(vsb)); |
347 |
72660 |
VSB_destroy(&vsb); |
348 |
72660 |
VSC_C_main->bans_persisted_bytes = |
349 |
72660 |
bans_persisted_bytes = ln; |
350 |
72660 |
VSC_C_main->bans_persisted_fragmentation = |
351 |
72660 |
bans_persisted_fragmentation = 0; |
352 |
72660 |
} |
353 |
|
|
354 |
|
/* |
355 |
|
* For both of these we do a full export on info failure to remove |
356 |
|
* holes in the exported list. |
357 |
|
* XXX: we should keep track of the size of holes in the last exported list |
358 |
|
* XXX: check if the ban_export should be batched in ban_cleantail |
359 |
|
*/ |
360 |
|
void |
361 |
40340 |
ban_info_new(const uint8_t *ban, unsigned len) |
362 |
|
{ |
363 |
|
/* XXX martin pls review if ban_mtx needs to be held */ |
364 |
40340 |
Lck_AssertHeld(&ban_mtx); |
365 |
40340 |
if (STV_BanInfoNew(ban, len)) |
366 |
0 |
ban_export(); |
367 |
40340 |
} |
368 |
|
|
369 |
|
void |
370 |
2800 |
ban_info_drop(const uint8_t *ban, unsigned len) |
371 |
|
{ |
372 |
|
/* XXX martin pls review if ban_mtx needs to be held */ |
373 |
2800 |
Lck_AssertHeld(&ban_mtx); |
374 |
2800 |
if (STV_BanInfoDrop(ban, len)) |
375 |
0 |
ban_export(); |
376 |
2800 |
} |
377 |
|
|
378 |
|
/*-------------------------------------------------------------------- |
379 |
|
* Put a skeleton ban in the list, unless there is an identical, |
380 |
|
* time & condition, ban already in place. |
381 |
|
* |
382 |
|
* If a newer ban has same condition, mark the inserted ban COMPLETED, |
383 |
|
* also mark any older bans, with the same condition COMPLETED. |
384 |
|
*/ |
385 |
|
|
386 |
|
static void |
387 |
1360 |
ban_reload(const uint8_t *ban, unsigned len) |
388 |
|
{ |
389 |
|
struct ban *b, *b2; |
390 |
1360 |
int duplicate = 0; |
391 |
1360 |
vtim_real t0, t1, t2 = 9e99; |
392 |
1360 |
ASSERT_CLI(); |
393 |
1360 |
Lck_AssertHeld(&ban_mtx); |
394 |
|
|
395 |
1360 |
t0 = ban_time(ban); |
396 |
1360 |
assert(len == ban_len(ban)); |
397 |
|
|
398 |
2960 |
VTAILQ_FOREACH(b, &ban_head, list) { |
399 |
2320 |
t1 = ban_time(b->spec); |
400 |
2320 |
assert(t1 < t2); |
401 |
2320 |
t2 = t1; |
402 |
2320 |
if (t1 == t0) |
403 |
320 |
return; |
404 |
2000 |
if (t1 < t0) |
405 |
400 |
break; |
406 |
1600 |
if (ban_equal(b->spec, ban)) |
407 |
960 |
duplicate = 1; |
408 |
1600 |
} |
409 |
|
|
410 |
1040 |
VSC_C_main->bans++; |
411 |
1040 |
VSC_C_main->bans_added++; |
412 |
|
|
413 |
1040 |
b2 = ban_alloc(); |
414 |
1040 |
AN(b2); |
415 |
1040 |
b2->spec = malloc(len); |
416 |
1040 |
AN(b2->spec); |
417 |
1040 |
memcpy(b2->spec, ban, len); |
418 |
1040 |
if (ban[BANS_FLAGS] & BANS_FLAG_REQ) { |
419 |
200 |
VSC_C_main->bans_req++; |
420 |
200 |
b2->flags |= BANS_FLAG_REQ; |
421 |
200 |
} |
422 |
1040 |
if (duplicate) |
423 |
720 |
VSC_C_main->bans_dups++; |
424 |
1040 |
if (duplicate || (ban[BANS_FLAGS] & BANS_FLAG_COMPLETED)) |
425 |
760 |
ban_mark_completed(b2); |
426 |
1040 |
if (b == NULL) |
427 |
640 |
VTAILQ_INSERT_TAIL(&ban_head, b2, list); |
428 |
|
else |
429 |
400 |
VTAILQ_INSERT_BEFORE(b, b2, list); |
430 |
1040 |
bans_persisted_bytes += len; |
431 |
1040 |
VSC_C_main->bans_persisted_bytes = bans_persisted_bytes; |
432 |
|
|
433 |
|
/* Hunt down older duplicates */ |
434 |
1640 |
for (b = VTAILQ_NEXT(b2, list); b != NULL; b = VTAILQ_NEXT(b, list)) { |
435 |
600 |
if (b->flags & BANS_FLAG_COMPLETED) |
436 |
560 |
continue; |
437 |
40 |
if (ban_equal(b->spec, ban)) { |
438 |
0 |
ban_mark_completed(b); |
439 |
0 |
VSC_C_main->bans_dups++; |
440 |
0 |
} |
441 |
40 |
} |
442 |
1360 |
} |
443 |
|
|
444 |
|
/*-------------------------------------------------------------------- |
445 |
|
* Reload a series of persisted ban specs |
446 |
|
*/ |
447 |
|
|
448 |
|
void |
449 |
1520 |
BAN_Reload(const uint8_t *ptr, unsigned len) |
450 |
|
{ |
451 |
|
const uint8_t *pe; |
452 |
|
unsigned l; |
453 |
|
|
454 |
1520 |
AZ(ban_shutdown); |
455 |
1520 |
pe = ptr + len; |
456 |
1520 |
Lck_Lock(&ban_mtx); |
457 |
2880 |
while (ptr < pe) { |
458 |
|
/* XXX: This can be optimized by traversing the live |
459 |
|
* ban list together with the reload list (combining |
460 |
|
* the loops in BAN_Reload and ban_reload). */ |
461 |
1360 |
l = ban_len(ptr); |
462 |
1360 |
assert(ptr + l <= pe); |
463 |
1360 |
ban_reload(ptr, l); |
464 |
1360 |
ptr += l; |
465 |
|
} |
466 |
1520 |
Lck_Unlock(&ban_mtx); |
467 |
1520 |
} |
468 |
|
|
469 |
|
/*-------------------------------------------------------------------- |
470 |
|
* Get a bans timestamp |
471 |
|
*/ |
472 |
|
|
473 |
|
vtim_real |
474 |
2800 |
BAN_Time(const struct ban *b) |
475 |
|
{ |
476 |
|
|
477 |
2800 |
if (b == NULL) |
478 |
880 |
return (0.0); |
479 |
|
|
480 |
1920 |
CHECK_OBJ_NOTNULL(b, BAN_MAGIC); |
481 |
1920 |
return (ban_time(b->spec)); |
482 |
2800 |
} |
483 |
|
|
484 |
|
/*-------------------------------------------------------------------- |
485 |
|
* Evaluate ban-spec |
486 |
|
*/ |
487 |
|
|
488 |
|
int |
489 |
2840 |
ban_evaluate(struct worker *wrk, const uint8_t *bsarg, struct objcore *oc, |
490 |
|
const struct http *reqhttp, unsigned *tests) |
491 |
|
{ |
492 |
|
struct ban_test bt; |
493 |
|
const uint8_t *bs, *be; |
494 |
|
const char *p; |
495 |
|
const char *arg1; |
496 |
|
double darg1, darg2; |
497 |
|
int rv; |
498 |
|
|
499 |
|
/* |
500 |
|
* for ttl and age, fix the point in time such that banning refers to |
501 |
|
* the same point in time when the ban is evaluated |
502 |
|
* |
503 |
|
* for grace/keep, we assume that the absolute values are pola and that |
504 |
|
* users will most likely also specify a ttl criterion if they want to |
505 |
|
* fix a point in time (such as "obj.ttl > 5h && obj.keep > 3h") |
506 |
|
*/ |
507 |
|
|
508 |
2840 |
bs = bsarg; |
509 |
2840 |
be = bs + ban_len(bs); |
510 |
2840 |
bs += BANS_HEAD_LEN; |
511 |
4880 |
while (bs < be) { |
512 |
3160 |
(*tests)++; |
513 |
3160 |
ban_iter(&bs, &bt); |
514 |
3160 |
arg1 = NULL; |
515 |
3160 |
darg1 = darg2 = nan(""); |
516 |
3160 |
switch (bt.arg1) { |
517 |
|
case BANS_ARG_URL: |
518 |
1080 |
AN(reqhttp); |
519 |
1080 |
arg1 = reqhttp->hd[HTTP_HDR_URL].b; |
520 |
1080 |
break; |
521 |
|
case BANS_ARG_REQHTTP: |
522 |
280 |
AN(reqhttp); |
523 |
280 |
(void)http_GetHdr(reqhttp, bt.arg1_spec, &p); |
524 |
280 |
arg1 = p; |
525 |
280 |
break; |
526 |
|
case BANS_ARG_OBJHTTP: |
527 |
1160 |
arg1 = HTTP_GetHdrPack(wrk, oc, bt.arg1_spec); |
528 |
1160 |
break; |
529 |
|
case BANS_ARG_OBJSTATUS: |
530 |
160 |
arg1 = HTTP_GetHdrPack(wrk, oc, H__Status); |
531 |
160 |
break; |
532 |
|
case BANS_ARG_OBJTTL: |
533 |
120 |
darg1 = oc->ttl + oc->t_origin; |
534 |
120 |
darg2 = bt.arg2_double + ban_time(bsarg); |
535 |
120 |
break; |
536 |
|
case BANS_ARG_OBJAGE: |
537 |
120 |
darg1 = 0.0 - oc->t_origin; |
538 |
120 |
darg2 = 0.0 - (ban_time(bsarg) - bt.arg2_double); |
539 |
120 |
break; |
540 |
|
case BANS_ARG_OBJGRACE: |
541 |
80 |
darg1 = oc->grace; |
542 |
80 |
darg2 = bt.arg2_double; |
543 |
80 |
break; |
544 |
|
case BANS_ARG_OBJKEEP: |
545 |
160 |
darg1 = oc->keep; |
546 |
160 |
darg2 = bt.arg2_double; |
547 |
160 |
break; |
548 |
|
default: |
549 |
0 |
WRONG("Wrong BAN_ARG code"); |
550 |
0 |
} |
551 |
|
|
552 |
3160 |
switch (bt.oper) { |
553 |
|
case BANS_OPER_EQ: |
554 |
1560 |
if (arg1 == NULL) { |
555 |
360 |
if (isnan(darg1) || darg1 != darg2) |
556 |
200 |
return (0); |
557 |
1360 |
} else if (strcmp(arg1, bt.arg2)) { |
558 |
480 |
return (0); |
559 |
|
} |
560 |
880 |
break; |
561 |
|
case BANS_OPER_NEQ: |
562 |
400 |
if (arg1 == NULL) { |
563 |
200 |
if (! isnan(darg1) && darg1 == darg2) |
564 |
80 |
return (0); |
565 |
320 |
} else if (!strcmp(arg1, bt.arg2)) { |
566 |
80 |
return (0); |
567 |
|
} |
568 |
240 |
break; |
569 |
|
case BANS_OPER_MATCH: |
570 |
960 |
if (arg1 == NULL) |
571 |
40 |
return (0); |
572 |
920 |
rv = VRE_match(bt.arg2_spec, arg1, 0, 0, NULL); |
573 |
920 |
xxxassert(rv >= -1); |
574 |
920 |
if (rv < 0) |
575 |
80 |
return (0); |
576 |
840 |
break; |
577 |
|
case BANS_OPER_NMATCH: |
578 |
0 |
if (arg1 == NULL) |
579 |
0 |
return (0); |
580 |
0 |
rv = VRE_match(bt.arg2_spec, arg1, 0, 0, NULL); |
581 |
0 |
xxxassert(rv >= -1); |
582 |
0 |
if (rv >= 0) |
583 |
0 |
return (0); |
584 |
0 |
break; |
585 |
|
case BANS_OPER_GT: |
586 |
160 |
AZ(arg1); |
587 |
160 |
assert(! isnan(darg1)); |
588 |
160 |
if (!(darg1 > darg2)) |
589 |
160 |
return (0); |
590 |
0 |
break; |
591 |
|
case BANS_OPER_GTE: |
592 |
0 |
AZ(arg1); |
593 |
0 |
assert(! isnan(darg1)); |
594 |
0 |
if (!(darg1 >= darg2)) |
595 |
0 |
return (0); |
596 |
0 |
break; |
597 |
|
case BANS_OPER_LT: |
598 |
40 |
AZ(arg1); |
599 |
40 |
assert(! isnan(darg1)); |
600 |
40 |
if (!(darg1 < darg2)) |
601 |
0 |
return (0); |
602 |
40 |
break; |
603 |
|
case BANS_OPER_LTE: |
604 |
40 |
AZ(arg1); |
605 |
40 |
assert(! isnan(darg1)); |
606 |
40 |
if (!(darg1 <= darg2)) |
607 |
0 |
return (0); |
608 |
40 |
break; |
609 |
|
default: |
610 |
0 |
WRONG("Wrong BAN_OPER code"); |
611 |
0 |
} |
612 |
|
} |
613 |
1720 |
return (1); |
614 |
2840 |
} |
615 |
|
|
616 |
|
/*-------------------------------------------------------------------- |
617 |
|
* Check an object against all applicable bans |
618 |
|
* |
619 |
|
* Return: |
620 |
|
* -1 not all bans checked, but none of the checked matched |
621 |
|
* Only if !has_req |
622 |
|
* 0 No bans matched, object moved to ban_start. |
623 |
|
* 1 Ban matched, object removed from ban list. |
624 |
|
*/ |
625 |
|
|
626 |
|
int |
627 |
151752 |
BAN_CheckObject(struct worker *wrk, struct objcore *oc, struct req *req) |
628 |
|
{ |
629 |
|
struct ban *b; |
630 |
|
struct vsl_log *vsl; |
631 |
|
struct ban *b0, *bn; |
632 |
|
unsigned tests; |
633 |
|
|
634 |
151752 |
CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); |
635 |
151752 |
CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC); |
636 |
151752 |
CHECK_OBJ_NOTNULL(req, REQ_MAGIC); |
637 |
151752 |
Lck_AssertHeld(&oc->objhead->mtx); |
638 |
151752 |
assert(oc->refcnt > 0); |
639 |
|
|
640 |
151752 |
vsl = req->vsl; |
641 |
|
|
642 |
151752 |
CHECK_OBJ_NOTNULL(oc->ban, BAN_MAGIC); |
643 |
|
|
644 |
|
/* First do an optimistic unlocked check */ |
645 |
151752 |
b0 = ban_start; |
646 |
151752 |
CHECK_OBJ_NOTNULL(b0, BAN_MAGIC); |
647 |
|
|
648 |
151752 |
if (b0 == oc->ban) |
649 |
149472 |
return (0); |
650 |
|
|
651 |
|
/* If that fails, make a safe check */ |
652 |
2280 |
Lck_Lock(&ban_mtx); |
653 |
2280 |
b0 = ban_start; |
654 |
2280 |
bn = oc->ban; |
655 |
2280 |
if (b0 != bn) |
656 |
2280 |
bn->refcount++; |
657 |
2280 |
Lck_Unlock(&ban_mtx); |
658 |
|
|
659 |
2280 |
AN(bn); |
660 |
|
|
661 |
2280 |
if (b0 == bn) |
662 |
0 |
return (0); |
663 |
|
|
664 |
2280 |
AN(b0); |
665 |
2280 |
AN(bn); |
666 |
|
|
667 |
|
/* |
668 |
|
* This loop is safe without locks, because we know we hold |
669 |
|
* a refcount on a ban somewhere in the list and we do not |
670 |
|
* inspect the list past that ban. |
671 |
|
*/ |
672 |
2280 |
tests = 0; |
673 |
3840 |
for (b = b0; b != bn; b = VTAILQ_NEXT(b, list)) { |
674 |
2840 |
CHECK_OBJ_NOTNULL(b, BAN_MAGIC); |
675 |
2840 |
if (b->flags & BANS_FLAG_COMPLETED) |
676 |
800 |
continue; |
677 |
2040 |
if (ban_evaluate(wrk, b->spec, oc, req->http, &tests)) |
678 |
1280 |
break; |
679 |
760 |
} |
680 |
|
|
681 |
2280 |
Lck_Lock(&ban_mtx); |
682 |
2280 |
bn->refcount--; |
683 |
2280 |
VSC_C_main->bans_tested++; |
684 |
2280 |
VSC_C_main->bans_tests_tested += tests; |
685 |
|
|
686 |
2280 |
if (b == bn) { |
687 |
|
/* not banned */ |
688 |
1000 |
oc->ban->refcount--; |
689 |
1000 |
VTAILQ_REMOVE(&oc->ban->objcore, oc, ban_list); |
690 |
1000 |
VTAILQ_INSERT_TAIL(&b0->objcore, oc, ban_list); |
691 |
1000 |
b0->refcount++; |
692 |
1000 |
oc->ban = b0; |
693 |
1000 |
b = NULL; |
694 |
1000 |
} |
695 |
2280 |
if (b != NULL) |
696 |
1280 |
VSC_C_main->bans_obj_killed++; |
697 |
|
|
698 |
2280 |
if (VTAILQ_LAST(&ban_head, banhead_s)->refcount == 0) |
699 |
1040 |
ban_kick_lurker(); |
700 |
|
|
701 |
2280 |
Lck_Unlock(&ban_mtx); |
702 |
|
|
703 |
2280 |
if (b == NULL) { |
704 |
|
/* not banned */ |
705 |
1000 |
ObjSendEvent(wrk, oc, OEV_BANCHG); |
706 |
1000 |
return (0); |
707 |
|
} else { |
708 |
2560 |
VSLb(vsl, SLT_ExpBan, |
709 |
1280 |
"%ju banned lookup", VXID(ObjGetXID(wrk, oc))); |
710 |
1280 |
return (1); |
711 |
|
} |
712 |
151752 |
} |
713 |
|
|
714 |
|
/*-------------------------------------------------------------------- |
715 |
|
* CLI functions to add bans |
716 |
|
*/ |
717 |
|
|
718 |
|
static void v_matchproto_(cli_func_t) |
719 |
3480 |
ccf_ban(struct cli *cli, const char * const *av, void *priv) |
720 |
|
{ |
721 |
|
int narg, i; |
722 |
|
struct ban_proto *bp; |
723 |
3480 |
const char *err = NULL; |
724 |
|
|
725 |
3480 |
(void)priv; |
726 |
|
|
727 |
|
/* First do some cheap checks on the arguments */ |
728 |
15080 |
for (narg = 0; av[narg + 2] != NULL; narg++) |
729 |
11600 |
continue; |
730 |
3480 |
if ((narg % 4) != 3) { |
731 |
80 |
VCLI_Out(cli, "Wrong number of arguments"); |
732 |
80 |
VCLI_SetResult(cli, CLIS_PARAM); |
733 |
80 |
return; |
734 |
|
} |
735 |
3600 |
for (i = 3; i < narg; i += 4) { |
736 |
240 |
if (strcmp(av[i + 2], "&&")) { |
737 |
40 |
VCLI_Out(cli, "Found \"%s\" expected &&", av[i + 2]); |
738 |
40 |
VCLI_SetResult(cli, CLIS_PARAM); |
739 |
40 |
return; |
740 |
|
} |
741 |
200 |
} |
742 |
|
|
743 |
3360 |
bp = BAN_Build(); |
744 |
3360 |
if (bp == NULL) { |
745 |
0 |
VCLI_Out(cli, "Out of Memory"); |
746 |
0 |
VCLI_SetResult(cli, CLIS_CANT); |
747 |
0 |
return; |
748 |
|
} |
749 |
6640 |
for (i = 0; i < narg; i += 4) { |
750 |
3560 |
err = BAN_AddTest(bp, av[i + 2], av[i + 3], av[i + 4]); |
751 |
3560 |
if (err) |
752 |
280 |
break; |
753 |
3280 |
} |
754 |
|
|
755 |
3360 |
if (err == NULL) { |
756 |
|
// XXX racy - grab wstat lock? |
757 |
3080 |
err = BAN_Commit(bp); |
758 |
3080 |
} |
759 |
|
|
760 |
3360 |
if (err != NULL) { |
761 |
280 |
VCLI_Out(cli, "%s", err); |
762 |
280 |
BAN_Abandon(bp); |
763 |
280 |
VCLI_SetResult(cli, CLIS_PARAM); |
764 |
280 |
} |
765 |
3480 |
} |
766 |
|
|
767 |
|
#define Ms 60 |
768 |
|
#define Hs (Ms * 60) |
769 |
|
#define Ds (Hs * 24) |
770 |
|
#define Ws (Ds * 7) |
771 |
|
#define Ys (Ds * 365) |
772 |
|
|
773 |
|
#define Xfmt(buf, var, s, unit) \ |
774 |
|
((var) >= s && (var) % s == 0) \ |
775 |
|
bprintf((buf), "%ju" unit, (var) / s) |
776 |
|
|
777 |
|
// XXX move to VTIM? |
778 |
|
#define vdur_render(buf, dur) do { \ |
779 |
|
uintmax_t dec = (uintmax_t)floor(dur); \ |
780 |
|
uintmax_t frac = (uintmax_t)floor((dur) * 1e3) % UINTMAX_C(1000); \ |
781 |
|
if (dec == 0 && frac == 0) \ |
782 |
|
(void) strncpy(buf, "0s", sizeof(buf)); \ |
783 |
|
else if (dec == 0) \ |
784 |
|
bprintf((buf), "%jums", frac); \ |
785 |
|
else if (frac != 0) \ |
786 |
|
bprintf((buf), "%ju.%03jus", dec, frac); \ |
787 |
|
else if Xfmt(buf, dec, Ys, "y"); \ |
788 |
|
else if Xfmt(buf, dec, Ws, "w"); \ |
789 |
|
else if Xfmt(buf, dec, Ds, "d"); \ |
790 |
|
else if Xfmt(buf, dec, Hs, "h"); \ |
791 |
|
else if Xfmt(buf, dec, Ms, "m"); \ |
792 |
|
else \ |
793 |
|
bprintf((buf), "%jus", dec); \ |
794 |
|
} while (0) |
795 |
|
|
796 |
|
static void |
797 |
11760 |
ban_render(struct cli *cli, const uint8_t *bs, int quote) |
798 |
|
{ |
799 |
|
struct ban_test bt; |
800 |
|
const uint8_t *be; |
801 |
|
char buf[64]; |
802 |
|
|
803 |
11760 |
be = bs + ban_len(bs); |
804 |
11760 |
bs += BANS_HEAD_LEN; |
805 |
20800 |
while (bs < be) { |
806 |
9040 |
ban_iter(&bs, &bt); |
807 |
9040 |
ASSERT_BAN_ARG(bt.arg1); |
808 |
9040 |
ASSERT_BAN_OPER(bt.oper); |
809 |
|
|
810 |
9040 |
if (BANS_HAS_ARG1_SPEC(bt.arg1)) |
811 |
4880 |
VCLI_Out(cli, "%s%.*s", |
812 |
2440 |
arg_name[BAN_ARGIDX(bt.arg1)], |
813 |
2440 |
bt.arg1_spec[0] - 1, bt.arg1_spec + 1); |
814 |
|
else |
815 |
6600 |
VCLI_Out(cli, "%s", arg_name[BAN_ARGIDX(bt.arg1)]); |
816 |
|
|
817 |
9040 |
VCLI_Out(cli, " %s ", ban_oper[BAN_OPERIDX(bt.oper)]); |
818 |
|
|
819 |
9040 |
if (BANS_HAS_ARG2_DOUBLE(bt.arg1)) { |
820 |
8560 |
vdur_render(buf, bt.arg2_double); |
821 |
4600 |
VCLI_Out(cli, "%s", buf); |
822 |
9040 |
} else if (quote) { |
823 |
520 |
VCLI_Quote(cli, bt.arg2); |
824 |
520 |
} else { |
825 |
3920 |
VCLI_Out(cli, "%s", bt.arg2); |
826 |
|
} |
827 |
|
|
828 |
9040 |
if (bs < be) |
829 |
520 |
VCLI_Out(cli, " && "); |
830 |
|
} |
831 |
11760 |
} |
832 |
|
|
833 |
|
static void |
834 |
2880 |
ban_list(struct cli *cli, struct ban *bl) |
835 |
|
{ |
836 |
|
struct ban *b; |
837 |
|
int64_t o; |
838 |
|
|
839 |
2880 |
VCLI_Out(cli, "Present bans:\n"); |
840 |
13680 |
VTAILQ_FOREACH(b, &ban_head, list) { |
841 |
10800 |
o = bl == b ? 1 : 0; |
842 |
21600 |
VCLI_Out(cli, "%10.6f %5ju %s", ban_time(b->spec), |
843 |
10800 |
(intmax_t)(b->refcount - o), |
844 |
10800 |
b->flags & BANS_FLAG_COMPLETED ? "C" : "-"); |
845 |
10800 |
if (DO_DEBUG(DBG_LURKER)) { |
846 |
3760 |
VCLI_Out(cli, "%s%s %p ", |
847 |
1880 |
b->flags & BANS_FLAG_REQ ? "R" : "-", |
848 |
1880 |
b->flags & BANS_FLAG_OBJ ? "O" : "-", |
849 |
1880 |
b); |
850 |
1880 |
} |
851 |
10800 |
VCLI_Out(cli, " "); |
852 |
10800 |
ban_render(cli, b->spec, 0); |
853 |
10800 |
VCLI_Out(cli, "\n"); |
854 |
10800 |
if (VCLI_Overflow(cli)) |
855 |
0 |
break; |
856 |
10800 |
if (DO_DEBUG(DBG_LURKER)) { |
857 |
1880 |
Lck_Lock(&ban_mtx); |
858 |
|
struct objcore *oc; |
859 |
3160 |
VTAILQ_FOREACH(oc, &b->objcore, ban_list) |
860 |
1280 |
VCLI_Out(cli, " oc = %p\n", oc); |
861 |
1880 |
Lck_Unlock(&ban_mtx); |
862 |
1880 |
} |
863 |
10800 |
} |
864 |
2880 |
} |
865 |
|
|
866 |
|
static void |
867 |
240 |
ban_list_json(struct cli *cli, const char * const *av, struct ban *bl) |
868 |
|
{ |
869 |
|
struct ban *b; |
870 |
|
int64_t o; |
871 |
240 |
int n = 0; |
872 |
|
int ocs; |
873 |
|
|
874 |
240 |
VCLI_JSON_begin(cli, 2, av); |
875 |
240 |
VCLI_Out(cli, ",\n"); |
876 |
1200 |
VTAILQ_FOREACH(b, &ban_head, list) { |
877 |
960 |
o = bl == b ? 1 : 0; |
878 |
960 |
VCLI_Out(cli, "%s", n ? ",\n" : ""); |
879 |
960 |
n++; |
880 |
960 |
VCLI_Out(cli, "{\n"); |
881 |
960 |
VSB_indent(cli->sb, 2); |
882 |
960 |
VCLI_Out(cli, "\"time\": %.6f,\n", ban_time(b->spec)); |
883 |
960 |
VCLI_Out(cli, "\"refs\": %ju,\n", (intmax_t)(b->refcount - o)); |
884 |
1920 |
VCLI_Out(cli, "\"completed\": %s,\n", |
885 |
960 |
b->flags & BANS_FLAG_COMPLETED ? "true" : "false"); |
886 |
960 |
VCLI_Out(cli, "\"spec\": \""); |
887 |
960 |
ban_render(cli, b->spec, 1); |
888 |
960 |
VCLI_Out(cli, "\""); |
889 |
|
|
890 |
960 |
if (DO_DEBUG(DBG_LURKER)) { |
891 |
240 |
VCLI_Out(cli, ",\n"); |
892 |
480 |
VCLI_Out(cli, "\"req_tests\": %s,\n", |
893 |
240 |
b->flags & BANS_FLAG_REQ ? "true" : "false"); |
894 |
480 |
VCLI_Out(cli, "\"obj_tests\": %s,\n", |
895 |
240 |
b->flags & BANS_FLAG_OBJ ? "true" : "false"); |
896 |
240 |
VCLI_Out(cli, "\"pointer\": \"%p\",\n", b); |
897 |
240 |
if (VCLI_Overflow(cli)) |
898 |
0 |
break; |
899 |
|
|
900 |
240 |
ocs = 0; |
901 |
240 |
VCLI_Out(cli, "\"objcores\": [\n"); |
902 |
240 |
VSB_indent(cli->sb, 2); |
903 |
240 |
Lck_Lock(&ban_mtx); |
904 |
|
struct objcore *oc; |
905 |
240 |
VTAILQ_FOREACH(oc, &b->objcore, ban_list) { |
906 |
0 |
if (ocs) |
907 |
0 |
VCLI_Out(cli, ",\n"); |
908 |
0 |
VCLI_Out(cli, "%p", oc); |
909 |
0 |
ocs++; |
910 |
0 |
} |
911 |
240 |
Lck_Unlock(&ban_mtx); |
912 |
240 |
VSB_indent(cli->sb, -2); |
913 |
240 |
VCLI_Out(cli, "\n]"); |
914 |
240 |
} |
915 |
960 |
VSB_indent(cli->sb, -2); |
916 |
960 |
VCLI_Out(cli, "\n}"); |
917 |
960 |
} |
918 |
240 |
VCLI_JSON_end(cli); |
919 |
240 |
} |
920 |
|
|
921 |
|
static void v_matchproto_(cli_func_t) |
922 |
3120 |
ccf_ban_list(struct cli *cli, const char * const *av, void *priv) |
923 |
|
{ |
924 |
|
struct ban *bl; |
925 |
|
|
926 |
3120 |
(void)priv; |
927 |
|
|
928 |
|
/* Get a reference so we are safe to traverse the list */ |
929 |
3120 |
Lck_Lock(&ban_mtx); |
930 |
3120 |
bl = VTAILQ_LAST(&ban_head, banhead_s); |
931 |
3120 |
bl->refcount++; |
932 |
3120 |
Lck_Unlock(&ban_mtx); |
933 |
|
|
934 |
3120 |
if (av[2] != NULL && strcmp(av[2], "-j") == 0) |
935 |
240 |
ban_list_json(cli, av, bl); |
936 |
|
else |
937 |
2880 |
ban_list(cli, bl); |
938 |
|
|
939 |
3120 |
Lck_Lock(&ban_mtx); |
940 |
3120 |
bl->refcount--; |
941 |
3120 |
ban_kick_lurker(); // XXX: Mostly for testcase b00009.vtc |
942 |
3120 |
Lck_Unlock(&ban_mtx); |
943 |
3120 |
} |
944 |
|
|
945 |
|
static struct cli_proto ban_cmds[] = { |
946 |
|
{ CLICMD_BAN, "", ccf_ban }, |
947 |
|
{ CLICMD_BAN_LIST, "", ccf_ban_list, |
948 |
|
ccf_ban_list }, |
949 |
|
{ NULL } |
950 |
|
}; |
951 |
|
|
952 |
|
/*-------------------------------------------------------------------- |
953 |
|
*/ |
954 |
|
|
955 |
|
void |
956 |
36540 |
BAN_Compile(void) |
957 |
|
{ |
958 |
|
struct ban *b; |
959 |
|
|
960 |
|
/* |
961 |
|
* All bans have been read from all persistent stevedores. Export |
962 |
|
* the compiled list |
963 |
|
*/ |
964 |
|
|
965 |
36540 |
ASSERT_CLI(); |
966 |
36540 |
AZ(ban_shutdown); |
967 |
|
|
968 |
36540 |
Lck_Lock(&ban_mtx); |
969 |
|
|
970 |
|
/* Report the place-holder ban */ |
971 |
36540 |
b = VTAILQ_FIRST(&ban_head); |
972 |
36540 |
ban_info_new(b->spec, ban_len(b->spec)); |
973 |
|
|
974 |
36540 |
ban_export(); |
975 |
|
|
976 |
36540 |
Lck_Unlock(&ban_mtx); |
977 |
|
|
978 |
36540 |
ban_start = VTAILQ_FIRST(&ban_head); |
979 |
36540 |
BAN_Release(); |
980 |
36540 |
} |
981 |
|
|
982 |
|
void |
983 |
36621 |
BAN_Init(void) |
984 |
|
{ |
985 |
|
struct ban_proto *bp; |
986 |
|
|
987 |
36621 |
BAN_Build_Init(); |
988 |
36621 |
Lck_New(&ban_mtx, lck_ban); |
989 |
36621 |
CLI_AddFuncs(ban_cmds); |
990 |
|
|
991 |
36621 |
ban_holds = 1; |
992 |
|
|
993 |
|
/* Add a placeholder ban */ |
994 |
36621 |
bp = BAN_Build(); |
995 |
36621 |
AN(bp); |
996 |
36621 |
PTOK(pthread_cond_init(&ban_lurker_cond, NULL)); |
997 |
36621 |
AZ(BAN_Commit(bp)); |
998 |
36621 |
Lck_Lock(&ban_mtx); |
999 |
36621 |
ban_mark_completed(VTAILQ_FIRST(&ban_head)); |
1000 |
36621 |
Lck_Unlock(&ban_mtx); |
1001 |
36621 |
} |
1002 |
|
|
1003 |
|
/*-------------------------------------------------------------------- |
1004 |
|
* Shutdown of the ban system. |
1005 |
|
* |
1006 |
|
* When this function returns, no new bans will be accepted, and no |
1007 |
|
* bans will be dropped (ban lurker thread stopped), so that no |
1008 |
|
* STV_BanInfo calls will be executed. |
1009 |
|
*/ |
1010 |
|
|
1011 |
|
void |
1012 |
36120 |
BAN_Shutdown(void) |
1013 |
|
{ |
1014 |
|
void *status; |
1015 |
|
|
1016 |
36120 |
Lck_Lock(&ban_mtx); |
1017 |
36120 |
ban_shutdown = 1; |
1018 |
36120 |
ban_kick_lurker(); |
1019 |
36120 |
Lck_Unlock(&ban_mtx); |
1020 |
|
|
1021 |
36120 |
PTOK(pthread_join(ban_thread, &status)); |
1022 |
36120 |
AZ(status); |
1023 |
|
|
1024 |
36120 |
Lck_Lock(&ban_mtx); |
1025 |
|
/* Export the ban list to compact it */ |
1026 |
36120 |
ban_export(); |
1027 |
36120 |
Lck_Unlock(&ban_mtx); |
1028 |
|
|
1029 |
36120 |
BAN_Build_Fini(); |
1030 |
36120 |
} |