]> git.ipfire.org Git - thirdparty/squid.git/blob - src/htcp.cc
Cleanup: zap CVS Id tags
[thirdparty/squid.git] / src / htcp.cc
1
2 /*
3 * $Id$
4 *
5 * DEBUG: section 31 Hypertext Caching Protocol
6 * AUTHOR: Duane Wesssels
7 *
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
10 *
11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 *
34 */
35
36 #include "squid.h"
37 #include "htcp.h"
38 #include "ACLChecklist.h"
39 #include "ACL.h"
40 #include "SquidTime.h"
41 #include "Store.h"
42 #include "StoreClient.h"
43 #include "HttpRequest.h"
44 #include "comm.h"
45 #include "MemBuf.h"
46 #include "http.h"
47 #include "icmp/net_db.h"
48
49 typedef struct _Countstr Countstr;
50
51 typedef struct _htcpHeader htcpHeader;
52
53 typedef struct _htcpDataHeader htcpDataHeader;
54
55 typedef struct _htcpDataHeaderSquid htcpDataHeaderSquid;
56
57 typedef struct _htcpAuthHeader htcpAuthHeader;
58
59 typedef struct _htcpStuff htcpStuff;
60
61 typedef struct _htcpDetail htcpDetail;
62
63 struct _Countstr {
64 u_int16_t length;
65 char *text;
66 };
67
68 struct _htcpHeader {
69 u_int16_t length;
70 u_char major;
71 u_char minor;
72 };
73
74 struct _htcpDataHeaderSquid {
75 u_int16_t length;
76
77 #if !WORDS_BIGENDIAN
78 unsigned int opcode:4;
79 unsigned int response:4;
80 #else
81 unsigned int response:4;
82 unsigned int opcode:4;
83 #endif
84
85 #if !WORDS_BIGENDIAN
86 unsigned int reserved:6;
87 unsigned int F1:1;
88 unsigned int RR:1;
89 #else
90 unsigned int RR:1;
91 unsigned int F1:1;
92 unsigned int reserved:6;
93 #endif
94
95 u_int32_t msg_id;
96 };
97
98 struct _htcpDataHeader {
99 u_int16_t length;
100
101 #if WORDS_BIGENDIAN
102 u_int8_t opcode:
103 4;
104 u_int8_t response:
105 4;
106 #else
107 u_int8_t response:
108 4;
109 u_int8_t opcode:
110 4;
111 #endif
112
113 #if WORDS_BIGENDIAN
114 u_int8_t reserved:
115 6;
116 u_int8_t F1:
117 1;
118 u_int8_t RR:
119 1;
120 #else
121 u_int8_t RR:
122 1;
123 u_int8_t F1:
124 1;
125 u_int8_t reserved:
126 6;
127 #endif
128
129 u_int32_t msg_id;
130 };
131
132 /* RR == 0 --> F1 = RESPONSE DESIRED FLAG */
133 /* RR == 1 --> F1 = MESSAGE OVERALL FLAG */
134 /* RR == 0 --> REQUEST */
135 /* RR == 1 --> RESPONSE */
136
137 struct _htcpAuthHeader {
138 u_int16_t length;
139 time_t sig_time;
140 time_t sig_expire;
141 Countstr key_name;
142 Countstr signature;
143 };
144
145 class htcpSpecifier : public StoreClient
146 {
147
148 public:
149 MEMPROXY_CLASS(htcpSpecifier);
150
151 void created (StoreEntry *newEntry);
152 void checkHit();
153 void checkedHit(StoreEntry *e);
154
155 void setFrom (IpAddress &from);
156 void setDataHeader (htcpDataHeader *);
157 char *method;
158 char *uri;
159 char *version;
160 char *req_hdrs;
161 HttpRequest *request;
162
163 private:
164 HttpRequest *checkHitRequest;
165
166 IpAddress from; // was a ptr. return to such IFF needed. otherwise copy should do.
167 htcpDataHeader *dhdr;
168 };
169
170 MEMPROXY_CLASS_INLINE(htcpSpecifier) /**DOCS_NOSEMI*/
171
172 struct _htcpDetail {
173 char *resp_hdrs;
174 char *entity_hdrs;
175 char *cache_hdrs;
176 };
177
178 struct _htcpStuff {
179 int op;
180 int rr;
181 int f1;
182 int response;
183 int reason;
184 u_int32_t msg_id;
185 htcpSpecifier S;
186 htcpDetail D;
187 };
188
189 enum {
190 HTCP_NOP,
191 HTCP_TST,
192 HTCP_MON,
193 HTCP_SET,
194 HTCP_CLR,
195 HTCP_END
196 };
197
198 static const char *const htcpOpcodeStr[] = {
199 "HTCP_NOP",
200 "HTCP_TST",
201 "HTCP_MON",
202 "HTCP_SET",
203 "HTCP_CLR",
204 "HTCP_END"
205 };
206
207 /*
208 * values for htcpDataHeader->response
209 */
210 enum {
211 AUTH_REQUIRED,
212 AUTH_FAILURE,
213 OPCODE_UNIMPLEMENTED,
214 MAJOR_VERSION_UNSUPPORTED,
215 MINOR_VERSION_UNSUPPORTED,
216 INVALID_OPCODE
217 };
218
219 /*
220 * values for htcpDataHeader->RR
221 */
222 enum {
223 RR_REQUEST,
224 RR_RESPONSE
225 };
226
227 static u_int32_t msg_id_counter = 0;
228 static int htcpInSocket = -1;
229 static int htcpOutSocket = -1;
230 #define N_QUERIED_KEYS 8192
231 static u_int32_t queried_id[N_QUERIED_KEYS];
232 static cache_key queried_keys[N_QUERIED_KEYS][SQUID_MD5_DIGEST_LENGTH];
233
234 static IpAddress queried_addr[N_QUERIED_KEYS];
235 static MemAllocator *htcpDetailPool = NULL;
236
237 static int old_squid_format = 0;
238
239
240 static ssize_t htcpBuildPacket(char *buf, size_t buflen, htcpStuff * stuff);
241 static htcpSpecifier *htcpUnpackSpecifier(char *buf, int sz);
242 static htcpDetail *htcpUnpackDetail(char *buf, int sz);
243 static ssize_t htcpBuildAuth(char *buf, size_t buflen);
244 static ssize_t htcpBuildCountstr(char *buf, size_t buflen, const char *s);
245 static ssize_t htcpBuildData(char *buf, size_t buflen, htcpStuff * stuff);
246 static ssize_t htcpBuildDetail(char *buf, size_t buflen, htcpStuff * stuff);
247 static ssize_t htcpBuildOpData(char *buf, size_t buflen, htcpStuff * stuff);
248 static ssize_t htcpBuildSpecifier(char *buf, size_t buflen, htcpStuff * stuff);
249 static ssize_t htcpBuildTstOpData(char *buf, size_t buflen, htcpStuff * stuff);
250 static void htcpFreeSpecifier(htcpSpecifier * s);
251 static void htcpFreeDetail(htcpDetail * s);
252
253 static void htcpHandleMsg(char *buf, int sz, IpAddress &from);
254
255 static void htcpHandleMon(htcpDataHeader *, char *buf, int sz, IpAddress &from);
256
257 static void htcpHandleNop(htcpDataHeader *, char *buf, int sz, IpAddress &from);
258
259 static void htcpHandleSet(htcpDataHeader *, char *buf, int sz, IpAddress &from);
260
261 static void htcpHandleTst(htcpDataHeader *, char *buf, int sz, IpAddress &from);
262 static void htcpRecv(int fd, void *data);
263
264 static void htcpSend(const char *buf, int len, IpAddress &to);
265
266 static void htcpTstReply(htcpDataHeader *, StoreEntry *, htcpSpecifier *, IpAddress &);
267
268 static void htcpHandleTstRequest(htcpDataHeader *, char *buf, int sz, IpAddress &from);
269
270 static void htcpHandleTstResponse(htcpDataHeader *, char *, int, IpAddress &);
271
272 static void
273 htcpHexdump(const char *tag, const char *s, int sz)
274 {
275 #if USE_HEXDUMP
276 int i;
277 int k;
278 char hex[80];
279 debugs(31, 3, "htcpHexdump " << tag);
280 memset(hex, '\0', 80);
281
282 for (i = 0; i < sz; i++) {
283 k = i % 16;
284 snprintf(&hex[k * 3], 4, " %02x", (int) *(s + i));
285
286 if (k < 15 && i < (sz - 1))
287 continue;
288
289 debugs(31, 3, "\t" << hex);
290
291 memset(hex, '\0', 80);
292 }
293
294 #endif
295 }
296
297 /*
298 * STUFF FOR SENDING HTCP MESSAGES
299 */
300
301 static ssize_t
302 htcpBuildAuth(char *buf, size_t buflen)
303 {
304 htcpAuthHeader auth;
305 size_t copy_sz = 0;
306 assert(2 == sizeof(u_int16_t));
307 auth.length = htons(2);
308 copy_sz += 2;
309 if (buflen < copy_sz)
310 return -1;
311 xmemcpy(buf, &auth, copy_sz);
312 return copy_sz;
313 }
314
315 static ssize_t
316 htcpBuildCountstr(char *buf, size_t buflen, const char *s)
317 {
318 u_int16_t length;
319 size_t len;
320 int off = 0;
321
322 if (buflen - off < 2)
323 return -1;
324
325 if (s)
326 len = strlen(s);
327 else
328 len = 0;
329
330 debugs(31, 3, "htcpBuildCountstr: LENGTH = " << len);
331
332 debugs(31, 3, "htcpBuildCountstr: TEXT = {" << (s ? s : "<NULL>") << "}");
333
334 length = htons((u_int16_t) len);
335
336 xmemcpy(buf + off, &length, 2);
337
338 off += 2;
339
340 if (buflen - off < len)
341 return -1;
342
343 if (len)
344 xmemcpy(buf + off, s, len);
345
346 off += len;
347
348 return off;
349 }
350
351 static ssize_t
352 htcpBuildSpecifier(char *buf, size_t buflen, htcpStuff * stuff)
353 {
354 ssize_t off = 0;
355 ssize_t s;
356 s = htcpBuildCountstr(buf + off, buflen - off, stuff->S.method);
357
358 if (s < 0)
359 return s;
360
361 off += s;
362
363 s = htcpBuildCountstr(buf + off, buflen - off, stuff->S.uri);
364
365 if (s < 0)
366 return s;
367
368 off += s;
369
370 s = htcpBuildCountstr(buf + off, buflen - off, stuff->S.version);
371
372 if (s < 0)
373 return s;
374
375 off += s;
376
377 s = htcpBuildCountstr(buf + off, buflen - off, stuff->S.req_hdrs);
378
379 if (s < 0)
380 return s;
381
382 off += s;
383
384 debugs(31, 3, "htcpBuildSpecifier: size " << off);
385
386 return off;
387 }
388
389 static ssize_t
390 htcpBuildDetail(char *buf, size_t buflen, htcpStuff * stuff)
391 {
392 ssize_t off = 0;
393 ssize_t s;
394 s = htcpBuildCountstr(buf + off, buflen - off, stuff->D.resp_hdrs);
395
396 if (s < 0)
397 return s;
398
399 off += s;
400
401 s = htcpBuildCountstr(buf + off, buflen - off, stuff->D.entity_hdrs);
402
403 if (s < 0)
404 return s;
405
406 off += s;
407
408 s = htcpBuildCountstr(buf + off, buflen - off, stuff->D.cache_hdrs);
409
410 if (s < 0)
411 return s;
412
413 off += s;
414
415 return off;
416 }
417
418 static ssize_t
419 htcpBuildTstOpData(char *buf, size_t buflen, htcpStuff * stuff)
420 {
421 switch (stuff->rr) {
422
423 case RR_REQUEST:
424 debugs(31, 3, "htcpBuildTstOpData: RR_REQUEST");
425 return htcpBuildSpecifier(buf, buflen, stuff);
426
427 case RR_RESPONSE:
428 debugs(31, 3, "htcpBuildTstOpData: RR_RESPONSE");
429 debugs(31, 3, "htcpBuildTstOpData: F1 = " << stuff->f1);
430
431 if (stuff->f1) /* cache miss */
432 return 0;
433 else /* cache hit */
434 return htcpBuildDetail(buf, buflen, stuff);
435
436 default:
437 fatal_dump("htcpBuildTstOpData: bad RR value");
438 }
439
440 return 0;
441 }
442
443 static ssize_t
444 htcpBuildClrOpData(char *buf, size_t buflen, htcpStuff * stuff)
445 {
446 u_short reason;
447
448 switch (stuff->rr) {
449 case RR_REQUEST:
450 debugs(31, 3, "htcpBuildClrOpData: RR_REQUEST");
451 reason = htons((u_short)stuff->reason);
452 xmemcpy(buf, &reason, 2);
453 return htcpBuildSpecifier(buf + 2, buflen - 2, stuff) + 2;
454 case RR_RESPONSE:
455 break;
456 default:
457 fatal_dump("htcpBuildClrOpData: bad RR value");
458 }
459
460 return 0;
461 }
462
463 static ssize_t
464 htcpBuildOpData(char *buf, size_t buflen, htcpStuff * stuff)
465 {
466 ssize_t off = 0;
467 debugs(31, 3, "htcpBuildOpData: opcode " << htcpOpcodeStr[stuff->op]);
468
469 switch (stuff->op) {
470
471 case HTCP_TST:
472 off = htcpBuildTstOpData(buf + off, buflen, stuff);
473 break;
474
475 case HTCP_CLR:
476 off = htcpBuildClrOpData(buf + off, buflen, stuff);
477 break;
478
479 default:
480 assert(0);
481 break;
482 }
483
484 return off;
485 }
486
487 static ssize_t
488 htcpBuildData(char *buf, size_t buflen, htcpStuff * stuff)
489 {
490 ssize_t off = 0;
491 ssize_t op_data_sz;
492 size_t hdr_sz = sizeof(htcpDataHeader);
493 htcpDataHeader hdr;
494
495 if (buflen < hdr_sz)
496 return -1;
497
498 off += hdr_sz; /* skip! */
499
500 op_data_sz = htcpBuildOpData(buf + off, buflen - off, stuff);
501
502 if (op_data_sz < 0)
503 return op_data_sz;
504
505 off += op_data_sz;
506
507 debugs(31, 3, "htcpBuildData: hdr.length = " << off);
508
509 hdr.length = (u_int16_t) off;
510
511 hdr.opcode = stuff->op;
512
513 hdr.response = stuff->response;
514
515 hdr.RR = stuff->rr;
516
517 hdr.F1 = stuff->f1;
518
519 hdr.msg_id = stuff->msg_id;
520
521 /* convert multi-byte fields */
522 hdr.length = htons(hdr.length);
523
524 hdr.msg_id = htonl(hdr.msg_id);
525
526 if (!old_squid_format) {
527 xmemcpy(buf, &hdr, hdr_sz);
528 } else {
529 htcpDataHeaderSquid hdrSquid;
530 memset(&hdrSquid, 0, sizeof(hdrSquid));
531 hdrSquid.length = hdr.length;
532 hdrSquid.opcode = hdr.opcode;
533 hdrSquid.response = hdr.response;
534 hdrSquid.F1 = hdr.F1;
535 hdrSquid.RR = hdr.RR;
536 xmemcpy(buf, &hdrSquid, hdr_sz);
537 }
538
539 debugs(31, 3, "htcpBuildData: size " << off);
540
541 return off;
542 }
543
544 /*
545 * Build an HTCP packet into buf, maximum length buflen.
546 * Returns the packet length, or zero on failure.
547 */
548 static ssize_t
549 htcpBuildPacket(char *buf, size_t buflen, htcpStuff * stuff)
550 {
551 ssize_t s;
552 ssize_t off = 0;
553 size_t hdr_sz = sizeof(htcpHeader);
554 htcpHeader hdr;
555 /* skip the header -- we don't know the overall length */
556
557 if (buflen < hdr_sz) {
558 return 0;
559 }
560
561 off += hdr_sz;
562 s = htcpBuildData(buf + off, buflen - off, stuff);
563
564 if (s < 0) {
565 return 0;
566 }
567
568 off += s;
569 s = htcpBuildAuth(buf + off, buflen - off);
570
571 if (s < 0) {
572 return 0;
573 }
574
575 off += s;
576 hdr.length = htons((u_int16_t) off);
577 hdr.major = 0;
578
579 if (old_squid_format)
580 hdr.minor = 0;
581 else
582 hdr.minor = 1;
583
584 xmemcpy(buf, &hdr, hdr_sz);
585
586 debugs(31, 3, "htcpBuildPacket: size " << off);
587
588 return off;
589 }
590
591 static void
592
593 htcpSend(const char *buf, int len, IpAddress &to)
594 {
595 int x;
596
597 debugs(31, 3, "htcpSend: " << to );
598 htcpHexdump("htcpSend", buf, len);
599
600 x = comm_udp_sendto(htcpOutSocket,
601 to,
602 buf,
603 len);
604
605 if (x < 0)
606 debugs(31, 3, "htcpSend: FD " << htcpOutSocket << " sendto: " << xstrerror());
607 else
608 statCounter.htcp.pkts_sent++;
609 }
610
611 /*
612 * STUFF FOR RECEIVING HTCP MESSAGES
613 */
614
615 void
616
617 htcpSpecifier::setFrom (IpAddress &aSocket)
618 {
619 from = aSocket;
620 }
621
622 void
623 htcpSpecifier::setDataHeader (htcpDataHeader *aDataHeader)
624 {
625 dhdr = aDataHeader;
626 }
627
628 static void
629 htcpFreeSpecifier(htcpSpecifier * s)
630 {
631 HTTPMSGUNLOCK(s->request);
632
633 delete s;
634 }
635
636 static void
637 htcpFreeDetail(htcpDetail * d)
638 {
639 htcpDetailPool->free(d);
640 }
641
642 /*
643 * Unpack an HTCP SPECIFIER in place
644 * This will overwrite any following AUTH block
645 */
646 static htcpSpecifier *
647 htcpUnpackSpecifier(char *buf, int sz)
648 {
649 htcpSpecifier *s = new htcpSpecifier;
650 HttpRequestMethod method;
651
652 /* Find length of METHOD */
653 u_int16_t l = ntohs(*(u_int16_t *) buf);
654 sz -= 2;
655 buf += 2;
656
657 if (l > sz) {
658 debugs(31, 3, "htcpUnpackSpecifier: failed to unpack METHOD");
659 htcpFreeSpecifier(s);
660 return NULL;
661 }
662
663 /* Set METHOD */
664 s->method = buf;
665
666 buf += l;
667
668 sz -= l;
669
670 /* Find length of URI */
671 l = ntohs(*(u_int16_t *) buf);
672
673 sz -= 2;
674
675 if (l > sz) {
676 debugs(31, 3, "htcpUnpackSpecifier: failed to unpack URI");
677 htcpFreeSpecifier(s);
678 return NULL;
679 }
680
681 /* Add terminating null to METHOD */
682 *buf = '\0';
683
684 /* Set URI */
685 buf += 2;
686
687 s->uri = buf;
688
689 buf += l;
690
691 sz -= l;
692
693 /* Find length of VERSION */
694 l = ntohs(*(u_int16_t *) buf);
695
696 sz -= 2;
697
698 if (l > sz) {
699 debugs(31, 3, "htcpUnpackSpecifier: failed to unpack VERSION");
700 htcpFreeSpecifier(s);
701 return NULL;
702 }
703
704 /* Add terminating null to URI */
705 *buf = '\0';
706
707 /* Set VERSION */
708 buf += 2;
709
710 s->version = buf;
711
712 buf += l;
713
714 sz -= l;
715
716 /* Find length of REQ-HDRS */
717 l = ntohs(*(u_int16_t *) buf);
718
719 sz -= 2;
720
721 if (l > sz) {
722 debugs(31, 3, "htcpUnpackSpecifier: failed to unpack REQ-HDRS");
723 htcpFreeSpecifier(s);
724 return NULL;
725 }
726
727 /* Add terminating null to URI */
728 *buf = '\0';
729
730 /* Set REQ-HDRS */
731 buf += 2;
732
733 s->req_hdrs = buf;
734
735 buf += l;
736
737 sz -= l;
738
739 debugs(31, 3, "htcpUnpackSpecifier: " << sz << " bytes left");
740
741 /*
742 * Add terminating null to REQ-HDRS. This is possible because we allocated
743 * an extra byte when we received the packet. This will overwrite any following
744 * AUTH block.
745 */
746 *buf = '\0';
747
748 /*
749 * Parse the request
750 */
751 method = HttpRequestMethod(s->method, NULL);
752
753 s->request = HttpRequest::CreateFromUrlAndMethod(s->uri, method == METHOD_NONE ? HttpRequestMethod(METHOD_GET) : method);
754
755 if (s->request)
756 HTTPMSGLOCK(s->request);
757
758 return s;
759 }
760
761 /*
762 * Unpack an HTCP DETAIL in place
763 * This will overwrite any following AUTH block
764 */
765 static htcpDetail *
766 htcpUnpackDetail(char *buf, int sz)
767 {
768 htcpDetail *d = static_cast<htcpDetail *>(htcpDetailPool->alloc());
769
770 /* Find length of RESP-HDRS */
771 u_int16_t l = ntohs(*(u_int16_t *) buf);
772 sz -= 2;
773 buf += 2;
774
775 if (l > sz) {
776 debugs(31, 3, "htcpUnpackDetail: failed to unpack RESP_HDRS");
777 htcpFreeDetail(d);
778 return NULL;
779 }
780
781 /* Set RESP-HDRS */
782 d->resp_hdrs = buf;
783
784 buf += l;
785
786 sz -= l;
787
788 /* Find length of ENTITY-HDRS */
789 l = ntohs(*(u_int16_t *) buf);
790
791 sz -= 2;
792
793 if (l > sz) {
794 debugs(31, 3, "htcpUnpackDetail: failed to unpack ENTITY_HDRS");
795 htcpFreeDetail(d);
796 return NULL;
797 }
798
799 /* Add terminating null to RESP-HDRS */
800 *buf = '\0';
801
802 /* Set ENTITY-HDRS */
803 buf += 2;
804
805 d->entity_hdrs = buf;
806
807 buf += l;
808
809 sz -= l;
810
811 /* Find length of CACHE-HDRS */
812 l = ntohs(*(u_int16_t *) buf);
813
814 sz -= 2;
815
816 if (l > sz) {
817 debugs(31, 3, "htcpUnpackDetail: failed to unpack CACHE_HDRS");
818 htcpFreeDetail(d);
819 return NULL;
820 }
821
822 /* Add terminating null to ENTITY-HDRS */
823 *buf = '\0';
824
825 /* Set CACHE-HDRS */
826 buf += 2;
827
828 d->cache_hdrs = buf;
829
830 buf += l;
831
832 sz -= l;
833
834 debugs(31, 3, "htcpUnpackDetail: " << sz << " bytes left");
835
836 /*
837 * Add terminating null to CACHE-HDRS. This is possible because we allocated
838 * an extra byte when we received the packet. This will overwrite any following
839 * AUTH block.
840 */
841 *buf = '\0';
842
843 return d;
844 }
845
846 static int
847
848 htcpAccessCheck(acl_access * acl, htcpSpecifier * s, IpAddress &from)
849 {
850 ACLChecklist checklist;
851 checklist.src_addr = from;
852 checklist.my_addr.SetNoAddr();
853 checklist.request = HTTPMSGLOCK(s->request);
854 checklist.accessList = cbdataReference(acl);
855 /* cbdataReferenceDone() happens in either fastCheck() or ~ACLCheckList */
856 int result = checklist.fastCheck();
857 return result;
858 }
859
860 static void
861 htcpTstReply(htcpDataHeader * dhdr, StoreEntry * e, htcpSpecifier * spec, IpAddress &from)
862 {
863 htcpStuff stuff;
864 static char pkt[8192];
865 HttpHeader hdr(hoHtcpReply);
866 MemBuf mb;
867 Packer p;
868 ssize_t pktlen;
869 memset(&stuff, '\0', sizeof(stuff));
870 stuff.op = HTCP_TST;
871 stuff.rr = RR_RESPONSE;
872 stuff.f1 = 0;
873 stuff.response = e ? 0 : 1;
874 debugs(31, 3, "htcpTstReply: response = " << stuff.response);
875 stuff.msg_id = dhdr->msg_id;
876
877 if (spec) {
878 mb.init();
879 packerToMemInit(&p, &mb);
880 stuff.S.method = spec->method;
881 stuff.S.uri = spec->uri;
882 stuff.S.version = spec->version;
883 stuff.S.req_hdrs = spec->req_hdrs;
884 hdr.putInt(HDR_AGE,
885 e->timestamp <= squid_curtime ?
886 squid_curtime - e->timestamp : 0);
887 hdr.packInto(&p);
888 stuff.D.resp_hdrs = xstrdup(mb.buf);
889 debugs(31, 3, "htcpTstReply: resp_hdrs = {" << stuff.D.resp_hdrs << "}");
890 mb.reset();
891 hdr.reset();
892
893 if (e->expires > -1)
894 hdr.putTime(HDR_EXPIRES, e->expires);
895
896 if (e->lastmod > -1)
897 hdr.putTime(HDR_LAST_MODIFIED, e->lastmod);
898
899 hdr.packInto(&p);
900
901 stuff.D.entity_hdrs = xstrdup(mb.buf);
902
903 debugs(31, 3, "htcpTstReply: entity_hdrs = {" << stuff.D.entity_hdrs << "}");
904
905 mb.reset();
906
907 hdr.reset();
908
909 #if USE_ICMP
910 if (char *host = urlHostname(spec->uri)) {
911 int rtt = 0;
912 int hops = 0;
913 int samp = 0;
914 netdbHostData(host, &samp, &rtt, &hops);
915
916 if (rtt || hops) {
917 char cto_buf[128];
918 snprintf(cto_buf, 128, "%s %d %f %d",
919 host, samp, 0.001 * rtt, hops);
920 hdr.putExt("Cache-to-Origin", cto_buf);
921 }
922 }
923 #endif /* USE_ICMP */
924
925 hdr.packInto(&p);
926 stuff.D.cache_hdrs = xstrdup(mb.buf);
927 debugs(31, 3, "htcpTstReply: cache_hdrs = {" << stuff.D.cache_hdrs << "}");
928 mb.clean();
929 hdr.clean();
930 packerClean(&p);
931 }
932
933 pktlen = htcpBuildPacket(pkt, sizeof(pkt), &stuff);
934
935 safe_free(stuff.D.resp_hdrs);
936 safe_free(stuff.D.entity_hdrs);
937 safe_free(stuff.D.cache_hdrs);
938
939 if (!pktlen) {
940 debugs(31, 3, "htcpTstReply: htcpBuildPacket() failed");
941 return;
942 }
943
944 htcpSend(pkt, (int) pktlen, from);
945 }
946
947 static void
948
949 htcpClrReply(htcpDataHeader * dhdr, int purgeSucceeded, IpAddress &from)
950 {
951 htcpStuff stuff;
952 static char pkt[8192];
953 ssize_t pktlen;
954
955 /* If dhdr->F1 == 0, no response desired */
956
957 if (dhdr->F1 == 0)
958 return;
959
960 memset(&stuff, '\0', sizeof(stuff));
961
962 stuff.op = HTCP_CLR;
963
964 stuff.rr = RR_RESPONSE;
965
966 stuff.f1 = 0;
967
968 stuff.response = purgeSucceeded ? 0 : 2;
969
970 debugs(31, 3, "htcpClrReply: response = " << stuff.response);
971
972 stuff.msg_id = dhdr->msg_id;
973
974 pktlen = htcpBuildPacket(pkt, sizeof(pkt), &stuff);
975
976 if (pktlen == 0) {
977 debugs(31, 3, "htcpClrReply: htcpBuildPacket() failed");
978 return;
979 }
980
981 htcpSend(pkt, (int) pktlen, from);
982 }
983
984 static void
985
986 htcpHandleNop(htcpDataHeader * hdr, char *buf, int sz, IpAddress &from)
987 {
988 debugs(31, 3, "htcpHandleNop: Unimplemented");
989 }
990
991 void
992 htcpSpecifier::checkHit()
993 {
994 char *blk_end;
995 checkHitRequest = request;
996
997 if (NULL == checkHitRequest) {
998 debugs(31, 3, "htcpCheckHit: NO; failed to parse URL");
999 checkedHit(NullStoreEntry::getInstance());
1000 return;
1001 }
1002
1003 blk_end = req_hdrs + strlen(req_hdrs);
1004
1005 if (!checkHitRequest->header.parse(req_hdrs, blk_end)) {
1006 debugs(31, 3, "htcpCheckHit: NO; failed to parse request headers");
1007 delete checkHitRequest;
1008 checkHitRequest = NULL;
1009 checkedHit(NullStoreEntry::getInstance());
1010 return;
1011 }
1012
1013 StoreEntry::getPublicByRequest(this, checkHitRequest);
1014 }
1015
1016 void
1017 htcpSpecifier::created (StoreEntry *e)
1018 {
1019 StoreEntry *hit=NULL;
1020 assert (e);
1021
1022 if (e->isNull()) {
1023 debugs(31, 3, "htcpCheckHit: NO; public object not found");
1024 } else if (!e->validToSend()) {
1025 debugs(31, 3, "htcpCheckHit: NO; entry not valid to send" );
1026 } else if (refreshCheckHTCP(e, checkHitRequest)) {
1027 debugs(31, 3, "htcpCheckHit: NO; cached response is stale");
1028 } else {
1029 debugs(31, 3, "htcpCheckHit: YES!?");
1030 hit = e;
1031 }
1032
1033 checkedHit (hit);
1034 }
1035
1036 static void
1037 htcpClrStoreEntry(StoreEntry * e)
1038 {
1039 debugs(31, 4, "htcpClrStoreEntry: Clearing store for entry: " << e->url() );
1040 e->releaseRequest();
1041 }
1042
1043 static int
1044 htcpClrStore(const htcpSpecifier * s)
1045 {
1046 HttpRequest *request = s->request;
1047 char *blk_end;
1048 StoreEntry *e = NULL;
1049 int released = 0;
1050
1051 if (request == NULL) {
1052 debugs(31, 3, "htcpClrStore: failed to parse URL");
1053 return -1;
1054 }
1055
1056 /* Parse request headers */
1057 blk_end = s->req_hdrs + strlen(s->req_hdrs);
1058
1059 if (!request->header.parse(s->req_hdrs, blk_end)) {
1060 debugs(31, 2, "htcpClrStore: failed to parse request headers");
1061 return -1;
1062 }
1063
1064 /* Lookup matching entries. This matches both GET and HEAD */
1065 while ((e = storeGetPublicByRequest(request)) != NULL) {
1066 if (e != NULL) {
1067 htcpClrStoreEntry(e);
1068 released++;
1069 }
1070 }
1071
1072 if (released) {
1073 debugs(31, 4, "htcpClrStore: Cleared " << released << " matching entries");
1074 return 1;
1075 } else {
1076 debugs(31, 4, "htcpClrStore: No matching entry found");
1077 return 0;
1078 }
1079 }
1080
1081 static void
1082
1083 htcpHandleTst(htcpDataHeader * hdr, char *buf, int sz, IpAddress &from)
1084 {
1085 debugs(31, 3, "htcpHandleTst: sz = " << sz);
1086
1087 if (hdr->RR == RR_REQUEST)
1088 htcpHandleTstRequest(hdr, buf, sz, from);
1089 else
1090 htcpHandleTstResponse(hdr, buf, sz, from);
1091 }
1092
1093 HtcpReplyData::HtcpReplyData() : hdr(hoHtcpReply)
1094 {}
1095
1096 static void
1097
1098 htcpHandleTstResponse(htcpDataHeader * hdr, char *buf, int sz, IpAddress &from)
1099 {
1100 htcpReplyData htcpReply;
1101 cache_key *key = NULL;
1102
1103 IpAddress *peer;
1104 htcpDetail *d = NULL;
1105 char *t;
1106
1107 if (queried_id[hdr->msg_id % N_QUERIED_KEYS] != hdr->msg_id) {
1108 debugs(31, 2, "htcpHandleTstResponse: No matching query id '" <<
1109 hdr->msg_id << "' (expected " <<
1110 queried_id[hdr->msg_id % N_QUERIED_KEYS] << ") from '" <<
1111 from << "'");
1112
1113 return;
1114 }
1115
1116 key = queried_keys[hdr->msg_id % N_QUERIED_KEYS];
1117
1118 if (!key) {
1119 debugs(31, 3, "htcpHandleTstResponse: No query key for response id '" << hdr->msg_id << "' from '" << from << "'");
1120 return;
1121 }
1122
1123 peer = &queried_addr[hdr->msg_id % N_QUERIED_KEYS];
1124
1125 if ( *peer != from || peer->GetPort() != from.GetPort() ) {
1126 debugs(31, 3, "htcpHandleTstResponse: Unexpected response source " << from );
1127 return;
1128 }
1129
1130 if (hdr->F1 == 1) {
1131 debugs(31, 2, "htcpHandleTstResponse: error condition, F1/MO == 1");
1132 return;
1133 }
1134
1135 htcpReply.msg_id = hdr->msg_id;
1136 debugs(31, 3, "htcpHandleTstResponse: msg_id = " << htcpReply.msg_id);
1137 htcpReply.hit = hdr->response ? 0 : 1;
1138
1139 if (hdr->F1) {
1140 debugs(31, 3, "htcpHandleTstResponse: MISS");
1141 } else {
1142 debugs(31, 3, "htcpHandleTstResponse: HIT");
1143 d = htcpUnpackDetail(buf, sz);
1144
1145 if (d == NULL) {
1146 debugs(31, 3, "htcpHandleTstResponse: bad DETAIL");
1147 return;
1148 }
1149
1150 if ((t = d->resp_hdrs))
1151 htcpReply.hdr.parse(t, t + strlen(t));
1152
1153 if ((t = d->entity_hdrs))
1154 htcpReply.hdr.parse(t, t + strlen(t));
1155
1156 if ((t = d->cache_hdrs))
1157 htcpReply.hdr.parse(t, t + strlen(t));
1158 }
1159
1160 debugs(31, 3, "htcpHandleTstResponse: key (" << key << ") " << storeKeyText(key));
1161 neighborsHtcpReply(key, &htcpReply, from);
1162 htcpReply.hdr.clean();
1163
1164 if (d)
1165 htcpFreeDetail(d);
1166 }
1167
1168 static void
1169
1170 htcpHandleTstRequest(htcpDataHeader * dhdr, char *buf, int sz, IpAddress &from)
1171 {
1172 /* buf should be a SPECIFIER */
1173 htcpSpecifier *s;
1174
1175 if (sz == 0) {
1176 debugs(31, 3, "htcpHandleTst: nothing to do");
1177 return;
1178 }
1179
1180 if (dhdr->F1 == 0)
1181 return;
1182
1183 /* s is a new object */
1184 s = htcpUnpackSpecifier(buf, sz);
1185
1186 s->setFrom (from);
1187
1188 s->setDataHeader (dhdr);
1189
1190 if (NULL == s) {
1191 debugs(31, 2, "htcpHandleTstRequest: htcpUnpackSpecifier failed");
1192 return;
1193 }
1194
1195 if (!s->request) {
1196 debugs(31, 2, "htcpHandleTstRequest: failed to parse request");
1197 htcpFreeSpecifier(s);
1198 return;
1199 }
1200
1201 if (!htcpAccessCheck(Config.accessList.htcp, s, from)) {
1202 debugs(31, 2, "htcpHandleTstRequest: Access denied");
1203 htcpFreeSpecifier(s);
1204 return;
1205 }
1206
1207 debugs(31, 3, "htcpHandleTstRequest: " << s->method << " " << s->uri << " " << s->version);
1208 debugs(31, 3, "htcpHandleTstRequest: " << s->req_hdrs);
1209 s->checkHit();
1210 }
1211
1212 void
1213 htcpSpecifier::checkedHit(StoreEntry *e)
1214 {
1215 if (e)
1216 htcpTstReply(dhdr, e, this, from); /* hit */
1217 else
1218 htcpTstReply(dhdr, NULL, NULL, from); /* cache miss */
1219
1220 htcpFreeSpecifier(this);
1221 }
1222
1223 static void
1224
1225 htcpHandleMon(htcpDataHeader * hdr, char *buf, int sz, IpAddress &from)
1226 {
1227 debugs(31, 3, "htcpHandleMon: Unimplemented");
1228 }
1229
1230 static void
1231
1232 htcpHandleSet(htcpDataHeader * hdr, char *buf, int sz, IpAddress &from)
1233 {
1234 debugs(31, 3, "htcpHandleSet: Unimplemented");
1235 }
1236
1237 static void
1238
1239 htcpHandleClr(htcpDataHeader * hdr, char *buf, int sz, IpAddress &from)
1240 {
1241 htcpSpecifier *s;
1242 /* buf[0/1] is reserved and reason */
1243 int reason = buf[1] << 4;
1244 debugs(31, 3, "htcpHandleClr: reason=" << reason);
1245 buf += 2;
1246 sz -= 2;
1247
1248 /* buf should be a SPECIFIER */
1249
1250 if (sz == 0) {
1251 debugs(31, 4, "htcpHandleClr: nothing to do");
1252 return;
1253 }
1254
1255 s = htcpUnpackSpecifier(buf, sz);
1256
1257 if (NULL == s) {
1258 debugs(31, 3, "htcpHandleClr: htcpUnpackSpecifier failed");
1259 return;
1260 }
1261
1262 if (!htcpAccessCheck(Config.accessList.htcp_clr, s, from)) {
1263 debugs(31, 2, "htcpHandleClr: Access denied");
1264 htcpFreeSpecifier(s);
1265 return;
1266 }
1267
1268 debugs(31, 5, "htcpHandleClr: " << s->method << " " << s->uri << " " << s->version);
1269 debugs(31, 5, "htcpHandleClr: request headers: " << s->req_hdrs);
1270
1271 /* Release objects from cache
1272 * analog to clientPurgeRequest in client_side.c
1273 */
1274
1275 switch (htcpClrStore(s)) {
1276
1277 case 1:
1278 htcpClrReply(hdr, 1, from); /* hit */
1279 break;
1280
1281 case 0:
1282 htcpClrReply(hdr, 0, from); /* miss */
1283 break;
1284
1285 default:
1286 break;
1287 }
1288
1289 htcpFreeSpecifier(s);
1290 }
1291
1292 /*
1293 * Forward a CLR request to all peers who have requested that CLRs be
1294 * forwarded to them.
1295 */
1296 static void
1297 htcpForwardClr(char *buf, int sz)
1298 {
1299 peer *p;
1300
1301 for (p = Config.peers; p; p = p->next) {
1302 if (!p->options.htcp) {
1303 continue;
1304 }
1305 if (!p->options.htcp_forward_clr) {
1306 continue;
1307 }
1308
1309 htcpSend(buf, sz, p->in_addr);
1310 }
1311 }
1312
1313 /*
1314 * Do the first pass of handling an HTCP message. This used to be two
1315 * separate functions, htcpHandle and htcpHandleData. They were merged to
1316 * allow for forwarding HTCP packets easily to other peers if desired.
1317 *
1318 * This function now works out what type of message we have received and then
1319 * hands it off to other functions to break apart message-specific data.
1320 */
1321 static void
1322 htcpHandleMsg(char *buf, int sz, IpAddress &from)
1323 {
1324 htcpHeader htcpHdr;
1325 htcpDataHeader hdr;
1326 char *hbuf;
1327 int hsz;
1328 assert (sz >= 0);
1329
1330 if ((size_t)sz < sizeof(htcpHeader)) {
1331 debugs(31, 3, "htcpHandle: msg size less than htcpHeader size");
1332 return;
1333 }
1334
1335 htcpHexdump("htcpHandle", buf, sz);
1336 xmemcpy(&htcpHdr, buf, sizeof(htcpHeader));
1337 htcpHdr.length = ntohs(htcpHdr.length);
1338
1339 if (htcpHdr.minor == 0)
1340 old_squid_format = 1;
1341 else
1342 old_squid_format = 0;
1343
1344 debugs(31, 3, "htcpHandle: htcpHdr.length = " << htcpHdr.length);
1345 debugs(31, 3, "htcpHandle: htcpHdr.major = " << htcpHdr.major);
1346 debugs(31, 3, "htcpHandle: htcpHdr.minor = " << htcpHdr.minor);
1347
1348 if (sz != htcpHdr.length) {
1349 debugs(31, 3, "htcpHandle: sz/" << sz << " != htcpHdr.length/" <<
1350 htcpHdr.length << " from " << from );
1351
1352 return;
1353 }
1354
1355 if (htcpHdr.major != 0) {
1356 debugs(31, 3, "htcpHandle: Unknown major version " << htcpHdr.major << " from " << from );
1357
1358 return;
1359 }
1360
1361 hbuf = buf + sizeof(htcpHeader);
1362 hsz = sz - sizeof(htcpHeader);
1363
1364 if ((size_t)hsz < sizeof(htcpDataHeader)) {
1365 debugs(31, 3, "htcpHandleData: msg size less than htcpDataHeader size");
1366 return;
1367 }
1368
1369 if (!old_squid_format) {
1370 xmemcpy(&hdr, hbuf, sizeof(hdr));
1371 } else {
1372 htcpDataHeaderSquid hdrSquid;
1373 xmemcpy(&hdrSquid, hbuf, sizeof(hdrSquid));
1374 hdr.length = hdrSquid.length;
1375 hdr.opcode = hdrSquid.opcode;
1376 hdr.response = hdrSquid.response;
1377 hdr.F1 = hdrSquid.F1;
1378 hdr.RR = hdrSquid.RR;
1379 hdr.reserved = 0;
1380 hdr.msg_id = hdrSquid.msg_id;
1381 }
1382
1383 hdr.length = ntohs(hdr.length);
1384 hdr.msg_id = ntohl(hdr.msg_id);
1385 debugs(31, 3, "htcpHandleData: hsz = " << hsz);
1386 debugs(31, 3, "htcpHandleData: length = " << hdr.length);
1387
1388 if (hdr.opcode >= HTCP_END) {
1389 debugs(31, 3, "htcpHandleData: client " << from << ", opcode " << hdr.opcode << " out of range");
1390 return;
1391 }
1392
1393 debugs(31, 3, "htcpHandleData: opcode = " << hdr.opcode << " " << htcpOpcodeStr[hdr.opcode]);
1394 debugs(31, 3, "htcpHandleData: response = " << hdr.response);
1395 debugs(31, 3, "htcpHandleData: F1 = " << hdr.F1);
1396 debugs(31, 3, "htcpHandleData: RR = " << hdr.RR);
1397 debugs(31, 3, "htcpHandleData: msg_id = " << hdr.msg_id);
1398
1399 if (hsz < hdr.length) {
1400 debugs(31, 3, "htcpHandleData: sz < hdr.length");
1401 return;
1402 }
1403
1404 /*
1405 * set sz = hdr.length so we ignore any AUTH fields following
1406 * the DATA.
1407 */
1408 hsz = (int) hdr.length;
1409 hbuf += sizeof(htcpDataHeader);
1410 hsz -= sizeof(htcpDataHeader);
1411 debugs(31, 3, "htcpHandleData: hsz = " << hsz);
1412
1413 htcpHexdump("htcpHandleData", hbuf, hsz);
1414
1415 switch (hdr.opcode) {
1416 case HTCP_NOP:
1417 htcpHandleNop(&hdr, hbuf, hsz, from);
1418 break;
1419 case HTCP_TST:
1420 htcpHandleTst(&hdr, hbuf, hsz, from);
1421 break;
1422 case HTCP_MON:
1423 htcpHandleMon(&hdr, hbuf, hsz, from);
1424 break;
1425 case HTCP_SET:
1426 htcpHandleSet(&hdr, hbuf, hsz, from);
1427 break;
1428 case HTCP_CLR:
1429 htcpHandleClr(&hdr, hbuf, hsz, from);
1430 htcpForwardClr(buf, sz);
1431 break;
1432 default:
1433 break;
1434 }
1435 }
1436
1437 static void
1438 htcpRecv(int fd, void *data)
1439 {
1440 static char buf[8192];
1441 int len;
1442 static IpAddress from;
1443
1444 /* Receive up to 8191 bytes, leaving room for a null */
1445
1446 len = comm_udp_recvfrom(fd, buf, sizeof(buf) - 1, 0, from);
1447
1448 debugs(31, 3, "htcpRecv: FD " << fd << ", " << len << " bytes from " << from );
1449
1450 if (len)
1451 statCounter.htcp.pkts_recv++;
1452
1453 htcpHandleMsg(buf, len, from);
1454
1455 commSetSelect(fd, COMM_SELECT_READ, htcpRecv, NULL, 0);
1456 }
1457
1458 /*
1459 * ======================================================================
1460 * PUBLIC FUNCTIONS
1461 * ======================================================================
1462 */
1463
1464 void
1465 htcpInit(void)
1466 {
1467 if (Config.Port.htcp <= 0) {
1468 debugs(31, 1, "HTCP Disabled.");
1469 return;
1470 }
1471
1472 IpAddress incomingAddr = Config.Addrs.udp_incoming;
1473 incomingAddr.SetPort(Config.Port.htcp);
1474
1475 enter_suid();
1476 htcpInSocket = comm_open(SOCK_DGRAM,
1477 IPPROTO_UDP,
1478 incomingAddr,
1479 COMM_NONBLOCKING,
1480 "HTCP Socket");
1481 leave_suid();
1482
1483 if (htcpInSocket < 0)
1484 fatal("Cannot open HTCP Socket");
1485
1486 commSetSelect(htcpInSocket, COMM_SELECT_READ, htcpRecv, NULL, 0);
1487
1488 debugs(31, 1, "Accepting HTCP messages on port " << Config.Port.htcp << ", FD " << htcpInSocket << ".");
1489
1490 if (!Config.Addrs.udp_outgoing.IsNoAddr()) {
1491 IpAddress outgoingAddr = Config.Addrs.udp_outgoing;
1492 outgoingAddr.SetPort(Config.Port.htcp);
1493
1494 enter_suid();
1495 htcpOutSocket = comm_open(SOCK_DGRAM,
1496 IPPROTO_UDP,
1497 outgoingAddr,
1498 COMM_NONBLOCKING,
1499 "Outgoing HTCP Socket");
1500 leave_suid();
1501
1502 if (htcpOutSocket < 0)
1503 fatal("Cannot open Outgoing HTCP Socket");
1504
1505 commSetSelect(htcpOutSocket, COMM_SELECT_READ, htcpRecv, NULL, 0);
1506
1507 debugs(31, 1, "Outgoing HTCP messages on port " << Config.Port.htcp << ", FD " << htcpOutSocket << ".");
1508
1509 fd_note(htcpInSocket, "Incoming HTCP socket");
1510 } else {
1511 htcpOutSocket = htcpInSocket;
1512 }
1513
1514 if (!htcpDetailPool) {
1515 htcpDetailPool = memPoolCreate("htcpDetail", sizeof(htcpDetail));
1516 }
1517 }
1518
1519 int
1520 htcpQuery(StoreEntry * e, HttpRequest * req, peer * p)
1521 {
1522 cache_key *save_key;
1523 static char pkt[8192];
1524 ssize_t pktlen;
1525 char vbuf[32];
1526 htcpStuff stuff;
1527 HttpHeader hdr(hoRequest);
1528 Packer pa;
1529 MemBuf mb;
1530 http_state_flags flags;
1531
1532 if (htcpInSocket < 0)
1533 return 0;
1534
1535 old_squid_format = p->options.htcp_oldsquid;
1536 memset(&flags, '\0', sizeof(flags));
1537 snprintf(vbuf, sizeof(vbuf), "%d/%d",
1538 req->http_ver.major, req->http_ver.minor);
1539 stuff.op = HTCP_TST;
1540 stuff.rr = RR_REQUEST;
1541 stuff.f1 = 1;
1542 stuff.response = 0;
1543 stuff.msg_id = ++msg_id_counter;
1544 stuff.S.method = (char *) RequestMethodStr(req->method);
1545 stuff.S.uri = (char *) e->url();
1546 stuff.S.version = vbuf;
1547 HttpStateData::httpBuildRequestHeader(req, req, e, &hdr, flags);
1548 mb.init();
1549 packerToMemInit(&pa, &mb);
1550 hdr.packInto(&pa);
1551 hdr.clean();
1552 packerClean(&pa);
1553 stuff.S.req_hdrs = mb.buf;
1554 pktlen = htcpBuildPacket(pkt, sizeof(pkt), &stuff);
1555 mb.clean();
1556 if (!pktlen) {
1557 debugs(31, 3, "htcpQuery: htcpBuildPacket() failed");
1558 return -1;
1559 }
1560
1561 htcpSend(pkt, (int) pktlen, p->in_addr);
1562
1563 queried_id[stuff.msg_id % N_QUERIED_KEYS] = stuff.msg_id;
1564 save_key = queried_keys[stuff.msg_id % N_QUERIED_KEYS];
1565 storeKeyCopy(save_key, (const cache_key *)e->key);
1566 queried_addr[stuff.msg_id % N_QUERIED_KEYS] = p->in_addr;
1567 debugs(31, 3, "htcpQuery: key (" << save_key << ") " << storeKeyText(save_key));
1568
1569 return 1;
1570 }
1571
1572 /*
1573 * Send an HTCP CLR message for a specified item to a given peer.
1574 */
1575 void
1576 htcpClear(StoreEntry * e, const char *uri, HttpRequest * req, const HttpRequestMethod &method, peer * p, htcp_clr_reason reason)
1577 {
1578 static char pkt[8192];
1579 ssize_t pktlen;
1580 char vbuf[32];
1581 htcpStuff stuff;
1582 HttpHeader hdr(hoRequest);
1583 Packer pa;
1584 MemBuf mb;
1585 http_state_flags flags;
1586
1587 if (htcpInSocket < 0)
1588 return;
1589
1590 old_squid_format = p->options.htcp_oldsquid;
1591 memset(&flags, '\0', sizeof(flags));
1592 snprintf(vbuf, sizeof(vbuf), "%d/%d",
1593 req->http_ver.major, req->http_ver.minor);
1594 stuff.op = HTCP_CLR;
1595 stuff.rr = RR_REQUEST;
1596 stuff.f1 = 0;
1597 stuff.response = 0;
1598 stuff.msg_id = ++msg_id_counter;
1599 switch (reason) {
1600 case HTCP_CLR_INVALIDATION:
1601 stuff.reason = 1;
1602 break;
1603 default:
1604 stuff.reason = 0;
1605 break;
1606 }
1607 stuff.S.method = (char *) RequestMethodStr(req->method);
1608 if (e == NULL || e->mem_obj == NULL) {
1609 if (uri == NULL) {
1610 return;
1611 }
1612 stuff.S.uri = xstrdup(uri);
1613 } else {
1614 stuff.S.uri = (char *) e->url();
1615 }
1616 stuff.S.version = vbuf;
1617 if (reason != HTCP_CLR_INVALIDATION) {
1618 HttpStateData::httpBuildRequestHeader(req, req, e, &hdr, flags);
1619 mb.init();
1620 packerToMemInit(&pa, &mb);
1621 hdr.packInto(&pa);
1622 hdr.clean();
1623 packerClean(&pa);
1624 stuff.S.req_hdrs = mb.buf;
1625 } else {
1626 stuff.S.req_hdrs = NULL;
1627 }
1628 pktlen = htcpBuildPacket(pkt, sizeof(pkt), &stuff);
1629 if (reason != HTCP_CLR_INVALIDATION) {
1630 mb.clean();
1631 }
1632 if (e == NULL) {
1633 xfree(stuff.S.uri);
1634 }
1635 if (!pktlen) {
1636 debugs(31, 3, "htcpClear: htcpBuildPacket() failed");
1637 return;
1638 }
1639
1640 htcpSend(pkt, (int) pktlen, p->in_addr);
1641 }
1642
1643 /*
1644 * htcpSocketShutdown only closes the 'in' socket if it is
1645 * different than the 'out' socket.
1646 */
1647 void
1648 htcpSocketShutdown(void)
1649 {
1650 if (htcpInSocket < 0)
1651 return;
1652
1653 if (htcpInSocket != htcpOutSocket) {
1654 debugs(12, 1, "FD " << htcpInSocket << " Closing HTCP socket");
1655 comm_close(htcpInSocket);
1656 }
1657
1658 /*
1659 * Here we set 'htcpInSocket' to -1 even though the HTCP 'in'
1660 * and 'out' sockets might be just one FD. This prevents this
1661 * function from executing repeatedly. When we are really ready to
1662 * exit or restart, main will comm_close the 'out' descriptor.
1663 */
1664 htcpInSocket = -1;
1665
1666 /*
1667 * Normally we only write to the outgoing HTCP socket, but
1668 * we also have a read handler there to catch messages sent
1669 * to that specific interface. During shutdown, we must
1670 * disable reading on the outgoing socket.
1671 */
1672 /* XXX Don't we need this handler to read replies while shutting down?
1673 * I think there should be a separate hander for reading replies..
1674 */
1675 assert(htcpOutSocket > -1);
1676
1677 commSetSelect(htcpOutSocket, COMM_SELECT_READ, NULL, NULL, 0);
1678 }
1679
1680 void
1681 htcpSocketClose(void)
1682 {
1683 htcpSocketShutdown();
1684
1685 if (htcpOutSocket > -1) {
1686 debugs(12, 1, "FD " << htcpOutSocket << " Closing HTCP socket");
1687 comm_close(htcpOutSocket);
1688 htcpOutSocket = -1;
1689 }
1690 }