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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors