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