]> git.ipfire.org Git - thirdparty/squid.git/blame - src/htcp.cc
Andres Kroonmaa suggests yield() on Solaris, rather than sched_yield()
[thirdparty/squid.git] / src / htcp.cc
CommitLineData
d5d466fc 1
2/*
6c40d272 3 * $Id: htcp.cc,v 1.32 2000/11/01 04:50:25 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
efd900cb 15 * the Regents of the University of California. Please see the
16 * COPYRIGHT file for full details. Squid incorporates software
17 * developed and/or copyrighted by other sources. Please see the
18 * CREDITS file for full details.
9cef6668 19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 *
d5d466fc 34 */
35
c1b92ccb 36#include "squid.h"
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
7e3ce7b9 60 unsigned int opcode:4;
61 unsigned int response:4;
eb9ae2f7 62#else
7e3ce7b9 63 unsigned int response:4;
64 unsigned int opcode:4;
eb9ae2f7 65#endif
66#if !WORDS_BIGENDIAN
7e3ce7b9 67 unsigned int reserved:6;
68 unsigned int F1:1;
69 unsigned int RR:1;
eb9ae2f7 70#else
7e3ce7b9 71 unsigned int RR:1;
72 unsigned int F1:1;
73 unsigned int reserved:6;
eb9ae2f7 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 */
9bc73deb 368 if (buflen < hdr_sz) {
369 xfree(buf);
d5d466fc 370 return NULL;
9bc73deb 371 }
d5d466fc 372 off += hdr_sz;
373 s = htcpBuildData(buf + off, buflen - off, stuff);
9bc73deb 374 if (s < 0) {
375 xfree(buf);
d5d466fc 376 return NULL;
9bc73deb 377 }
d5d466fc 378 off += s;
379 s = htcpBuildAuth(buf + off, buflen - off);
9bc73deb 380 if (s < 0) {
381 xfree(buf);
d5d466fc 382 return NULL;
9bc73deb 383 }
d5d466fc 384 off += s;
1afe05c5 385 hdr.length = htons((u_short) off);
d5d466fc 386 hdr.major = 0;
387 hdr.minor = 0;
388 xmemcpy(buf, &hdr, hdr_sz);
389 *len = off;
d87ebd78 390 debug(31, 3) ("htcpBuildPacket: size %d\n", (int) off);
d5d466fc 391 return buf;
3340a3e6 392}
393
56714a1a 394static void
395htcpSend(const char *buf, int len, struct sockaddr_in *to)
3340a3e6 396{
d5d466fc 397 int x;
d87ebd78 398 debug(31, 3) ("htcpSend: %s/%d\n",
56714a1a 399 inet_ntoa(to->sin_addr), (int) ntohs(to->sin_port));
400 htcpHexdump("htcpSend", buf, len);
d5d466fc 401 x = comm_udp_sendto(htcpOutSocket,
56714a1a 402 to,
d5d466fc 403 sizeof(struct sockaddr_in),
404 buf,
405 len);
406 if (x < 0)
407 debug(31, 0) ("htcpSend: FD %d sendto: %s\n", htcpOutSocket, xstrerror());
3340a3e6 408}
409
eb9ae2f7 410/*
411 * STUFF FOR RECEIVING HTCP MESSAGES
412 */
413
414static void
415htcpFreeSpecifier(htcpSpecifier * s)
416{
3a3c723d 417 safe_free(s->method);
418 safe_free(s->uri);
419 safe_free(s->version);
420 safe_free(s->req_hdrs);
9bc73deb 421 memFree(s, MEM_HTCP_SPECIFIER);
eb9ae2f7 422}
423
a2edf5dc 424static void
425htcpFreeDetail(htcpDetail * d)
426{
3a3c723d 427 safe_free(d->resp_hdrs);
428 safe_free(d->entity_hdrs);
429 safe_free(d->cache_hdrs);
9bc73deb 430 memFree(d, MEM_HTCP_DETAIL);
a2edf5dc 431}
432
56714a1a 433static int
eb9ae2f7 434htcpUnpackCountstr(char *buf, int sz, char **str)
435{
1afe05c5 436 u_short l;
d87ebd78 437 debug(31, 3) ("htcpUnpackCountstr: sz = %d\n", sz);
1afe05c5 438 if (sz < 2) {
d87ebd78 439 debug(31, 3) ("htcpUnpackCountstr: sz < 2\n");
1afe05c5 440 return -1;
441 }
56714a1a 442 htcpHexdump("htcpUnpackCountstr", buf, sz);
1afe05c5 443 xmemcpy(&l, buf, 2);
56714a1a 444 l = ntohs(l);
1afe05c5 445 buf += 2;
446 sz -= 2;
d87ebd78 447 debug(31, 3) ("htcpUnpackCountstr: LENGTH = %d\n", (int) l);
1afe05c5 448 if (sz < l) {
d87ebd78 449 debug(31, 3) ("htcpUnpackCountstr: sz(%d) < l(%d)\n", sz, l);
1afe05c5 450 return -1;
451 }
452 if (str) {
453 *str = xmalloc(l + 1);
454 xstrncpy(*str, buf, l + 1);
d87ebd78 455 debug(31, 3) ("htcpUnpackCountstr: TEXT = {%s}\n", *str);
1afe05c5 456 }
457 return (int) l + 2;
eb9ae2f7 458}
459
56714a1a 460static htcpSpecifier *
eb9ae2f7 461htcpUnpackSpecifier(char *buf, int sz)
462{
9bc73deb 463 htcpSpecifier *s = memAllocate(MEM_HTCP_SPECIFIER);
1afe05c5 464 int o;
d87ebd78 465 debug(31, 3) ("htcpUnpackSpecifier: %d bytes\n", (int) sz);
1afe05c5 466 o = htcpUnpackCountstr(buf, sz, &s->method);
467 if (o < 0) {
468 debug(31, 1) ("htcpUnpackSpecifier: failed to unpack METHOD\n");
469 htcpFreeSpecifier(s);
470 return NULL;
471 }
472 buf += o;
473 sz -= o;
1afe05c5 474 o = htcpUnpackCountstr(buf, sz, &s->uri);
475 if (o < 0) {
476 debug(31, 1) ("htcpUnpackSpecifier: failed to unpack URI\n");
477 htcpFreeSpecifier(s);
478 return NULL;
479 }
480 buf += o;
481 sz -= o;
1afe05c5 482 o = htcpUnpackCountstr(buf, sz, &s->version);
483 if (o < 0) {
484 debug(31, 1) ("htcpUnpackSpecifier: failed to unpack VERSION\n");
485 htcpFreeSpecifier(s);
486 return NULL;
487 }
488 buf += o;
489 sz -= o;
1afe05c5 490 o = htcpUnpackCountstr(buf, sz, &s->req_hdrs);
491 if (o < 0) {
492 debug(31, 1) ("htcpUnpackSpecifier: failed to unpack REQ-HDRS\n");
493 htcpFreeSpecifier(s);
494 return NULL;
495 }
496 buf += o;
497 sz -= o;
d87ebd78 498 debug(31, 3) ("htcpUnpackSpecifier: %d bytes left\n", sz);
1afe05c5 499 return s;
eb9ae2f7 500}
501
a2edf5dc 502static htcpDetail *
503htcpUnpackDetail(char *buf, int sz)
504{
9bc73deb 505 htcpDetail *d = memAllocate(MEM_HTCP_DETAIL);
a2edf5dc 506 int o;
d87ebd78 507 debug(31, 3) ("htcpUnpackDetail: %d bytes\n", (int) sz);
a2edf5dc 508 o = htcpUnpackCountstr(buf, sz, &d->resp_hdrs);
509 if (o < 0) {
510 debug(31, 1) ("htcpUnpackDetail: failed to unpack RESP_HDRS\n");
511 htcpFreeDetail(d);
512 return NULL;
513 }
514 buf += o;
515 sz -= o;
516 o = htcpUnpackCountstr(buf, sz, &d->entity_hdrs);
517 if (o < 0) {
518 debug(31, 1) ("htcpUnpackDetail: failed to unpack ENTITY_HDRS\n");
519 htcpFreeDetail(d);
520 return NULL;
521 }
522 buf += o;
523 sz -= o;
524 o = htcpUnpackCountstr(buf, sz, &d->cache_hdrs);
525 if (o < 0) {
526 debug(31, 1) ("htcpUnpackDetail: failed to unpack CACHE_HDRS\n");
527 htcpFreeDetail(d);
528 return NULL;
529 }
530 buf += o;
531 sz -= o;
d87ebd78 532 debug(31, 3) ("htcpUnpackDetail: %d bytes left\n", sz);
a2edf5dc 533 return d;
534}
535
eb9ae2f7 536static void
886f2785 537htcpTstReply(htcpDataHeader * dhdr, StoreEntry * e, htcpSpecifier * spec, struct sockaddr_in *from)
60fac9b5 538{
539 htcpStuff stuff;
540 char *pkt;
2dcc81d4 541 HttpHeader hdr;
542 MemBuf mb;
543 Packer p;
60fac9b5 544 ssize_t pktlen;
2dcc81d4 545 char *host;
546 int rtt = 0;
547 int hops = 0;
548 int samp = 0;
549 char cto_buf[128];
9bc73deb 550 memset(&stuff, '\0', sizeof(stuff));
60fac9b5 551 stuff.op = HTCP_TST;
552 stuff.rr = RR_RESPONSE;
44e237d0 553 stuff.f1 = 0;
554 stuff.response = e ? 0 : 1;
7e3ce7b9 555 debug(31, 3) ("htcpTstReply: response = %d\n", stuff.response);
26df9ec6 556 stuff.msg_id = dhdr->msg_id;
60fac9b5 557 if (spec) {
2dcc81d4 558 memBufDefInit(&mb);
559 packerToMemInit(&p, &mb);
560 httpHeaderInit(&hdr, hoHtcpReply);
a2edf5dc 561 stuff.S.method = spec->method;
562 stuff.S.uri = spec->uri;
563 stuff.S.version = spec->version;
564 stuff.S.req_hdrs = spec->req_hdrs;
2dcc81d4 565 httpHeaderPutInt(&hdr, HDR_AGE,
566 e->timestamp <= squid_curtime ?
567 squid_curtime - e->timestamp : 0);
568 httpHeaderPackInto(&hdr, &p);
a2edf5dc 569 stuff.D.resp_hdrs = xstrdup(mb.buf);
d87ebd78 570 debug(31, 3) ("htcpTstReply: resp_hdrs = {%s}\n", stuff.D.resp_hdrs);
2dcc81d4 571 memBufReset(&mb);
572 httpHeaderReset(&hdr);
573 if (e->expires > -1)
574 httpHeaderPutTime(&hdr, HDR_EXPIRES, e->expires);
575 if (e->lastmod > -1)
576 httpHeaderPutTime(&hdr, HDR_LAST_MODIFIED, e->lastmod);
577 httpHeaderPackInto(&hdr, &p);
a2edf5dc 578 stuff.D.entity_hdrs = xstrdup(mb.buf);
d87ebd78 579 debug(31, 3) ("htcpTstReply: entity_hdrs = {%s}\n", stuff.D.entity_hdrs);
2dcc81d4 580 memBufReset(&mb);
581 httpHeaderReset(&hdr);
582 if ((host = urlHostname(spec->uri))) {
583 netdbHostData(host, &samp, &rtt, &hops);
584 if (rtt || hops) {
585 snprintf(cto_buf, 128, "%s %d %f %d",
886f2785 586 host, samp, 0.001 * rtt, hops);
2dcc81d4 587 httpHeaderPutExt(&hdr, "Cache-to-Origin", cto_buf);
588 }
589 }
590 httpHeaderPackInto(&hdr, &p);
a2edf5dc 591 stuff.D.cache_hdrs = xstrdup(mb.buf);
d87ebd78 592 debug(31, 3) ("htcpTstReply: cache_hdrs = {%s}\n", stuff.D.cache_hdrs);
2dcc81d4 593 memBufClean(&mb);
594 httpHeaderClean(&hdr);
595 packerClean(&p);
60fac9b5 596 }
597 pkt = htcpBuildPacket(&stuff, &pktlen);
598 if (pkt == NULL) {
599 debug(31, 0) ("htcpTstReply: htcpBuildPacket() failed\n");
600 return;
601 }
602 htcpSend(pkt, (int) pktlen, from);
3a3c723d 603 xfree(pkt);
60fac9b5 604}
605
606static void
607htcpHandleNop(htcpDataHeader * hdr, char *buf, int sz, struct sockaddr_in *from)
eb9ae2f7 608{
d87ebd78 609 debug(31, 3) ("htcpHandleNop: Unimplemented\n");
eb9ae2f7 610}
611
32b3cf93 612static StoreEntry *
613htcpCheckHit(const htcpSpecifier * s)
614{
615 request_t *request;
616 method_t m = urlParseMethod(s->method);
617 StoreEntry *e = storeGetPublic(s->uri, m);
7e3ce7b9 618 char *blk_end;
619 if (NULL == e) {
620 debug(31, 3) ("htcpCheckHit: NO; public object not found\n");
32b3cf93 621 return NULL;
7e3ce7b9 622 }
623 if (!storeEntryValidToSend(e)) {
624 debug(31, 3) ("htcpCheckHit: NO; entry not valid to send\n");
32b3cf93 625 return NULL;
7e3ce7b9 626 }
32b3cf93 627 request = urlParse(m, s->uri);
7e3ce7b9 628 if (NULL == request) {
629 debug(31, 3) ("htcpCheckHit: NO; failed to parse URL\n");
32b3cf93 630 return NULL;
7e3ce7b9 631 }
632 blk_end = s->req_hdrs + strlen(s->req_hdrs);
633 if (!httpHeaderParse(&request->header, s->req_hdrs, blk_end)) {
634 debug(31, 3) ("htcpCheckHit: NO; failed to parse request headers\n");
32b3cf93 635 e = NULL;
7e3ce7b9 636 } else if (refreshCheckHTCP(e, request)) {
637 debug(31, 3) ("htcpCheckHit: NO; cached response is stale\n");
32b3cf93 638 e = NULL;
7e3ce7b9 639 } else {
640 debug(31, 3) ("htcpCheckHit: YES!?\n");
641 }
32b3cf93 642 requestDestroy(request);
643 return e;
644}
645
eb9ae2f7 646static void
60fac9b5 647htcpHandleTst(htcpDataHeader * hdr, char *buf, int sz, struct sockaddr_in *from)
eb9ae2f7 648{
d87ebd78 649 debug(31, 3) ("htcpHandleTst: sz = %d\n", (int) sz);
60fac9b5 650 if (hdr->RR == RR_REQUEST)
26df9ec6 651 htcpHandleTstRequest(hdr, buf, sz, from);
60fac9b5 652 else
653 htcpHandleTstResponse(hdr, buf, sz, from);
654}
655
656static void
657htcpHandleTstResponse(htcpDataHeader * hdr, char *buf, int sz, struct sockaddr_in *from)
658{
a2edf5dc 659 htcpReplyData htcpReply;
660 cache_key *key = NULL;
26df9ec6 661 htcpDetail *d = NULL;
a2edf5dc 662 char *t;
44e237d0 663 if (hdr->F1 == 1) {
886f2785 664 debug(31, 1) ("htcpHandleTstResponse: error condition, F1/MO == 1\n");
44e237d0 665 return;
666 }
a2edf5dc 667 memset(&htcpReply, '\0', sizeof(htcpReply));
668 httpHeaderInit(&htcpReply.hdr, hoHtcpReply);
26df9ec6 669 htcpReply.msg_id = hdr->msg_id;
d87ebd78 670 debug(31, 3) ("htcpHandleTstResponse: msg_id = %d\n", (int) htcpReply.msg_id);
44e237d0 671 htcpReply.hit = hdr->response ? 0 : 1;
26df9ec6 672 if (hdr->F1) {
d87ebd78 673 debug(31, 3) ("htcpHandleTstResponse: MISS\n");
26df9ec6 674 } else {
d87ebd78 675 debug(31, 3) ("htcpHandleTstResponse: HIT\n");
26df9ec6 676 d = htcpUnpackDetail(buf, sz);
677 if (d == NULL) {
678 debug(31, 1) ("htcpHandleTstResponse: bad DETAIL\n");
679 return;
680 }
681 if ((t = d->resp_hdrs))
682 httpHeaderParse(&htcpReply.hdr, t, t + strlen(t));
683 if ((t = d->entity_hdrs))
684 httpHeaderParse(&htcpReply.hdr, t, t + strlen(t));
685 if ((t = d->cache_hdrs))
686 httpHeaderParse(&htcpReply.hdr, t, t + strlen(t));
a2edf5dc 687 }
26df9ec6 688 key = queried_keys[htcpReply.msg_id % N_QUERIED_KEYS];
d87ebd78 689 debug(31, 3) ("htcpHandleTstResponse: key (%p) %s\n", key, storeKeyText(key));
a2edf5dc 690 neighborsHtcpReply(key, &htcpReply, from);
9bc73deb 691 httpHeaderClean(&htcpReply.hdr);
26df9ec6 692 if (d)
886f2785 693 htcpFreeDetail(d);
60fac9b5 694}
695
696static void
886f2785 697htcpHandleTstRequest(htcpDataHeader * dhdr, char *buf, int sz, struct sockaddr_in *from)
60fac9b5 698{
699 /* buf should be a SPECIFIER */
700 htcpSpecifier *s;
701 StoreEntry *e;
60fac9b5 702 if (sz == 0) {
d87ebd78 703 debug(31, 3) ("htcpHandleTst: nothing to do\n");
60fac9b5 704 return;
705 }
44e237d0 706 if (dhdr->F1 == 0)
707 return;
60fac9b5 708 s = htcpUnpackSpecifier(buf, sz);
1afe05c5 709 if (NULL == s) {
d87ebd78 710 debug(31, 3) ("htcpHandleTstRequest: htcpUnpackSpecifier failed\n");
1afe05c5 711 return;
712 }
d87ebd78 713 debug(31, 3) ("htcpHandleTstRequest: %s %s %s\n",
1afe05c5 714 s->method,
715 s->uri,
716 s->version);
d87ebd78 717 debug(31, 3) ("htcpHandleTstRequest: %s\n", s->req_hdrs);
32b3cf93 718 if ((e = htcpCheckHit(s)))
719 htcpTstReply(dhdr, e, s, from); /* hit */
720 else
721 htcpTstReply(dhdr, NULL, NULL, from); /* cache miss */
60fac9b5 722 htcpFreeSpecifier(s);
d9f9d78b 723}
724
725static void
60fac9b5 726htcpHandleMon(htcpDataHeader * hdr, char *buf, int sz, struct sockaddr_in *from)
eb9ae2f7 727{
d87ebd78 728 debug(31, 3) ("htcpHandleMon: Unimplemented\n");
eb9ae2f7 729}
730
731static void
60fac9b5 732htcpHandleSet(htcpDataHeader * hdr, char *buf, int sz, struct sockaddr_in *from)
eb9ae2f7 733{
d87ebd78 734 debug(31, 3) ("htcpHandleSet: Unimplemented\n");
eb9ae2f7 735}
736
737static void
56714a1a 738htcpHandleData(char *buf, int sz, struct sockaddr_in *from)
eb9ae2f7 739{
740 htcpDataHeader hdr;
741 if (sz < sizeof(htcpDataHeader)) {
1afe05c5 742 debug(31, 0) ("htcpHandleData: msg size less than htcpDataHeader size\n");
eb9ae2f7 743 return;
744 }
745 xmemcpy(&hdr, buf, sizeof(htcpDataHeader));
746 hdr.length = ntohs(hdr.length);
26df9ec6 747 hdr.msg_id = ntohl(hdr.msg_id);
d87ebd78 748 debug(31, 3) ("htcpHandleData: sz = %d\n", sz);
749 debug(31, 3) ("htcpHandleData: length = %d\n", (int) hdr.length);
2e531e20 750 if (hdr.opcode > HTCP_END) {
1afe05c5 751 debug(31, 0) ("htcpHandleData: opcode %d out of range\n",
eb9ae2f7 752 (int) hdr.opcode);
753 return;
754 }
d87ebd78 755 debug(31, 3) ("htcpHandleData: opcode = %d %s\n",
eb9ae2f7 756 (int) hdr.opcode, htcpOpcodeStr[hdr.opcode]);
d87ebd78 757 debug(31, 3) ("htcpHandleData: response = %d\n", (int) hdr.response);
758 debug(31, 3) ("htcpHandleData: F1 = %d\n", (int) hdr.F1);
759 debug(31, 3) ("htcpHandleData: RR = %d\n", (int) hdr.RR);
760 debug(31, 3) ("htcpHandleData: msg_id = %d\n", (int) hdr.msg_id);
eb9ae2f7 761 if (sz < hdr.length) {
1afe05c5 762 debug(31, 0) ("htcpHandle: sz < hdr.length\n");
eb9ae2f7 763 return;
764 }
60fac9b5 765 /*
766 * set sz = hdr.length so we ignore any AUTH fields following
767 * the DATA.
768 */
769 sz = (int) hdr.length;
eb9ae2f7 770 buf += sizeof(htcpDataHeader);
771 sz -= sizeof(htcpDataHeader);
d87ebd78 772 debug(31, 3) ("htcpHandleData: sz = %d\n", sz);
56714a1a 773 htcpHexdump("htcpHandleData", buf, sz);
1afe05c5 774 switch (hdr.opcode) {
eb9ae2f7 775 case HTCP_NOP:
60fac9b5 776 htcpHandleNop(&hdr, buf, sz, from);
eb9ae2f7 777 break;
778 case HTCP_TST:
60fac9b5 779 htcpHandleTst(&hdr, buf, sz, from);
eb9ae2f7 780 break;
781 case HTCP_MON:
60fac9b5 782 htcpHandleMon(&hdr, buf, sz, from);
eb9ae2f7 783 break;
784 case HTCP_SET:
60fac9b5 785 htcpHandleSet(&hdr, buf, sz, from);
eb9ae2f7 786 break;
787 default:
788 assert(0);
789 break;
790 }
791}
792
793static void
794htcpHandle(char *buf, int sz, struct sockaddr_in *from)
795{
796 htcpHeader htcpHdr;
797 if (sz < sizeof(htcpHeader)) {
1afe05c5 798 debug(31, 0) ("htcpHandle: msg size less than htcpHeader size\n");
eb9ae2f7 799 return;
800 }
56714a1a 801 htcpHexdump("htcpHandle", buf, sz);
eb9ae2f7 802 xmemcpy(&htcpHdr, buf, sizeof(htcpHeader));
803 htcpHdr.length = ntohs(htcpHdr.length);
d87ebd78 804 debug(31, 3) ("htcpHandle: htcpHdr.length = %d\n", (int) htcpHdr.length);
805 debug(31, 3) ("htcpHandle: htcpHdr.major = %d\n", (int) htcpHdr.major);
806 debug(31, 3) ("htcpHandle: htcpHdr.minor = %d\n", (int) htcpHdr.minor);
eb9ae2f7 807 if (sz != htcpHdr.length) {
efd900cb 808 debug(31, 1) ("htcpHandle: sz != htcpHdr.length\n");
eb9ae2f7 809 return;
810 }
811 buf += sizeof(htcpHeader);
812 sz -= sizeof(htcpHeader);
56714a1a 813 htcpHandleData(buf, sz, from);
eb9ae2f7 814}
815
56714a1a 816static void
eb9ae2f7 817htcpRecv(int fd, void *data)
818{
819 static char buf[8192];
820 int len;
821 static struct sockaddr_in from;
822 int flen = sizeof(struct sockaddr_in);
823 memset(&from, '\0', flen);
83704487 824 statCounter.syscalls.sock.recvfroms++;
eb9ae2f7 825 len = recvfrom(fd, buf, 8192, 0, (struct sockaddr *) &from, &flen);
d87ebd78 826 debug(31, 3) ("htcpRecv: FD %d, %d bytes from %s:%d\n",
eb9ae2f7 827 fd, len, inet_ntoa(from.sin_addr), ntohs(from.sin_port));
828 htcpHandle(buf, len, &from);
829 commSetSelect(fd, COMM_SELECT_READ, htcpRecv, NULL, 0);
830}
831
56714a1a 832/*
833 * ======================================================================
834 * PUBLIC FUNCTIONS
835 * ======================================================================
836 */
837
d5d466fc 838void
839htcpInit(void)
3340a3e6 840{
d5d466fc 841 enter_suid();
842 htcpInSocket = comm_open(SOCK_DGRAM,
843 0,
844 Config.Addrs.udp_incoming,
845 Config.Port.htcp,
846 COMM_NONBLOCKING,
847 "HTCP Socket");
848 leave_suid();
849 if (htcpInSocket < 0)
850 fatal("Cannot open HTCP Socket");
851 commSetSelect(htcpInSocket, COMM_SELECT_READ, htcpRecv, NULL, 0);
ba3eec6b 852 debug(31, 1) ("Accepting HTCP messages on port %d, FD %d.\n",
d5d466fc 853 (int) Config.Port.htcp, htcpInSocket);
854 if (Config.Addrs.udp_outgoing.s_addr != no_addr.s_addr) {
855 enter_suid();
856 htcpOutSocket = comm_open(SOCK_DGRAM,
857 0,
858 Config.Addrs.udp_outgoing,
859 Config.Port.htcp,
860 COMM_NONBLOCKING,
861 "Outgoing HTCP Socket");
862 leave_suid();
863 if (htcpOutSocket < 0)
864 fatal("Cannot open Outgoing HTCP Socket");
865 commSetSelect(htcpOutSocket, COMM_SELECT_READ, htcpRecv, NULL, 0);
ba3eec6b 866 debug(31, 1) ("Outgoing HTCP messages on port %d, FD %d.\n",
d5d466fc 867 (int) Config.Port.htcp, htcpOutSocket);
868 fd_note(htcpInSocket, "Incoming HTCP socket");
869 } else {
870 htcpOutSocket = htcpInSocket;
871 }
9bc73deb 872 memDataInit(MEM_HTCP_SPECIFIER, "htcpSpecifier", sizeof(htcpSpecifier), 0);
873 memDataInit(MEM_HTCP_DETAIL, "htcpDetail", sizeof(htcpDetail), 0);
59c4d35b 874}
72549e05 875
56714a1a 876void
877htcpQuery(StoreEntry * e, request_t * req, peer * p)
878{
26df9ec6 879 cache_key *save_key;
56714a1a 880 char *pkt;
881 ssize_t pktlen;
882 char vbuf[32];
883 htcpStuff stuff;
884 HttpHeader hdr;
885 Packer pa;
886 MemBuf mb;
9c48373d 887 http_state_flags flags;
888 memset(&flags, '\0', sizeof(flags));
56714a1a 889 snprintf(vbuf, sizeof(vbuf), "%3.1f", req->http_ver);
890 stuff.op = HTCP_TST;
891 stuff.rr = RR_REQUEST;
892 stuff.f1 = 1;
893 stuff.response = 0;
26df9ec6 894 stuff.msg_id = ++msg_id_counter;
9c48373d 895 stuff.S.method = (char *) RequestMethodStr[req->method];
896 stuff.S.uri = (char *) storeUrl(e);
a2edf5dc 897 stuff.S.version = vbuf;
9c48373d 898 httpBuildRequestHeader(req, req, e, &hdr, -1, flags);
56714a1a 899 memBufDefInit(&mb);
900 packerToMemInit(&pa, &mb);
901 httpHeaderPackInto(&hdr, &pa);
902 httpHeaderClean(&hdr);
903 packerClean(&pa);
a2edf5dc 904 stuff.S.req_hdrs = mb.buf;
56714a1a 905 pkt = htcpBuildPacket(&stuff, &pktlen);
9bc73deb 906 memBufClean(&mb);
56714a1a 907 if (pkt == NULL) {
908 debug(31, 0) ("htcpQuery: htcpBuildPacket() failed\n");
909 return;
910 }
911 htcpSend(pkt, (int) pktlen, &p->in_addr);
26df9ec6 912 save_key = queried_keys[stuff.msg_id % N_QUERIED_KEYS];
6c40d272 913 storeKeyCopy(save_key, e->hash.key);
d87ebd78 914 debug(31, 3) ("htcpQuery: key (%p) %s\n", save_key, storeKeyText(save_key));
3a3c723d 915 xfree(pkt);
56714a1a 916}
917
72549e05 918/*
919 * htcpSocketShutdown only closes the 'in' socket if it is
920 * different than the 'out' socket.
1afe05c5 921 */
72549e05 922void
923htcpSocketShutdown(void)
1afe05c5 924{
72549e05 925 if (htcpInSocket < 0)
1afe05c5 926 return;
927 if (htcpInSocket != htcpOutSocket) {
928 debug(12, 1) ("FD %d Closing HTCP socket\n", htcpInSocket);
929 comm_close(htcpInSocket);
930 }
72549e05 931 /*
932 * Here we set 'htcpInSocket' to -1 even though the HTCP 'in'
933 * and 'out' sockets might be just one FD. This prevents this
934 * function from executing repeatedly. When we are really ready to
935 * exit or restart, main will comm_close the 'out' descriptor.
1afe05c5 936 */
72549e05 937 htcpInSocket = -1;
938 /*
939 * Normally we only write to the outgoing HTCP socket, but
940 * we also have a read handler there to catch messages sent
941 * to that specific interface. During shutdown, we must
942 * disable reading on the outgoing socket.
1afe05c5 943 */
72549e05 944 assert(htcpOutSocket > -1);
945 commSetSelect(htcpOutSocket, COMM_SELECT_READ, NULL, NULL, 0);
946}
947
1afe05c5 948void
72549e05 949htcpSocketClose(void)
950{
951 htcpSocketShutdown();
952 if (htcpOutSocket > -1) {
1afe05c5 953 debug(12, 1) ("FD %d Closing HTCP socket\n", htcpOutSocket);
954 comm_close(htcpOutSocket);
955 }
956}