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