3 * $Id: htcp.cc,v 1.79 2008/01/20 08:54:28 amosjeffries Exp $
5 * DEBUG: section 31 Hypertext Caching Protocol
6 * AUTHOR: Duane Wesssels
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
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.
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.
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.
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.
38 #include "ACLChecklist.h"
40 #include "SquidTime.h"
42 #include "StoreClient.h"
43 #include "HttpRequest.h"
48 typedef struct _Countstr Countstr
;
50 typedef struct _htcpHeader htcpHeader
;
52 typedef struct _htcpDataHeader htcpDataHeader
;
54 typedef struct _htcpDataHeaderSquid htcpDataHeaderSquid
;
56 typedef struct _htcpAuthHeader htcpAuthHeader
;
58 typedef struct _htcpStuff htcpStuff
;
60 typedef struct _htcpDetail htcpDetail
;
75 struct _htcpDataHeaderSquid
83 unsigned int response
:
87 unsigned int response
:
95 unsigned int reserved
:
111 unsigned int reserved
:
118 struct _htcpDataHeader
161 /* RR == 0 --> F1 = RESPONSE DESIRED FLAG */
162 /* RR == 1 --> F1 = MESSAGE OVERALL FLAG */
163 /* RR == 0 --> REQUEST */
164 /* RR == 1 --> RESPONSE */
166 struct _htcpAuthHeader
175 class htcpSpecifier
: public StoreClient
179 MEMPROXY_CLASS(htcpSpecifier
);
181 void created (StoreEntry
*newEntry
);
183 void checkedHit(StoreEntry
*e
);
185 void setFrom (IPAddress
&from
);
186 void setDataHeader (htcpDataHeader
*);
191 HttpRequest
*request
;
194 HttpRequest
*checkHitRequest
;
196 IPAddress from
; // was a ptr. return to such IFF needed. otherwise copy should do.
197 htcpDataHeader
*dhdr
;
200 MEMPROXY_CLASS_INLINE(htcpSpecifier
)
229 static const char *const htcpOpcodeStr
[] =
240 * values for htcpDataHeader->response
245 OPCODE_UNIMPLEMENTED
,
246 MAJOR_VERSION_UNSUPPORTED
,
247 MINOR_VERSION_UNSUPPORTED
,
252 * values for htcpDataHeader->RR
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
];
266 static IPAddress queried_addr
[N_QUERIED_KEYS
];
267 static MemAllocator
*htcpDetailPool
= NULL
;
269 static int old_squid_format
= 0;
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
);
285 static void htcpHandle(char *buf
, int sz
, IPAddress
&from
);
287 static void htcpHandleData(char *buf
, int sz
, IPAddress
&from
);
289 static void htcpHandleMon(htcpDataHeader
*, char *buf
, int sz
, IPAddress
&from
);
291 static void htcpHandleNop(htcpDataHeader
*, char *buf
, int sz
, IPAddress
&from
);
293 static void htcpHandleSet(htcpDataHeader
*, char *buf
, int sz
, IPAddress
&from
);
295 static void htcpHandleTst(htcpDataHeader
*, char *buf
, int sz
, IPAddress
&from
);
296 static void htcpRecv(int fd
, void *data
);
298 static void htcpSend(const char *buf
, int len
, IPAddress
&to
);
300 static void htcpTstReply(htcpDataHeader
*, StoreEntry
*, htcpSpecifier
*, IPAddress
&);
302 static void htcpHandleTstRequest(htcpDataHeader
*, char *buf
, int sz
, IPAddress
&from
);
304 static void htcpHandleTstResponse(htcpDataHeader
*, char *, int, IPAddress
&);
307 htcpHexdump(const char *tag
, const char *s
, int sz
)
313 debugs(31, 3, "htcpHexdump " << tag
);
314 memset(hex
, '\0', 80);
316 for (i
= 0; i
< sz
; i
++) {
318 snprintf(&hex
[k
* 3], 4, " %02x", (int) *(s
+ i
));
320 if (k
< 15 && i
< (sz
- 1))
323 debugs(31, 3, "\t" << hex
);
325 memset(hex
, '\0', 80);
332 * STUFF FOR SENDING HTCP MESSAGES
336 htcpBuildAuth(char *buf
, size_t buflen
)
340 assert(2 == sizeof(u_int16_t
));
341 auth
.length
= htons(2);
343 if (buflen
< copy_sz
)
345 xmemcpy(buf
, &auth
, copy_sz
);
350 htcpBuildCountstr(char *buf
, size_t buflen
, const char *s
)
356 if (buflen
- off
< 2)
364 debugs(31, 3, "htcpBuildCountstr: LENGTH = " << len
);
366 debugs(31, 3, "htcpBuildCountstr: TEXT = {" << (s
? s
: "<NULL>") << "}");
368 length
= htons((u_int16_t
) len
);
370 xmemcpy(buf
+ off
, &length
, 2);
374 if (buflen
- off
< len
)
378 xmemcpy(buf
+ off
, s
, len
);
386 htcpBuildSpecifier(char *buf
, size_t buflen
, htcpStuff
* stuff
)
390 s
= htcpBuildCountstr(buf
+ off
, buflen
- off
, stuff
->S
.method
);
397 s
= htcpBuildCountstr(buf
+ off
, buflen
- off
, stuff
->S
.uri
);
404 s
= htcpBuildCountstr(buf
+ off
, buflen
- off
, stuff
->S
.version
);
411 s
= htcpBuildCountstr(buf
+ off
, buflen
- off
, stuff
->S
.req_hdrs
);
418 debugs(31, 3, "htcpBuildSpecifier: size " << off
);
424 htcpBuildDetail(char *buf
, size_t buflen
, htcpStuff
* stuff
)
428 s
= htcpBuildCountstr(buf
+ off
, buflen
- off
, stuff
->D
.resp_hdrs
);
435 s
= htcpBuildCountstr(buf
+ off
, buflen
- off
, stuff
->D
.entity_hdrs
);
442 s
= htcpBuildCountstr(buf
+ off
, buflen
- off
, stuff
->D
.cache_hdrs
);
453 htcpBuildTstOpData(char *buf
, size_t buflen
, htcpStuff
* stuff
)
458 debugs(31, 3, "htcpBuildTstOpData: RR_REQUEST");
459 return htcpBuildSpecifier(buf
, buflen
, stuff
);
462 debugs(31, 3, "htcpBuildTstOpData: RR_RESPONSE");
463 debugs(31, 3, "htcpBuildTstOpData: F1 = " << stuff
->f1
);
465 if (stuff
->f1
) /* cache miss */
468 return htcpBuildDetail(buf
, buflen
, stuff
);
471 fatal_dump("htcpBuildTstOpData: bad RR value");
478 htcpBuildOpData(char *buf
, size_t buflen
, htcpStuff
* stuff
)
481 debugs(31, 3, "htcpBuildOpData: opcode " << htcpOpcodeStr
[stuff
->op
]);
486 off
= htcpBuildTstOpData(buf
+ off
, buflen
, stuff
);
490 /* nothing to be done */
502 htcpBuildData(char *buf
, size_t buflen
, htcpStuff
* stuff
)
506 size_t hdr_sz
= sizeof(htcpDataHeader
);
512 off
+= hdr_sz
; /* skip! */
514 op_data_sz
= htcpBuildOpData(buf
+ off
, buflen
- off
, stuff
);
521 debugs(31, 3, "htcpBuildData: hdr.length = " << off
);
523 hdr
.length
= (u_int16_t
) off
;
525 hdr
.opcode
= stuff
->op
;
527 hdr
.response
= stuff
->response
;
533 hdr
.msg_id
= stuff
->msg_id
;
535 /* convert multi-byte fields */
536 hdr
.length
= htons(hdr
.length
);
538 hdr
.msg_id
= htonl(hdr
.msg_id
);
540 if (!old_squid_format
) {
541 xmemcpy(buf
, &hdr
, hdr_sz
);
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
);
553 debugs(31, 3, "htcpBuildData: size " << off
);
559 * Build an HTCP packet into buf, maximum length buflen.
560 * Returns the packet length, or zero on failure.
563 htcpBuildPacket(char *buf
, size_t buflen
, htcpStuff
* stuff
)
567 size_t hdr_sz
= sizeof(htcpHeader
);
569 /* skip the header -- we don't know the overall length */
571 if (buflen
< hdr_sz
) {
576 s
= htcpBuildData(buf
+ off
, buflen
- off
, stuff
);
583 s
= htcpBuildAuth(buf
+ off
, buflen
- off
);
590 hdr
.length
= htons((u_int16_t
) off
);
593 if (old_squid_format
)
598 xmemcpy(buf
, &hdr
, hdr_sz
);
600 debugs(31, 3, "htcpBuildPacket: size " << off
);
607 htcpSend(const char *buf
, int len
, IPAddress
&to
)
611 debugs(31, 3, "htcpSend: " << to
);
612 htcpHexdump("htcpSend", buf
, len
);
614 x
= comm_udp_sendto(htcpOutSocket
,
620 debugs(31, 1, "htcpSend: FD " << htcpOutSocket
<< " sendto: " << xstrerror());
622 statCounter
.htcp
.pkts_sent
++;
626 * STUFF FOR RECEIVING HTCP MESSAGES
631 htcpSpecifier::setFrom (IPAddress
&aSocket
)
637 htcpSpecifier::setDataHeader (htcpDataHeader
*aDataHeader
)
643 htcpFreeSpecifier(htcpSpecifier
* s
)
645 HTTPMSGUNLOCK(s
->request
);
651 htcpFreeDetail(htcpDetail
* d
)
653 htcpDetailPool
->free(d
);
657 * Unpack an HTCP SPECIFIER in place
658 * This will overwrite any following AUTH block
660 static htcpSpecifier
*
661 htcpUnpackSpecifier(char *buf
, int sz
)
663 htcpSpecifier
*s
= new htcpSpecifier
;
664 HttpRequestMethod method
;
666 /* Find length of METHOD */
667 u_int16_t l
= ntohs(*(u_int16_t
*) buf
);
672 debugs(31, 1, "htcpUnpackSpecifier: failed to unpack METHOD");
673 htcpFreeSpecifier(s
);
684 /* Find length of URI */
685 l
= ntohs(*(u_int16_t
*) buf
);
690 debugs(31, 1, "htcpUnpackSpecifier: failed to unpack URI");
691 htcpFreeSpecifier(s
);
695 /* Add terminating null to METHOD */
707 /* Find length of VERSION */
708 l
= ntohs(*(u_int16_t
*) buf
);
713 debugs(31, 1, "htcpUnpackSpecifier: failed to unpack VERSION");
714 htcpFreeSpecifier(s
);
718 /* Add terminating null to URI */
730 /* Find length of REQ-HDRS */
731 l
= ntohs(*(u_int16_t
*) buf
);
736 debugs(31, 1, "htcpUnpackSpecifier: failed to unpack REQ-HDRS");
737 htcpFreeSpecifier(s
);
741 /* Add terminating null to URI */
753 debugs(31, 3, "htcpUnpackSpecifier: " << sz
<< " bytes left");
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
765 method
= HttpRequestMethod(s
->method
);
767 s
->request
= HttpRequest::CreateFromUrlAndMethod(s
->uri
, method
== METHOD_NONE
? HttpRequestMethod(METHOD_GET
) : method
);
770 HTTPMSGLOCK(s
->request
);
776 * Unpack an HTCP DETAIL in place
777 * This will overwrite any following AUTH block
780 htcpUnpackDetail(char *buf
, int sz
)
782 htcpDetail
*d
= static_cast<htcpDetail
*>(htcpDetailPool
->alloc());
784 /* Find length of RESP-HDRS */
785 u_int16_t l
= ntohs(*(u_int16_t
*) buf
);
790 debugs(31, 1, "htcpUnpackDetail: failed to unpack RESP_HDRS");
802 /* Find length of ENTITY-HDRS */
803 l
= ntohs(*(u_int16_t
*) buf
);
808 debugs(31, 1, "htcpUnpackDetail: failed to unpack ENTITY_HDRS");
813 /* Add terminating null to RESP-HDRS */
816 /* Set ENTITY-HDRS */
819 d
->entity_hdrs
= buf
;
825 /* Find length of CACHE-HDRS */
826 l
= ntohs(*(u_int16_t
*) buf
);
831 debugs(31, 1, "htcpUnpackDetail: failed to unpack CACHE_HDRS");
836 /* Add terminating null to ENTITY-HDRS */
848 debugs(31, 3, "htcpUnpackDetail: " << sz
<< " bytes left");
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
862 htcpAccessCheck(acl_access
* acl
, htcpSpecifier
* s
, IPAddress
&from
)
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();
876 htcpTstReply(htcpDataHeader
* dhdr
, StoreEntry
* e
, htcpSpecifier
* spec
, IPAddress
&from
)
879 static char pkt
[8192];
880 HttpHeader
hdr(hoHtcpReply
);
889 memset(&stuff
, '\0', sizeof(stuff
));
891 stuff
.rr
= RR_RESPONSE
;
893 stuff
.response
= e
? 0 : 1;
894 debugs(31, 3, "htcpTstReply: response = " << stuff
.response
);
895 stuff
.msg_id
= dhdr
->msg_id
;
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
;
906 e
->timestamp
<= squid_curtime
?
907 squid_curtime
- e
->timestamp
: 0);
909 stuff
.D
.resp_hdrs
= xstrdup(mb
.buf
);
910 debugs(31, 3, "htcpTstReply: resp_hdrs = {" << stuff
.D
.resp_hdrs
<< "}");
915 hdr
.putTime(HDR_EXPIRES
, e
->expires
);
918 hdr
.putTime(HDR_LAST_MODIFIED
, e
->lastmod
);
922 stuff
.D
.entity_hdrs
= xstrdup(mb
.buf
);
924 debugs(31, 3, "htcpTstReply: entity_hdrs = {" << stuff
.D
.entity_hdrs
<< "}");
930 if ((host
= urlHostname(spec
->uri
))) {
931 netdbHostData(host
, &samp
, &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
);
941 stuff
.D
.cache_hdrs
= xstrdup(mb
.buf
);
942 debugs(31, 3, "htcpTstReply: cache_hdrs = {" << stuff
.D
.cache_hdrs
<< "}");
948 pktlen
= htcpBuildPacket(pkt
, sizeof(pkt
), &stuff
);
950 safe_free(stuff
.D
.resp_hdrs
);
951 safe_free(stuff
.D
.entity_hdrs
);
952 safe_free(stuff
.D
.cache_hdrs
);
956 debugs(31, 1, "htcpTstReply: htcpBuildPacket() failed");
960 htcpSend(pkt
, (int) pktlen
, from
);
965 htcpClrReply(htcpDataHeader
* dhdr
, int purgeSucceeded
, IPAddress
&from
)
968 static char pkt
[8192];
971 /* If dhdr->F1 == 0, no response desired */
976 memset(&stuff
, '\0', sizeof(stuff
));
980 stuff
.rr
= RR_RESPONSE
;
984 stuff
.response
= purgeSucceeded
? 0 : 2;
986 debugs(31, 3, "htcpClrReply: response = " << stuff
.response
);
988 stuff
.msg_id
= dhdr
->msg_id
;
990 pktlen
= htcpBuildPacket(pkt
, sizeof(pkt
), &stuff
);
994 debugs(31, 1, "htcpClrReply: htcpBuildPacket() failed");
998 htcpSend(pkt
, (int) pktlen
, from
);
1003 htcpHandleNop(htcpDataHeader
* hdr
, char *buf
, int sz
, IPAddress
&from
)
1005 debugs(31, 3, "htcpHandleNop: Unimplemented");
1009 htcpSpecifier::checkHit()
1012 checkHitRequest
= request
;
1014 if (NULL
== checkHitRequest
) {
1015 debugs(31, 3, "htcpCheckHit: NO; failed to parse URL");
1016 checkedHit(NullStoreEntry::getInstance());
1020 blk_end
= req_hdrs
+ strlen(req_hdrs
);
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());
1030 StoreEntry::getPublicByRequest(this, checkHitRequest
);
1034 htcpSpecifier::created (StoreEntry
*e
)
1036 StoreEntry
*hit
=NULL
;
1040 debugs(31, 3, "htcpCheckHit: NO; public object not found");
1042 else if (!e
->validToSend()) {
1043 debugs(31, 3, "htcpCheckHit: NO; entry not valid to send" );
1045 else if (refreshCheckHTCP(e
, checkHitRequest
)) {
1046 debugs(31, 3, "htcpCheckHit: NO; cached response is stale");
1049 debugs(31, 3, "htcpCheckHit: YES!?");
1057 htcpClrStoreEntry(StoreEntry
* e
)
1059 debugs(31, 4, "htcpClrStoreEntry: Clearing store for entry: " << e
->url() );
1060 e
->releaseRequest();
1064 htcpClrStore(const htcpSpecifier
* s
)
1066 HttpRequest
*request
= s
->request
;
1068 StoreEntry
*e
= NULL
;
1071 if (request
== NULL
) {
1072 debugs(31, 3, "htcpClrStore: failed to parse URL");
1076 /* Parse request headers */
1077 blk_end
= s
->req_hdrs
+ strlen(s
->req_hdrs
);
1079 if (!request
->header
.parse(s
->req_hdrs
, blk_end
)) {
1080 debugs(31, 2, "htcpClrStore: failed to parse request headers");
1084 /* Lookup matching entries. This matches both GET and HEAD */
1085 while ((e
= storeGetPublicByRequest(request
)) != NULL
) {
1087 htcpClrStoreEntry(e
);
1093 debugs(31, 4, "htcpClrStore: Cleared " << released
<< " matching entries");
1096 debugs(31, 4, "htcpClrStore: No matching entry found");
1103 htcpHandleTst(htcpDataHeader
* hdr
, char *buf
, int sz
, IPAddress
&from
)
1105 debugs(31, 3, "htcpHandleTst: sz = " << sz
);
1107 if (hdr
->RR
== RR_REQUEST
)
1108 htcpHandleTstRequest(hdr
, buf
, sz
, from
);
1110 htcpHandleTstResponse(hdr
, buf
, sz
, from
);
1113 HtcpReplyData::HtcpReplyData() : hdr(hoHtcpReply
)
1118 htcpHandleTstResponse(htcpDataHeader
* hdr
, char *buf
, int sz
, IPAddress
&from
)
1120 htcpReplyData htcpReply
;
1121 cache_key
*key
= NULL
;
1124 htcpDetail
*d
= NULL
;
1127 if (queried_id
[hdr
->msg_id
% N_QUERIED_KEYS
] != hdr
->msg_id
)
1129 debugs(31, 2, "htcpHandleTstResponse: No matching query id '" <<
1130 hdr
->msg_id
<< "' (expected " <<
1131 queried_id
[hdr
->msg_id
% N_QUERIED_KEYS
] << ") from '" <<
1137 key
= queried_keys
[hdr
->msg_id
% N_QUERIED_KEYS
];
1141 debugs(31, 1, "htcpHandleTstResponse: No query key for response id '" << hdr
->msg_id
<< "' from '" << from
<< "'");
1145 peer
= &queried_addr
[hdr
->msg_id
% N_QUERIED_KEYS
];
1147 if ( *peer
!= from
|| peer
->GetPort() != from
.GetPort() )
1149 debugs(31, 1, "htcpHandleTstResponse: Unexpected response source " << from
);
1155 debugs(31, 2, "htcpHandleTstResponse: error condition, F1/MO == 1");
1159 htcpReply
.msg_id
= hdr
->msg_id
;
1160 debugs(31, 3, "htcpHandleTstResponse: msg_id = " << htcpReply
.msg_id
);
1161 htcpReply
.hit
= hdr
->response
? 0 : 1;
1165 debugs(31, 3, "htcpHandleTstResponse: MISS");
1168 debugs(31, 3, "htcpHandleTstResponse: HIT");
1169 d
= htcpUnpackDetail(buf
, sz
);
1172 debugs(31, 1, "htcpHandleTstResponse: bad DETAIL");
1176 if ((t
= d
->resp_hdrs
))
1177 htcpReply
.hdr
.parse(t
, t
+ strlen(t
));
1179 if ((t
= d
->entity_hdrs
))
1180 htcpReply
.hdr
.parse(t
, t
+ strlen(t
));
1182 if ((t
= d
->cache_hdrs
))
1183 htcpReply
.hdr
.parse(t
, t
+ strlen(t
));
1186 debugs(31, 3, "htcpHandleTstResponse: key (" << key
<< ") " << storeKeyText(key
));
1187 neighborsHtcpReply(key
, &htcpReply
, from
);
1188 htcpReply
.hdr
.clean();
1196 htcpHandleTstRequest(htcpDataHeader
* dhdr
, char *buf
, int sz
, IPAddress
&from
)
1198 /* buf should be a SPECIFIER */
1203 debugs(31, 3, "htcpHandleTst: nothing to do");
1210 /* s is a new object */
1211 s
= htcpUnpackSpecifier(buf
, sz
);
1215 s
->setDataHeader (dhdr
);
1219 debugs(31, 2, "htcpHandleTstRequest: htcpUnpackSpecifier failed");
1225 debugs(31, 2, "htcpHandleTstRequest: failed to parse request");
1226 htcpFreeSpecifier(s
);
1230 if (!htcpAccessCheck(Config
.accessList
.htcp
, s
, from
))
1232 debugs(31, 2, "htcpHandleTstRequest: Access denied");
1233 htcpFreeSpecifier(s
);
1237 debugs(31, 3, "htcpHandleTstRequest: " << s
->method
<< " " << s
->uri
<< " " << s
->version
);
1238 debugs(31, 3, "htcpHandleTstRequest: " << s
->req_hdrs
);
1243 htcpSpecifier::checkedHit(StoreEntry
*e
)
1246 htcpTstReply(dhdr
, e
, this, from
); /* hit */
1248 htcpTstReply(dhdr
, NULL
, NULL
, from
); /* cache miss */
1250 htcpFreeSpecifier(this);
1255 htcpHandleMon(htcpDataHeader
* hdr
, char *buf
, int sz
, IPAddress
&from
)
1257 debugs(31, 3, "htcpHandleMon: Unimplemented");
1262 htcpHandleSet(htcpDataHeader
* hdr
, char *buf
, int sz
, IPAddress
&from
)
1264 debugs(31, 3, "htcpHandleSet: Unimplemented");
1269 htcpHandleClr(htcpDataHeader
* hdr
, char *buf
, int sz
, IPAddress
&from
)
1272 /* buf[0/1] is reserved and reason */
1273 int reason
= buf
[1] << 4;
1274 debugs(31, 3, "htcpHandleClr: reason=" << reason
);
1278 /* buf should be a SPECIFIER */
1282 debugs(31, 4, "htcpHandleClr: nothing to do");
1286 s
= htcpUnpackSpecifier(buf
, sz
);
1290 debugs(31, 3, "htcpHandleClr: htcpUnpackSpecifier failed");
1294 if (!htcpAccessCheck(Config
.accessList
.htcp_clr
, s
, from
))
1296 debugs(31, 2, "htcpHandleClr: Access denied");
1297 htcpFreeSpecifier(s
);
1301 debugs(31, 5, "htcpHandleClr: " << s
->method
<< " " << s
->uri
<< " " << s
->version
);
1302 debugs(31, 5, "htcpHandleClr: request headers: " << s
->req_hdrs
);
1304 /* Release objects from cache
1305 * analog to clientPurgeRequest in client_side.c
1308 switch (htcpClrStore(s
))
1312 htcpClrReply(hdr
, 1, from
); /* hit */
1316 htcpClrReply(hdr
, 0, from
); /* miss */
1323 htcpFreeSpecifier(s
);
1328 htcpHandleData(char *buf
, int sz
, IPAddress
&from
)
1332 if ((size_t)sz
< sizeof(htcpDataHeader
))
1334 debugs(31, 1, "htcpHandleData: msg size less than htcpDataHeader size");
1338 if (!old_squid_format
)
1340 xmemcpy(&hdr
, buf
, sizeof(hdr
));
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
;
1351 hdr
.msg_id
= hdrSquid
.msg_id
;
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
);
1359 if (hdr
.opcode
>= HTCP_END
)
1361 debugs(31, 1, "htcpHandleData: client " << from
<< ", opcode " << hdr
.opcode
<< " out of range");
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
);
1371 if (sz
< hdr
.length
)
1373 debugs(31, 1, "htcpHandleData: sz < hdr.length");
1378 * set sz = hdr.length so we ignore any AUTH fields following
1381 sz
= (int) hdr
.length
;
1383 buf
+= sizeof(htcpDataHeader
);
1385 sz
-= sizeof(htcpDataHeader
);
1387 debugs(31, 3, "htcpHandleData: sz = " << sz
);
1389 htcpHexdump("htcpHandleData", buf
, sz
);
1395 htcpHandleNop(&hdr
, buf
, sz
, from
);
1399 htcpHandleTst(&hdr
, buf
, sz
, from
);
1403 htcpHandleMon(&hdr
, buf
, sz
, from
);
1407 htcpHandleSet(&hdr
, buf
, sz
, from
);
1411 htcpHandleClr(&hdr
, buf
, sz
, from
);
1421 htcpHandle(char *buf
, int sz
, IPAddress
&from
)
1426 if ((size_t)sz
< sizeof(htcpHeader
))
1428 debugs(31, 1, "htcpHandle: msg size less than htcpHeader size");
1432 htcpHexdump("htcpHandle", buf
, sz
);
1433 xmemcpy(&htcpHdr
, buf
, sizeof(htcpHeader
));
1434 htcpHdr
.length
= ntohs(htcpHdr
.length
);
1436 if (htcpHdr
.minor
== 0)
1437 old_squid_format
= 1;
1439 old_squid_format
= 0;
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
);
1445 if (sz
!= htcpHdr
.length
)
1447 debugs(31, 1, "htcpHandle: sz/" << sz
<< " != htcpHdr.length/" <<
1448 htcpHdr
.length
<< " from " << from
);
1453 if (htcpHdr
.major
!= 0)
1455 debugs(31, 1, "htcpHandle: Unknown major version " << htcpHdr
.major
<< " from " << from
);
1460 buf
+= sizeof(htcpHeader
);
1461 sz
-= sizeof(htcpHeader
);
1462 htcpHandleData(buf
, sz
, from
);
1466 htcpRecv(int fd
, void *data
)
1468 static char buf
[8192];
1470 static IPAddress from
;
1472 /* Receive up to 8191 bytes, leaving room for a null */
1474 len
= comm_udp_recvfrom(fd
, buf
, sizeof(buf
) - 1, 0, from
);
1476 debugs(31, 3, "htcpRecv: FD " << fd
<< ", " << len
<< " bytes from " << from
);
1479 statCounter
.htcp
.pkts_recv
++;
1481 htcpHandle(buf
, len
, from
);
1483 commSetSelect(fd
, COMM_SELECT_READ
, htcpRecv
, NULL
, 0);
1487 * ======================================================================
1489 * ======================================================================
1497 if (Config
.Port
.htcp
<= 0) {
1498 debugs(31, 1, "HTCP Disabled.");
1501 sendOn
= Config
.Addrs
.udp_outgoing
;
1502 sendOn
.SetPort(Config
.Port
.htcp
);
1505 htcpInSocket
= comm_open(SOCK_DGRAM
,
1512 if (htcpInSocket
< 0)
1513 fatal("Cannot open HTCP Socket");
1515 commSetSelect(htcpInSocket
, COMM_SELECT_READ
, htcpRecv
, NULL
, 0);
1517 debugs(31, 1, "Accepting HTCP messages on port " << Config
.Port
.htcp
<< ", FD " << htcpInSocket
<< ".");
1519 if (!Config
.Addrs
.udp_outgoing
.IsNoAddr()) {
1521 htcpOutSocket
= comm_open(SOCK_DGRAM
,
1525 "Outgoing HTCP Socket");
1528 if (htcpOutSocket
< 0)
1529 fatal("Cannot open Outgoing HTCP Socket");
1531 commSetSelect(htcpOutSocket
, COMM_SELECT_READ
, htcpRecv
, NULL
, 0);
1533 debugs(31, 1, "Outgoing HTCP messages on port " << Config
.Port
.htcp
<< ", FD " << htcpOutSocket
<< ".");
1535 fd_note(htcpInSocket
, "Incoming HTCP socket");
1537 htcpOutSocket
= htcpInSocket
;
1540 if (!htcpDetailPool
) {
1541 htcpDetailPool
= memPoolCreate("htcpDetail", sizeof(htcpDetail
));
1546 htcpQuery(StoreEntry
* e
, HttpRequest
* req
, peer
* p
)
1548 cache_key
*save_key
;
1549 static char pkt
[8192];
1553 HttpHeader
hdr(hoRequest
);
1556 http_state_flags flags
;
1558 if (htcpInSocket
< 0)
1561 old_squid_format
= p
->options
.htcp_oldsquid
;
1563 memset(&flags
, '\0', sizeof(flags
));
1565 snprintf(vbuf
, sizeof(vbuf
), "%d/%d",
1566 req
->http_ver
.major
, req
->http_ver
.minor
);
1568 stuff
.op
= HTCP_TST
;
1570 stuff
.rr
= RR_REQUEST
;
1576 stuff
.msg_id
= ++msg_id_counter
;
1578 stuff
.S
.method
= (char *) RequestMethodStr(req
->method
);
1580 stuff
.S
.uri
= (char *) e
->url();
1582 stuff
.S
.version
= vbuf
;
1584 HttpStateData::httpBuildRequestHeader(req
, req
, e
, &hdr
, flags
);
1588 packerToMemInit(&pa
, &mb
);
1596 stuff
.S
.req_hdrs
= mb
.buf
;
1598 pktlen
= htcpBuildPacket(pkt
, sizeof(pkt
), &stuff
);
1603 debugs(31, 1, "htcpQuery: htcpBuildPacket() failed");
1607 htcpSend(pkt
, (int) pktlen
, p
->in_addr
);
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
));
1617 * htcpSocketShutdown only closes the 'in' socket if it is
1618 * different than the 'out' socket.
1621 htcpSocketShutdown(void)
1623 if (htcpInSocket
< 0)
1626 if (htcpInSocket
!= htcpOutSocket
) {
1627 debugs(12, 1, "FD " << htcpInSocket
<< " Closing HTCP socket");
1628 comm_close(htcpInSocket
);
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.
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.
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..
1648 assert(htcpOutSocket
> -1);
1650 commSetSelect(htcpOutSocket
, COMM_SELECT_READ
, NULL
, NULL
, 0);
1654 htcpSocketClose(void)
1656 htcpSocketShutdown();
1658 if (htcpOutSocket
> -1) {
1659 debugs(12, 1, "FD " << htcpOutSocket
<< " Closing HTCP socket");
1660 comm_close(htcpOutSocket
);