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