]> git.ipfire.org Git - thirdparty/squid.git/blob - src/htcp.cc
merge changes from SQUID_2_3 branch
[thirdparty/squid.git] / src / htcp.cc
1
2 /*
3 * $Id: htcp.cc,v 1.29 1999/12/30 17:36:35 wessels Exp $
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 *
34 */
35
36 #include "squid.h"
37
38 typedef struct _Countstr Countstr;
39 typedef struct _htcpHeader htcpHeader;
40 typedef struct _htcpDataHeader htcpDataHeader;
41 typedef struct _htcpAuthHeader htcpAuthHeader;
42 typedef struct _htcpStuff htcpStuff;
43 typedef struct _htcpSpecifier htcpSpecifier;
44 typedef struct _htcpDetail htcpDetail;
45
46 struct _Countstr {
47 u_short length;
48 char *text;
49 };
50
51 struct _htcpHeader {
52 u_short length;
53 u_char major;
54 u_char minor;
55 };
56
57 struct _htcpDataHeader {
58 u_short length;
59 #if !WORDS_BIGENDIAN
60 unsigned int opcode:4;
61 unsigned int response:4;
62 #else
63 unsigned int response:4;
64 unsigned int opcode:4;
65 #endif
66 #if !WORDS_BIGENDIAN
67 unsigned int reserved:6;
68 unsigned int F1:1;
69 unsigned int RR:1;
70 #else
71 unsigned int RR:1;
72 unsigned int F1:1;
73 unsigned int reserved:6;
74 #endif
75 u_num32 msg_id;
76 };
77
78 /* RR == 0 --> F1 = RESPONSE DESIRED FLAG */
79 /* RR == 1 --> F1 = MESSAGE OVERALL FLAG */
80 /* RR == 0 --> REQUEST */
81 /* RR == 1 --> RESPONSE */
82
83 struct _htcpAuthHeader {
84 u_short length;
85 time_t sig_time;
86 time_t sig_expire;
87 Countstr key_name;
88 Countstr signature;
89 };
90
91 struct _htcpSpecifier {
92 char *method;
93 char *uri;
94 char *version;
95 char *req_hdrs;
96 };
97
98 struct _htcpDetail {
99 char *resp_hdrs;
100 char *entity_hdrs;
101 char *cache_hdrs;
102 };
103
104 struct _htcpStuff {
105 int op;
106 int rr;
107 int f1;
108 int response;
109 u_num32 msg_id;
110 htcpSpecifier S;
111 htcpDetail D;
112 };
113
114 enum {
115 HTCP_NOP,
116 HTCP_TST,
117 HTCP_MON,
118 HTCP_SET,
119 HTCP_CLR,
120 HTCP_END
121 };
122
123 static const char *const htcpOpcodeStr[] =
124 {
125 "HTCP_NOP",
126 "HTCP_TST",
127 "HTCP_MON",
128 "HTCP_SET",
129 "HTCP_CLR",
130 "HTCP_END"
131 };
132
133 /*
134 * values for htcpDataHeader->response
135 */
136 enum {
137 AUTH_REQUIRED,
138 AUTH_FAILURE,
139 OPCODE_UNIMPLEMENTED,
140 MAJOR_VERSION_UNSUPPORTED,
141 MINOR_VERSION_UNSUPPORTED,
142 INVALID_OPCODE
143 };
144
145 /*
146 * values for htcpDataHeader->RR
147 */
148 enum {
149 RR_REQUEST,
150 RR_RESPONSE
151 };
152
153 static u_num32 msg_id_counter = 0;
154 static int htcpInSocket = -1;
155 static int htcpOutSocket = -1;
156 #define N_QUERIED_KEYS 256
157 static cache_key queried_keys[N_QUERIED_KEYS][MD5_DIGEST_CHARS];
158
159 static char *htcpBuildPacket(htcpStuff * stuff, ssize_t * len);
160 static htcpSpecifier *htcpUnpackSpecifier(char *buf, int sz);
161 static htcpDetail *htcpUnpackDetail(char *buf, int sz);
162 static int htcpUnpackCountstr(char *buf, int sz, char **str);
163 static ssize_t htcpBuildAuth(char *buf, size_t buflen);
164 static ssize_t htcpBuildCountstr(char *buf, size_t buflen, const char *s);
165 static ssize_t htcpBuildData(char *buf, size_t buflen, htcpStuff * stuff);
166 static ssize_t htcpBuildDetail(char *buf, size_t buflen, htcpStuff * stuff);
167 static ssize_t htcpBuildOpData(char *buf, size_t buflen, htcpStuff * stuff);
168 static ssize_t htcpBuildSpecifier(char *buf, size_t buflen, htcpStuff * stuff);
169 static ssize_t htcpBuildTstOpData(char *buf, size_t buflen, htcpStuff * stuff);
170 static void htcpFreeSpecifier(htcpSpecifier * s);
171 static void htcpFreeDetail(htcpDetail * s);
172 static void htcpHandle(char *buf, int sz, struct sockaddr_in *from);
173 static void htcpHandleData(char *buf, int sz, struct sockaddr_in *from);
174 static void htcpHandleMon(htcpDataHeader *, char *buf, int sz, struct sockaddr_in *from);
175 static void htcpHandleNop(htcpDataHeader *, char *buf, int sz, struct sockaddr_in *from);
176 static void htcpHandleSet(htcpDataHeader *, char *buf, int sz, struct sockaddr_in *from);
177 static void htcpHandleTst(htcpDataHeader *, char *buf, int sz, struct sockaddr_in *from);
178 static void htcpRecv(int fd, void *data);
179 static void htcpSend(const char *buf, int len, struct sockaddr_in *to);
180 static void htcpTstReply(htcpDataHeader *, StoreEntry *, htcpSpecifier *, struct sockaddr_in *);
181 static void htcpHandleTstRequest(htcpDataHeader *, char *buf, int sz, struct sockaddr_in *from);
182 static void htcpHandleTstResponse(htcpDataHeader *, char *, int, struct sockaddr_in *);
183 static StoreEntry *htcpCheckHit(const htcpSpecifier *);
184
185 static void
186 htcpHexdump(const char *tag, const char *s, int sz)
187 {
188 #if USE_HEXDUMP
189 int i;
190 int k;
191 char hex[80];
192 debug(31, 3) ("htcpHexdump %s\n", tag);
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;
199 debug(31, 3) ("\t%s\n", hex);
200 memset(hex, '\0', 80);
201 }
202 #endif
203 }
204
205 /*
206 * STUFF FOR SENDING HTCP MESSAGES
207 */
208
209 static ssize_t
210 htcpBuildAuth(char *buf, size_t buflen)
211 {
212 htcpAuthHeader auth;
213 size_t copy_sz = 0;
214 assert(2 == sizeof(u_short));
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
222 static ssize_t
223 htcpBuildCountstr(char *buf, size_t buflen, const char *s)
224 {
225 u_short length;
226 size_t len;
227 off_t off = 0;
228 if (buflen - off < 2)
229 return -1;
230 if (s)
231 len = strlen(s);
232 else
233 len = 0;
234 debug(31, 3) ("htcpBuildCountstr: LENGTH = %d\n", len);
235 debug(31, 3) ("htcpBuildCountstr: TEXT = {%s}\n", s ? s : "<NULL>");
236 length = htons((u_short) len);
237 xmemcpy(buf + off, &length, 2);
238 off += 2;
239 if (buflen - off < len)
240 return -1;
241 if (len)
242 xmemcpy(buf + off, s, len);
243 off += len;
244 return off;
245 }
246
247 static ssize_t
248 htcpBuildSpecifier(char *buf, size_t buflen, htcpStuff * stuff)
249 {
250 ssize_t off = 0;
251 ssize_t s;
252 s = htcpBuildCountstr(buf + off, buflen - off, stuff->S.method);
253 if (s < 0)
254 return s;
255 off += s;
256 s = htcpBuildCountstr(buf + off, buflen - off, stuff->S.uri);
257 if (s < 0)
258 return s;
259 off += s;
260 s = htcpBuildCountstr(buf + off, buflen - off, stuff->S.version);
261 if (s < 0)
262 return s;
263 off += s;
264 s = htcpBuildCountstr(buf + off, buflen - off, stuff->S.req_hdrs);
265 if (s < 0)
266 return s;
267 off += s;
268 debug(31, 3) ("htcpBuildSpecifier: size %d\n", (int) off);
269 return off;
270 }
271
272 static ssize_t
273 htcpBuildDetail(char *buf, size_t buflen, htcpStuff * stuff)
274 {
275 ssize_t off = 0;
276 ssize_t s;
277 s = htcpBuildCountstr(buf + off, buflen - off, stuff->D.resp_hdrs);
278 if (s < 0)
279 return s;
280 off += s;
281 s = htcpBuildCountstr(buf + off, buflen - off, stuff->D.entity_hdrs);
282 if (s < 0)
283 return s;
284 off += s;
285 s = htcpBuildCountstr(buf + off, buflen - off, stuff->D.cache_hdrs);
286 if (s < 0)
287 return s;
288 off += s;
289 return off;
290 }
291
292 static ssize_t
293 htcpBuildTstOpData(char *buf, size_t buflen, htcpStuff * stuff)
294 {
295 switch (stuff->rr) {
296 case RR_REQUEST:
297 debug(31, 3) ("htcpBuildTstOpData: RR_REQUEST\n");
298 return htcpBuildSpecifier(buf, buflen, stuff);
299 case RR_RESPONSE:
300 debug(31, 3) ("htcpBuildTstOpData: RR_RESPONSE\n");
301 debug(31, 3) ("htcpBuildTstOpData: F1 = %d\n", stuff->f1);
302 if (stuff->f1) /* cache miss */
303 return 0;
304 else /* cache hit */
305 return htcpBuildDetail(buf, buflen, stuff);
306 default:
307 fatal_dump("htcpBuildTstOpData: bad RR value");
308 }
309 return 0;
310 }
311
312 static ssize_t
313 htcpBuildOpData(char *buf, size_t buflen, htcpStuff * stuff)
314 {
315 ssize_t off = 0;
316 debug(31, 3) ("htcpBuildOpData: opcode %s\n",
317 htcpOpcodeStr[stuff->op]);
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
329 static ssize_t
330 htcpBuildData(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;
343 debug(31, 3) ("htcpBuildData: hdr.length = %d\n", (int) off);
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;
349 hdr.msg_id = stuff->msg_id;
350 /* convert multi-byte fields */
351 hdr.length = htons(hdr.length);
352 hdr.msg_id = htonl(hdr.msg_id);
353 xmemcpy(buf, &hdr, hdr_sz);
354 debug(31, 3) ("htcpBuildData: size %d\n", (int) off);
355 return off;
356 }
357
358 static char *
359 htcpBuildPacket(htcpStuff * stuff, ssize_t * len)
360 {
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 xfree(buf);
370 return NULL;
371 }
372 off += hdr_sz;
373 s = htcpBuildData(buf + off, buflen - off, stuff);
374 if (s < 0) {
375 xfree(buf);
376 return NULL;
377 }
378 off += s;
379 s = htcpBuildAuth(buf + off, buflen - off);
380 if (s < 0) {
381 xfree(buf);
382 return NULL;
383 }
384 off += s;
385 hdr.length = htons((u_short) off);
386 hdr.major = 0;
387 hdr.minor = 0;
388 xmemcpy(buf, &hdr, hdr_sz);
389 *len = off;
390 debug(31, 3) ("htcpBuildPacket: size %d\n", (int) off);
391 return buf;
392 }
393
394 static void
395 htcpSend(const char *buf, int len, struct sockaddr_in *to)
396 {
397 int x;
398 debug(31, 3) ("htcpSend: %s/%d\n",
399 inet_ntoa(to->sin_addr), (int) ntohs(to->sin_port));
400 htcpHexdump("htcpSend", buf, len);
401 x = comm_udp_sendto(htcpOutSocket,
402 to,
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());
408 }
409
410 /*
411 * STUFF FOR RECEIVING HTCP MESSAGES
412 */
413
414 static void
415 htcpFreeSpecifier(htcpSpecifier * s)
416 {
417 safe_free(s->method);
418 safe_free(s->uri);
419 safe_free(s->version);
420 safe_free(s->req_hdrs);
421 memFree(s, MEM_HTCP_SPECIFIER);
422 }
423
424 static void
425 htcpFreeDetail(htcpDetail * d)
426 {
427 safe_free(d->resp_hdrs);
428 safe_free(d->entity_hdrs);
429 safe_free(d->cache_hdrs);
430 memFree(d, MEM_HTCP_DETAIL);
431 }
432
433 static int
434 htcpUnpackCountstr(char *buf, int sz, char **str)
435 {
436 u_short l;
437 debug(31, 3) ("htcpUnpackCountstr: sz = %d\n", sz);
438 if (sz < 2) {
439 debug(31, 3) ("htcpUnpackCountstr: sz < 2\n");
440 return -1;
441 }
442 htcpHexdump("htcpUnpackCountstr", buf, sz);
443 xmemcpy(&l, buf, 2);
444 l = ntohs(l);
445 buf += 2;
446 sz -= 2;
447 debug(31, 3) ("htcpUnpackCountstr: LENGTH = %d\n", (int) l);
448 if (sz < l) {
449 debug(31, 3) ("htcpUnpackCountstr: sz(%d) < l(%d)\n", sz, l);
450 return -1;
451 }
452 if (str) {
453 *str = xmalloc(l + 1);
454 xstrncpy(*str, buf, l + 1);
455 debug(31, 3) ("htcpUnpackCountstr: TEXT = {%s}\n", *str);
456 }
457 return (int) l + 2;
458 }
459
460 static htcpSpecifier *
461 htcpUnpackSpecifier(char *buf, int sz)
462 {
463 htcpSpecifier *s = memAllocate(MEM_HTCP_SPECIFIER);
464 int o;
465 debug(31, 3) ("htcpUnpackSpecifier: %d bytes\n", (int) sz);
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;
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;
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;
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;
498 debug(31, 3) ("htcpUnpackSpecifier: %d bytes left\n", sz);
499 return s;
500 }
501
502 static htcpDetail *
503 htcpUnpackDetail(char *buf, int sz)
504 {
505 htcpDetail *d = memAllocate(MEM_HTCP_DETAIL);
506 int o;
507 debug(31, 3) ("htcpUnpackDetail: %d bytes\n", (int) sz);
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;
532 debug(31, 3) ("htcpUnpackDetail: %d bytes left\n", sz);
533 return d;
534 }
535
536 static void
537 htcpTstReply(htcpDataHeader * dhdr, StoreEntry * e, htcpSpecifier * spec, struct sockaddr_in *from)
538 {
539 htcpStuff stuff;
540 char *pkt;
541 HttpHeader hdr;
542 MemBuf mb;
543 Packer p;
544 ssize_t pktlen;
545 char *host;
546 int rtt = 0;
547 int hops = 0;
548 int samp = 0;
549 char cto_buf[128];
550 memset(&stuff, '\0', sizeof(stuff));
551 stuff.op = HTCP_TST;
552 stuff.rr = RR_RESPONSE;
553 stuff.f1 = 0;
554 stuff.response = e ? 0 : 1;
555 debug(31, 3) ("htcpTstReply: response = %d\n", stuff.response);
556 stuff.msg_id = dhdr->msg_id;
557 if (spec) {
558 memBufDefInit(&mb);
559 packerToMemInit(&p, &mb);
560 httpHeaderInit(&hdr, hoHtcpReply);
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;
565 httpHeaderPutInt(&hdr, HDR_AGE,
566 e->timestamp <= squid_curtime ?
567 squid_curtime - e->timestamp : 0);
568 httpHeaderPackInto(&hdr, &p);
569 stuff.D.resp_hdrs = xstrdup(mb.buf);
570 debug(31, 3) ("htcpTstReply: resp_hdrs = {%s}\n", stuff.D.resp_hdrs);
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);
578 stuff.D.entity_hdrs = xstrdup(mb.buf);
579 debug(31, 3) ("htcpTstReply: entity_hdrs = {%s}\n", stuff.D.entity_hdrs);
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",
586 host, samp, 0.001 * rtt, hops);
587 httpHeaderPutExt(&hdr, "Cache-to-Origin", cto_buf);
588 }
589 }
590 httpHeaderPackInto(&hdr, &p);
591 stuff.D.cache_hdrs = xstrdup(mb.buf);
592 debug(31, 3) ("htcpTstReply: cache_hdrs = {%s}\n", stuff.D.cache_hdrs);
593 memBufClean(&mb);
594 httpHeaderClean(&hdr);
595 packerClean(&p);
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);
603 xfree(pkt);
604 }
605
606 static void
607 htcpHandleNop(htcpDataHeader * hdr, char *buf, int sz, struct sockaddr_in *from)
608 {
609 debug(31, 3) ("htcpHandleNop: Unimplemented\n");
610 }
611
612 static StoreEntry *
613 htcpCheckHit(const htcpSpecifier * s)
614 {
615 request_t *request;
616 method_t m = urlParseMethod(s->method);
617 StoreEntry *e = storeGetPublic(s->uri, m);
618 char *blk_end;
619 if (NULL == e) {
620 debug(31, 3) ("htcpCheckHit: NO; public object not found\n");
621 return NULL;
622 }
623 if (!storeEntryValidToSend(e)) {
624 debug(31, 3) ("htcpCheckHit: NO; entry not valid to send\n");
625 return NULL;
626 }
627 request = urlParse(m, s->uri);
628 if (NULL == request) {
629 debug(31, 3) ("htcpCheckHit: NO; failed to parse URL\n");
630 return NULL;
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");
635 e = NULL;
636 } else if (refreshCheckHTCP(e, request)) {
637 debug(31, 3) ("htcpCheckHit: NO; cached response is stale\n");
638 e = NULL;
639 } else {
640 debug(31, 3) ("htcpCheckHit: YES!?\n");
641 }
642 requestDestroy(request);
643 return e;
644 }
645
646 static void
647 htcpHandleTst(htcpDataHeader * hdr, char *buf, int sz, struct sockaddr_in *from)
648 {
649 debug(31, 3) ("htcpHandleTst: sz = %d\n", (int) sz);
650 if (hdr->RR == RR_REQUEST)
651 htcpHandleTstRequest(hdr, buf, sz, from);
652 else
653 htcpHandleTstResponse(hdr, buf, sz, from);
654 }
655
656 static void
657 htcpHandleTstResponse(htcpDataHeader * hdr, char *buf, int sz, struct sockaddr_in *from)
658 {
659 htcpReplyData htcpReply;
660 cache_key *key = NULL;
661 htcpDetail *d = NULL;
662 char *t;
663 if (hdr->F1 == 1) {
664 debug(31, 1) ("htcpHandleTstResponse: error condition, F1/MO == 1\n");
665 return;
666 }
667 memset(&htcpReply, '\0', sizeof(htcpReply));
668 httpHeaderInit(&htcpReply.hdr, hoHtcpReply);
669 htcpReply.msg_id = hdr->msg_id;
670 debug(31, 3) ("htcpHandleTstResponse: msg_id = %d\n", (int) htcpReply.msg_id);
671 htcpReply.hit = hdr->response ? 0 : 1;
672 if (hdr->F1) {
673 debug(31, 3) ("htcpHandleTstResponse: MISS\n");
674 } else {
675 debug(31, 3) ("htcpHandleTstResponse: HIT\n");
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));
687 }
688 key = queried_keys[htcpReply.msg_id % N_QUERIED_KEYS];
689 debug(31, 3) ("htcpHandleTstResponse: key (%p) %s\n", key, storeKeyText(key));
690 neighborsHtcpReply(key, &htcpReply, from);
691 httpHeaderClean(&htcpReply.hdr);
692 if (d)
693 htcpFreeDetail(d);
694 }
695
696 static void
697 htcpHandleTstRequest(htcpDataHeader * dhdr, char *buf, int sz, struct sockaddr_in *from)
698 {
699 /* buf should be a SPECIFIER */
700 htcpSpecifier *s;
701 StoreEntry *e;
702 if (sz == 0) {
703 debug(31, 3) ("htcpHandleTst: nothing to do\n");
704 return;
705 }
706 if (dhdr->F1 == 0)
707 return;
708 s = htcpUnpackSpecifier(buf, sz);
709 if (NULL == s) {
710 debug(31, 3) ("htcpHandleTstRequest: htcpUnpackSpecifier failed\n");
711 return;
712 }
713 debug(31, 3) ("htcpHandleTstRequest: %s %s %s\n",
714 s->method,
715 s->uri,
716 s->version);
717 debug(31, 3) ("htcpHandleTstRequest: %s\n", s->req_hdrs);
718 if ((e = htcpCheckHit(s)))
719 htcpTstReply(dhdr, e, s, from); /* hit */
720 else
721 htcpTstReply(dhdr, NULL, NULL, from); /* cache miss */
722 htcpFreeSpecifier(s);
723 }
724
725 static void
726 htcpHandleMon(htcpDataHeader * hdr, char *buf, int sz, struct sockaddr_in *from)
727 {
728 debug(31, 3) ("htcpHandleMon: Unimplemented\n");
729 }
730
731 static void
732 htcpHandleSet(htcpDataHeader * hdr, char *buf, int sz, struct sockaddr_in *from)
733 {
734 debug(31, 3) ("htcpHandleSet: Unimplemented\n");
735 }
736
737 static void
738 htcpHandleData(char *buf, int sz, struct sockaddr_in *from)
739 {
740 htcpDataHeader hdr;
741 if (sz < sizeof(htcpDataHeader)) {
742 debug(31, 0) ("htcpHandleData: msg size less than htcpDataHeader size\n");
743 return;
744 }
745 xmemcpy(&hdr, buf, sizeof(htcpDataHeader));
746 hdr.length = ntohs(hdr.length);
747 hdr.msg_id = ntohl(hdr.msg_id);
748 debug(31, 3) ("htcpHandleData: sz = %d\n", sz);
749 debug(31, 3) ("htcpHandleData: length = %d\n", (int) hdr.length);
750 if (hdr.opcode > HTCP_END) {
751 debug(31, 0) ("htcpHandleData: opcode %d out of range\n",
752 (int) hdr.opcode);
753 return;
754 }
755 debug(31, 3) ("htcpHandleData: opcode = %d %s\n",
756 (int) hdr.opcode, htcpOpcodeStr[hdr.opcode]);
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);
761 if (sz < hdr.length) {
762 debug(31, 0) ("htcpHandle: sz < hdr.length\n");
763 return;
764 }
765 /*
766 * set sz = hdr.length so we ignore any AUTH fields following
767 * the DATA.
768 */
769 sz = (int) hdr.length;
770 buf += sizeof(htcpDataHeader);
771 sz -= sizeof(htcpDataHeader);
772 debug(31, 3) ("htcpHandleData: sz = %d\n", sz);
773 htcpHexdump("htcpHandleData", buf, sz);
774 switch (hdr.opcode) {
775 case HTCP_NOP:
776 htcpHandleNop(&hdr, buf, sz, from);
777 break;
778 case HTCP_TST:
779 htcpHandleTst(&hdr, buf, sz, from);
780 break;
781 case HTCP_MON:
782 htcpHandleMon(&hdr, buf, sz, from);
783 break;
784 case HTCP_SET:
785 htcpHandleSet(&hdr, buf, sz, from);
786 break;
787 default:
788 assert(0);
789 break;
790 }
791 }
792
793 static void
794 htcpHandle(char *buf, int sz, struct sockaddr_in *from)
795 {
796 htcpHeader htcpHdr;
797 if (sz < sizeof(htcpHeader)) {
798 debug(31, 0) ("htcpHandle: msg size less than htcpHeader size\n");
799 return;
800 }
801 htcpHexdump("htcpHandle", buf, sz);
802 xmemcpy(&htcpHdr, buf, sizeof(htcpHeader));
803 htcpHdr.length = ntohs(htcpHdr.length);
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);
807 if (sz != htcpHdr.length) {
808 debug(31, 0) ("htcpHandle: sz != htcpHdr.length\n");
809 return;
810 }
811 buf += sizeof(htcpHeader);
812 sz -= sizeof(htcpHeader);
813 htcpHandleData(buf, sz, from);
814 }
815
816 static void
817 htcpRecv(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);
824 Counter.syscalls.sock.recvfroms++;
825 len = recvfrom(fd, buf, 8192, 0, (struct sockaddr *) &from, &flen);
826 debug(31, 3) ("htcpRecv: FD %d, %d bytes from %s:%d\n",
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
832 /*
833 * ======================================================================
834 * PUBLIC FUNCTIONS
835 * ======================================================================
836 */
837
838 void
839 htcpInit(void)
840 {
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);
852 debug(31, 1) ("Accepting HTCP messages on port %d, FD %d.\n",
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);
866 debug(31, 1) ("Outgoing HTCP messages on port %d, FD %d.\n",
867 (int) Config.Port.htcp, htcpOutSocket);
868 fd_note(htcpInSocket, "Incoming HTCP socket");
869 } else {
870 htcpOutSocket = htcpInSocket;
871 }
872 memDataInit(MEM_HTCP_SPECIFIER, "htcpSpecifier", sizeof(htcpSpecifier), 0);
873 memDataInit(MEM_HTCP_DETAIL, "htcpDetail", sizeof(htcpDetail), 0);
874 }
875
876 void
877 htcpQuery(StoreEntry * e, request_t * req, peer * p)
878 {
879 cache_key *save_key;
880 char *pkt;
881 ssize_t pktlen;
882 char vbuf[32];
883 htcpStuff stuff;
884 HttpHeader hdr;
885 Packer pa;
886 MemBuf mb;
887 http_state_flags flags;
888 memset(&flags, '\0', sizeof(flags));
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;
894 stuff.msg_id = ++msg_id_counter;
895 stuff.S.method = (char *) RequestMethodStr[req->method];
896 stuff.S.uri = (char *) storeUrl(e);
897 stuff.S.version = vbuf;
898 httpBuildRequestHeader(req, req, e, &hdr, -1, flags);
899 memBufDefInit(&mb);
900 packerToMemInit(&pa, &mb);
901 httpHeaderPackInto(&hdr, &pa);
902 httpHeaderClean(&hdr);
903 packerClean(&pa);
904 stuff.S.req_hdrs = mb.buf;
905 pkt = htcpBuildPacket(&stuff, &pktlen);
906 memBufClean(&mb);
907 if (pkt == NULL) {
908 debug(31, 0) ("htcpQuery: htcpBuildPacket() failed\n");
909 return;
910 }
911 htcpSend(pkt, (int) pktlen, &p->in_addr);
912 save_key = queried_keys[stuff.msg_id % N_QUERIED_KEYS];
913 storeKeyCopy(save_key, e->key);
914 debug(31, 3) ("htcpQuery: key (%p) %s\n", save_key, storeKeyText(save_key));
915 xfree(pkt);
916 }
917
918 /*
919 * htcpSocketShutdown only closes the 'in' socket if it is
920 * different than the 'out' socket.
921 */
922 void
923 htcpSocketShutdown(void)
924 {
925 if (htcpInSocket < 0)
926 return;
927 if (htcpInSocket != htcpOutSocket) {
928 debug(12, 1) ("FD %d Closing HTCP socket\n", htcpInSocket);
929 comm_close(htcpInSocket);
930 }
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.
936 */
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.
943 */
944 assert(htcpOutSocket > -1);
945 commSetSelect(htcpOutSocket, COMM_SELECT_READ, NULL, NULL, 0);
946 }
947
948 void
949 htcpSocketClose(void)
950 {
951 htcpSocketShutdown();
952 if (htcpOutSocket > -1) {
953 debug(12, 1) ("FD %d Closing HTCP socket\n", htcpOutSocket);
954 comm_close(htcpOutSocket);
955 }
956 }