]> git.ipfire.org Git - thirdparty/squid.git/blame - src/peer_digest.cc
Cleaned up ICP logging/counting and ICP/CD stats output
[thirdparty/squid.git] / src / peer_digest.cc
CommitLineData
9b7de833 1
2/*
ddc0f170 3 * $Id: peer_digest.cc,v 1.8 1998/04/09 21:15:02 rousskov Exp $
9b7de833 4 *
5 * DEBUG: section 72 Peer Digest Routines
6 * AUTHOR: Alex Rousskov
7 *
8 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
9 * --------------------------------------------------------
10 *
11 * Squid is the result of efforts by numerous individuals from the
12 * Internet community. Development is led by Duane Wessels of the
13 * National Laboratory for Applied Network Research and funded by
14 * the National Science Foundation.
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 *
30 */
31
32#include "squid.h"
33
7a2e5bb5 34#if SQUID_PEER_DIGEST
35
9b7de833 36/* local types */
37
38/* local prototypes */
395b813e 39static void peerDigestClean(peer *p);
40static time_t peerDigestNextDisDelay(const peer *p);
00485c29 41static time_t peerDigestExpiresDelay(const peer *p, const StoreEntry *e);
395b813e 42static void peerDigestDisable(peer *p);
43static void peerDigestDelay(peer *p, int disable, time_t delay);
9b7de833 44static void peerDigestValidate(peer *p);
45static void peerDigestRequest(peer *p);
46static void peerDigestFetchReply(void *data, char *buf, ssize_t size);
47static void peerDigestRequest(peer *p);
48static void peerDigestSwapInHeaders(void *data, char *buf, ssize_t size);
49static void peerDigestSwapInCBlock(void *data, char *buf, ssize_t size);
50static void peerDigestSwapInMask(void *data, char *buf, ssize_t size);
51static int peerDigestFetchedEnough(DigestFetchState *fetch, char *buf, ssize_t size, const char *step_name);
52static void peerDigestFetchFinish(DigestFetchState *fetch, char *buf, const char *err_msg);
53static int peerDigestSetCBlock(peer *p, const char *buf);
54static int peerDigestUpdateMask(peer *peer, int offset, const char *buf, int size);
395b813e 55#define max_delay(t1,t2) ((t1) >= (t2) ? (t1) : (t2))
56
9b7de833 57
58/* local constants */
59#define StoreDigestCBlockSize sizeof(StoreDigestCBlock)
60
61/* min interval for requesting digests from the same peer */
f868ab44 62static const time_t PeerDigestRequestMinGap = 10 * 60; /* seconds */
bd890734 63
395b813e 64/* min interval for requesting digests at start */
bd890734 65static const time_t GlobalDigestRequestMinGap = 1 * 60; /* seconds */
66
67/* local vars */
68static time_t global_last_req_timestamp = 0;
9b7de833 69
70void
71peerDigestInit(peer *p)
72{
73 assert(p);
74 assert(!p->digest.flags);
75 assert(!p->digest.cd);
76 assert(SM_PAGE_SIZE == 4096); /* we use MEM_4K_BUF */
77 if (EBIT_TEST(p->options, NEIGHBOR_NO_DIGEST)) {
395b813e 78 peerDigestDisable(p);
9b7de833 79 } else {
80 cbdataLock(p);
81 peerDigestValidate(p);
82 }
83 EBIT_SET(p->digest.flags, PD_INITED);
84}
85
86/* no pending events or requests should exist when you call this */
87static void
88peerDigestClean(peer *p)
89{
90 if (!cbdataValid(p))
00485c29 91 debug(72, 2) ("peerDigest: note: peer '%s' was reset or deleted\n", p->host);
9b7de833 92 assert(!EBIT_TEST(p->digest.flags, PD_REQUESTED));
395b813e 93 peerDigestDisable(p);
9b7de833 94 cbdataUnlock(p);
95}
96
395b813e 97/* disables peer for good */
98static void
99peerDigestDisable(peer *p)
100{
101 peerDigestDelay(p, 1, -1);
102}
103
00485c29 104/* next delay for a disabled entry */
395b813e 105static time_t
106peerDigestNextDisDelay(const peer *p)
107{
108 assert(p);
109 return p->digest.last_dis_delay ?
110 2 * p->digest.last_dis_delay : /* exponential backoff */
111 PeerDigestRequestMinGap; /* minimal delay */
112}
113
00485c29 114/* artificially increases expires to avoid race conditions */
115static time_t
116peerDigestExpiresDelay(const peer *p, const StoreEntry *e)
117{
118 assert(p);
119 if (!e)
120 return 0;
121 if (e->expires > 0)
122 return e->expires + PeerDigestRequestMinGap - squid_curtime;
123 return PeerDigestRequestMinGap;
124}
125
126
395b813e 127/* delays/disables digest for a psecified delay (disables forever if negative delay) */
128static void
129peerDigestDelay(peer *p, int disable, time_t delay)
130{
131 assert(p);
132 if (disable) {
133 EBIT_SET(p->digest.flags, PD_DISABLED);
134 p->digest.last_dis_delay = delay;
135 }
136 if (delay >= 0) {
137 assert(delay || !disable);
138 debug(72, 2) ("peerDigestDelay: %s: peer %s for %d secs till %s\n",
139 disable ? "disabling" : "delaying",
140 p->host, delay, mkrfc1123(squid_curtime + delay));
141 eventAdd("peerDigestValidate", (EVH*) peerDigestValidate,
142 p, delay);
143 } else {
144 assert(disable);
145 debug(72, 2) ("peerDigestDisable: disabling peer %s for good\n",
146 p->host);
147 /* just in case, will not need it anymore */
148 EBIT_CLR(p->digest.flags, PD_USABLE);
149 }
150}
151
9b7de833 152/* request new digest if our copy is too old; schedule next validation */
153static void
154peerDigestValidate(peer *p)
155{
156 StoreEntry *e = NULL;
157 int do_request;
158 time_t req_time = squid_curtime;
159 assert(p);
160 debug(72, 3) ("peerDigestValidate: digest %s\n", p->host);
161 if (!cbdataValid(p)) {
162 peerDigestClean(p);
163 return;
164 }
395b813e 165 debug(72, 3) ("current GMT time: %s\n", mkrfc1123(squid_curtime));
9b7de833 166 assert(!EBIT_TEST(p->digest.flags, PD_REQUESTED));
395b813e 167 debug(72, 3) ("peerDigestValidate: %s was %s disabled\n",
168 p->host, p->digest.last_dis_delay ? "" : "not");
169 if (1 /* p->digest.cd */) {
9b7de833 170 const cache_key *key;
171 key = storeKeyPublic(urlRInternal(p->host, p->http_port, NULL, StoreDigestUrlPath), METHOD_GET);
172 e = storeGet(key);
173 debug(72, 3) ("peerDigestValidate: %s store entry, key: %s, exp: %s\n",
174 e ? "has" : "no", storeKeyText(key), mkrfc1123(e ? e->expires : 0));
175 }
176 /* currently we rely on entry->expire information */
00485c29 177 {
178 const time_t exp_delay = peerDigestExpiresDelay(p, e);
179 do_request = exp_delay <= 0;
180 req_time = squid_curtime + exp_delay;
181 if (req_time < squid_curtime)
182 req_time = squid_curtime;
183 }
bd890734 184 /* do not request too often from one peer */
9b7de833 185 if (req_time - p->digest.last_req_timestamp < PeerDigestRequestMinGap) {
186 if (do_request) {
bd890734 187 debug(72, 2) ("peerDigestValidate: %s, avoiding too close peer requests (%d secs).\n",
9b7de833 188 p->host, req_time - p->digest.last_req_timestamp);
189 do_request = 0;
190 }
191 req_time = p->digest.last_req_timestamp + PeerDigestRequestMinGap;
192 }
395b813e 193 /* at start, do not request too often from all peers */
194 if (!EBIT_TEST(p->digest.flags, PD_INITED) &&
195 req_time - global_last_req_timestamp < GlobalDigestRequestMinGap) {
bd890734 196 if (do_request) {
197 debug(72, 2) ("peerDigestValidate: %s, avoiding too close requests (%d secs).\n",
198 p->host, req_time - global_last_req_timestamp);
199 do_request = 0;
200 }
201 req_time = global_last_req_timestamp + GlobalDigestRequestMinGap;
395b813e 202 /* otherwise we have all but one peer returning at the same moment @?@ */
203 debug(72, 5) ("peerDigestValidate: inc req_time (%+d) in anticipation of more reqs\n",
204 (int)(req_time - global_last_req_timestamp));
205 global_last_req_timestamp = req_time;
bd890734 206 }
9b7de833 207 /* start request if needed */
208 if (do_request) {
209 static nest_level = 0;
210 nest_level++;
211 assert(nest_level == 1);
395b813e 212 debug(72, 2) ("peerDigestValidate: %s requesting; old entry expires: %s\n",
213 p->host, e ? mkrfc1123(e->expires) : "no entry");
214 /* will eventually disable digests or call peerDigest Delay */
9b7de833 215 peerDigestRequest(p);
216 nest_level--;
395b813e 217 } else {
218 /* schedule next re-validation */
219 assert(req_time > squid_curtime);
220 peerDigestDelay(p, !p->digest.cd, req_time - squid_curtime);
9b7de833 221 }
9b7de833 222}
223
224/* ask peer cache for a fresh digest */
225static void
226peerDigestRequest(peer *p)
227{
228 StoreEntry *e, *old_e;
229 char *url;
230 const cache_key *key;
231 request_t *req;
232 DigestFetchState *fetch = NULL;
233 assert(p);
234 EBIT_SET(p->digest.flags, PD_REQUESTED);
235 /* compute future request components */
236 url = urlRInternal(p->host, p->http_port, "", StoreDigestUrlPath);
237 key = storeKeyPublic(url, METHOD_GET);
238 debug(72,2) ("peerDigestRequest: %s key: %s\n", url, storeKeyText(key));
395b813e 239 req = requestLink(urlParse(METHOD_GET, url));
9b7de833 240 assert(req);
241 /* add custom headers */
242 /* rewrite this when requests get new header interface */
243 assert(!req->headers);
244 {
245 MemBuf mb;
246 memBufDefInit(&mb);
247 memBufPrintf(&mb, "Accept: %s,text/html\r\n", StoreDigestMimeStr);
248 memBufPrintf(&mb, "Cache-control: only-if-cached\r\n");
249 memBufAppend(&mb, "\r\n", 2);
250 /* kludge! */
251 assert(memBufFreeFunc(&mb) == &xfree);
252 req->headers = mb.buf;
253 req->headers_sz = mb.size;
254 }
255 /* create fetch state structure */
256 fetch = memAllocate(MEM_DIGEST_FETCH_STATE);
257 cbdataAdd(fetch, MEM_DIGEST_FETCH_STATE);
258 fetch->peer = p;
259 fetch->start_time = squid_curtime;
260 p->digest.last_req_timestamp = squid_curtime;
bd890734 261 global_last_req_timestamp = squid_curtime;
9b7de833 262 EBIT_SET(req->flags, REQ_CACHABLE);
9b7de833 263 /* the rest is based on clientProcessExpired() */
264 EBIT_SET(req->flags, REQ_REFRESH);
265 old_e = fetch->old_entry = storeGet(key);
266 if (old_e) {
267 debug(72,5) ("peerDigestRequest: found old entry\n");
268 storeLockObject(old_e);
269 storeCreateMemObject(old_e, url, url);
270 storeClientListAdd(old_e, fetch);
271 }
272 e = fetch->entry = storeCreateEntry(url, url, req->flags, req->method);
395b813e 273 debug(72,5) ("peerDigestRequest: new entry is private: %d\n",
9b7de833 274 (int)EBIT_TEST(e->flag, KEY_PRIVATE));
275 storeClientListAdd(e, fetch);
276 /* set lastmod to trigger IMS request if possible */
277 if (old_e)
278 e->lastmod = old_e->lastmod;
279 fetch->offset = 0;
395b813e 280 debug(72,3) ("peerDigestRequest: forwarding to protoDispatch...\n");
9b7de833 281 /* push towards peer cache */
282 protoDispatch(0, e, req);
283 storeClientCopy(e, 0, 0, SM_PAGE_SIZE, memAllocate(MEM_4K_BUF),
284 peerDigestFetchReply, fetch);
285}
286
287/* waits for full http headers to be received and parses them */
288static void
289peerDigestFetchReply(void *data, char *buf, ssize_t size)
290{
291 DigestFetchState *fetch = data;
292 peer *peer = fetch->peer;
293 assert(peer && buf);
294 assert(!fetch->offset);
295 if (peerDigestFetchedEnough(fetch, buf, size, "peerDigestFetchReply"))
296 return;
297 if (headersEnd(buf, size)) {
298 http_status status;
299 HttpReply *reply = fetch->entry->mem_obj->reply;
300 assert(reply);
301 httpReplyParse(reply, buf);
302 status = reply->sline.status;
303 debug(72, 3) ("peerDigestFetchHeaders: status: %d, expires: %s\n",
304 status, mkrfc1123(reply->expires));
305 /* this "if" is based on clientHandleIMSReply() */
306 if (status == HTTP_NOT_MODIFIED) {
307 request_t *r = NULL;
308 /* our old entry is fine */
309 assert(fetch->old_entry);
310 if (!fetch->old_entry->mem_obj->request)
311 fetch->old_entry->mem_obj->request = r =
312 requestLink(fetch->old_entry->mem_obj->request);
313 httpReplyUpdateOnNotModified(fetch->old_entry->mem_obj->reply, reply);
314 storeTimestampsSet(fetch->old_entry);
315 /* get rid of 304 reply */
316 storeUnregister(fetch->entry, fetch);
317 /* paranoid assert: storeUnregister should not call us recursively */
318 assert(fetch->entry);
319 storeUnlockObject(fetch->entry);
320 fetch->entry = fetch->old_entry;
321 fetch->old_entry = NULL;
322 requestUnlink(r);
323 fetch->entry->mem_obj->request = NULL;
324 } else
325 if (status == HTTP_OK) {
326 /* get rid of old entry if any */
327 if (fetch->old_entry) {
328 debug(72, 3) ("peerDigestFetchReply: got new digest, requesting release of old digest\n");
329 storeUnregister(fetch->old_entry, fetch);
330 storeReleaseRequest(fetch->old_entry);
331 storeUnlockObject(fetch->old_entry);
332 fetch->old_entry = NULL;
333 }
334 } else {
335 /* some kind of a bug */
395b813e 336 peerDigestFetchFinish(fetch, buf, httpStatusLineReason(&reply->sline));
9b7de833 337 return;
338 }
339 /* must have a ready-to-use store entry if we got here */
340 /* can we stay with the old digest? */
341 if (status == HTTP_NOT_MODIFIED && fetch->peer->digest.cd)
342 peerDigestFetchFinish(fetch, buf, NULL);
343 else
344 storeClientCopy(fetch->entry, /* have to swap in */
345 0, 0, SM_PAGE_SIZE, buf, peerDigestSwapInHeaders, fetch);
346 return;
347 } else {
348 /* need more data, do we have space? */
349 if (size >= SM_PAGE_SIZE)
350 peerDigestFetchFinish(fetch, buf, "too big header");
351 else
352 storeClientCopy(fetch->entry, size, 0, SM_PAGE_SIZE, buf,
353 peerDigestFetchReply, fetch);
354 }
355}
356
357/* fetch headers from disk, pass on to SwapInCBlock */
358static void
359peerDigestSwapInHeaders(void *data, char *buf, ssize_t size)
360{
361 DigestFetchState *fetch = data;
362 peer *peer = fetch->peer;
363 size_t hdr_size;
364 assert(peer && buf);
365 assert(!fetch->offset);
366 if (peerDigestFetchedEnough(fetch, buf, size, "peerDigestSwapInHeaders"))
367 return;
368 if ((hdr_size = headersEnd(buf, size))) {
369 assert(fetch->entry->mem_obj->reply);
370 if (!fetch->entry->mem_obj->reply->sline.status)
371 httpReplyParse(fetch->entry->mem_obj->reply, buf);
372 assert(fetch->entry->mem_obj->reply->sline.status == HTTP_OK);
373 fetch->offset += hdr_size;
374 storeClientCopy(fetch->entry, size, fetch->offset,
375 SM_PAGE_SIZE, buf,
376 peerDigestSwapInCBlock, fetch);
377 } else {
378 /* need more data, do we have space? */
379 if (size >= SM_PAGE_SIZE)
380 peerDigestFetchFinish(fetch, buf, "too big stored header");
381 else
382 storeClientCopy(fetch->entry, size, 0, SM_PAGE_SIZE, buf,
383 peerDigestSwapInHeaders, fetch);
384 }
385}
386
387static void
388peerDigestSwapInCBlock(void *data, char *buf, ssize_t size)
389{
390 DigestFetchState *fetch = data;
391 peer *peer = fetch->peer;
392 HttpReply *rep = fetch->entry->mem_obj->reply;
393 const int seen = fetch->offset + size;
394 assert(peer && buf && rep);
395 if (peerDigestFetchedEnough(fetch, buf, size, "peerDigestSwapInCBlock"))
396 return;
397 if (size >= StoreDigestCBlockSize) {
398 if (peerDigestSetCBlock(peer, buf)) {
399 fetch->offset += StoreDigestCBlockSize;
400 storeClientCopy(fetch->entry, seen, fetch->offset,
401 SM_PAGE_SIZE, buf,
402 peerDigestSwapInMask, fetch);
403 } else {
404 peerDigestFetchFinish(fetch, buf, "invalid digest cblock");
405 }
406 } else {
407 /* need more data, do we have space? */
408 if (size >= SM_PAGE_SIZE)
409 peerDigestFetchFinish(fetch, buf, "too big cblock");
410 else
411 storeClientCopy(fetch->entry, size, 0, SM_PAGE_SIZE, buf,
412 peerDigestSwapInCBlock, fetch);
413 }
414}
415
416static void
417peerDigestSwapInMask(void *data, char *buf, ssize_t size)
418{
419 DigestFetchState *fetch = data;
420 peer *peer = fetch->peer;
421 HttpReply *rep = fetch->entry->mem_obj->reply;
422 const int seen = fetch->offset + size;
423 assert(peer && buf && rep);
395b813e 424 if (peerDigestFetchedEnough(fetch, buf, size, "peerDigestSwapInMask"))
9b7de833 425 return;
426 if (peerDigestUpdateMask(peer, fetch->mask_offset, buf, size)) {
427 fetch->offset += size;
428 fetch->mask_offset += size;
429 storeClientCopy(fetch->entry, seen, fetch->offset,
430 SM_PAGE_SIZE, buf,
431 peerDigestSwapInMask, fetch);
432 } else {
433 peerDigestFetchFinish(fetch, buf, "invalid mask");
434 }
435}
436
437static int
438peerDigestFetchedEnough(DigestFetchState *fetch, char *buf, ssize_t size, const char *step_name)
439{
440 const char *reason = NULL;
441 const char *no_bug = NULL;
442
395b813e 443 debug(72, 6) ("%s: %s offset: %d size: %d.\n",
9b7de833 444 step_name, fetch->peer->host, fetch->offset, size);
445
446 /* test exiting conditions */
447 if (size < 0) reason = "swap failure";
448 else if (!size) reason = no_bug = "eof";
449 else if (!fetch->entry) reason = "swap abort(?)";
450 else if (fetch->entry->store_status == STORE_ABORTED) reason = "swap abort";
395b813e 451 else if (!cbdataValid(fetch->peer)) reason = "peer disappeared";
9b7de833 452
453 /* report exit reason */
454 if (reason) {
455 debug(72, 3) ("%s: exiting on %s\n", step_name, reason);
456 peerDigestFetchFinish(fetch, buf, no_bug ? NULL : reason);
457 }
458 return reason != NULL;
459}
460
461/* free state structures, disables digest on error */
462/* this probably should mimic httpRequestFree() but it does not! @?@ @?@ */
463static void
464peerDigestFetchFinish(DigestFetchState *fetch, char *buf, const char *err_msg)
465{
466 peer *peer = fetch->peer;
467 MemObject *mem = fetch->entry->mem_obj;
468 request_t *req = mem->request;
469 const time_t expires = fetch->entry->expires;
470 const time_t fetch_resp_time = squid_curtime - fetch->start_time;
471 const off_t b_read = (fetch->entry->swap_status == STORE_PENDING) ? mem->inmem_hi : mem->object_sz;
9b7de833 472 if (!err_msg && !peer->digest.cd)
473 err_msg = "null digest (internal bug?)";
474 if (!err_msg && fetch->mask_offset != peer->digest.cd->mask_size)
475 err_msg = "premature eof";
476 if (fetch->old_entry) {
477 debug(72,2) ("peerDigestFetchFinish: deleting old entry\n");
478 storeUnregister(fetch->old_entry, fetch);
479 storeReleaseRequest(fetch->old_entry);
480 storeUnlockObject(fetch->old_entry);
481 fetch->old_entry = NULL;
482 }
395b813e 483 assert(fetch->entry);
9b7de833 484 if (err_msg) {
485 debug(72, 1) ("disabling corrupted (%s) digest from %s\n",
486 err_msg, peer->host);
487 if (peer->digest.cd) {
488 cacheDigestDestroy(peer->digest.cd);
489 peer->digest.cd = NULL;
490 }
395b813e 491 /* disable for a while */
9b7de833 492 EBIT_CLR(peer->digest.flags, PD_USABLE);
395b813e 493 peerDigestDelay(peer, 1,
00485c29 494 max_delay(
495 peerDigestExpiresDelay(peer, fetch->entry),
395b813e 496 peerDigestNextDisDelay(peer)));
9b7de833 497 /* release buggy entry */
498 storeReleaseRequest(fetch->entry);
499 } else {
500 storeComplete(fetch->entry);
501 EBIT_SET(peer->digest.flags, PD_USABLE);
395b813e 502 EBIT_CLR(peer->digest.flags, PD_DISABLED);
503 peer->digest.last_dis_delay = 0;
00485c29 504 peerDigestDelay(peer, 0,
505 max_delay(peerDigestExpiresDelay(peer, fetch->entry), 0));
9b7de833 506 }
507 storeUnregister(fetch->entry, fetch);
508 storeUnlockObject(fetch->entry);
395b813e 509 requestUnlink(req);
9b7de833 510 fetch->entry = NULL;
511 cbdataFree(fetch);
512 fetch = NULL;
513 memFree(MEM_4K_BUF, buf);
395b813e 514 /* set it here and in peerDigestRequest to protect against long downloads */
515 peer->digest.last_req_timestamp = squid_curtime;
516 peer->digest.last_fetch_resp_time = fetch_resp_time;
9b7de833 517 EBIT_CLR(peer->digest.flags, PD_REQUESTED);
ddc0f170 518 /* update global stats */
9b7de833 519 kb_incr(&Counter.cd.kbytes_recv, (size_t)b_read);
00485c29 520 Counter.cd.msgs_recv++;
ddc0f170 521 /* update peer stats */
522 kb_incr(&peer->digest.stats.kbytes_recv, (size_t)b_read);
523 peer->digest.stats.msgs_recv++;
395b813e 524 debug(72, 2) ("peerDigestFetchFinish: %s done; took: %d secs; expires: %s\n",
9b7de833 525 peer->host, fetch_resp_time, mkrfc1123(expires));
9b7de833 526}
527
528static int
529peerDigestSetCBlock(peer *peer, const char *buf)
530{
531 StoreDigestCBlock cblock;
532 int freed_size = 0;
533 xmemcpy(&cblock, buf, sizeof(cblock));
534 /* network -> host conversions */
535 cblock.ver.current = ntohs(cblock.ver.current);
536 cblock.ver.required = ntohs(cblock.ver.required);
537 cblock.capacity = ntohl(cblock.capacity);
538 cblock.count = ntohl(cblock.count);
539 cblock.del_count = ntohl(cblock.del_count);
540 cblock.mask_size = ntohl(cblock.mask_size);
541 debug(72,2) ("got digest cblock from %s; ver: %d (req: %d)\n",
542 peer->host, (int)cblock.ver.current, (int)cblock.ver.required);
543 debug(72,2) ("\t size: %d bytes, e-cnt: %d, e-util: %d%%\n",
544 cblock.mask_size, cblock.count,
545 xpercentInt(cblock.count, cblock.capacity));
546 /* check version requirements */
547 if (cblock.ver.required > CacheDigestVer.current) {
548 debug(72,1) ("%s digest requires version %d; have: %d\n",
549 peer->host, cblock.ver.required, CacheDigestVer.current);
550 return 0;
551 }
552 /* check consistency */
553 if (cblock.ver.required > cblock.ver.current ||
554 cblock.mask_size <= 0 || cblock.capacity <= 0) {
555 debug(72,0) ("%s digest cblock is corrupted.\n", peer->host);
556 return 0;
557 }
558 /*
559 * no cblock bugs below this point
560 */
561 /* check size changes */
562 if (peer->digest.cd && cblock.mask_size != peer->digest.cd->mask_size) {
563 debug(72,2) ("%s digest changed size: %d -> %d\n",
564 peer->host, cblock.mask_size, peer->digest.cd->mask_size);
565 freed_size = peer->digest.cd->mask_size;
566 cacheDigestDestroy(peer->digest.cd);
567 peer->digest.cd = NULL;
568 }
569 if (!peer->digest.cd) {
570 debug(72,2) ("cloning %s digest; size: %d (%+d) bytes\n",
571 peer->host, cblock.mask_size, (int) (cblock.mask_size - freed_size));
572 peer->digest.cd = cacheDigestSizedCreate(cblock.mask_size, cblock.capacity);
573 if (cblock.mask_size >= freed_size)
574 kb_incr(&Counter.cd.memory, cblock.mask_size - freed_size);
575 }
576 /* these assignments leave us in an inconsistent state until we finish reading the digest */
577 peer->digest.cd->count = cblock.count;
578 peer->digest.cd->del_count = cblock.del_count;
579 return 1;
580}
581
582/* updates current mask. checks for overflows */
583static int
584peerDigestUpdateMask(peer *peer, int offset, const char *buf, int size)
585{
586 if (size) {
587 assert(offset >= 0);
588 assert(peer->digest.cd);
589 if (offset + size > peer->digest.cd->mask_size) {
590 debug(72,0) ("peerDigestUpdateMask: %s digest is larger than expected: %d > %d\n",
591 peer->host, offset + size, peer->digest.cd->mask_size);
592 return 0;
593 }
594 xmemcpy(peer->digest.cd->mask + offset, buf, size);
595 }
596 return 1;
597}
598
7a2e5bb5 599#endif