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