]> git.ipfire.org Git - thirdparty/squid.git/blame - src/htcp.cc
url checksum debugging; sometimes URL memory gets trashed
[thirdparty/squid.git] / src / htcp.cc
CommitLineData
d5d466fc 1
2/*
32b3cf93 3 * $Id: htcp.cc,v 1.27 1999/06/10 06:10:30 wessels Exp $
9cef6668 4 *
5 * DEBUG: section 31 Hypertext Caching Protocol
6 * AUTHOR: Duane Wesssels
7 *
8 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
9 * ----------------------------------------------------------
10 *
11 * Squid is the result of efforts by numerous individuals from the
12 * Internet community. Development is led by Duane Wessels of the
13 * National Laboratory for Applied Network Research and funded by the
14 * National Science Foundation. Squid is Copyrighted (C) 1998 by
15 * Duane Wessels and the University of California San Diego. Please
16 * see the COPYRIGHT file for full details. Squid incorporates
17 * software developed and/or copyrighted by other sources. Please see
18 * the CREDITS file for full details.
19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 *
d5d466fc 34 */
35
c1b92ccb 36#include "squid.h"
37
38typedef struct _Countstr Countstr;
39typedef struct _htcpHeader htcpHeader;
40typedef struct _htcpDataHeader htcpDataHeader;
41typedef struct _htcpAuthHeader htcpAuthHeader;
d5d466fc 42typedef struct _htcpStuff htcpStuff;
eb9ae2f7 43typedef struct _htcpSpecifier htcpSpecifier;
a2edf5dc 44typedef struct _htcpDetail htcpDetail;
c1b92ccb 45
46struct _Countstr {
59c4d35b 47 u_short length;
48 char *text;
c1b92ccb 49};
50
51struct _htcpHeader {
59c4d35b 52 u_short length;
53 u_char major;
54 u_char minor;
c1b92ccb 55};
56
57struct _htcpDataHeader {
59c4d35b 58 u_short length;
eb9ae2f7 59#if !WORDS_BIGENDIAN
59c4d35b 60 u_char opcode:4;
61 u_char response:4;
eb9ae2f7 62#else
63 u_char response:4;
64 u_char opcode:4;
65#endif
66#if !WORDS_BIGENDIAN
59c4d35b 67 u_char reserved:6;
68 u_char F1:1;
eb9ae2f7 69 u_char RR:1;
70#else
71 u_char RR:1;
72 u_char F1:1;
73 u_char reserved:6;
74#endif
75 u_num32 msg_id;
76};
77
59c4d35b 78 /* RR == 0 --> F1 = RESPONSE DESIRED FLAG */
79 /* RR == 1 --> F1 = MESSAGE OVERALL FLAG */
59c4d35b 80 /* RR == 0 --> REQUEST */
81 /* RR == 1 --> RESPONSE */
c1b92ccb 82
83struct _htcpAuthHeader {
59c4d35b 84 u_short length;
85 time_t sig_time;
86 time_t sig_expire;
87 Countstr key_name;
88 Countstr signature;
c1b92ccb 89};
90
eb9ae2f7 91struct _htcpSpecifier {
92 char *method;
93 char *uri;
94 char *version;
95 char *req_hdrs;
96};
97
a2edf5dc 98struct _htcpDetail {
99 char *resp_hdrs;
100 char *entity_hdrs;
101 char *cache_hdrs;
102};
103
d5d466fc 104struct _htcpStuff {
105 int op;
106 int rr;
107 int f1;
108 int response;
26df9ec6 109 u_num32 msg_id;
a2edf5dc 110 htcpSpecifier S;
111 htcpDetail D;
c1b92ccb 112};
113
114enum {
59c4d35b 115 HTCP_NOP,
116 HTCP_TST,
117 HTCP_MON,
118 HTCP_SET,
eb9ae2f7 119 HTCP_CLR,
120 HTCP_END
121};
122
1afe05c5 123static const char *const htcpOpcodeStr[] =
124{
125 "HTCP_NOP",
126 "HTCP_TST",
127 "HTCP_MON",
128 "HTCP_SET",
129 "HTCP_CLR",
130 "HTCP_END"
c1b92ccb 131};
132
133/*
134 * values for htcpDataHeader->response
135 */
136enum {
59c4d35b 137 AUTH_REQUIRED,
138 AUTH_FAILURE,
139 OPCODE_UNIMPLEMENTED,
140 MAJOR_VERSION_UNSUPPORTED,
141 MINOR_VERSION_UNSUPPORTED,
142 INVALID_OPCODE
c1b92ccb 143};
144
145/*
146 * values for htcpDataHeader->RR
147 */
148enum {
59c4d35b 149 RR_REQUEST,
150 RR_RESPONSE
c1b92ccb 151};
152
d5d466fc 153static u_num32 msg_id_counter = 0;
154static int htcpInSocket = -1;
155static int htcpOutSocket = -1;
26df9ec6 156#define N_QUERIED_KEYS 256
157static cache_key queried_keys[N_QUERIED_KEYS][MD5_DIGEST_CHARS];
59c4d35b 158
56714a1a 159static char *htcpBuildPacket(htcpStuff * stuff, ssize_t * len);
160static htcpSpecifier *htcpUnpackSpecifier(char *buf, int sz);
a2edf5dc 161static htcpDetail *htcpUnpackDetail(char *buf, int sz);
56714a1a 162static int htcpUnpackCountstr(char *buf, int sz, char **str);
163static ssize_t htcpBuildAuth(char *buf, size_t buflen);
164static ssize_t htcpBuildCountstr(char *buf, size_t buflen, const char *s);
165static ssize_t htcpBuildData(char *buf, size_t buflen, htcpStuff * stuff);
166static ssize_t htcpBuildDetail(char *buf, size_t buflen, htcpStuff * stuff);
167static ssize_t htcpBuildOpData(char *buf, size_t buflen, htcpStuff * stuff);
168static ssize_t htcpBuildSpecifier(char *buf, size_t buflen, htcpStuff * stuff);
169static ssize_t htcpBuildTstOpData(char *buf, size_t buflen, htcpStuff * stuff);
170static void htcpFreeSpecifier(htcpSpecifier * s);
a2edf5dc 171static void htcpFreeDetail(htcpDetail * s);
56714a1a 172static void htcpHandle(char *buf, int sz, struct sockaddr_in *from);
173static void htcpHandleData(char *buf, int sz, struct sockaddr_in *from);
60fac9b5 174static void htcpHandleMon(htcpDataHeader *, char *buf, int sz, struct sockaddr_in *from);
175static void htcpHandleNop(htcpDataHeader *, char *buf, int sz, struct sockaddr_in *from);
176static void htcpHandleSet(htcpDataHeader *, char *buf, int sz, struct sockaddr_in *from);
177static void htcpHandleTst(htcpDataHeader *, char *buf, int sz, struct sockaddr_in *from);
56714a1a 178static void htcpRecv(int fd, void *data);
179static void htcpSend(const char *buf, int len, struct sockaddr_in *to);
26df9ec6 180static void htcpTstReply(htcpDataHeader *, StoreEntry *, htcpSpecifier *, struct sockaddr_in *);
181static void htcpHandleTstRequest(htcpDataHeader *, char *buf, int sz, struct sockaddr_in *from);
60fac9b5 182static void htcpHandleTstResponse(htcpDataHeader *, char *, int, struct sockaddr_in *);
32b3cf93 183static StoreEntry *htcpCheckHit(const htcpSpecifier *);
56714a1a 184
185static void
186htcpHexdump(const char *tag, const char *s, int sz)
187{
95eb77fe 188#if USE_HEXDUMP
60fac9b5 189 int i;
190 int k;
191 char hex[80];
d87ebd78 192 debug(31, 3) ("htcpHexdump %s\n", tag);
60fac9b5 193 memset(hex, '\0', 80);
194 for (i = 0; i < sz; i++) {
195 k = i % 16;
196 snprintf(&hex[k * 3], 4, " %02x", (int) *(s + i));
197 if (k < 15 && i < (sz - 1))
198 continue;
d87ebd78 199 debug(31, 3) ("\t%s\n", hex);
56714a1a 200 memset(hex, '\0', 80);
60fac9b5 201 }
95eb77fe 202#endif
56714a1a 203}
d9f9d78b 204
eb9ae2f7 205/*
206 * STUFF FOR SENDING HTCP MESSAGES
207 */
208
56714a1a 209static ssize_t
d5d466fc 210htcpBuildAuth(char *buf, size_t buflen)
59c4d35b 211{
3340a3e6 212 htcpAuthHeader auth;
213 size_t copy_sz = 0;
59c4d35b 214 assert(2 == sizeof(u_short));
3340a3e6 215 auth.length = htons(2);
216 copy_sz += 2;
217 assert(buflen >= copy_sz);
218 xmemcpy(buf, &auth, copy_sz);
219 return copy_sz;
220}
221
56714a1a 222static ssize_t
d5d466fc 223htcpBuildCountstr(char *buf, size_t buflen, const char *s)
224{
225 u_short length;
56714a1a 226 size_t len;
d5d466fc 227 off_t off = 0;
228 if (buflen - off < 2)
229 return -1;
56714a1a 230 if (s)
60fac9b5 231 len = strlen(s);
56714a1a 232 else
233 len = 0;
d87ebd78 234 debug(31, 3) ("htcpBuildCountstr: LENGTH = %d\n", len);
235 debug(31, 3) ("htcpBuildCountstr: TEXT = {%s}\n", s ? s : "<NULL>");
d5d466fc 236 length = htons((u_short) len);
237 xmemcpy(buf + off, &length, 2);
238 off += 2;
239 if (buflen - off < len)
240 return -1;
56714a1a 241 if (len)
60fac9b5 242 xmemcpy(buf + off, s, len);
d5d466fc 243 off += len;
244 return off;
245}
246
56714a1a 247static ssize_t
d5d466fc 248htcpBuildSpecifier(char *buf, size_t buflen, htcpStuff * stuff)
249{
250 ssize_t off = 0;
251 ssize_t s;
a2edf5dc 252 s = htcpBuildCountstr(buf + off, buflen - off, stuff->S.method);
d5d466fc 253 if (s < 0)
254 return s;
255 off += s;
a2edf5dc 256 s = htcpBuildCountstr(buf + off, buflen - off, stuff->S.uri);
d5d466fc 257 if (s < 0)
258 return s;
259 off += s;
a2edf5dc 260 s = htcpBuildCountstr(buf + off, buflen - off, stuff->S.version);
d5d466fc 261 if (s < 0)
262 return s;
263 off += s;
a2edf5dc 264 s = htcpBuildCountstr(buf + off, buflen - off, stuff->S.req_hdrs);
d5d466fc 265 if (s < 0)
266 return s;
267 off += s;
d87ebd78 268 debug(31, 3) ("htcpBuildSpecifier: size %d\n", (int) off);
d5d466fc 269 return off;
270}
271
56714a1a 272static ssize_t
273htcpBuildDetail(char *buf, size_t buflen, htcpStuff * stuff)
274{
275 ssize_t off = 0;
276 ssize_t s;
a2edf5dc 277 s = htcpBuildCountstr(buf + off, buflen - off, stuff->D.resp_hdrs);
56714a1a 278 if (s < 0)
279 return s;
280 off += s;
a2edf5dc 281 s = htcpBuildCountstr(buf + off, buflen - off, stuff->D.entity_hdrs);
56714a1a 282 if (s < 0)
283 return s;
284 off += s;
a2edf5dc 285 s = htcpBuildCountstr(buf + off, buflen - off, stuff->D.cache_hdrs);
56714a1a 286 if (s < 0)
287 return s;
288 off += s;
289 return off;
290}
291
292static ssize_t
d5d466fc 293htcpBuildTstOpData(char *buf, size_t buflen, htcpStuff * stuff)
294{
0cdcddb9 295 switch (stuff->rr) {
d9f9d78b 296 case RR_REQUEST:
d87ebd78 297 debug(31, 3) ("htcpBuildTstOpData: RR_REQUEST\n");
0cdcddb9 298 return htcpBuildSpecifier(buf, buflen, stuff);
d9f9d78b 299 case RR_RESPONSE:
d87ebd78 300 debug(31, 3) ("htcpBuildTstOpData: RR_RESPONSE\n");
301 debug(31, 3) ("htcpBuildTstOpData: F1 = %d\n", stuff->f1);
60fac9b5 302 if (stuff->f1) /* cache miss */
303 return 0;
304 else /* cache hit */
305 return htcpBuildDetail(buf, buflen, stuff);
d9f9d78b 306 default:
307 fatal_dump("htcpBuildTstOpData: bad RR value");
0cdcddb9 308 }
309 return 0;
d5d466fc 310}
311
56714a1a 312static ssize_t
d5d466fc 313htcpBuildOpData(char *buf, size_t buflen, htcpStuff * stuff)
314{
315 ssize_t off = 0;
d87ebd78 316 debug(31, 3) ("htcpBuildOpData: opcode %s\n",
56714a1a 317 htcpOpcodeStr[stuff->op]);
d5d466fc 318 switch (stuff->op) {
319 case HTCP_TST:
320 off = htcpBuildTstOpData(buf + off, buflen, stuff);
321 break;
322 default:
323 assert(0);
324 break;
325 }
326 return off;
327}
328
56714a1a 329static ssize_t
d5d466fc 330htcpBuildData(char *buf, size_t buflen, htcpStuff * stuff)
331{
332 ssize_t off = 0;
333 ssize_t op_data_sz;
334 size_t hdr_sz = sizeof(htcpDataHeader);
335 htcpDataHeader hdr;
336 if (buflen < hdr_sz)
337 return -1;
338 off += hdr_sz; /* skip! */
339 op_data_sz = htcpBuildOpData(buf + off, buflen - off, stuff);
340 if (op_data_sz < 0)
341 return op_data_sz;
342 off += op_data_sz;
d87ebd78 343 debug(31, 3) ("htcpBuildData: hdr.length = %d\n", (int) off);
d5d466fc 344 hdr.length = (u_short) off;
345 hdr.opcode = stuff->op;
346 hdr.response = stuff->response;
347 hdr.RR = stuff->rr;
348 hdr.F1 = stuff->f1;
26df9ec6 349 hdr.msg_id = stuff->msg_id;
d5d466fc 350 /* convert multi-byte fields */
351 hdr.length = htons(hdr.length);
eb9ae2f7 352 hdr.msg_id = htonl(hdr.msg_id);
d5d466fc 353 xmemcpy(buf, &hdr, hdr_sz);
d87ebd78 354 debug(31, 3) ("htcpBuildData: size %d\n", (int) off);
d5d466fc 355 return off;
356}
357
56714a1a 358static char *
d5d466fc 359htcpBuildPacket(htcpStuff * stuff, ssize_t * len)
3340a3e6 360{
d5d466fc 361 size_t buflen = 8192;
362 size_t s;
363 ssize_t off = 0;
364 size_t hdr_sz = sizeof(htcpHeader);
365 htcpHeader hdr;
366 char *buf = xcalloc(buflen, 1);
367 /* skip the header -- we don't know the overall length */
368 if (buflen < hdr_sz)
369 return NULL;
370 off += hdr_sz;
371 s = htcpBuildData(buf + off, buflen - off, stuff);
372 if (s < 0)
373 return NULL;
374 off += s;
375 s = htcpBuildAuth(buf + off, buflen - off);
376 if (s < 0)
377 return NULL;
378 off += s;
1afe05c5 379 hdr.length = htons((u_short) off);
d5d466fc 380 hdr.major = 0;
381 hdr.minor = 0;
382 xmemcpy(buf, &hdr, hdr_sz);
383 *len = off;
d87ebd78 384 debug(31, 3) ("htcpBuildPacket: size %d\n", (int) off);
d5d466fc 385 return buf;
3340a3e6 386}
387
56714a1a 388static void
389htcpSend(const char *buf, int len, struct sockaddr_in *to)
3340a3e6 390{
d5d466fc 391 int x;
d87ebd78 392 debug(31, 3) ("htcpSend: %s/%d\n",
56714a1a 393 inet_ntoa(to->sin_addr), (int) ntohs(to->sin_port));
394 htcpHexdump("htcpSend", buf, len);
d5d466fc 395 x = comm_udp_sendto(htcpOutSocket,
56714a1a 396 to,
d5d466fc 397 sizeof(struct sockaddr_in),
398 buf,
399 len);
400 if (x < 0)
401 debug(31, 0) ("htcpSend: FD %d sendto: %s\n", htcpOutSocket, xstrerror());
3340a3e6 402}
403
eb9ae2f7 404/*
405 * STUFF FOR RECEIVING HTCP MESSAGES
406 */
407
408static void
409htcpFreeSpecifier(htcpSpecifier * s)
410{
3a3c723d 411 safe_free(s->method);
412 safe_free(s->uri);
413 safe_free(s->version);
414 safe_free(s->req_hdrs);
415 xfree(s);
eb9ae2f7 416}
417
a2edf5dc 418static void
419htcpFreeDetail(htcpDetail * d)
420{
3a3c723d 421 safe_free(d->resp_hdrs);
422 safe_free(d->entity_hdrs);
423 safe_free(d->cache_hdrs);
424 xfree(d);
a2edf5dc 425}
426
56714a1a 427static int
eb9ae2f7 428htcpUnpackCountstr(char *buf, int sz, char **str)
429{
1afe05c5 430 u_short l;
d87ebd78 431 debug(31, 3) ("htcpUnpackCountstr: sz = %d\n", sz);
1afe05c5 432 if (sz < 2) {
d87ebd78 433 debug(31, 3) ("htcpUnpackCountstr: sz < 2\n");
1afe05c5 434 return -1;
435 }
56714a1a 436 htcpHexdump("htcpUnpackCountstr", buf, sz);
1afe05c5 437 xmemcpy(&l, buf, 2);
56714a1a 438 l = ntohs(l);
1afe05c5 439 buf += 2;
440 sz -= 2;
d87ebd78 441 debug(31, 3) ("htcpUnpackCountstr: LENGTH = %d\n", (int) l);
1afe05c5 442 if (sz < l) {
d87ebd78 443 debug(31, 3) ("htcpUnpackCountstr: sz(%d) < l(%d)\n", sz, l);
1afe05c5 444 return -1;
445 }
446 if (str) {
447 *str = xmalloc(l + 1);
448 xstrncpy(*str, buf, l + 1);
d87ebd78 449 debug(31, 3) ("htcpUnpackCountstr: TEXT = {%s}\n", *str);
1afe05c5 450 }
451 return (int) l + 2;
eb9ae2f7 452}
453
56714a1a 454static htcpSpecifier *
eb9ae2f7 455htcpUnpackSpecifier(char *buf, int sz)
456{
1afe05c5 457 htcpSpecifier *s = xcalloc(1, sizeof(htcpSpecifier));
458 int o;
d87ebd78 459 debug(31, 3) ("htcpUnpackSpecifier: %d bytes\n", (int) sz);
1afe05c5 460 o = htcpUnpackCountstr(buf, sz, &s->method);
461 if (o < 0) {
462 debug(31, 1) ("htcpUnpackSpecifier: failed to unpack METHOD\n");
463 htcpFreeSpecifier(s);
464 return NULL;
465 }
466 buf += o;
467 sz -= o;
1afe05c5 468 o = htcpUnpackCountstr(buf, sz, &s->uri);
469 if (o < 0) {
470 debug(31, 1) ("htcpUnpackSpecifier: failed to unpack URI\n");
471 htcpFreeSpecifier(s);
472 return NULL;
473 }
474 buf += o;
475 sz -= o;
1afe05c5 476 o = htcpUnpackCountstr(buf, sz, &s->version);
477 if (o < 0) {
478 debug(31, 1) ("htcpUnpackSpecifier: failed to unpack VERSION\n");
479 htcpFreeSpecifier(s);
480 return NULL;
481 }
482 buf += o;
483 sz -= o;
1afe05c5 484 o = htcpUnpackCountstr(buf, sz, &s->req_hdrs);
485 if (o < 0) {
486 debug(31, 1) ("htcpUnpackSpecifier: failed to unpack REQ-HDRS\n");
487 htcpFreeSpecifier(s);
488 return NULL;
489 }
490 buf += o;
491 sz -= o;
d87ebd78 492 debug(31, 3) ("htcpUnpackSpecifier: %d bytes left\n", sz);
1afe05c5 493 return s;
eb9ae2f7 494}
495
a2edf5dc 496static htcpDetail *
497htcpUnpackDetail(char *buf, int sz)
498{
499 htcpDetail *d = xcalloc(1, sizeof(htcpDetail));
500 int o;
d87ebd78 501 debug(31, 3) ("htcpUnpackDetail: %d bytes\n", (int) sz);
a2edf5dc 502 o = htcpUnpackCountstr(buf, sz, &d->resp_hdrs);
503 if (o < 0) {
504 debug(31, 1) ("htcpUnpackDetail: failed to unpack RESP_HDRS\n");
505 htcpFreeDetail(d);
506 return NULL;
507 }
508 buf += o;
509 sz -= o;
510 o = htcpUnpackCountstr(buf, sz, &d->entity_hdrs);
511 if (o < 0) {
512 debug(31, 1) ("htcpUnpackDetail: failed to unpack ENTITY_HDRS\n");
513 htcpFreeDetail(d);
514 return NULL;
515 }
516 buf += o;
517 sz -= o;
518 o = htcpUnpackCountstr(buf, sz, &d->cache_hdrs);
519 if (o < 0) {
520 debug(31, 1) ("htcpUnpackDetail: failed to unpack CACHE_HDRS\n");
521 htcpFreeDetail(d);
522 return NULL;
523 }
524 buf += o;
525 sz -= o;
d87ebd78 526 debug(31, 3) ("htcpUnpackDetail: %d bytes left\n", sz);
a2edf5dc 527 return d;
528}
529
eb9ae2f7 530static void
886f2785 531htcpTstReply(htcpDataHeader * dhdr, StoreEntry * e, htcpSpecifier * spec, struct sockaddr_in *from)
60fac9b5 532{
533 htcpStuff stuff;
534 char *pkt;
2dcc81d4 535 HttpHeader hdr;
536 MemBuf mb;
537 Packer p;
60fac9b5 538 ssize_t pktlen;
2dcc81d4 539 char *host;
540 int rtt = 0;
541 int hops = 0;
542 int samp = 0;
543 char cto_buf[128];
60fac9b5 544 stuff.op = HTCP_TST;
545 stuff.rr = RR_RESPONSE;
44e237d0 546 stuff.f1 = 0;
547 stuff.response = e ? 0 : 1;
26df9ec6 548 stuff.msg_id = dhdr->msg_id;
60fac9b5 549 if (spec) {
2dcc81d4 550 memBufDefInit(&mb);
551 packerToMemInit(&p, &mb);
552 httpHeaderInit(&hdr, hoHtcpReply);
a2edf5dc 553 stuff.S.method = spec->method;
554 stuff.S.uri = spec->uri;
555 stuff.S.version = spec->version;
556 stuff.S.req_hdrs = spec->req_hdrs;
2dcc81d4 557 httpHeaderPutInt(&hdr, HDR_AGE,
558 e->timestamp <= squid_curtime ?
559 squid_curtime - e->timestamp : 0);
560 httpHeaderPackInto(&hdr, &p);
a2edf5dc 561 stuff.D.resp_hdrs = xstrdup(mb.buf);
d87ebd78 562 debug(31, 3) ("htcpTstReply: resp_hdrs = {%s}\n", stuff.D.resp_hdrs);
2dcc81d4 563 memBufReset(&mb);
564 httpHeaderReset(&hdr);
565 if (e->expires > -1)
566 httpHeaderPutTime(&hdr, HDR_EXPIRES, e->expires);
567 if (e->lastmod > -1)
568 httpHeaderPutTime(&hdr, HDR_LAST_MODIFIED, e->lastmod);
569 httpHeaderPackInto(&hdr, &p);
a2edf5dc 570 stuff.D.entity_hdrs = xstrdup(mb.buf);
d87ebd78 571 debug(31, 3) ("htcpTstReply: entity_hdrs = {%s}\n", stuff.D.entity_hdrs);
2dcc81d4 572 memBufReset(&mb);
573 httpHeaderReset(&hdr);
574 if ((host = urlHostname(spec->uri))) {
575 netdbHostData(host, &samp, &rtt, &hops);
576 if (rtt || hops) {
577 snprintf(cto_buf, 128, "%s %d %f %d",
886f2785 578 host, samp, 0.001 * rtt, hops);
2dcc81d4 579 httpHeaderPutExt(&hdr, "Cache-to-Origin", cto_buf);
580 }
581 }
582 httpHeaderPackInto(&hdr, &p);
a2edf5dc 583 stuff.D.cache_hdrs = xstrdup(mb.buf);
d87ebd78 584 debug(31, 3) ("htcpTstReply: cache_hdrs = {%s}\n", stuff.D.cache_hdrs);
2dcc81d4 585 memBufClean(&mb);
586 httpHeaderClean(&hdr);
587 packerClean(&p);
60fac9b5 588 }
589 pkt = htcpBuildPacket(&stuff, &pktlen);
590 if (pkt == NULL) {
591 debug(31, 0) ("htcpTstReply: htcpBuildPacket() failed\n");
592 return;
593 }
594 htcpSend(pkt, (int) pktlen, from);
3a3c723d 595 xfree(pkt);
60fac9b5 596}
597
598static void
599htcpHandleNop(htcpDataHeader * hdr, char *buf, int sz, struct sockaddr_in *from)
eb9ae2f7 600{
d87ebd78 601 debug(31, 3) ("htcpHandleNop: Unimplemented\n");
eb9ae2f7 602}
603
32b3cf93 604static StoreEntry *
605htcpCheckHit(const htcpSpecifier * s)
606{
607 request_t *request;
608 method_t m = urlParseMethod(s->method);
609 StoreEntry *e = storeGetPublic(s->uri, m);
610 if (NULL == e)
611 return NULL;
612 if (!storeEntryValidToSend(e))
613 return NULL;
614 request = urlParse(m, s->uri);
615 if (NULL == request)
616 return NULL;
617 if (!httpRequestParseHeader(request, s->req_hdrs))
618 e = NULL;
619 else if (refreshCheckHTCP(e, request))
620 e = NULL;
621 requestDestroy(request);
622 return e;
623}
624
eb9ae2f7 625static void
60fac9b5 626htcpHandleTst(htcpDataHeader * hdr, char *buf, int sz, struct sockaddr_in *from)
eb9ae2f7 627{
d87ebd78 628 debug(31, 3) ("htcpHandleTst: sz = %d\n", (int) sz);
60fac9b5 629 if (hdr->RR == RR_REQUEST)
26df9ec6 630 htcpHandleTstRequest(hdr, buf, sz, from);
60fac9b5 631 else
632 htcpHandleTstResponse(hdr, buf, sz, from);
633}
634
635static void
636htcpHandleTstResponse(htcpDataHeader * hdr, char *buf, int sz, struct sockaddr_in *from)
637{
a2edf5dc 638 htcpReplyData htcpReply;
639 cache_key *key = NULL;
26df9ec6 640 htcpDetail *d = NULL;
a2edf5dc 641 char *t;
44e237d0 642 if (hdr->F1 == 1) {
886f2785 643 debug(31, 1) ("htcpHandleTstResponse: error condition, F1/MO == 1\n");
44e237d0 644 return;
645 }
a2edf5dc 646 memset(&htcpReply, '\0', sizeof(htcpReply));
647 httpHeaderInit(&htcpReply.hdr, hoHtcpReply);
26df9ec6 648 htcpReply.msg_id = hdr->msg_id;
d87ebd78 649 debug(31, 3) ("htcpHandleTstResponse: msg_id = %d\n", (int) htcpReply.msg_id);
44e237d0 650 htcpReply.hit = hdr->response ? 0 : 1;
26df9ec6 651 if (hdr->F1) {
d87ebd78 652 debug(31, 3) ("htcpHandleTstResponse: MISS\n");
26df9ec6 653 } else {
d87ebd78 654 debug(31, 3) ("htcpHandleTstResponse: HIT\n");
26df9ec6 655 d = htcpUnpackDetail(buf, sz);
656 if (d == NULL) {
657 debug(31, 1) ("htcpHandleTstResponse: bad DETAIL\n");
658 return;
659 }
660 if ((t = d->resp_hdrs))
661 httpHeaderParse(&htcpReply.hdr, t, t + strlen(t));
662 if ((t = d->entity_hdrs))
663 httpHeaderParse(&htcpReply.hdr, t, t + strlen(t));
664 if ((t = d->cache_hdrs))
665 httpHeaderParse(&htcpReply.hdr, t, t + strlen(t));
a2edf5dc 666 }
26df9ec6 667 key = queried_keys[htcpReply.msg_id % N_QUERIED_KEYS];
d87ebd78 668 debug(31, 3) ("htcpHandleTstResponse: key (%p) %s\n", key, storeKeyText(key));
a2edf5dc 669 neighborsHtcpReply(key, &htcpReply, from);
26df9ec6 670 if (d)
886f2785 671 htcpFreeDetail(d);
60fac9b5 672}
673
674static void
886f2785 675htcpHandleTstRequest(htcpDataHeader * dhdr, char *buf, int sz, struct sockaddr_in *from)
60fac9b5 676{
677 /* buf should be a SPECIFIER */
678 htcpSpecifier *s;
679 StoreEntry *e;
60fac9b5 680 if (sz == 0) {
d87ebd78 681 debug(31, 3) ("htcpHandleTst: nothing to do\n");
60fac9b5 682 return;
683 }
44e237d0 684 if (dhdr->F1 == 0)
685 return;
60fac9b5 686 s = htcpUnpackSpecifier(buf, sz);
1afe05c5 687 if (NULL == s) {
d87ebd78 688 debug(31, 3) ("htcpHandleTstRequest: htcpUnpackSpecifier failed\n");
1afe05c5 689 return;
690 }
d87ebd78 691 debug(31, 3) ("htcpHandleTstRequest: %s %s %s\n",
1afe05c5 692 s->method,
693 s->uri,
694 s->version);
d87ebd78 695 debug(31, 3) ("htcpHandleTstRequest: %s\n", s->req_hdrs);
32b3cf93 696 if ((e = htcpCheckHit(s)))
697 htcpTstReply(dhdr, e, s, from); /* hit */
698 else
699 htcpTstReply(dhdr, NULL, NULL, from); /* cache miss */
60fac9b5 700 htcpFreeSpecifier(s);
d9f9d78b 701}
702
703static void
60fac9b5 704htcpHandleMon(htcpDataHeader * hdr, char *buf, int sz, struct sockaddr_in *from)
eb9ae2f7 705{
d87ebd78 706 debug(31, 3) ("htcpHandleMon: Unimplemented\n");
eb9ae2f7 707}
708
709static void
60fac9b5 710htcpHandleSet(htcpDataHeader * hdr, char *buf, int sz, struct sockaddr_in *from)
eb9ae2f7 711{
d87ebd78 712 debug(31, 3) ("htcpHandleSet: Unimplemented\n");
eb9ae2f7 713}
714
715static void
56714a1a 716htcpHandleData(char *buf, int sz, struct sockaddr_in *from)
eb9ae2f7 717{
718 htcpDataHeader hdr;
719 if (sz < sizeof(htcpDataHeader)) {
1afe05c5 720 debug(31, 0) ("htcpHandleData: msg size less than htcpDataHeader size\n");
eb9ae2f7 721 return;
722 }
723 xmemcpy(&hdr, buf, sizeof(htcpDataHeader));
724 hdr.length = ntohs(hdr.length);
26df9ec6 725 hdr.msg_id = ntohl(hdr.msg_id);
d87ebd78 726 debug(31, 3) ("htcpHandleData: sz = %d\n", sz);
727 debug(31, 3) ("htcpHandleData: length = %d\n", (int) hdr.length);
2e531e20 728 if (hdr.opcode > HTCP_END) {
1afe05c5 729 debug(31, 0) ("htcpHandleData: opcode %d out of range\n",
eb9ae2f7 730 (int) hdr.opcode);
731 return;
732 }
d87ebd78 733 debug(31, 3) ("htcpHandleData: opcode = %d %s\n",
eb9ae2f7 734 (int) hdr.opcode, htcpOpcodeStr[hdr.opcode]);
d87ebd78 735 debug(31, 3) ("htcpHandleData: response = %d\n", (int) hdr.response);
736 debug(31, 3) ("htcpHandleData: F1 = %d\n", (int) hdr.F1);
737 debug(31, 3) ("htcpHandleData: RR = %d\n", (int) hdr.RR);
738 debug(31, 3) ("htcpHandleData: msg_id = %d\n", (int) hdr.msg_id);
eb9ae2f7 739 if (sz < hdr.length) {
1afe05c5 740 debug(31, 0) ("htcpHandle: sz < hdr.length\n");
eb9ae2f7 741 return;
742 }
60fac9b5 743 /*
744 * set sz = hdr.length so we ignore any AUTH fields following
745 * the DATA.
746 */
747 sz = (int) hdr.length;
eb9ae2f7 748 buf += sizeof(htcpDataHeader);
749 sz -= sizeof(htcpDataHeader);
d87ebd78 750 debug(31, 3) ("htcpHandleData: sz = %d\n", sz);
56714a1a 751 htcpHexdump("htcpHandleData", buf, sz);
1afe05c5 752 switch (hdr.opcode) {
eb9ae2f7 753 case HTCP_NOP:
60fac9b5 754 htcpHandleNop(&hdr, buf, sz, from);
eb9ae2f7 755 break;
756 case HTCP_TST:
60fac9b5 757 htcpHandleTst(&hdr, buf, sz, from);
eb9ae2f7 758 break;
759 case HTCP_MON:
60fac9b5 760 htcpHandleMon(&hdr, buf, sz, from);
eb9ae2f7 761 break;
762 case HTCP_SET:
60fac9b5 763 htcpHandleSet(&hdr, buf, sz, from);
eb9ae2f7 764 break;
765 default:
766 assert(0);
767 break;
768 }
769}
770
771static void
772htcpHandle(char *buf, int sz, struct sockaddr_in *from)
773{
774 htcpHeader htcpHdr;
775 if (sz < sizeof(htcpHeader)) {
1afe05c5 776 debug(31, 0) ("htcpHandle: msg size less than htcpHeader size\n");
eb9ae2f7 777 return;
778 }
56714a1a 779 htcpHexdump("htcpHandle", buf, sz);
eb9ae2f7 780 xmemcpy(&htcpHdr, buf, sizeof(htcpHeader));
781 htcpHdr.length = ntohs(htcpHdr.length);
d87ebd78 782 debug(31, 3) ("htcpHandle: htcpHdr.length = %d\n", (int) htcpHdr.length);
783 debug(31, 3) ("htcpHandle: htcpHdr.major = %d\n", (int) htcpHdr.major);
784 debug(31, 3) ("htcpHandle: htcpHdr.minor = %d\n", (int) htcpHdr.minor);
eb9ae2f7 785 if (sz != htcpHdr.length) {
1afe05c5 786 debug(31, 0) ("htcpHandle: sz != htcpHdr.length\n");
eb9ae2f7 787 return;
788 }
789 buf += sizeof(htcpHeader);
790 sz -= sizeof(htcpHeader);
56714a1a 791 htcpHandleData(buf, sz, from);
eb9ae2f7 792}
793
56714a1a 794static void
eb9ae2f7 795htcpRecv(int fd, void *data)
796{
797 static char buf[8192];
798 int len;
799 static struct sockaddr_in from;
800 int flen = sizeof(struct sockaddr_in);
801 memset(&from, '\0', flen);
886f2785 802 Counter.syscalls.sock.recvfroms++;
eb9ae2f7 803 len = recvfrom(fd, buf, 8192, 0, (struct sockaddr *) &from, &flen);
d87ebd78 804 debug(31, 3) ("htcpRecv: FD %d, %d bytes from %s:%d\n",
eb9ae2f7 805 fd, len, inet_ntoa(from.sin_addr), ntohs(from.sin_port));
806 htcpHandle(buf, len, &from);
807 commSetSelect(fd, COMM_SELECT_READ, htcpRecv, NULL, 0);
808}
809
56714a1a 810/*
811 * ======================================================================
812 * PUBLIC FUNCTIONS
813 * ======================================================================
814 */
815
d5d466fc 816void
817htcpInit(void)
3340a3e6 818{
d5d466fc 819 enter_suid();
820 htcpInSocket = comm_open(SOCK_DGRAM,
821 0,
822 Config.Addrs.udp_incoming,
823 Config.Port.htcp,
824 COMM_NONBLOCKING,
825 "HTCP Socket");
826 leave_suid();
827 if (htcpInSocket < 0)
828 fatal("Cannot open HTCP Socket");
829 commSetSelect(htcpInSocket, COMM_SELECT_READ, htcpRecv, NULL, 0);
ba3eec6b 830 debug(31, 1) ("Accepting HTCP messages on port %d, FD %d.\n",
d5d466fc 831 (int) Config.Port.htcp, htcpInSocket);
832 if (Config.Addrs.udp_outgoing.s_addr != no_addr.s_addr) {
833 enter_suid();
834 htcpOutSocket = comm_open(SOCK_DGRAM,
835 0,
836 Config.Addrs.udp_outgoing,
837 Config.Port.htcp,
838 COMM_NONBLOCKING,
839 "Outgoing HTCP Socket");
840 leave_suid();
841 if (htcpOutSocket < 0)
842 fatal("Cannot open Outgoing HTCP Socket");
843 commSetSelect(htcpOutSocket, COMM_SELECT_READ, htcpRecv, NULL, 0);
ba3eec6b 844 debug(31, 1) ("Outgoing HTCP messages on port %d, FD %d.\n",
d5d466fc 845 (int) Config.Port.htcp, htcpOutSocket);
846 fd_note(htcpInSocket, "Incoming HTCP socket");
847 } else {
848 htcpOutSocket = htcpInSocket;
849 }
59c4d35b 850}
72549e05 851
56714a1a 852void
853htcpQuery(StoreEntry * e, request_t * req, peer * p)
854{
26df9ec6 855 cache_key *save_key;
56714a1a 856 char *pkt;
857 ssize_t pktlen;
858 char vbuf[32];
859 htcpStuff stuff;
860 HttpHeader hdr;
861 Packer pa;
862 MemBuf mb;
9c48373d 863 http_state_flags flags;
864 memset(&flags, '\0', sizeof(flags));
56714a1a 865 snprintf(vbuf, sizeof(vbuf), "%3.1f", req->http_ver);
866 stuff.op = HTCP_TST;
867 stuff.rr = RR_REQUEST;
868 stuff.f1 = 1;
869 stuff.response = 0;
26df9ec6 870 stuff.msg_id = ++msg_id_counter;
9c48373d 871 stuff.S.method = (char *) RequestMethodStr[req->method];
872 stuff.S.uri = (char *) storeUrl(e);
a2edf5dc 873 stuff.S.version = vbuf;
9c48373d 874 httpBuildRequestHeader(req, req, e, &hdr, -1, flags);
56714a1a 875 memBufDefInit(&mb);
876 packerToMemInit(&pa, &mb);
877 httpHeaderPackInto(&hdr, &pa);
878 httpHeaderClean(&hdr);
879 packerClean(&pa);
a2edf5dc 880 stuff.S.req_hdrs = mb.buf;
56714a1a 881 pkt = htcpBuildPacket(&stuff, &pktlen);
882 if (pkt == NULL) {
883 debug(31, 0) ("htcpQuery: htcpBuildPacket() failed\n");
884 return;
885 }
886 htcpSend(pkt, (int) pktlen, &p->in_addr);
26df9ec6 887 save_key = queried_keys[stuff.msg_id % N_QUERIED_KEYS];
888 storeKeyCopy(save_key, e->key);
d87ebd78 889 debug(31, 3) ("htcpQuery: key (%p) %s\n", save_key, storeKeyText(save_key));
3a3c723d 890 xfree(pkt);
56714a1a 891}
892
72549e05 893/*
894 * htcpSocketShutdown only closes the 'in' socket if it is
895 * different than the 'out' socket.
1afe05c5 896 */
72549e05 897void
898htcpSocketShutdown(void)
1afe05c5 899{
72549e05 900 if (htcpInSocket < 0)
1afe05c5 901 return;
902 if (htcpInSocket != htcpOutSocket) {
903 debug(12, 1) ("FD %d Closing HTCP socket\n", htcpInSocket);
904 comm_close(htcpInSocket);
905 }
72549e05 906 /*
907 * Here we set 'htcpInSocket' to -1 even though the HTCP 'in'
908 * and 'out' sockets might be just one FD. This prevents this
909 * function from executing repeatedly. When we are really ready to
910 * exit or restart, main will comm_close the 'out' descriptor.
1afe05c5 911 */
72549e05 912 htcpInSocket = -1;
913 /*
914 * Normally we only write to the outgoing HTCP socket, but
915 * we also have a read handler there to catch messages sent
916 * to that specific interface. During shutdown, we must
917 * disable reading on the outgoing socket.
1afe05c5 918 */
72549e05 919 assert(htcpOutSocket > -1);
920 commSetSelect(htcpOutSocket, COMM_SELECT_READ, NULL, NULL, 0);
921}
922
1afe05c5 923void
72549e05 924htcpSocketClose(void)
925{
926 htcpSocketShutdown();
927 if (htcpOutSocket > -1) {
1afe05c5 928 debug(12, 1) ("FD %d Closing HTCP socket\n", htcpOutSocket);
929 comm_close(htcpOutSocket);
930 }
931}