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