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