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"
25 #include "HttpRequest.h"
26 #include "icmp/net_db.h"
27 #include "ip/tools.h"
28 #include "md5.h"
29 #include "mem/forward.h"
30 #include "MemBuf.h"
31 #include "refresh.h"
32 #include "SquidConfig.h"
33 #include "SquidTime.h"
34 #include "StatCounters.h"
35 #include "Store.h"
36 #include "store_key_md5.h"
37 #include "StoreClient.h"
38 #include "tools.h"
39 
40 typedef struct _Countstr Countstr;
41 
42 typedef struct _htcpHeader htcpHeader;
43 
45 
47 
49 
50 struct _Countstr {
51  uint16_t length;
52  char *text;
53 };
54 
55 struct _htcpHeader {
56  uint16_t length;
57  u_char major;
58  u_char minor;
59 };
60 
62  uint16_t length;
63 
64 #if !WORDS_BIGENDIAN
65  unsigned int opcode:4;
66  unsigned int response:4;
67 #else
68  unsigned int response:4;
69  unsigned int opcode:4;
70 #endif
71 
72 #if !WORDS_BIGENDIAN
73  unsigned int reserved:6;
74  unsigned int F1:1;
75  unsigned int RR:1;
76 #else
77  unsigned int RR:1;
78  unsigned int F1:1;
79  unsigned int reserved:6;
80 #endif
81 
82  uint32_t msg_id;
83 };
84 
86  uint16_t length;
87 
88 #if WORDS_BIGENDIAN
89  uint8_t opcode:4;
90  uint8_t response:4;
91 #else
92  uint8_t response:4;
93  uint8_t opcode:4;
94 #endif
95 
96 #if WORDS_BIGENDIAN
97  uint8_t reserved:6;
98  uint8_t F1:1;
99  uint8_t RR:1;
100 #else
101  uint8_t RR:1;
102  uint8_t F1:1;
103  uint8_t reserved:6;
104 #endif
105 
106  uint32_t msg_id;
107 };
108 
109 /* RR == 0 --> F1 = RESPONSE DESIRED FLAG */
110 /* RR == 1 --> F1 = MESSAGE OVERALL FLAG */
111 /* RR == 0 --> REQUEST */
112 /* RR == 1 --> RESPONSE */
113 
115  uint16_t length;
116  time_t sig_time;
117  time_t sig_expire;
120 };
121 
122 class htcpSpecifier : public RefCountable, public StoreClient
123 {
125 
126 public:
128 
129  void checkHit();
130  void checkedHit(StoreEntry *);
131 
132  void setFrom(Ip::Address &anIp) { from = anIp; }
133  void setDataHeader(htcpDataHeader *aDataHeader) {
134  dhdr = aDataHeader;
135  }
136 
137  /* StoreClient API */
138  void created(StoreEntry *);
139  virtual LogTags *loggingTags();
140  virtual void fillChecklist(ACLFilledChecklist &) const;
141 
142 public:
143  const char *method = nullptr;
144  char *uri = nullptr;
145  char *version = nullptr;
146  char *req_hdrs = nullptr;
147  size_t reqHdrsSz = 0;
149 
152 
153 private:
155 
157  htcpDataHeader *dhdr = nullptr;
158 };
159 
161 {
163 public:
164  char *resp_hdrs = nullptr;
165  size_t respHdrsSz = 0;
166 
167  char *entity_hdrs = nullptr;
168  size_t entityHdrsSz = 0;
169 
170  char *cache_hdrs = nullptr;
171  size_t cacheHdrsSz = 0;
172 };
173 
175 {
176 public:
177  htcpStuff(uint32_t id, int o, int r, int f) :
178  op(o),
179  rr(r),
180  f1(f),
181  msg_id(id)
182  {}
183 
184  int op = 0;
185  int rr = 0;
186  int f1 = 0;
187  int response = 0;
188  int reason = 0;
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 &, const int, const LogTags_ot, 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, const int opcode, const char *url)
272 {
273  if (!al)
274  al = new AccessLogEntry();
275  al->cache.caddr = caddr;
276  al->htcp.opcode = htcpOpcodeStr[opcode];
277  al->url = url;
278  al->setVirginUrlForMissingRequest(al->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");
924  checkedHit(nullptr);
925  return;
926  }
927 
929  debugs(31, 3, "htcpCheckHit: NO; failed to parse request headers");
930  checkHitRequest = nullptr;
931  checkedHit(nullptr);
932  return;
933  }
934 
936 }
937 
938 void
940 {
941  StoreEntry *hit = nullptr;
942 
943  if (!e) {
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->hittingRequiresCollapsing() && !startCollapsingOn(*e, false)) {
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)
960  // e->abandon();
961 }
962 
963 LogTags *
965 {
966  // calling htcpSyncAle() here would not change cache.code
967  if (!al)
968  al = new AccessLogEntry();
969  return &al->cache.code;
970 }
971 
972 void
974 {
975  checklist.setRequest(request.getRaw());
977  checklist.al = al;
978 }
979 
980 static void
982 {
983  debugs(31, 4, "htcpClrStoreEntry: Clearing store for entry: " << e->url() );
984  e->releaseRequest();
985 }
986 
987 static int
989 {
990  HttpRequestPointer request(s->request);
991  if (!request) {
992  debugs(31, 3, "htcpClrStore: failed to parse URL");
993  return -1;
994  }
995 
996  /* Parse request headers */
997  if (!request->parseHeader(s->req_hdrs, s->reqHdrsSz)) {
998  debugs(31, 2, "htcpClrStore: failed to parse request headers");
999  return -1;
1000  }
1001 
1002  StoreEntry *e = nullptr;
1003  int released = 0;
1004  /* Lookup matching entries. This matches both GET and HEAD */
1005  while ((e = storeGetPublicByRequest(request.getRaw()))) {
1006  htcpClrStoreEntry(e);
1007  ++released;
1008  }
1009 
1010  if (released) {
1011  debugs(31, 4, "htcpClrStore: Cleared " << released << " matching entries");
1012  return 1;
1013  } else {
1014  debugs(31, 4, "htcpClrStore: No matching entry found");
1015  return 0;
1016  }
1017 }
1018 
1019 static void
1020 
1021 htcpHandleTst(htcpDataHeader * hdr, char *buf, int sz, Ip::Address &from)
1022 {
1023  debugs(31, 3, "htcpHandleTst: sz = " << sz);
1024 
1025  if (hdr->RR == RR_REQUEST)
1026  htcpHandleTstRequest(hdr, buf, sz, from);
1027  else
1028  htcpHandleTstResponse(hdr, buf, sz, from);
1029 }
1030 
1032  hit(0), hdr(hoHtcpReply), msg_id(0), version(0.0)
1033 {
1034  memset(&cto, 0, sizeof(cto));
1035 }
1036 
1037 bool
1038 HtcpReplyData::parseHeader(const char *buffer, const size_t size)
1039 {
1040  Http::ContentLengthInterpreter interpreter;
1041  // no applyStatusCodeRules() -- HTCP replies lack cached HTTP status code
1042  return hdr.parse(buffer, size, interpreter);
1043 }
1044 
1045 static void
1046 
1048 {
1049  HtcpReplyData htcpReply;
1050  cache_key *key = NULL;
1051 
1052  Ip::Address *peer;
1053  htcpDetail *d = NULL;
1054  char *t;
1055 
1056  if (queried_id[hdr->msg_id % N_QUERIED_KEYS] != hdr->msg_id) {
1057  debugs(31, 2, "htcpHandleTstResponse: No matching query id '" <<
1058  hdr->msg_id << "' (expected " <<
1059  queried_id[hdr->msg_id % N_QUERIED_KEYS] << ") from '" <<
1060  from << "'");
1061 
1062  return;
1063  }
1064 
1065  key = queried_keys[hdr->msg_id % N_QUERIED_KEYS];
1066 
1067  if (!key) {
1068  debugs(31, 3, "htcpHandleTstResponse: No query key for response id '" << hdr->msg_id << "' from '" << from << "'");
1069  return;
1070  }
1071 
1072  peer = &queried_addr[hdr->msg_id % N_QUERIED_KEYS];
1073 
1074  if ( *peer != from || peer->port() != from.port() ) {
1075  debugs(31, 3, "htcpHandleTstResponse: Unexpected response source " << from );
1076  return;
1077  }
1078 
1079  if (hdr->F1 == 1) {
1080  debugs(31, 2, "htcpHandleTstResponse: error condition, F1/MO == 1");
1081  return;
1082  }
1083 
1084  htcpReply.msg_id = hdr->msg_id;
1085  debugs(31, 3, "htcpHandleTstResponse: msg_id = " << htcpReply.msg_id);
1086  htcpReply.hit = hdr->response ? 0 : 1;
1087 
1088  if (hdr->F1) {
1089  debugs(31, 3, "htcpHandleTstResponse: MISS");
1090  } else {
1091  debugs(31, 3, "htcpHandleTstResponse: HIT");
1092  d = htcpUnpackDetail(buf, sz);
1093 
1094  if (d == NULL) {
1095  debugs(31, 3, "htcpHandleTstResponse: bad DETAIL");
1096  return;
1097  }
1098 
1099  if ((t = d->resp_hdrs))
1100  htcpReply.parseHeader(t, d->respHdrsSz);
1101 
1102  if ((t = d->entity_hdrs))
1103  htcpReply.parseHeader(t, d->entityHdrsSz);
1104 
1105  if ((t = d->cache_hdrs))
1106  htcpReply.parseHeader(t, d->cacheHdrsSz);
1107  }
1108 
1109  debugs(31, 3, "htcpHandleTstResponse: key (" << key << ") " << storeKeyText(key));
1110  neighborsHtcpReply(key, &htcpReply, from);
1111  htcpReply.hdr.clean();
1112 
1113  delete d;
1114 }
1115 
1116 static void
1118 {
1119  if (sz == 0) {
1120  debugs(31, 3, "htcpHandleTst: nothing to do");
1121  return;
1122  }
1123 
1124  if (dhdr->F1 == 0)
1125  return;
1126 
1127  /* buf should be a SPECIFIER */
1129 
1130  if (!s) {
1131  debugs(31, 3, "htcpHandleTstRequest: htcpUnpackSpecifier failed");
1132  htcpLogHtcp(from, dhdr->opcode, LOG_UDP_INVALID, dash_str, nullptr);
1133  return;
1134  } else {
1135  s->setFrom(from);
1136  s->setDataHeader(dhdr);
1137  }
1138 
1139  if (!s->request) {
1140  debugs(31, 3, "htcpHandleTstRequest: failed to parse request");
1141  htcpLogHtcp(from, dhdr->opcode, LOG_UDP_INVALID, dash_str, s->al);
1142  return;
1143  }
1144 
1145  if (!htcpAccessAllowed(Config.accessList.htcp, s, from)) {
1146  debugs(31, 3, "htcpHandleTstRequest: Access denied");
1147  htcpLogHtcp(from, dhdr->opcode, LOG_UDP_DENIED, s->uri, s->al);
1148  return;
1149  }
1150 
1151  debugs(31, 2, "HTCP TST request: " << s->method << " " << s->uri << " " << s->version);
1152  debugs(31, 2, "HTCP TST headers: " << s->req_hdrs);
1153  s->checkHit();
1154 }
1155 
1156 void
1158 {
1159  if (e) {
1160  htcpTstReply(dhdr, e, this, from); /* hit */
1162  } else {
1163  htcpTstReply(dhdr, NULL, NULL, from); /* cache miss */
1165  }
1166 }
1167 
1168 static void
1169 htcpHandleClr(htcpDataHeader * hdr, char *buf, int sz, Ip::Address &from)
1170 {
1171  /* buf[0/1] is reserved and reason */
1172  int reason = buf[1] << 4;
1173  debugs(31, 2, "HTCP CLR reason: " << reason);
1174  buf += 2;
1175  sz -= 2;
1176 
1177  /* buf should be a SPECIFIER */
1178 
1179  if (sz == 0) {
1180  debugs(31, 4, "htcpHandleClr: nothing to do");
1181  htcpLogHtcp(from, hdr->opcode, LOG_UDP_INVALID, dash_str, nullptr);
1182  return;
1183  }
1184 
1186 
1187  if (!s) {
1188  debugs(31, 3, "htcpHandleClr: htcpUnpackSpecifier failed");
1189  htcpLogHtcp(from, hdr->opcode, LOG_UDP_INVALID, dash_str, nullptr);
1190  return;
1191  } else {
1192  s->setFrom(from);
1193  s->setDataHeader(hdr);
1194  }
1195 
1196  if (!s->request) {
1197  debugs(31, 3, "htcpHandleTstRequest: failed to parse request");
1198  htcpLogHtcp(from, hdr->opcode, LOG_UDP_INVALID, dash_str, s->al);
1199  return;
1200  }
1201 
1202  if (!htcpAccessAllowed(Config.accessList.htcp_clr, s, from)) {
1203  debugs(31, 3, "htcpHandleClr: Access denied");
1204  htcpLogHtcp(from, hdr->opcode, LOG_UDP_DENIED, s->uri, s->al);
1205  return;
1206  }
1207 
1208  debugs(31, 2, "HTCP CLR request: " << s->method << " " << s->uri << " " << s->version);
1209  debugs(31, 2, "HTCP CLR headers: " << s->req_hdrs);
1210 
1211  /* Release objects from cache
1212  * analog to clientPurgeRequest in client_side.c
1213  */
1214 
1215  switch (htcpClrStore(s)) {
1216 
1217  case 1:
1218  htcpClrReply(hdr, 1, from); /* hit */
1219  htcpLogHtcp(from, hdr->opcode, LOG_UDP_HIT, s->uri, s->al);
1220  break;
1221 
1222  case 0:
1223  htcpClrReply(hdr, 0, from); /* miss */
1224  htcpLogHtcp(from, hdr->opcode, LOG_UDP_MISS, s->uri, s->al);
1225  break;
1226 
1227  default:
1228  break;
1229  }
1230 }
1231 
1232 /*
1233  * Forward a CLR request to all peers who have requested that CLRs be
1234  * forwarded to them.
1235  */
1236 static void
1237 htcpForwardClr(char *buf, int sz)
1238 {
1239  CachePeer *p;
1240 
1241  for (p = Config.peers; p; p = p->next) {
1242  if (!p->options.htcp) {
1243  continue;
1244  }
1245  if (!p->options.htcp_forward_clr) {
1246  continue;
1247  }
1248 
1249  htcpSend(buf, sz, p->in_addr);
1250  }
1251 }
1252 
1253 /*
1254  * Do the first pass of handling an HTCP message. This used to be two
1255  * separate functions, htcpHandle and htcpHandleData. They were merged to
1256  * allow for forwarding HTCP packets easily to other peers if desired.
1257  *
1258  * This function now works out what type of message we have received and then
1259  * hands it off to other functions to break apart message-specific data.
1260  */
1261 static void
1262 htcpHandleMsg(char *buf, int sz, Ip::Address &from)
1263 {
1264  htcpHeader htcpHdr;
1265  htcpDataHeader hdr;
1266  char *hbuf;
1267  int hsz;
1268 
1269  if (sz < 0 || (size_t)sz < sizeof(htcpHeader)) {
1270  // These are highly likely to be attack packets. Should probably get a bigger warning.
1271  debugs(31, 2, "htcpHandle: msg size less than htcpHeader size from " << from);
1272  return;
1273  }
1274 
1275  htcpHexdump("htcpHandle", buf, sz);
1276  memcpy(&htcpHdr, buf, sizeof(htcpHeader));
1277  htcpHdr.length = ntohs(htcpHdr.length);
1278 
1279  if (htcpHdr.minor == 0)
1280  old_squid_format = 1;
1281  else
1282  old_squid_format = 0;
1283 
1284  debugs(31, 3, "htcpHandle: htcpHdr.length = " << htcpHdr.length);
1285  debugs(31, 3, "htcpHandle: htcpHdr.major = " << htcpHdr.major);
1286  debugs(31, 3, "htcpHandle: htcpHdr.minor = " << htcpHdr.minor);
1287 
1288  if (sz != htcpHdr.length) {
1289  debugs(31, 3, "htcpHandle: sz/" << sz << " != htcpHdr.length/" <<
1290  htcpHdr.length << " from " << from );
1291 
1292  return;
1293  }
1294 
1295  if (htcpHdr.major != 0) {
1296  debugs(31, 3, "htcpHandle: Unknown major version " << htcpHdr.major << " from " << from );
1297 
1298  return;
1299  }
1300 
1301  hbuf = buf + sizeof(htcpHeader);
1302  hsz = sz - sizeof(htcpHeader);
1303 
1304  if ((size_t)hsz < sizeof(htcpDataHeader)) {
1305  debugs(31, 3, "htcpHandleData: msg size less than htcpDataHeader size");
1306  return;
1307  }
1308 
1309  if (!old_squid_format) {
1310  memcpy(&hdr, hbuf, sizeof(hdr));
1311  } else {
1312  htcpDataHeaderSquid hdrSquid;
1313  memcpy(&hdrSquid, hbuf, sizeof(hdrSquid));
1314  hdr.length = hdrSquid.length;
1315  hdr.opcode = hdrSquid.opcode;
1316  hdr.response = hdrSquid.response;
1317  hdr.F1 = hdrSquid.F1;
1318  hdr.RR = hdrSquid.RR;
1319  hdr.reserved = 0;
1320  hdr.msg_id = hdrSquid.msg_id;
1321  }
1322 
1323  hdr.length = ntohs(hdr.length);
1324  hdr.msg_id = ntohl(hdr.msg_id);
1325  debugs(31, 3, "htcpHandleData: hsz = " << hsz);
1326  debugs(31, 3, "htcpHandleData: length = " << hdr.length);
1327 
1328  if (hdr.opcode >= HTCP_END) {
1329  debugs(31, 3, "htcpHandleData: client " << from << ", opcode " << hdr.opcode << " out of range");
1330  return;
1331  }
1332 
1333  debugs(31, 3, "htcpHandleData: opcode = " << hdr.opcode << " " << htcpOpcodeStr[hdr.opcode]);
1334  debugs(31, 3, "htcpHandleData: response = " << hdr.response);
1335  debugs(31, 3, "htcpHandleData: F1 = " << hdr.F1);
1336  debugs(31, 3, "htcpHandleData: RR = " << hdr.RR);
1337  debugs(31, 3, "htcpHandleData: msg_id = " << hdr.msg_id);
1338 
1339  if (hsz < hdr.length) {
1340  debugs(31, 3, "htcpHandleData: sz < hdr.length");
1341  return;
1342  }
1343 
1344  /*
1345  * set sz = hdr.length so we ignore any AUTH fields following
1346  * the DATA.
1347  */
1348  hsz = (int) hdr.length;
1349  hbuf += sizeof(htcpDataHeader);
1350  hsz -= sizeof(htcpDataHeader);
1351  debugs(31, 3, "htcpHandleData: hsz = " << hsz);
1352 
1353  htcpHexdump("htcpHandleData", hbuf, hsz);
1354 
1355  switch (hdr.opcode) {
1356  case HTCP_NOP:
1357  debugs(31, 3, "HTCP NOP not implemented");
1358  break;
1359  case HTCP_TST:
1360  htcpHandleTst(&hdr, hbuf, hsz, from);
1361  break;
1362  case HTCP_MON:
1363  debugs(31, 3, "HTCP MON not implemented");
1364  break;
1365  case HTCP_SET:
1366  debugs(31, 3, "HTCP SET not implemented");
1367  break;
1368  case HTCP_CLR:
1369  htcpHandleClr(&hdr, hbuf, hsz, from);
1370  htcpForwardClr(buf, sz);
1371  break;
1372  default:
1373  break;
1374  }
1375 }
1376 
1377 static void
1378 htcpRecv(int fd, void *)
1379 {
1380  static char buf[8192];
1381  int len;
1382  static Ip::Address from;
1383 
1384  /* Receive up to 8191 bytes, leaving room for a null */
1385 
1386  len = comm_udp_recvfrom(fd, buf, sizeof(buf) - 1, 0, from);
1387 
1388  debugs(31, 3, "htcpRecv: FD " << fd << ", " << len << " bytes from " << from );
1389 
1390  if (len)
1392 
1393  htcpHandleMsg(buf, len, from);
1394 
1396 }
1397 
1398 /*
1399  * ======================================================================
1400  * PUBLIC FUNCTIONS
1401  * ======================================================================
1402  */
1403 
1404 void
1406 {
1407  if (Config.Port.htcp <= 0) {
1408  debugs(31, DBG_IMPORTANT, "HTCP Disabled.");
1409  return;
1410  }
1411 
1412  htcpIncomingConn = new Comm::Connection;
1413  htcpIncomingConn->local = Config.Addrs.udp_incoming;
1414  htcpIncomingConn->local.port(Config.Port.htcp);
1415 
1416  if (!Ip::EnableIpv6 && !htcpIncomingConn->local.setIPv4()) {
1417  debugs(31, DBG_CRITICAL, "ERROR: IPv6 is disabled. " << htcpIncomingConn->local << " is not an IPv4 address.");
1418  fatal("HTCP port cannot be opened.");
1419  }
1420  /* split-stack for now requires default IPv4-only HTCP */
1421  if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && htcpIncomingConn->local.isAnyAddr()) {
1422  htcpIncomingConn->local.setIPv4();
1423  }
1424 
1425  AsyncCall::Pointer call = asyncCall(31, 2,
1426  "htcpIncomingConnectionOpened",
1428 
1429  Ipc::StartListening(SOCK_DGRAM,
1430  IPPROTO_UDP,
1431  htcpIncomingConn,
1432  Ipc::fdnInHtcpSocket, call);
1433 
1434  if (!Config.Addrs.udp_outgoing.isNoAddr()) {
1435  htcpOutgoingConn = new Comm::Connection;
1436  htcpOutgoingConn->local = Config.Addrs.udp_outgoing;
1437  htcpOutgoingConn->local.port(Config.Port.htcp);
1438 
1439  if (!Ip::EnableIpv6 && !htcpOutgoingConn->local.setIPv4()) {
1440  debugs(31, DBG_CRITICAL, "ERROR: IPv6 is disabled. " << htcpOutgoingConn->local << " is not an IPv4 address.");
1441  fatal("HTCP port cannot be opened.");
1442  }
1443  /* split-stack for now requires default IPv4-only HTCP */
1444  if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && htcpOutgoingConn->local.isAnyAddr()) {
1445  htcpOutgoingConn->local.setIPv4();
1446  }
1447 
1448  enter_suid();
1449  comm_open_listener(SOCK_DGRAM, IPPROTO_UDP, htcpOutgoingConn, "Outgoing HTCP Socket");
1450  leave_suid();
1451 
1452  if (!Comm::IsConnOpen(htcpOutgoingConn))
1453  fatal("Cannot open Outgoing HTCP Socket");
1454 
1455  Comm::SetSelect(htcpOutgoingConn->fd, COMM_SELECT_READ, htcpRecv, NULL, 0);
1456 
1457  debugs(31, DBG_IMPORTANT, "Sending HTCP messages from " << htcpOutgoingConn->local);
1458  }
1459 
1460 }
1461 
1462 static void
1464 {
1465  if (!Comm::IsConnOpen(conn))
1466  fatal("Cannot open HTCP Socket");
1467 
1469 
1470  debugs(31, DBG_CRITICAL, "Accepting HTCP messages on " << conn->local);
1471 
1473  htcpOutgoingConn = conn;
1474  debugs(31, DBG_IMPORTANT, "Sending HTCP messages from " << htcpOutgoingConn->local);
1475  }
1476 }
1477 
1478 int
1480 {
1481  cache_key *save_key;
1482  static char pkt[8192];
1483  ssize_t pktlen;
1484  char vbuf[32];
1485  HttpHeader hdr(hoRequest);
1486  Http::StateFlags flags;
1487 
1488  if (!Comm::IsConnOpen(htcpIncomingConn))
1489  return 0;
1490 
1492  snprintf(vbuf, sizeof(vbuf), "%d/%d",
1493  req->http_ver.major, req->http_ver.minor);
1494 
1496  SBuf sb = req->method.image();
1497  stuff.S.method = sb.c_str();
1498  stuff.S.uri = (char *) e->url();
1499  stuff.S.version = vbuf;
1500  HttpStateData::httpBuildRequestHeader(req, e, NULL, &hdr, flags);
1501  MemBuf mb;
1502  mb.init();
1503  hdr.packInto(&mb);
1504  hdr.clean();
1505  stuff.S.req_hdrs = mb.buf;
1506  pktlen = htcpBuildPacket(pkt, sizeof(pkt), &stuff);
1507  mb.clean();
1508  if (!pktlen) {
1509  debugs(31, 3, "htcpQuery: htcpBuildPacket() failed");
1510  return -1;
1511  }
1512 
1513  htcpSend(pkt, (int) pktlen, p->in_addr);
1514 
1515  queried_id[stuff.msg_id % N_QUERIED_KEYS] = stuff.msg_id;
1516  save_key = queried_keys[stuff.msg_id % N_QUERIED_KEYS];
1517  storeKeyCopy(save_key, (const cache_key *)e->key);
1518  queried_addr[stuff.msg_id % N_QUERIED_KEYS] = p->in_addr;
1519  debugs(31, 3, "htcpQuery: key (" << save_key << ") " << storeKeyText(save_key));
1520 
1521  return 1;
1522 }
1523 
1524 /*
1525  * Send an HTCP CLR message for a specified item to a given CachePeer.
1526  */
1527 void
1528 htcpClear(StoreEntry * e, const char *uri, HttpRequest * req, const HttpRequestMethod &, CachePeer * p, htcp_clr_reason reason)
1529 {
1530  static char pkt[8192];
1531  ssize_t pktlen;
1532  char vbuf[32];
1533  HttpHeader hdr(hoRequest);
1534  MemBuf mb;
1535  Http::StateFlags flags;
1536 
1537  if (!Comm::IsConnOpen(htcpIncomingConn))
1538  return;
1539 
1541  snprintf(vbuf, sizeof(vbuf), "%d/%d",
1542  req->http_ver.major, req->http_ver.minor);
1543 
1545  if (reason == HTCP_CLR_INVALIDATION)
1546  stuff.reason = 1;
1547 
1548  SBuf sb = req->method.image();
1549  stuff.S.method = sb.c_str();
1550  if (e == NULL || e->mem_obj == NULL) {
1551  if (uri == NULL) {
1552  return;
1553  }
1554  stuff.S.uri = xstrdup(uri);
1555  } else {
1556  stuff.S.uri = (char *) e->url();
1557  }
1558  stuff.S.version = vbuf;
1559  if (reason != HTCP_CLR_INVALIDATION) {
1560  HttpStateData::httpBuildRequestHeader(req, e, NULL, &hdr, flags);
1561  mb.init();
1562  hdr.packInto(&mb);
1563  hdr.clean();
1564  stuff.S.req_hdrs = mb.buf;
1565  } else {
1566  stuff.S.req_hdrs = NULL;
1567  }
1568  pktlen = htcpBuildPacket(pkt, sizeof(pkt), &stuff);
1569  if (reason != HTCP_CLR_INVALIDATION) {
1570  mb.clean();
1571  }
1572  if (e == NULL) {
1573  xfree(stuff.S.uri);
1574  }
1575  if (!pktlen) {
1576  debugs(31, 3, "htcpClear: htcpBuildPacket() failed");
1577  return;
1578  }
1579 
1580  htcpSend(pkt, (int) pktlen, p->in_addr);
1581 }
1582 
1583 /*
1584  * htcpSocketShutdown only closes the 'in' socket if it is
1585  * different than the 'out' socket.
1586  */
1587 void
1589 {
1590  if (!Comm::IsConnOpen(htcpIncomingConn))
1591  return;
1592 
1593  debugs(12, DBG_IMPORTANT, "Stop accepting HTCP on " << htcpIncomingConn->local);
1594  /*
1595  * Here we just unlink htcpIncomingConn because the HTCP 'in'
1596  * and 'out' sockets might be just one FD. This prevents this
1597  * function from executing repeatedly. When we are really ready to
1598  * exit or restart, main will comm_close the 'out' descriptor.
1599  */
1600  htcpIncomingConn = NULL;
1601 
1602  /*
1603  * Normally we only write to the outgoing HTCP socket, but
1604  * we also have a read handler there to catch messages sent
1605  * to that specific interface. During shutdown, we must
1606  * disable reading on the outgoing socket.
1607  */
1608  /* XXX Don't we need this handler to read replies while shutting down?
1609  * I think there should be a separate hander for reading replies..
1610  */
1611  assert(Comm::IsConnOpen(htcpOutgoingConn));
1612 
1613  Comm::SetSelect(htcpOutgoingConn->fd, COMM_SELECT_READ, NULL, NULL, 0);
1614 }
1615 
1616 void
1618 {
1620 
1621  if (htcpOutgoingConn != NULL) {
1622  debugs(12, DBG_IMPORTANT, "Stop sending HTCP from " << htcpOutgoingConn->local);
1623  htcpOutgoingConn = NULL;
1624  }
1625 }
1626 
1627 static void
1628 htcpLogHtcp(Ip::Address &caddr, const int opcode, const LogTags_ot logcode, const char *url, AccessLogEntryPointer al)
1629 {
1630  if (!Config.onoff.log_udp)
1631  return;
1632 
1633  htcpSyncAle(al, caddr, opcode, url);
1634 
1635  assert(logcode != LOG_TAG_NONE);
1636  al->cache.code.update(logcode);
1637 
1638  accessLogLog(al, NULL);
1639 }
1640 
bool setIPv4()
Definition: Address.cc:217
static void htcpHandleClr(htcpDataHeader *hdr, char *buf, int sz, Ip::Address &from)
Definition: htcp.cc:1169
htcpStuff(uint32_t id, int o, int r, int f)
Definition: htcp.cc:177
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
bool startCollapsingOn(const StoreEntry &, const bool doingRevalidation)
Definition: store_client.cc:65
#define COMM_SELECT_READ
Definition: defines.h:36
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:236
static void htcpSend(const char *buf, int len, Ip::Address &to)
Definition: htcp.cc:586
struct _htcpHeader htcpHeader
Definition: htcp.cc:42
static void htcpIncomingConnectionOpened(const Comm::ConnectionPointer &conn, int errNo)
Definition: htcp.cc:1463
const char * method
Definition: htcp.cc:143
bool parseHeader(const char *buffer, const size_t size)
parses request header from the buffer
Definition: htcp.cc:1038
Countstr signature
Definition: htcp.cc:119
htcp_clr_reason
Definition: enums.h:233
#define MEMPROXY_CLASS(CLASS)
static void htcpClrReply(htcpDataHeader *dhdr, int purgeSucceeded, Ip::Address &from)
Definition: htcp.cc:891
int validToSend() const
Definition: store.cc:1414
static int htcpClrStore(const htcpSpecifier::Pointer &s)
Definition: htcp.cc:988
unsigned int reserved
Definition: htcp.cc:73
CachePeer * next
Definition: CachePeer.h:154
void htcpOpenPorts(void)
Definition: htcp.cc:1405
HttpRequest::Pointer checkHitRequest
Definition: htcp.cc:154
u_char minor
Definition: htcp.cc:58
void accessLogLog(AccessLogEntry::Pointer &, ACLChecklist *checklist)
Definition: access_log.cc:144
virtual LogTags * loggingTags()
Definition: htcp.cc:964
static const char *const htcpOpcodeStr[]
Definition: htcp.cc:203
Definition: SBuf.h:86
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:144
HttpRequestMethod method
Definition: HttpRequest.h:106
bool isNoAddr() const
Definition: Address.cc:277
CachePeer * peers
Definition: SquidConfig.h:247
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:30
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:1157
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:1161
static cache_key queried_keys[N_QUERIED_KEYS][SQUID_MD5_DIGEST_LENGTH]
Definition: htcp.cc:239
uint8_t reserved
Definition: htcp.cc:103
int hit
Definition: htcp.h:29
HttpRequest::Pointer request
Definition: htcp.cc:148
void neighborsHtcpReply(const cache_key *, HtcpReplyData *, const Ip::Address &)
Definition: neighbors.cc:1712
AnyP::ProtocolVersion http_ver
Definition: Message.h:72
#define DBG_CRITICAL
Definition: Debug.h:45
uint8_t response
Definition: htcp.cc:92
char * p
Definition: membanger.c:43
void htcpClosePorts(void)
Definition: htcp.cc:1617
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:66
time_t expires
Definition: Store.h:202
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
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:611
struct StatCounters::@131 htcp
time_t squid_curtime
Definition: stub_time.cc:17
bool isAnyAddr() const
Definition: Address.cc:163
time_t timestamp
Definition: Store.h:200
static void htcpHandleTst(htcpDataHeader *, char *buf, int sz, Ip::Address &from)
Definition: htcp.cc:1021
static void getPublicByRequest(StoreClient *aClient, HttpRequest *request)
Definition: store.cc:502
AsyncCall * asyncCall(int aDebugSection, int aDebugLevel, const char *aName, const Dialer &aDialer)
Definition: AsyncCall.h:156
unsigned short htcp
Definition: SquidConfig.h:138
void init(mb_size_t szInit, mb_size_t szMax)
Definition: MemBuf.cc:96
uint16_t length
Definition: htcp.cc:56
void fatal_dump(const char *message)
Definition: fatal.cc:78
size_t cacheHdrsSz
Definition: htcp.cc:171
void setFrom(Ip::Address &anIp)
Definition: htcp.cc:132
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:1588
char * resp_hdrs
Definition: htcp.cc:164
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:65
size_t reqHdrsSz
size of the req_hdrs content
Definition: htcp.cc:147
uint16_t length
Definition: htcp.cc:51
#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:1378
HtcpReplyData()
Definition: htcp.cc:1031
void SetSelect(int, unsigned int, PF *, void *, time_t)
Mark an FD to be watched for its IO status.
Definition: ModDevPoll.cc:225
LogTags_ot
Definition: LogTags.h:22
char * cache_hdrs
Definition: htcp.cc:170
int parse(const char *header_start, size_t len, Http::ContentLengthInterpreter &interpreter)
Definition: HttpHeader.cc:370
static void htcpLogHtcp(Ip::Address &, const int, const LogTags_ot, const char *, AccessLogEntryPointer)
Definition: htcp.cc:1628
struct SquidConfig::@99 Port
uint32_t msg_id
Definition: htcp.cc:82
#define SQUID_MD5_DIGEST_LENGTH
Definition: md5.h:66
static void htcpSyncAle(AccessLogEntryPointer &al, const Ip::Address &caddr, const int opcode, const char *url)
Definition: htcp.cc:271
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:115
static void htcpHandleMsg(char *buf, int sz, Ip::Address &from)
Definition: htcp.cc:1262
htcpDetail D
Definition: htcp.cc:191
void putTime(Http::HdrType id, time_t htime)
Definition: HttpHeader.cc:1063
size_t entityHdrsSz
Definition: htcp.cc:168
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:86
unsigned int F1
Definition: htcp.cc:74
char * version
Definition: htcp.cc:145
uint32_t msg_id
Definition: htcp.cc:189
AccessLogEntryPointer al
optimization: nil until needed
Definition: htcp.cc:151
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
struct SquidConfig::@113 accessList
size_t respHdrsSz
Definition: htcp.cc:165
Ip::Address udp_incoming
Definition: SquidConfig.h:235
bool parseHeader(Http1::Parser &hp)
Definition: HttpRequest.cc:654
void releaseRequest(const bool shareable=false)
Definition: store.cc:446
static ssize_t htcpBuildTstOpData(char *buf, size_t buflen, htcpStuff *stuff)
Definition: htcp.cc:422
const char * c_str()
Definition: SBuf.cc:526
static ssize_t htcpBuildSpecifier(char *buf, size_t buflen, htcpStuff *stuff)
Definition: htcp.cc:355
MemObject * mem_obj
Definition: Store.h:197
void putInt(Http::HdrType id, int number)
Definition: HttpHeader.cc:1045
void checkHit()
Definition: htcp.cc:918
unsigned int RR
Definition: htcp.cc:75
uint8_t opcode
Definition: htcp.cc:93
int unsigned int const char *desc STUB void int len
Definition: stub_fd.cc:20
const char * url() const
Definition: store.cc:1600
static HttpRequest * FromUrl(const char *url, const MasterXaction::Pointer &, const HttpRequestMethod &method=Http::METHOD_GET)
Definition: HttpRequest.cc:523
void const char * buf
Definition: stub_helper.cc:16
class AccessLogEntry::CacheDetails cache
struct SquidConfig::@112 onoff
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:384
char * req_hdrs
Definition: htcp.cc:146
struct SquidConfig::@107 Addrs
RefCount< htcpSpecifier > Pointer
Definition: htcp.cc:124
Ip::Address local
Definition: Connection.h:135
int htcpQuery(StoreEntry *e, HttpRequest *req, CachePeer *p)
Definition: htcp.cc:1479
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
void setDataHeader(htcpDataHeader *aDataHeader)
Definition: htcp.cc:133
char * text
Definition: htcp.cc:52
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:187
static ssize_t htcpBuildDetail(char *buf, size_t buflen, htcpStuff *stuff)
Definition: htcp.cc:393
Countstr key_name
Definition: htcp.cc:118
struct _htcpDataHeader htcpDataHeader
Definition: htcp.cc:44
void HttpRequestMethodXXX(char const *)
void htcpClear(StoreEntry *e, const char *uri, HttpRequest *req, const HttpRequestMethod &, CachePeer *p, htcp_clr_reason reason)
Definition: htcp.cc:1528
#define N_QUERIED_KEYS
Definition: htcp.cc:237
static void htcpHandleTstRequest(htcpDataHeader *, char *buf, int sz, Ip::Address &from)
Definition: htcp.cc:1117
uint32_t msg_id
Definition: htcp.cc:106
virtual void fillChecklist(ACLFilledChecklist &) const
configure the ACL checklist with the current transaction state
Definition: htcp.cc:973
size_t HttpReply *STUB StoreEntry const KeyScope scope const HttpRequestMethod & method
Definition: stub_store.cc:122
static void htcpForwardClr(char *buf, int sz)
Definition: htcp.cc:1237
cache_key * storeKeyCopy(cache_key *dst, const cache_key *src)
bool hittingRequiresCollapsing() const
whether this entry can feed collapsed requests and only them
Definition: Store.h:192
time_t sig_time
Definition: htcp.cc:116
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:31
struct CachePeer::@31 options
void packInto(Packable *p, bool mask_sensitive_info=false) const
Definition: HttpHeader.cc:554
void netdbHostData(const char *host, int *samp, int *rtt, int *hops)
Definition: net_db.cc:1067
static void htcpClrStoreEntry(StoreEntry *e)
Definition: htcp.cc:981
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:528
uint16_t length
Definition: htcp.cc:62
#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:102
dials a UDP port-opened call
Definition: UdpOpenDialer.h:18
htcpDataHeader * dhdr
Definition: htcp.cc:157
uint8_t RR
Definition: htcp.cc:101
int rr
Definition: htcp.cc:185
time_t sig_expire
Definition: htcp.cc:117
C * getRaw() const
Definition: RefCount.h:74
class SquidConfig Config
Definition: SquidConfig.cc:12
Ip::Address from
Definition: htcp.cc:156
#define NULL
Definition: types.h:166
A StoreEntry::getPublic*() caller.
Definition: StoreClient.h:23
int size
Definition: ModDevPoll.cc:77
static void htcpHandleTstResponse(htcpDataHeader *, char *, int, Ip::Address &)
Definition: htcp.cc:1047
u_char major
Definition: htcp.cc:57
const char * dash_str
char * entity_hdrs
Definition: htcp.cc:167

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors