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