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