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