]> git.ipfire.org Git - thirdparty/squid.git/blame - src/htcp.cc
Correct EUI logging documentation
[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"
924f73bc 37#include "htcp.h"
c0941a6a
AR
38#include "acl/FilledChecklist.h"
39#include "acl/Acl.h"
e0f8b709 40#include "ip/tools.h"
985c86bc 41#include "SquidTime.h"
e6ccf245 42#include "Store.h"
43#include "StoreClient.h"
528b2c61 44#include "HttpRequest.h"
402d6bec 45#include "comm.h"
0eb49b6d 46#include "MemBuf.h"
3b0d7130 47#include "http.h"
9b5c4a9a 48#include "icmp/net_db.h"
a8b1cdf6 49#include "AccessLogEntry.h"
013e320c
AR
50#include "ipc/StartListening.h"
51
52/// dials htcpIncomingConnectionOpened call
53class HtcpListeningStartedDialer: public CallDialer,
5667a628 54 public Ipc::StartListeningCb
013e320c
AR
55{
56public:
57 typedef void (*Handler)(int fd, int errNo);
58 HtcpListeningStartedDialer(Handler aHandler): handler(aHandler) {}
59
60 virtual void print(std::ostream &os) const { startPrint(os) << ')'; }
61
62 virtual bool canDial(AsyncCall &) const { return true; }
63 virtual void dial(AsyncCall &) { (handler)(fd, errNo); }
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
013e320c 247static void htcpIncomingConnectionOpened(int fd, int errNo);
09aabd84 248static uint32_t msg_id_counter = 0;
013e320c 249
d5d466fc 250static int htcpInSocket = -1;
251static int htcpOutSocket = -1;
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{
470 u_short reason;
26ac0430 471
4f4fa815
BR
472 switch (stuff->rr) {
473 case RR_REQUEST:
474 debugs(31, 3, "htcpBuildClrOpData: RR_REQUEST");
475 reason = htons((u_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
62e76326 616
b7ac5457 617htcpSend(const char *buf, int len, Ip::Address &to)
3340a3e6 618{
d5d466fc 619 int x;
cc192b50 620
621 debugs(31, 3, "htcpSend: " << to );
56714a1a 622 htcpHexdump("htcpSend", buf, len);
cc192b50 623
d5d466fc 624 x = comm_udp_sendto(htcpOutSocket,
62e76326 625 to,
62e76326 626 buf,
627 len);
628
d5d466fc 629 if (x < 0)
56deee1e 630 debugs(31, 3, "htcpSend: FD " << htcpOutSocket << " sendto: " << xstrerror());
c4ebc830 631 else
632 statCounter.htcp.pkts_sent++;
3340a3e6 633}
634
eb9ae2f7 635/*
636 * STUFF FOR RECEIVING HTCP MESSAGES
637 */
638
e6ccf245 639void
62e76326 640
b7ac5457 641htcpSpecifier::setFrom(Ip::Address &aSocket)
e6ccf245 642{
643 from = aSocket;
644}
645
646void
b7ac5457 647htcpSpecifier::setDataHeader(htcpDataHeader *aDataHeader)
e6ccf245 648{
649 dhdr = aDataHeader;
650}
651
eb9ae2f7 652static void
653htcpFreeSpecifier(htcpSpecifier * s)
654{
5401aa8d 655 HTTPMSGUNLOCK(s->request);
656
e6ccf245 657 delete s;
eb9ae2f7 658}
659
a2edf5dc 660static void
661htcpFreeDetail(htcpDetail * d)
662{
dc47f531 663 htcpDetailPool->freeOne(d);
a2edf5dc 664}
665
5401aa8d 666/*
667 * Unpack an HTCP SPECIFIER in place
668 * This will overwrite any following AUTH block
669 */
56714a1a 670static htcpSpecifier *
eb9ae2f7 671htcpUnpackSpecifier(char *buf, int sz)
672{
e6ccf245 673 htcpSpecifier *s = new htcpSpecifier;
60745f24 674 HttpRequestMethod method;
62e76326 675
5401aa8d 676 /* Find length of METHOD */
09aabd84 677 uint16_t l = ntohs(*(uint16_t *) buf);
5401aa8d 678 sz -= 2;
679 buf += 2;
680
681 if (l > sz) {
56deee1e 682 debugs(31, 3, "htcpUnpackSpecifier: failed to unpack METHOD");
62e76326 683 htcpFreeSpecifier(s);
684 return NULL;
1afe05c5 685 }
62e76326 686
5401aa8d 687 /* Set METHOD */
688 s->method = buf;
5401aa8d 689 buf += l;
5401aa8d 690 sz -= l;
3a47664f 691 debugs(31, 6, "htcpUnpackSpecifier: METHOD (" << l << "/" << sz << ") '" << s->method << "'");
5401aa8d 692
693 /* Find length of URI */
09aabd84 694 l = ntohs(*(uint16_t *) buf);
5401aa8d 695 sz -= 2;
696
697 if (l > sz) {
56deee1e 698 debugs(31, 3, "htcpUnpackSpecifier: failed to unpack URI");
62e76326 699 htcpFreeSpecifier(s);
700 return NULL;
1afe05c5 701 }
62e76326 702
5401aa8d 703 /* Add terminating null to METHOD */
704 *buf = '\0';
5401aa8d 705 buf += 2;
706
3a47664f 707 /* Set URI */
5401aa8d 708 s->uri = buf;
5401aa8d 709 buf += l;
5401aa8d 710 sz -= l;
3a47664f 711 debugs(31, 6, "htcpUnpackSpecifier: URI (" << l << "/" << sz << ") '" << s->uri << "'");
5401aa8d 712
713 /* Find length of VERSION */
09aabd84 714 l = ntohs(*(uint16_t *) buf);
5401aa8d 715 sz -= 2;
62e76326 716
5401aa8d 717 if (l > sz) {
56deee1e 718 debugs(31, 3, "htcpUnpackSpecifier: failed to unpack VERSION");
62e76326 719 htcpFreeSpecifier(s);
720 return NULL;
1afe05c5 721 }
62e76326 722
5401aa8d 723 /* Add terminating null to URI */
724 *buf = '\0';
5401aa8d 725 buf += 2;
726
3a47664f 727 /* Set VERSION */
5401aa8d 728 s->version = buf;
5401aa8d 729 buf += l;
5401aa8d 730 sz -= l;
3a47664f 731 debugs(31, 6, "htcpUnpackSpecifier: VERSION (" << l << "/" << sz << ") '" << s->version << "'");
5401aa8d 732
733 /* Find length of REQ-HDRS */
09aabd84 734 l = ntohs(*(uint16_t *) buf);
5401aa8d 735 sz -= 2;
62e76326 736
5401aa8d 737 if (l > sz) {
56deee1e 738 debugs(31, 3, "htcpUnpackSpecifier: failed to unpack REQ-HDRS");
62e76326 739 htcpFreeSpecifier(s);
740 return NULL;
1afe05c5 741 }
62e76326 742
5401aa8d 743 /* Add terminating null to URI */
744 *buf = '\0';
5401aa8d 745 buf += 2;
746
3a47664f 747 /* Set REQ-HDRS */
5401aa8d 748 s->req_hdrs = buf;
5401aa8d 749 buf += l;
5401aa8d 750 sz -= l;
3a47664f 751 debugs(31, 6, "htcpUnpackSpecifier: REQ-HDRS (" << l << "/" << sz << ") '" << s->req_hdrs << "'");
5401aa8d 752
bf8fe701 753 debugs(31, 3, "htcpUnpackSpecifier: " << sz << " bytes left");
5401aa8d 754
755 /*
26ac0430 756 * Add terminating null to REQ-HDRS. This is possible because we allocated
5401aa8d 757 * an extra byte when we received the packet. This will overwrite any following
758 * AUTH block.
759 */
760 *buf = '\0';
761
762 /*
763 * Parse the request
764 */
914b89a2 765 method = HttpRequestMethod(s->method, NULL);
5401aa8d 766
60745f24 767 s->request = HttpRequest::CreateFromUrlAndMethod(s->uri, method == METHOD_NONE ? HttpRequestMethod(METHOD_GET) : method);
5401aa8d 768
b8def95f 769 if (s->request)
26ac0430 770 HTTPMSGLOCK(s->request);
b8def95f 771
1afe05c5 772 return s;
eb9ae2f7 773}
774
5401aa8d 775/*
776 * Unpack an HTCP DETAIL in place
777 * This will overwrite any following AUTH block
778 */
a2edf5dc 779static htcpDetail *
780htcpUnpackDetail(char *buf, int sz)
781{
b001e822 782 htcpDetail *d = static_cast<htcpDetail *>(htcpDetailPool->alloc());
62e76326 783
5401aa8d 784 /* Find length of RESP-HDRS */
09aabd84 785 uint16_t l = ntohs(*(uint16_t *) buf);
5401aa8d 786 sz -= 2;
787 buf += 2;
788
789 if (l > sz) {
56deee1e 790 debugs(31, 3, "htcpUnpackDetail: failed to unpack RESP_HDRS");
62e76326 791 htcpFreeDetail(d);
792 return NULL;
a2edf5dc 793 }
62e76326 794
5401aa8d 795 /* Set RESP-HDRS */
796 d->resp_hdrs = buf;
797
798 buf += l;
799
800 sz -= l;
62e76326 801
5401aa8d 802 /* Find length of ENTITY-HDRS */
09aabd84 803 l = ntohs(*(uint16_t *) buf);
5401aa8d 804
805 sz -= 2;
806
807 if (l > sz) {
56deee1e 808 debugs(31, 3, "htcpUnpackDetail: failed to unpack ENTITY_HDRS");
62e76326 809 htcpFreeDetail(d);
810 return NULL;
a2edf5dc 811 }
62e76326 812
5401aa8d 813 /* Add terminating null to RESP-HDRS */
814 *buf = '\0';
815
816 /* Set ENTITY-HDRS */
817 buf += 2;
818
819 d->entity_hdrs = buf;
62e76326 820
5401aa8d 821 buf += l;
822
823 sz -= l;
824
825 /* Find length of CACHE-HDRS */
09aabd84 826 l = ntohs(*(uint16_t *) buf);
5401aa8d 827
828 sz -= 2;
829
830 if (l > sz) {
56deee1e 831 debugs(31, 3, "htcpUnpackDetail: failed to unpack CACHE_HDRS");
62e76326 832 htcpFreeDetail(d);
833 return NULL;
a2edf5dc 834 }
62e76326 835
5401aa8d 836 /* Add terminating null to ENTITY-HDRS */
837 *buf = '\0';
838
839 /* Set CACHE-HDRS */
840 buf += 2;
841
842 d->cache_hdrs = buf;
843
844 buf += l;
845
846 sz -= l;
847
bf8fe701 848 debugs(31, 3, "htcpUnpackDetail: " << sz << " bytes left");
5401aa8d 849
850 /*
26ac0430 851 * Add terminating null to CACHE-HDRS. This is possible because we allocated
5401aa8d 852 * an extra byte when we received the packet. This will overwrite any following
853 * AUTH block.
854 */
855 *buf = '\0';
856
a2edf5dc 857 return d;
858}
859
5401aa8d 860static int
b7ac5457 861htcpAccessCheck(acl_access * acl, htcpSpecifier * s, Ip::Address &from)
5401aa8d 862{
b50e327b
AJ
863 /* default deny if no access list present */
864 if (!acl)
865 return 0;
866
c0941a6a 867 ACLFilledChecklist checklist(acl, s->request, NULL);
cc192b50 868 checklist.src_addr = from;
869 checklist.my_addr.SetNoAddr();
5401aa8d 870 int result = checklist.fastCheck();
871 return result;
872}
873
eb9ae2f7 874static void
b7ac5457 875htcpTstReply(htcpDataHeader * dhdr, StoreEntry * e, htcpSpecifier * spec, Ip::Address &from)
60fac9b5 876{
877 htcpStuff stuff;
5401aa8d 878 static char pkt[8192];
75faaa7a 879 HttpHeader hdr(hoHtcpReply);
2dcc81d4 880 MemBuf mb;
881 Packer p;
60fac9b5 882 ssize_t pktlen;
9bc73deb 883 memset(&stuff, '\0', sizeof(stuff));
60fac9b5 884 stuff.op = HTCP_TST;
885 stuff.rr = RR_RESPONSE;
44e237d0 886 stuff.f1 = 0;
887 stuff.response = e ? 0 : 1;
bf8fe701 888 debugs(31, 3, "htcpTstReply: response = " << stuff.response);
26df9ec6 889 stuff.msg_id = dhdr->msg_id;
62e76326 890
26ac0430 891 if (spec) {
2fe7eff9 892 mb.init();
62e76326 893 packerToMemInit(&p, &mb);
62e76326 894 stuff.S.method = spec->method;
895 stuff.S.uri = spec->uri;
896 stuff.S.version = spec->version;
897 stuff.S.req_hdrs = spec->req_hdrs;
af6a12ee 898 if (e)
89982fc0
AJ
899 hdr.putInt(HDR_AGE, (e->timestamp <= squid_curtime ? (squid_curtime - e->timestamp) : 0) );
900 else
901 hdr.putInt(HDR_AGE, 0);
61f4f11b 902 hdr.packInto(&p);
62e76326 903 stuff.D.resp_hdrs = xstrdup(mb.buf);
bf8fe701 904 debugs(31, 3, "htcpTstReply: resp_hdrs = {" << stuff.D.resp_hdrs << "}");
2fe7eff9 905 mb.reset();
61f4f11b 906 hdr.reset();
62e76326 907
89982fc0 908 if (e && e->expires > -1)
61f4f11b 909 hdr.putTime(HDR_EXPIRES, e->expires);
62e76326 910
89982fc0 911 if (e && e->lastmod > -1)
61f4f11b 912 hdr.putTime(HDR_LAST_MODIFIED, e->lastmod);
62e76326 913
61f4f11b 914 hdr.packInto(&p);
62e76326 915
916 stuff.D.entity_hdrs = xstrdup(mb.buf);
917
bf8fe701 918 debugs(31, 3, "htcpTstReply: entity_hdrs = {" << stuff.D.entity_hdrs << "}");
62e76326 919
2fe7eff9 920 mb.reset();
62e76326 921
61f4f11b 922 hdr.reset();
62e76326 923
9b5c4a9a 924#if USE_ICMP
c517f84a 925 if (char *host = urlHostname(spec->uri)) {
9e008dda
AJ
926 int rtt = 0;
927 int hops = 0;
9b5c4a9a 928 int samp = 0;
62e76326 929 netdbHostData(host, &samp, &rtt, &hops);
930
931 if (rtt || hops) {
c517f84a 932 char cto_buf[128];
62e76326 933 snprintf(cto_buf, 128, "%s %d %f %d",
934 host, samp, 0.001 * rtt, hops);
61f4f11b 935 hdr.putExt("Cache-to-Origin", cto_buf);
62e76326 936 }
937 }
9b5c4a9a 938#endif /* USE_ICMP */
62e76326 939
61f4f11b 940 hdr.packInto(&p);
62e76326 941 stuff.D.cache_hdrs = xstrdup(mb.buf);
bf8fe701 942 debugs(31, 3, "htcpTstReply: cache_hdrs = {" << stuff.D.cache_hdrs << "}");
2fe7eff9 943 mb.clean();
519e0948 944 hdr.clean();
62e76326 945 packerClean(&p);
60fac9b5 946 }
62e76326 947
5401aa8d 948 pktlen = htcpBuildPacket(pkt, sizeof(pkt), &stuff);
62e76326 949
0203ca6d 950 safe_free(stuff.D.resp_hdrs);
951 safe_free(stuff.D.entity_hdrs);
952 safe_free(stuff.D.cache_hdrs);
953
26ac0430 954 if (!pktlen) {
56deee1e 955 debugs(31, 3, "htcpTstReply: htcpBuildPacket() failed");
5401aa8d 956 return;
957 }
958
959 htcpSend(pkt, (int) pktlen, from);
960}
961
962static void
963
b7ac5457 964htcpClrReply(htcpDataHeader * dhdr, int purgeSucceeded, Ip::Address &from)
5401aa8d 965{
966 htcpStuff stuff;
967 static char pkt[8192];
968 ssize_t pktlen;
969
970 /* If dhdr->F1 == 0, no response desired */
971
972 if (dhdr->F1 == 0)
973 return;
974
975 memset(&stuff, '\0', sizeof(stuff));
976
977 stuff.op = HTCP_CLR;
978
979 stuff.rr = RR_RESPONSE;
980
981 stuff.f1 = 0;
982
983 stuff.response = purgeSucceeded ? 0 : 2;
984
bf8fe701 985 debugs(31, 3, "htcpClrReply: response = " << stuff.response);
5401aa8d 986
987 stuff.msg_id = dhdr->msg_id;
988
989 pktlen = htcpBuildPacket(pkt, sizeof(pkt), &stuff);
990
26ac0430 991 if (pktlen == 0) {
56deee1e 992 debugs(31, 3, "htcpClrReply: htcpBuildPacket() failed");
62e76326 993 return;
60fac9b5 994 }
62e76326 995
60fac9b5 996 htcpSend(pkt, (int) pktlen, from);
60fac9b5 997}
998
999static void
62e76326 1000
b7ac5457 1001htcpHandleNop(htcpDataHeader * hdr, char *buf, int sz, Ip::Address &from)
eb9ae2f7 1002{
bf8fe701 1003 debugs(31, 3, "htcpHandleNop: Unimplemented");
eb9ae2f7 1004}
1005
e6ccf245 1006void
1007htcpSpecifier::checkHit()
32b3cf93 1008{
7e3ce7b9 1009 char *blk_end;
5401aa8d 1010 checkHitRequest = request;
62e76326 1011
e6ccf245 1012 if (NULL == checkHitRequest) {
bf8fe701 1013 debugs(31, 3, "htcpCheckHit: NO; failed to parse URL");
62e76326 1014 checkedHit(NullStoreEntry::getInstance());
1015 return;
7e3ce7b9 1016 }
62e76326 1017
e6ccf245 1018 blk_end = req_hdrs + strlen(req_hdrs);
62e76326 1019
61f4f11b 1020 if (!checkHitRequest->header.parse(req_hdrs, blk_end)) {
bf8fe701 1021 debugs(31, 3, "htcpCheckHit: NO; failed to parse request headers");
5cafad19 1022 delete checkHitRequest;
62e76326 1023 checkHitRequest = NULL;
1024 checkedHit(NullStoreEntry::getInstance());
1025 return;
f66a9ef4 1026 }
62e76326 1027
3b13a8fd 1028 StoreEntry::getPublicByRequest(this, checkHitRequest);
e6ccf245 1029}
1030
1031void
3b13a8fd 1032htcpSpecifier::created (StoreEntry *e)
e6ccf245 1033{
1034 StoreEntry *hit=NULL;
1035 assert (e);
62e76326 1036
e6ccf245 1037 if (e->isNull()) {
bf8fe701 1038 debugs(31, 3, "htcpCheckHit: NO; public object not found");
26ac0430 1039 } else if (!e->validToSend()) {
bf8fe701 1040 debugs(31, 3, "htcpCheckHit: NO; entry not valid to send" );
26ac0430 1041 } else if (refreshCheckHTCP(e, checkHitRequest)) {
bf8fe701 1042 debugs(31, 3, "htcpCheckHit: NO; cached response is stale");
26ac0430 1043 } else {
cc192b50 1044 debugs(31, 3, "htcpCheckHit: YES!?");
1045 hit = e;
7e3ce7b9 1046 }
62e76326 1047
e6ccf245 1048 checkedHit (hit);
32b3cf93 1049}
1050
5401aa8d 1051static void
1052htcpClrStoreEntry(StoreEntry * e)
1053{
bf8fe701 1054 debugs(31, 4, "htcpClrStoreEntry: Clearing store for entry: " << e->url() );
d88e3c49 1055 e->releaseRequest();
5401aa8d 1056}
1057
1058static int
1059htcpClrStore(const htcpSpecifier * s)
1060{
1061 HttpRequest *request = s->request;
1062 char *blk_end;
1063 StoreEntry *e = NULL;
1064 int released = 0;
1065
1066 if (request == NULL) {
bf8fe701 1067 debugs(31, 3, "htcpClrStore: failed to parse URL");
5401aa8d 1068 return -1;
1069 }
1070
1071 /* Parse request headers */
1072 blk_end = s->req_hdrs + strlen(s->req_hdrs);
1073
1074 if (!request->header.parse(s->req_hdrs, blk_end)) {
bf8fe701 1075 debugs(31, 2, "htcpClrStore: failed to parse request headers");
5401aa8d 1076 return -1;
1077 }
1078
1079 /* Lookup matching entries. This matches both GET and HEAD */
1080 while ((e = storeGetPublicByRequest(request)) != NULL) {
1081 if (e != NULL) {
1082 htcpClrStoreEntry(e);
1083 released++;
1084 }
1085 }
1086
1087 if (released) {
bf8fe701 1088 debugs(31, 4, "htcpClrStore: Cleared " << released << " matching entries");
5401aa8d 1089 return 1;
1090 } else {
bf8fe701 1091 debugs(31, 4, "htcpClrStore: No matching entry found");
5401aa8d 1092 return 0;
1093 }
1094}
1095
eb9ae2f7 1096static void
62e76326 1097
b7ac5457 1098htcpHandleTst(htcpDataHeader * hdr, char *buf, int sz, Ip::Address &from)
eb9ae2f7 1099{
4a7a3d56 1100 debugs(31, 3, "htcpHandleTst: sz = " << sz);
62e76326 1101
60fac9b5 1102 if (hdr->RR == RR_REQUEST)
62e76326 1103 htcpHandleTstRequest(hdr, buf, sz, from);
60fac9b5 1104 else
62e76326 1105 htcpHandleTstResponse(hdr, buf, sz, from);
60fac9b5 1106}
1107
75faaa7a 1108HtcpReplyData::HtcpReplyData() : hdr(hoHtcpReply)
1109{}
1110
60fac9b5 1111static void
62e76326 1112
b7ac5457 1113htcpHandleTstResponse(htcpDataHeader * hdr, char *buf, int sz, Ip::Address &from)
60fac9b5 1114{
a2edf5dc 1115 htcpReplyData htcpReply;
1116 cache_key *key = NULL;
5401aa8d 1117
b7ac5457 1118 Ip::Address *peer;
26df9ec6 1119 htcpDetail *d = NULL;
a2edf5dc 1120 char *t;
62e76326 1121
26ac0430 1122 if (queried_id[hdr->msg_id % N_QUERIED_KEYS] != hdr->msg_id) {
bf8fe701 1123 debugs(31, 2, "htcpHandleTstResponse: No matching query id '" <<
1124 hdr->msg_id << "' (expected " <<
1125 queried_id[hdr->msg_id % N_QUERIED_KEYS] << ") from '" <<
cc192b50 1126 from << "'");
bf8fe701 1127
5401aa8d 1128 return;
1129 }
1130
1131 key = queried_keys[hdr->msg_id % N_QUERIED_KEYS];
1132
26ac0430 1133 if (!key) {
56deee1e 1134 debugs(31, 3, "htcpHandleTstResponse: No query key for response id '" << hdr->msg_id << "' from '" << from << "'");
5401aa8d 1135 return;
1136 }
1137
1138 peer = &queried_addr[hdr->msg_id % N_QUERIED_KEYS];
1139
26ac0430 1140 if ( *peer != from || peer->GetPort() != from.GetPort() ) {
56deee1e 1141 debugs(31, 3, "htcpHandleTstResponse: Unexpected response source " << from );
5401aa8d 1142 return;
1143 }
1144
26ac0430 1145 if (hdr->F1 == 1) {
bf8fe701 1146 debugs(31, 2, "htcpHandleTstResponse: error condition, F1/MO == 1");
62e76326 1147 return;
44e237d0 1148 }
62e76326 1149
26df9ec6 1150 htcpReply.msg_id = hdr->msg_id;
4a7a3d56 1151 debugs(31, 3, "htcpHandleTstResponse: msg_id = " << htcpReply.msg_id);
44e237d0 1152 htcpReply.hit = hdr->response ? 0 : 1;
62e76326 1153
26ac0430 1154 if (hdr->F1) {
bf8fe701 1155 debugs(31, 3, "htcpHandleTstResponse: MISS");
26ac0430 1156 } else {
bf8fe701 1157 debugs(31, 3, "htcpHandleTstResponse: HIT");
62e76326 1158 d = htcpUnpackDetail(buf, sz);
1159
1160 if (d == NULL) {
56deee1e 1161 debugs(31, 3, "htcpHandleTstResponse: bad DETAIL");
62e76326 1162 return;
1163 }
1164
1165 if ((t = d->resp_hdrs))
61f4f11b 1166 htcpReply.hdr.parse(t, t + strlen(t));
62e76326 1167
1168 if ((t = d->entity_hdrs))
61f4f11b 1169 htcpReply.hdr.parse(t, t + strlen(t));
62e76326 1170
1171 if ((t = d->cache_hdrs))
61f4f11b 1172 htcpReply.hdr.parse(t, t + strlen(t));
a2edf5dc 1173 }
62e76326 1174
bf8fe701 1175 debugs(31, 3, "htcpHandleTstResponse: key (" << key << ") " << storeKeyText(key));
a2edf5dc 1176 neighborsHtcpReply(key, &htcpReply, from);
519e0948 1177 htcpReply.hdr.clean();
62e76326 1178
26df9ec6 1179 if (d)
62e76326 1180 htcpFreeDetail(d);
60fac9b5 1181}
1182
1183static void
62e76326 1184
b7ac5457 1185htcpHandleTstRequest(htcpDataHeader * dhdr, char *buf, int sz, Ip::Address &from)
60fac9b5 1186{
1187 /* buf should be a SPECIFIER */
1188 htcpSpecifier *s;
62e76326 1189
26ac0430 1190 if (sz == 0) {
bf8fe701 1191 debugs(31, 3, "htcpHandleTst: nothing to do");
62e76326 1192 return;
60fac9b5 1193 }
62e76326 1194
44e237d0 1195 if (dhdr->F1 == 0)
62e76326 1196 return;
1197
e6ccf245 1198 /* s is a new object */
60fac9b5 1199 s = htcpUnpackSpecifier(buf, sz);
62e76326 1200
a8b1cdf6 1201 s->setFrom(from);
62e76326 1202
a8b1cdf6 1203 s->setDataHeader(dhdr);
62e76326 1204
26ac0430 1205 if (NULL == s) {
bf8fe701 1206 debugs(31, 2, "htcpHandleTstRequest: htcpUnpackSpecifier failed");
a8b1cdf6 1207 htcpLogHtcp(from, dhdr->opcode, LOG_UDP_INVALID, dash_str);
5401aa8d 1208 return;
1209 }
1210
26ac0430 1211 if (!s->request) {
bf8fe701 1212 debugs(31, 2, "htcpHandleTstRequest: failed to parse request");
a8b1cdf6 1213 htcpLogHtcp(from, dhdr->opcode, LOG_UDP_INVALID, dash_str);
5401aa8d 1214 htcpFreeSpecifier(s);
1215 return;
1216 }
1217
26ac0430 1218 if (!htcpAccessCheck(Config.accessList.htcp, s, from)) {
bf8fe701 1219 debugs(31, 2, "htcpHandleTstRequest: Access denied");
a8b1cdf6 1220 htcpLogHtcp(from, dhdr->opcode, LOG_UDP_DENIED, s->uri);
5401aa8d 1221 htcpFreeSpecifier(s);
62e76326 1222 return;
1afe05c5 1223 }
62e76326 1224
bf8fe701 1225 debugs(31, 3, "htcpHandleTstRequest: " << s->method << " " << s->uri << " " << s->version);
1226 debugs(31, 3, "htcpHandleTstRequest: " << s->req_hdrs);
e6ccf245 1227 s->checkHit();
1228}
1229
1230void
1231htcpSpecifier::checkedHit(StoreEntry *e)
1232{
a8b1cdf6 1233 if (e) {
62e76326 1234 htcpTstReply(dhdr, e, this, from); /* hit */
a8b1cdf6
AJ
1235 htcpLogHtcp(from, dhdr->opcode, LOG_UDP_HIT, uri);
1236 } else {
62e76326 1237 htcpTstReply(dhdr, NULL, NULL, from); /* cache miss */
a8b1cdf6
AJ
1238 htcpLogHtcp(from, dhdr->opcode, LOG_UDP_MISS, uri);
1239 }
62e76326 1240
e6ccf245 1241 htcpFreeSpecifier(this);
d9f9d78b 1242}
1243
1244static void
62e76326 1245
b7ac5457 1246htcpHandleMon(htcpDataHeader * hdr, char *buf, int sz, Ip::Address &from)
eb9ae2f7 1247{
bf8fe701 1248 debugs(31, 3, "htcpHandleMon: Unimplemented");
eb9ae2f7 1249}
1250
1251static void
62e76326 1252
b7ac5457 1253htcpHandleSet(htcpDataHeader * hdr, char *buf, int sz, Ip::Address &from)
eb9ae2f7 1254{
bf8fe701 1255 debugs(31, 3, "htcpHandleSet: Unimplemented");
eb9ae2f7 1256}
1257
1258static void
b7ac5457 1259htcpHandleClr(htcpDataHeader * hdr, char *buf, int sz, Ip::Address &from)
5401aa8d 1260{
1261 htcpSpecifier *s;
1262 /* buf[0/1] is reserved and reason */
1263 int reason = buf[1] << 4;
bf8fe701 1264 debugs(31, 3, "htcpHandleClr: reason=" << reason);
5401aa8d 1265 buf += 2;
1266 sz -= 2;
1267
1268 /* buf should be a SPECIFIER */
1269
26ac0430 1270 if (sz == 0) {
bf8fe701 1271 debugs(31, 4, "htcpHandleClr: nothing to do");
a8b1cdf6 1272 htcpLogHtcp(from, hdr->opcode, LOG_UDP_INVALID, dash_str);
5401aa8d 1273 return;
1274 }
1275
1276 s = htcpUnpackSpecifier(buf, sz);
1277
26ac0430 1278 if (NULL == s) {
bf8fe701 1279 debugs(31, 3, "htcpHandleClr: htcpUnpackSpecifier failed");
a8b1cdf6 1280 htcpLogHtcp(from, hdr->opcode, LOG_UDP_INVALID, dash_str);
5401aa8d 1281 return;
1282 }
1283
3a47664f
AJ
1284 if (!s->request) {
1285 debugs(31, 2, "htcpHandleTstRequest: failed to parse request");
002122d5 1286 htcpLogHtcp(from, hdr->opcode, LOG_UDP_INVALID, dash_str);
6412f46c
AJ
1287 htcpFreeSpecifier(s);
1288 return;
1289 }
1290
26ac0430 1291 if (!htcpAccessCheck(Config.accessList.htcp_clr, s, from)) {
bf8fe701 1292 debugs(31, 2, "htcpHandleClr: Access denied");
a8b1cdf6 1293 htcpLogHtcp(from, hdr->opcode, LOG_UDP_DENIED, s->uri);
5401aa8d 1294 htcpFreeSpecifier(s);
1295 return;
1296 }
1297
bf8fe701 1298 debugs(31, 5, "htcpHandleClr: " << s->method << " " << s->uri << " " << s->version);
1299 debugs(31, 5, "htcpHandleClr: request headers: " << s->req_hdrs);
5401aa8d 1300
1301 /* Release objects from cache
1302 * analog to clientPurgeRequest in client_side.c
1303 */
1304
26ac0430 1305 switch (htcpClrStore(s)) {
5401aa8d 1306
1307 case 1:
1308 htcpClrReply(hdr, 1, from); /* hit */
a8b1cdf6 1309 htcpLogHtcp(from, hdr->opcode, LOG_UDP_HIT, s->uri);
5401aa8d 1310 break;
1311
1312 case 0:
1313 htcpClrReply(hdr, 0, from); /* miss */
a8b1cdf6 1314 htcpLogHtcp(from, hdr->opcode, LOG_UDP_MISS, s->uri);
5401aa8d 1315 break;
1316
1317 default:
1318 break;
1319 }
1320
1321 htcpFreeSpecifier(s);
1322}
1323
1bd06eff
BR
1324/*
1325 * Forward a CLR request to all peers who have requested that CLRs be
1326 * forwarded to them.
1327 */
4f4fa815
BR
1328static void
1329htcpForwardClr(char *buf, int sz)
1330{
1331 peer *p;
26ac0430 1332
90bd689c 1333 for (p = Config.peers; p; p = p->next) {
4f4fa815
BR
1334 if (!p->options.htcp) {
1335 continue;
1336 }
1337 if (!p->options.htcp_forward_clr) {
1338 continue;
1339 }
26ac0430 1340
4f4fa815
BR
1341 htcpSend(buf, sz, p->in_addr);
1342 }
1343}
1344
1bd06eff
BR
1345/*
1346 * Do the first pass of handling an HTCP message. This used to be two
1347 * separate functions, htcpHandle and htcpHandleData. They were merged to
1348 * allow for forwarding HTCP packets easily to other peers if desired.
1349 *
1350 * This function now works out what type of message we have received and then
1351 * hands it off to other functions to break apart message-specific data.
1352 */
5401aa8d 1353static void
b7ac5457 1354htcpHandleMsg(char *buf, int sz, Ip::Address &from)
4f4fa815
BR
1355{
1356 htcpHeader htcpHdr;
eb9ae2f7 1357 htcpDataHeader hdr;
4f4fa815
BR
1358 char *hbuf;
1359 int hsz;
1360 assert (sz >= 0);
62e76326 1361
26ac0430 1362 if ((size_t)sz < sizeof(htcpHeader)) {
56deee1e 1363 debugs(31, 3, "htcpHandle: msg size less than htcpHeader size");
4f4fa815
BR
1364 return;
1365 }
1366
1367 htcpHexdump("htcpHandle", buf, sz);
41d00cd3 1368 memcpy(&htcpHdr, buf, sizeof(htcpHeader));
4f4fa815
BR
1369 htcpHdr.length = ntohs(htcpHdr.length);
1370
1371 if (htcpHdr.minor == 0)
1372 old_squid_format = 1;
1373 else
1374 old_squid_format = 0;
1375
1376 debugs(31, 3, "htcpHandle: htcpHdr.length = " << htcpHdr.length);
1377 debugs(31, 3, "htcpHandle: htcpHdr.major = " << htcpHdr.major);
1378 debugs(31, 3, "htcpHandle: htcpHdr.minor = " << htcpHdr.minor);
1379
26ac0430 1380 if (sz != htcpHdr.length) {
56deee1e 1381 debugs(31, 3, "htcpHandle: sz/" << sz << " != htcpHdr.length/" <<
4f4fa815
BR
1382 htcpHdr.length << " from " << from );
1383
1384 return;
1385 }
1386
26ac0430 1387 if (htcpHdr.major != 0) {
56deee1e 1388 debugs(31, 3, "htcpHandle: Unknown major version " << htcpHdr.major << " from " << from );
4f4fa815
BR
1389
1390 return;
1391 }
1392
90bd689c
BR
1393 hbuf = buf + sizeof(htcpHeader);
1394 hsz = sz - sizeof(htcpHeader);
4f4fa815 1395
26ac0430 1396 if ((size_t)hsz < sizeof(htcpDataHeader)) {
56deee1e 1397 debugs(31, 3, "htcpHandleData: msg size less than htcpDataHeader size");
62e76326 1398 return;
eb9ae2f7 1399 }
62e76326 1400
26ac0430 1401 if (!old_squid_format) {
41d00cd3 1402 memcpy(&hdr, hbuf, sizeof(hdr));
4f4fa815 1403 } else {
527ee50d 1404 htcpDataHeaderSquid hdrSquid;
41d00cd3 1405 memcpy(&hdrSquid, hbuf, sizeof(hdrSquid));
5401aa8d 1406 hdr.length = hdrSquid.length;
527ee50d 1407 hdr.opcode = hdrSquid.opcode;
1408 hdr.response = hdrSquid.response;
1409 hdr.F1 = hdrSquid.F1;
1410 hdr.RR = hdrSquid.RR;
1411 hdr.reserved = 0;
1412 hdr.msg_id = hdrSquid.msg_id;
1413 }
1414
eb9ae2f7 1415 hdr.length = ntohs(hdr.length);
26df9ec6 1416 hdr.msg_id = ntohl(hdr.msg_id);
4f4fa815 1417 debugs(31, 3, "htcpHandleData: hsz = " << hsz);
4a7a3d56 1418 debugs(31, 3, "htcpHandleData: length = " << hdr.length);
62e76326 1419
4f4fa815 1420 if (hdr.opcode >= HTCP_END) {
56deee1e 1421 debugs(31, 3, "htcpHandleData: client " << from << ", opcode " << hdr.opcode << " out of range");
62e76326 1422 return;
eb9ae2f7 1423 }
62e76326 1424
4a7a3d56 1425 debugs(31, 3, "htcpHandleData: opcode = " << hdr.opcode << " " << htcpOpcodeStr[hdr.opcode]);
1426 debugs(31, 3, "htcpHandleData: response = " << hdr.response);
1427 debugs(31, 3, "htcpHandleData: F1 = " << hdr.F1);
1428 debugs(31, 3, "htcpHandleData: RR = " << hdr.RR);
1429 debugs(31, 3, "htcpHandleData: msg_id = " << hdr.msg_id);
62e76326 1430
4f4fa815 1431 if (hsz < hdr.length) {
56deee1e 1432 debugs(31, 3, "htcpHandleData: sz < hdr.length");
62e76326 1433 return;
eb9ae2f7 1434 }
62e76326 1435
60fac9b5 1436 /*
1437 * set sz = hdr.length so we ignore any AUTH fields following
1438 * the DATA.
1439 */
4f4fa815
BR
1440 hsz = (int) hdr.length;
1441 hbuf += sizeof(htcpDataHeader);
1442 hsz -= sizeof(htcpDataHeader);
1443 debugs(31, 3, "htcpHandleData: hsz = " << hsz);
62e76326 1444
4f4fa815 1445 htcpHexdump("htcpHandleData", hbuf, hsz);
62e76326 1446
4f4fa815 1447 switch (hdr.opcode) {
eb9ae2f7 1448 case HTCP_NOP:
4f4fa815 1449 htcpHandleNop(&hdr, hbuf, hsz, from);
62e76326 1450 break;
eb9ae2f7 1451 case HTCP_TST:
4f4fa815 1452 htcpHandleTst(&hdr, hbuf, hsz, from);
62e76326 1453 break;
eb9ae2f7 1454 case HTCP_MON:
4f4fa815 1455 htcpHandleMon(&hdr, hbuf, hsz, from);
62e76326 1456 break;
eb9ae2f7 1457 case HTCP_SET:
4f4fa815 1458 htcpHandleSet(&hdr, hbuf, hsz, from);
62e76326 1459 break;
2caa57ef 1460 case HTCP_CLR:
4f4fa815
BR
1461 htcpHandleClr(&hdr, hbuf, hsz, from);
1462 htcpForwardClr(buf, sz);
62e76326 1463 break;
eb9ae2f7 1464 default:
4f4fa815 1465 break;
527ee50d 1466 }
eb9ae2f7 1467}
1468
56714a1a 1469static void
eb9ae2f7 1470htcpRecv(int fd, void *data)
1471{
1472 static char buf[8192];
1473 int len;
b7ac5457 1474 static Ip::Address from;
62e76326 1475
5401aa8d 1476 /* Receive up to 8191 bytes, leaving room for a null */
1477
cc192b50 1478 len = comm_udp_recvfrom(fd, buf, sizeof(buf) - 1, 0, from);
1479
1480 debugs(31, 3, "htcpRecv: FD " << fd << ", " << len << " bytes from " << from );
c4ebc830 1481
1482 if (len)
1483 statCounter.htcp.pkts_recv++;
1484
56deee1e 1485 htcpHandleMsg(buf, len, from);
c4ebc830 1486
eb9ae2f7 1487 commSetSelect(fd, COMM_SELECT_READ, htcpRecv, NULL, 0);
1488}
1489
56714a1a 1490/*
1491 * ======================================================================
1492 * PUBLIC FUNCTIONS
1493 * ======================================================================
1494 */
1495
d5d466fc 1496void
1497htcpInit(void)
3340a3e6 1498{
775fa4ba 1499 if (Config.Port.htcp <= 0) {
bf8fe701 1500 debugs(31, 1, "HTCP Disabled.");
62e76326 1501 return;
775fa4ba 1502 }
9e54a52f 1503
b7ac5457 1504 Ip::Address incomingAddr = Config.Addrs.udp_incoming;
9e54a52f 1505 incomingAddr.SetPort(Config.Port.htcp);
62e76326 1506
e0f8b709
AJ
1507 if (!Ip::EnableIpv6 && !incomingAddr.SetIPv4()) {
1508 debugs(31, DBG_CRITICAL, "ERROR: IPv6 is disabled. " << incomingAddr << " is not an IPv4 address.");
1509 fatal("HTCP port cannot be opened.");
1510 }
e0209dae
AJ
1511 /* split-stack for now requires default IPv4-only HTCP */
1512 if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && incomingAddr.IsAnyAddr()) {
1513 incomingAddr.SetIPv4();
1514 }
e0f8b709 1515
013e320c 1516 AsyncCall::Pointer call = asyncCall(31, 2,
5667a628
AR
1517 "htcpIncomingConnectionOpened",
1518 HtcpListeningStartedDialer(&htcpIncomingConnectionOpened));
62e76326 1519
013e320c 1520 Ipc::StartListening(SOCK_DGRAM,
5667a628
AR
1521 IPPROTO_UDP,
1522 incomingAddr,
1523 COMM_NONBLOCKING,
1524 Ipc::fdnInHtcpSocket, call);
62e76326 1525
cc192b50 1526 if (!Config.Addrs.udp_outgoing.IsNoAddr()) {
b7ac5457 1527 Ip::Address outgoingAddr = Config.Addrs.udp_outgoing;
9e54a52f
AR
1528 outgoingAddr.SetPort(Config.Port.htcp);
1529
e0f8b709
AJ
1530 if (!Ip::EnableIpv6 && !outgoingAddr.SetIPv4()) {
1531 debugs(31, DBG_CRITICAL, "ERROR: IPv6 is disabled. " << outgoingAddr << " is not an IPv4 address.");
1532 fatal("HTCP port cannot be opened.");
1533 }
e0209dae
AJ
1534 /* split-stack for now requires default IPv4-only HTCP */
1535 if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && outgoingAddr.IsAnyAddr()) {
1536 outgoingAddr.SetIPv4();
1537 }
1538
62e76326 1539 enter_suid();
31be869c 1540 htcpOutSocket = comm_open_listener(SOCK_DGRAM,
04f7fd38
AJ
1541 IPPROTO_UDP,
1542 outgoingAddr,
1543 COMM_NONBLOCKING,
1544 "Outgoing HTCP Socket");
62e76326 1545 leave_suid();
1546
1547 if (htcpOutSocket < 0)
1548 fatal("Cannot open Outgoing HTCP Socket");
1549
1550 commSetSelect(htcpOutSocket, COMM_SELECT_READ, htcpRecv, NULL, 0);
1551
4a7a3d56 1552 debugs(31, 1, "Outgoing HTCP messages on port " << Config.Port.htcp << ", FD " << htcpOutSocket << ".");
62e76326 1553
1554 fd_note(htcpInSocket, "Incoming HTCP socket");
d5d466fc 1555 }
62e76326 1556
e6ccf245 1557 if (!htcpDetailPool) {
04eb0689 1558 htcpDetailPool = memPoolCreate("htcpDetail", sizeof(htcpDetail));
675f3dff 1559 }
59c4d35b 1560}
72549e05 1561
013e320c
AR
1562static void
1563htcpIncomingConnectionOpened(int fd, int errNo)
1564{
1565 htcpInSocket = fd;
1566
1567 if (htcpInSocket < 0)
1568 fatal("Cannot open HTCP Socket");
1569
1570 commSetSelect(htcpInSocket, COMM_SELECT_READ, htcpRecv, NULL, 0);
1571
1572 debugs(31, 1, "Accepting HTCP messages on port " << Config.Port.htcp << ", FD " << htcpInSocket << ".");
1573
1574 if (Config.Addrs.udp_outgoing.IsNoAddr())
1575 htcpOutSocket = htcpInSocket;
1576}
1577
bebf08ff 1578int
190154cf 1579htcpQuery(StoreEntry * e, HttpRequest * req, peer * p)
56714a1a 1580{
26df9ec6 1581 cache_key *save_key;
5401aa8d 1582 static char pkt[8192];
56714a1a 1583 ssize_t pktlen;
1584 char vbuf[32];
1585 htcpStuff stuff;
75faaa7a 1586 HttpHeader hdr(hoRequest);
56714a1a 1587 Packer pa;
1588 MemBuf mb;
9c48373d 1589 http_state_flags flags;
775fa4ba 1590
1591 if (htcpInSocket < 0)
bebf08ff 1592 return 0;
775fa4ba 1593
527ee50d 1594 old_squid_format = p->options.htcp_oldsquid;
9c48373d 1595 memset(&flags, '\0', sizeof(flags));
7af0a8e6 1596 snprintf(vbuf, sizeof(vbuf), "%d/%d",
62e76326 1597 req->http_ver.major, req->http_ver.minor);
56714a1a 1598 stuff.op = HTCP_TST;
1599 stuff.rr = RR_REQUEST;
1600 stuff.f1 = 1;
1601 stuff.response = 0;
26df9ec6 1602 stuff.msg_id = ++msg_id_counter;
60745f24 1603 stuff.S.method = (char *) RequestMethodStr(req->method);
3900307b 1604 stuff.S.uri = (char *) e->url();
a2edf5dc 1605 stuff.S.version = vbuf;
3b0d7130 1606 HttpStateData::httpBuildRequestHeader(req, req, e, &hdr, flags);
2fe7eff9 1607 mb.init();
56714a1a 1608 packerToMemInit(&pa, &mb);
61f4f11b 1609 hdr.packInto(&pa);
519e0948 1610 hdr.clean();
56714a1a 1611 packerClean(&pa);
a2edf5dc 1612 stuff.S.req_hdrs = mb.buf;
5401aa8d 1613 pktlen = htcpBuildPacket(pkt, sizeof(pkt), &stuff);
2fe7eff9 1614 mb.clean();
5401aa8d 1615 if (!pktlen) {
56deee1e 1616 debugs(31, 3, "htcpQuery: htcpBuildPacket() failed");
bebf08ff 1617 return -1;
56714a1a 1618 }
26ac0430 1619
cc192b50 1620 htcpSend(pkt, (int) pktlen, p->in_addr);
1621
5401aa8d 1622 queried_id[stuff.msg_id % N_QUERIED_KEYS] = stuff.msg_id;
26df9ec6 1623 save_key = queried_keys[stuff.msg_id % N_QUERIED_KEYS];
332dafa2 1624 storeKeyCopy(save_key, (const cache_key *)e->key);
5401aa8d 1625 queried_addr[stuff.msg_id % N_QUERIED_KEYS] = p->in_addr;
bf8fe701 1626 debugs(31, 3, "htcpQuery: key (" << save_key << ") " << storeKeyText(save_key));
bebf08ff
AJ
1627
1628 return 1;
56714a1a 1629}
1630
1bd06eff
BR
1631/*
1632 * Send an HTCP CLR message for a specified item to a given peer.
1633 */
4f4fa815 1634void
8dceeee3 1635htcpClear(StoreEntry * e, const char *uri, HttpRequest * req, const HttpRequestMethod &method, peer * p, htcp_clr_reason reason)
4f4fa815
BR
1636{
1637 static char pkt[8192];
1638 ssize_t pktlen;
1639 char vbuf[32];
1640 htcpStuff stuff;
bb7c31c8 1641 HttpHeader hdr(hoRequest);
4f4fa815
BR
1642 Packer pa;
1643 MemBuf mb;
1644 http_state_flags flags;
1645
1646 if (htcpInSocket < 0)
30fca662 1647 return;
4f4fa815
BR
1648
1649 old_squid_format = p->options.htcp_oldsquid;
1650 memset(&flags, '\0', sizeof(flags));
1651 snprintf(vbuf, sizeof(vbuf), "%d/%d",
26ac0430 1652 req->http_ver.major, req->http_ver.minor);
4f4fa815
BR
1653 stuff.op = HTCP_CLR;
1654 stuff.rr = RR_REQUEST;
1655 stuff.f1 = 0;
1656 stuff.response = 0;
1657 stuff.msg_id = ++msg_id_counter;
1658 switch (reason) {
1659 case HTCP_CLR_INVALIDATION:
26ac0430
AJ
1660 stuff.reason = 1;
1661 break;
4f4fa815 1662 default:
26ac0430
AJ
1663 stuff.reason = 0;
1664 break;
4f4fa815
BR
1665 }
1666 stuff.S.method = (char *) RequestMethodStr(req->method);
1667 if (e == NULL || e->mem_obj == NULL) {
26ac0430 1668 if (uri == NULL) {
4f4fa815 1669 return;
26ac0430
AJ
1670 }
1671 stuff.S.uri = xstrdup(uri);
4f4fa815 1672 } else {
26ac0430 1673 stuff.S.uri = (char *) e->url();
4f4fa815
BR
1674 }
1675 stuff.S.version = vbuf;
1676 if (reason != HTCP_CLR_INVALIDATION) {
1677 HttpStateData::httpBuildRequestHeader(req, req, e, &hdr, flags);
1678 mb.init();
1679 packerToMemInit(&pa, &mb);
1680 hdr.packInto(&pa);
1681 hdr.clean();
1682 packerClean(&pa);
26ac0430 1683 stuff.S.req_hdrs = mb.buf;
8dceeee3
BR
1684 } else {
1685 stuff.S.req_hdrs = NULL;
4f4fa815
BR
1686 }
1687 pktlen = htcpBuildPacket(pkt, sizeof(pkt), &stuff);
1688 if (reason != HTCP_CLR_INVALIDATION) {
1689 mb.clean();
1690 }
1691 if (e == NULL) {
26ac0430 1692 xfree(stuff.S.uri);
4f4fa815
BR
1693 }
1694 if (!pktlen) {
26ac0430
AJ
1695 debugs(31, 3, "htcpClear: htcpBuildPacket() failed");
1696 return;
4f4fa815 1697 }
26ac0430 1698
4f4fa815
BR
1699 htcpSend(pkt, (int) pktlen, p->in_addr);
1700}
1701
62e76326 1702/*
72549e05 1703 * htcpSocketShutdown only closes the 'in' socket if it is
1704 * different than the 'out' socket.
1afe05c5 1705 */
72549e05 1706void
1707htcpSocketShutdown(void)
1afe05c5 1708{
72549e05 1709 if (htcpInSocket < 0)
62e76326 1710 return;
1711
1afe05c5 1712 if (htcpInSocket != htcpOutSocket) {
bf8fe701 1713 debugs(12, 1, "FD " << htcpInSocket << " Closing HTCP socket");
62e76326 1714 comm_close(htcpInSocket);
1afe05c5 1715 }
62e76326 1716
1717 /*
72549e05 1718 * Here we set 'htcpInSocket' to -1 even though the HTCP 'in'
1719 * and 'out' sockets might be just one FD. This prevents this
1720 * function from executing repeatedly. When we are really ready to
1721 * exit or restart, main will comm_close the 'out' descriptor.
1afe05c5 1722 */
72549e05 1723 htcpInSocket = -1;
62e76326 1724
1725 /*
72549e05 1726 * Normally we only write to the outgoing HTCP socket, but
1727 * we also have a read handler there to catch messages sent
1728 * to that specific interface. During shutdown, we must
1729 * disable reading on the outgoing socket.
1afe05c5 1730 */
675f3dff 1731 /* XXX Don't we need this handler to read replies while shutting down?
1732 * I think there should be a separate hander for reading replies..
1733 */
72549e05 1734 assert(htcpOutSocket > -1);
62e76326 1735
72549e05 1736 commSetSelect(htcpOutSocket, COMM_SELECT_READ, NULL, NULL, 0);
1737}
1738
1afe05c5 1739void
72549e05 1740htcpSocketClose(void)
1741{
1742 htcpSocketShutdown();
62e76326 1743
72549e05 1744 if (htcpOutSocket > -1) {
bf8fe701 1745 debugs(12, 1, "FD " << htcpOutSocket << " Closing HTCP socket");
62e76326 1746 comm_close(htcpOutSocket);
1747 htcpOutSocket = -1;
1afe05c5 1748 }
1749}
a8b1cdf6
AJ
1750
1751static void
b7ac5457 1752htcpLogHtcp(Ip::Address &caddr, int opcode, log_type logcode, const char *url)
a8b1cdf6
AJ
1753{
1754 AccessLogEntry al;
1755 if (LOG_TAG_NONE == logcode)
04f7fd38 1756 return;
a8b1cdf6 1757 if (!Config.onoff.log_udp)
04f7fd38 1758 return;
a8b1cdf6
AJ
1759 al.htcp.opcode = htcpOpcodeStr[opcode];
1760 al.url = url;
1761 al.cache.caddr = caddr;
1762 al.cache.code = logcode;
1763 al.cache.msec = 0;
1764 accessLogLog(&al, NULL);
1765}