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