]> git.ipfire.org Git - thirdparty/squid.git/blame - src/htcp.cc
progress
[thirdparty/squid.git] / src / htcp.cc
CommitLineData
d5d466fc 1
2/*
56714a1a 3 * $Id: htcp.cc,v 1.13 1998/08/25 06:20:42 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;
c1b92ccb 44
45struct _Countstr {
59c4d35b 46 u_short length;
47 char *text;
c1b92ccb 48};
49
50struct _htcpHeader {
59c4d35b 51 u_short length;
52 u_char major;
53 u_char minor;
c1b92ccb 54};
55
56struct _htcpDataHeader {
59c4d35b 57 u_short length;
eb9ae2f7 58#if !WORDS_BIGENDIAN
59c4d35b 59 u_char opcode:4;
60 u_char response:4;
eb9ae2f7 61#else
62 u_char response:4;
63 u_char opcode:4;
64#endif
65#if !WORDS_BIGENDIAN
59c4d35b 66 u_char reserved:6;
67 u_char F1:1;
eb9ae2f7 68 u_char RR:1;
69#else
70 u_char RR:1;
71 u_char F1:1;
72 u_char reserved:6;
73#endif
74 u_num32 msg_id;
75};
76
59c4d35b 77 /* RR == 0 --> F1 = RESPONSE DESIRED FLAG */
78 /* RR == 1 --> F1 = MESSAGE OVERALL FLAG */
59c4d35b 79 /* RR == 0 --> REQUEST */
80 /* RR == 1 --> RESPONSE */
c1b92ccb 81
82struct _htcpAuthHeader {
59c4d35b 83 u_short length;
84 time_t sig_time;
85 time_t sig_expire;
86 Countstr key_name;
87 Countstr signature;
c1b92ccb 88};
89
eb9ae2f7 90struct _htcpSpecifier {
91 char *method;
92 char *uri;
93 char *version;
94 char *req_hdrs;
95};
96
d5d466fc 97struct _htcpStuff {
98 int op;
99 int rr;
100 int f1;
101 int response;
102 const char *method;
103 const char *uri;
104 const char *version;
105 const char *req_hdrs;
56714a1a 106 const char *resp_hdrs;
107 const char *entity_hdrs;
108 const char *cache_hdrs;
c1b92ccb 109};
110
111enum {
59c4d35b 112 HTCP_NOP,
113 HTCP_TST,
114 HTCP_MON,
115 HTCP_SET,
eb9ae2f7 116 HTCP_CLR,
117 HTCP_END
118};
119
1afe05c5 120static const char *const htcpOpcodeStr[] =
121{
122 "HTCP_NOP",
123 "HTCP_TST",
124 "HTCP_MON",
125 "HTCP_SET",
126 "HTCP_CLR",
127 "HTCP_END"
c1b92ccb 128};
129
130/*
131 * values for htcpDataHeader->response
132 */
133enum {
59c4d35b 134 AUTH_REQUIRED,
135 AUTH_FAILURE,
136 OPCODE_UNIMPLEMENTED,
137 MAJOR_VERSION_UNSUPPORTED,
138 MINOR_VERSION_UNSUPPORTED,
139 INVALID_OPCODE
c1b92ccb 140};
141
142/*
143 * values for htcpDataHeader->RR
144 */
145enum {
59c4d35b 146 RR_REQUEST,
147 RR_RESPONSE
c1b92ccb 148};
149
d5d466fc 150static u_num32 msg_id_counter = 0;
151static int htcpInSocket = -1;
152static int htcpOutSocket = -1;
59c4d35b 153
56714a1a 154static char *htcpBuildPacket(htcpStuff * stuff, ssize_t * len);
155static htcpSpecifier *htcpUnpackSpecifier(char *buf, int sz);
156static int htcpUnpackCountstr(char *buf, int sz, char **str);
157static ssize_t htcpBuildAuth(char *buf, size_t buflen);
158static ssize_t htcpBuildCountstr(char *buf, size_t buflen, const char *s);
159static ssize_t htcpBuildData(char *buf, size_t buflen, htcpStuff * stuff);
160static ssize_t htcpBuildDetail(char *buf, size_t buflen, htcpStuff * stuff);
161static ssize_t htcpBuildOpData(char *buf, size_t buflen, htcpStuff * stuff);
162static ssize_t htcpBuildSpecifier(char *buf, size_t buflen, htcpStuff * stuff);
163static ssize_t htcpBuildTstOpData(char *buf, size_t buflen, htcpStuff * stuff);
164static void htcpFreeSpecifier(htcpSpecifier * s);
165static void htcpHandle(char *buf, int sz, struct sockaddr_in *from);
166static void htcpHandleData(char *buf, int sz, struct sockaddr_in *from);
167static void htcpHandleMon(char *buf, int sz, struct sockaddr_in *from);
168static void htcpHandleNop(char *buf, int sz, struct sockaddr_in *from);
169static void htcpHandleSet(char *buf, int sz, struct sockaddr_in *from);
170static void htcpHandleTst(char *buf, int sz, struct sockaddr_in *from);
171static void htcpRecv(int fd, void *data);
172static void htcpSend(const char *buf, int len, struct sockaddr_in *to);
173static void htcpTstReply(StoreEntry *, htcpSpecifier *, struct sockaddr_in *);
174
175static void
176htcpHexdump(const char *tag, const char *s, int sz)
177{
178 int i;
179 int k;
180 char hex[80];
181 debug(31,1)("htcpHexdump %s\n", tag);
182 memset(hex, '\0', 80);
183 for (i=0; i<sz; i++) {
184 k = i % 16;
185 snprintf(&hex[k*3], 4, " %02x", (int) *(s+i));
186 if (k < 15 && i < (sz-1))
187 continue;
188 debug(31,1)("\t%s\n", hex);
189 memset(hex, '\0', 80);
190 }
191}
d9f9d78b 192
eb9ae2f7 193/*
194 * STUFF FOR SENDING HTCP MESSAGES
195 */
196
56714a1a 197static ssize_t
d5d466fc 198htcpBuildAuth(char *buf, size_t buflen)
59c4d35b 199{
3340a3e6 200 htcpAuthHeader auth;
201 size_t copy_sz = 0;
59c4d35b 202 assert(2 == sizeof(u_short));
3340a3e6 203 auth.length = htons(2);
204 copy_sz += 2;
205 assert(buflen >= copy_sz);
206 xmemcpy(buf, &auth, copy_sz);
207 return copy_sz;
208}
209
56714a1a 210static ssize_t
d5d466fc 211htcpBuildCountstr(char *buf, size_t buflen, const char *s)
212{
213 u_short length;
56714a1a 214 size_t len;
d5d466fc 215 off_t off = 0;
216 if (buflen - off < 2)
217 return -1;
56714a1a 218 if (s)
219 len = strlen(s);
220 else
221 len = 0;
222 debug(31,1)("htcpBuildCountstr: LENGTH = %d\n", len);
223 debug(31,1)("htcpBuildCountstr: TEXT = {%s}\n", s);
d5d466fc 224 length = htons((u_short) len);
225 xmemcpy(buf + off, &length, 2);
226 off += 2;
227 if (buflen - off < len)
228 return -1;
56714a1a 229 if (len)
230 xmemcpy(buf + off, s, len);
d5d466fc 231 off += len;
232 return off;
233}
234
56714a1a 235static ssize_t
d5d466fc 236htcpBuildSpecifier(char *buf, size_t buflen, htcpStuff * stuff)
237{
238 ssize_t off = 0;
239 ssize_t s;
240 s = htcpBuildCountstr(buf + off, buflen - off, stuff->method);
241 if (s < 0)
242 return s;
243 off += s;
244 s = htcpBuildCountstr(buf + off, buflen - off, stuff->uri);
245 if (s < 0)
246 return s;
247 off += s;
248 s = htcpBuildCountstr(buf + off, buflen - off, stuff->version);
249 if (s < 0)
250 return s;
251 off += s;
252 s = htcpBuildCountstr(buf + off, buflen - off, stuff->req_hdrs);
253 if (s < 0)
254 return s;
255 off += s;
56714a1a 256 debug(31,1)("htcpBuildSpecifier: size %d\n", (int) off);
d5d466fc 257 return off;
258}
259
56714a1a 260static ssize_t
261htcpBuildDetail(char *buf, size_t buflen, htcpStuff * stuff)
262{
263 ssize_t off = 0;
264 ssize_t s;
265 s = htcpBuildCountstr(buf + off, buflen - off, stuff->resp_hdrs);
266 if (s < 0)
267 return s;
268 off += s;
269 s = htcpBuildCountstr(buf + off, buflen - off, stuff->entity_hdrs);
270 if (s < 0)
271 return s;
272 off += s;
273 s = htcpBuildCountstr(buf + off, buflen - off, stuff->cache_hdrs);
274 if (s < 0)
275 return s;
276 off += s;
277 return off;
278}
279
280static ssize_t
d5d466fc 281htcpBuildTstOpData(char *buf, size_t buflen, htcpStuff * stuff)
282{
0cdcddb9 283 switch (stuff->rr) {
d9f9d78b 284 case RR_REQUEST:
56714a1a 285 debug(31,1)("htcpBuildTstOpData: RR_REQUEST\n");
0cdcddb9 286 return htcpBuildSpecifier(buf, buflen, stuff);
d9f9d78b 287 case RR_RESPONSE:
56714a1a 288 debug(31,1)("htcpBuildTstOpData: RR_RESPONSE\n");
0cdcddb9 289 return htcpBuildDetail(buf, buflen, stuff);
d9f9d78b 290 default:
291 fatal_dump("htcpBuildTstOpData: bad RR value");
0cdcddb9 292 }
293 return 0;
d5d466fc 294}
295
56714a1a 296static ssize_t
d5d466fc 297htcpBuildOpData(char *buf, size_t buflen, htcpStuff * stuff)
298{
299 ssize_t off = 0;
56714a1a 300 debug(31,1)("htcpBuildOpData: opcode %s\n",
301 htcpOpcodeStr[stuff->op]);
d5d466fc 302 switch (stuff->op) {
303 case HTCP_TST:
304 off = htcpBuildTstOpData(buf + off, buflen, stuff);
305 break;
306 default:
307 assert(0);
308 break;
309 }
310 return off;
311}
312
56714a1a 313static ssize_t
d5d466fc 314htcpBuildData(char *buf, size_t buflen, htcpStuff * stuff)
315{
316 ssize_t off = 0;
317 ssize_t op_data_sz;
318 size_t hdr_sz = sizeof(htcpDataHeader);
319 htcpDataHeader hdr;
320 if (buflen < hdr_sz)
321 return -1;
322 off += hdr_sz; /* skip! */
323 op_data_sz = htcpBuildOpData(buf + off, buflen - off, stuff);
324 if (op_data_sz < 0)
325 return op_data_sz;
326 off += op_data_sz;
56714a1a 327 debug(31,1)("htcpBuildData: hdr.length = %d\n", (int) off);
d5d466fc 328 hdr.length = (u_short) off;
329 hdr.opcode = stuff->op;
330 hdr.response = stuff->response;
331 hdr.RR = stuff->rr;
332 hdr.F1 = stuff->f1;
333 hdr.msg_id = ++msg_id_counter;
334 /* convert multi-byte fields */
335 hdr.length = htons(hdr.length);
eb9ae2f7 336 hdr.msg_id = htonl(hdr.msg_id);
d5d466fc 337 xmemcpy(buf, &hdr, hdr_sz);
56714a1a 338 debug(31,1)("htcpBuildData: size %d\n", (int) off);
d5d466fc 339 return off;
340}
341
56714a1a 342static char *
d5d466fc 343htcpBuildPacket(htcpStuff * stuff, ssize_t * len)
3340a3e6 344{
d5d466fc 345 size_t buflen = 8192;
346 size_t s;
347 ssize_t off = 0;
348 size_t hdr_sz = sizeof(htcpHeader);
349 htcpHeader hdr;
350 char *buf = xcalloc(buflen, 1);
351 /* skip the header -- we don't know the overall length */
352 if (buflen < hdr_sz)
353 return NULL;
354 off += hdr_sz;
355 s = htcpBuildData(buf + off, buflen - off, stuff);
356 if (s < 0)
357 return NULL;
358 off += s;
359 s = htcpBuildAuth(buf + off, buflen - off);
360 if (s < 0)
361 return NULL;
362 off += s;
1afe05c5 363 hdr.length = htons((u_short) off);
d5d466fc 364 hdr.major = 0;
365 hdr.minor = 0;
366 xmemcpy(buf, &hdr, hdr_sz);
367 *len = off;
56714a1a 368 debug(31,1)("htcpBuildPacket: size %d\n", (int) off);
d5d466fc 369 return buf;
3340a3e6 370}
371
56714a1a 372static void
373htcpSend(const char *buf, int len, struct sockaddr_in *to)
3340a3e6 374{
d5d466fc 375 int x;
56714a1a 376 debug(31,1)("htcpSend: %s/%d\n",
377 inet_ntoa(to->sin_addr), (int) ntohs(to->sin_port));
378 htcpHexdump("htcpSend", buf, len);
d5d466fc 379 x = comm_udp_sendto(htcpOutSocket,
56714a1a 380 to,
d5d466fc 381 sizeof(struct sockaddr_in),
382 buf,
383 len);
384 if (x < 0)
385 debug(31, 0) ("htcpSend: FD %d sendto: %s\n", htcpOutSocket, xstrerror());
3340a3e6 386}
387
eb9ae2f7 388/*
389 * STUFF FOR RECEIVING HTCP MESSAGES
390 */
391
392static void
393htcpFreeSpecifier(htcpSpecifier * s)
394{
395 safe_free(s->method);
396 safe_free(s->uri);
397 safe_free(s->version);
398 safe_free(s->req_hdrs);
399 xfree(s);
400}
401
56714a1a 402static int
eb9ae2f7 403htcpUnpackCountstr(char *buf, int sz, char **str)
404{
1afe05c5 405 u_short l;
406 debug(31, 1) ("htcpUnpackCountstr: sz = %d\n", sz);
407 if (sz < 2) {
408 debug(31, 1) ("htcpUnpackCountstr: sz < 2\n");
409 return -1;
410 }
56714a1a 411 htcpHexdump("htcpUnpackCountstr", buf, sz);
1afe05c5 412 xmemcpy(&l, buf, 2);
56714a1a 413 l = ntohs(l);
1afe05c5 414 buf += 2;
415 sz -= 2;
416 debug(31, 1) ("htcpUnpackCountstr: LENGTH = %d\n", (int) l);
417 if (sz < l) {
418 debug(31, 1) ("htcpUnpackCountstr: sz(%d) < l(%d)\n", sz, l);
419 return -1;
420 }
421 if (str) {
422 *str = xmalloc(l + 1);
423 xstrncpy(*str, buf, l + 1);
56714a1a 424 debug(31, 1) ("htcpUnpackCountstr: TEXT = {%s}\n", *str);
1afe05c5 425 }
426 return (int) l + 2;
eb9ae2f7 427}
428
56714a1a 429static htcpSpecifier *
eb9ae2f7 430htcpUnpackSpecifier(char *buf, int sz)
431{
1afe05c5 432 htcpSpecifier *s = xcalloc(1, sizeof(htcpSpecifier));
433 int o;
56714a1a 434 debug(31, 1) ("htcpUnpackSpecifier: %d bytes\n", (int) sz);
1afe05c5 435 o = htcpUnpackCountstr(buf, sz, &s->method);
436 if (o < 0) {
437 debug(31, 1) ("htcpUnpackSpecifier: failed to unpack METHOD\n");
438 htcpFreeSpecifier(s);
439 return NULL;
440 }
441 buf += o;
442 sz -= o;
443
444 o = htcpUnpackCountstr(buf, sz, &s->uri);
445 if (o < 0) {
446 debug(31, 1) ("htcpUnpackSpecifier: failed to unpack URI\n");
447 htcpFreeSpecifier(s);
448 return NULL;
449 }
450 buf += o;
451 sz -= o;
452
453 o = htcpUnpackCountstr(buf, sz, &s->version);
454 if (o < 0) {
455 debug(31, 1) ("htcpUnpackSpecifier: failed to unpack VERSION\n");
456 htcpFreeSpecifier(s);
457 return NULL;
458 }
459 buf += o;
460 sz -= o;
461
462 o = htcpUnpackCountstr(buf, sz, &s->req_hdrs);
463 if (o < 0) {
464 debug(31, 1) ("htcpUnpackSpecifier: failed to unpack REQ-HDRS\n");
465 htcpFreeSpecifier(s);
466 return NULL;
467 }
468 buf += o;
469 sz -= o;
470
56714a1a 471 debug(31,1)("htcpUnpackSpecifier: %d bytes left\n", sz);
1afe05c5 472 return s;
eb9ae2f7 473}
474
475static void
56714a1a 476htcpHandleNop(char *buf, int sz, struct sockaddr_in *from)
eb9ae2f7 477{
1afe05c5 478 debug(31, 1) ("htcpHandleNop: Unimplemented\n");
eb9ae2f7 479}
480
481static void
56714a1a 482htcpHandleTst(char *buf, int sz, struct sockaddr_in *from)
eb9ae2f7 483{
1afe05c5 484 /* buf should be a SPECIFIER */
485 htcpSpecifier *s = htcpUnpackSpecifier(buf, sz);
d9f9d78b 486 StoreEntry *e;
487 const cache_key *key;
488 method_t m;
56714a1a 489 debug(31, 1) ("htcpHandleTst: sz = %d\n", (int) sz);
490#if WIP
491 if (NULL == p) {
492 debug(31, 1) ("htcpHandle: HTCP message from non-peer: %s:%d\n",
493 inet_ntoa(from->sin_addr), (int) ntohs(from->sin_port));
494 return;
495 }
496#endif
1afe05c5 497 if (NULL == s) {
498 debug(31, 1) ("htcpHandleTst: htcpUnpackSpecifier failed\n");
499 return;
500 }
501 debug(31, 1) ("htcpHandleTst: %s %s %s\n",
502 s->method,
503 s->uri,
504 s->version);
d9f9d78b 505 m = urlParseMethod(s->method);
1afe05c5 506 debug(31, 1) ("htcpHandleTst: %s\n", s->req_hdrs);
d9f9d78b 507 key = storeKeyPublic(s->uri, m);
508 e = storeGet(key);
509 if (NULL == e) {
510 /* cache miss */
56714a1a 511 htcpTstReply(NULL, NULL, from);
d9f9d78b 512#if WIP
513 } else if (!checkHeaders()) {
514 /* refresh/other miss */
56714a1a 515 htcpTstReply(NULL, NULL, from);
d9f9d78b 516#endif
517 } else {
518 /* hit */
56714a1a 519 assert(e);
520 assert(s);
521 assert(from);
522 htcpTstReply(e, s, from);
d9f9d78b 523 }
524}
525
526static void
56714a1a 527htcpTstReply(StoreEntry * e, htcpSpecifier * spec, struct sockaddr_in *from)
d9f9d78b 528{
529 htcpStuff stuff;
530 char *pkt;
531 ssize_t pktlen;
56714a1a 532 assert(spec);
d9f9d78b 533 stuff.op = HTCP_TST;
534 stuff.rr = RR_RESPONSE;
535 stuff.f1 = e ? 0 : 1;
536 stuff.method = spec->method;
537 stuff.uri = spec->uri;
538 stuff.version = spec->version;
539 stuff.req_hdrs = spec->req_hdrs;
56714a1a 540 stuff.resp_hdrs = NULL;
541 stuff.entity_hdrs = NULL;
542 stuff.cache_hdrs = NULL;
d9f9d78b 543 pkt = htcpBuildPacket(&stuff, &pktlen);
544 if (pkt == NULL) {
545 debug(31, 0) ("htcpTstReply: htcpBuildPacket() failed\n");
546 return;
547 }
56714a1a 548 htcpSend(pkt, (int) pktlen, from);
d9f9d78b 549 xfree(pkt);
eb9ae2f7 550}
551
552static void
56714a1a 553htcpHandleMon(char *buf, int sz, struct sockaddr_in *from)
eb9ae2f7 554{
1afe05c5 555 debug(31, 1) ("htcpHandleMon: Unimplemented\n");
eb9ae2f7 556}
557
558static void
56714a1a 559htcpHandleSet(char *buf, int sz, struct sockaddr_in *from)
eb9ae2f7 560{
1afe05c5 561 debug(31, 1) ("htcpHandleSet: Unimplemented\n");
eb9ae2f7 562}
563
564static void
56714a1a 565htcpHandleData(char *buf, int sz, struct sockaddr_in *from)
eb9ae2f7 566{
567 htcpDataHeader hdr;
568 if (sz < sizeof(htcpDataHeader)) {
1afe05c5 569 debug(31, 0) ("htcpHandleData: msg size less than htcpDataHeader size\n");
eb9ae2f7 570 return;
571 }
572 xmemcpy(&hdr, buf, sizeof(htcpDataHeader));
573 hdr.length = ntohs(hdr.length);
574 hdr.msg_id = ntohs(hdr.msg_id);
56714a1a 575 debug(31, 1) ("htcpHandleData: sz = %d\n", sz);
1afe05c5 576 debug(31, 1) ("htcpHandleData: length = %d\n", (int) hdr.length);
eb9ae2f7 577 if (hdr.opcode < HTCP_NOP || hdr.opcode > HTCP_END) {
1afe05c5 578 debug(31, 0) ("htcpHandleData: opcode %d out of range\n",
eb9ae2f7 579 (int) hdr.opcode);
580 return;
581 }
1afe05c5 582 debug(31, 1) ("htcpHandleData: opcode = %d %s\n",
eb9ae2f7 583 (int) hdr.opcode, htcpOpcodeStr[hdr.opcode]);
1afe05c5 584 debug(31, 1) ("htcpHandleData: response = %d\n", (int) hdr.response);
585 debug(31, 1) ("htcpHandleData: F1 = %d\n", (int) hdr.F1);
586 debug(31, 1) ("htcpHandleData: RR = %d\n", (int) hdr.RR);
587 debug(31, 1) ("htcpHandleData: msg_id = %#x\n", (int) hdr.msg_id);
eb9ae2f7 588 if (sz < hdr.length) {
1afe05c5 589 debug(31, 0) ("htcpHandle: sz < hdr.length\n");
eb9ae2f7 590 return;
591 }
592 buf += sizeof(htcpDataHeader);
593 sz -= sizeof(htcpDataHeader);
56714a1a 594 debug(31, 1) ("htcpHandleData: sz = %d\n", sz);
595 htcpHexdump("htcpHandleData", buf, sz);
1afe05c5 596 switch (hdr.opcode) {
eb9ae2f7 597 case HTCP_NOP:
56714a1a 598 htcpHandleNop(buf, sz, from);
eb9ae2f7 599 break;
600 case HTCP_TST:
56714a1a 601 htcpHandleTst(buf, sz, from);
eb9ae2f7 602 break;
603 case HTCP_MON:
56714a1a 604 htcpHandleMon(buf, sz, from);
eb9ae2f7 605 break;
606 case HTCP_SET:
56714a1a 607 htcpHandleSet(buf, sz, from);
eb9ae2f7 608 break;
609 default:
610 assert(0);
611 break;
612 }
613}
614
615static void
616htcpHandle(char *buf, int sz, struct sockaddr_in *from)
617{
618 htcpHeader htcpHdr;
619 if (sz < sizeof(htcpHeader)) {
1afe05c5 620 debug(31, 0) ("htcpHandle: msg size less than htcpHeader size\n");
eb9ae2f7 621 return;
622 }
56714a1a 623 htcpHexdump("htcpHandle", buf, sz);
eb9ae2f7 624 xmemcpy(&htcpHdr, buf, sizeof(htcpHeader));
625 htcpHdr.length = ntohs(htcpHdr.length);
1afe05c5 626 debug(31, 1) ("htcpHandle: htcpHdr.length = %d\n", (int) htcpHdr.length);
627 debug(31, 1) ("htcpHandle: htcpHdr.major = %d\n", (int) htcpHdr.major);
628 debug(31, 1) ("htcpHandle: htcpHdr.minor = %d\n", (int) htcpHdr.minor);
eb9ae2f7 629 if (sz != htcpHdr.length) {
1afe05c5 630 debug(31, 0) ("htcpHandle: sz != htcpHdr.length\n");
eb9ae2f7 631 return;
632 }
633 buf += sizeof(htcpHeader);
634 sz -= sizeof(htcpHeader);
56714a1a 635 htcpHandleData(buf, sz, from);
eb9ae2f7 636}
637
56714a1a 638static void
eb9ae2f7 639htcpRecv(int fd, void *data)
640{
641 static char buf[8192];
642 int len;
643 static struct sockaddr_in from;
644 int flen = sizeof(struct sockaddr_in);
645 memset(&from, '\0', flen);
646 len = recvfrom(fd, buf, 8192, 0, (struct sockaddr *) &from, &flen);
647 debug(31, 0) ("htcpRecv: FD %d, %d bytes from %s:%d\n",
648 fd, len, inet_ntoa(from.sin_addr), ntohs(from.sin_port));
649 htcpHandle(buf, len, &from);
650 commSetSelect(fd, COMM_SELECT_READ, htcpRecv, NULL, 0);
651}
652
56714a1a 653/*
654 * ======================================================================
655 * PUBLIC FUNCTIONS
656 * ======================================================================
657 */
658
d5d466fc 659void
660htcpInit(void)
3340a3e6 661{
d5d466fc 662 enter_suid();
663 htcpInSocket = comm_open(SOCK_DGRAM,
664 0,
665 Config.Addrs.udp_incoming,
666 Config.Port.htcp,
667 COMM_NONBLOCKING,
668 "HTCP Socket");
669 leave_suid();
670 if (htcpInSocket < 0)
671 fatal("Cannot open HTCP Socket");
672 commSetSelect(htcpInSocket, COMM_SELECT_READ, htcpRecv, NULL, 0);
ba3eec6b 673 debug(31, 1) ("Accepting HTCP messages on port %d, FD %d.\n",
d5d466fc 674 (int) Config.Port.htcp, htcpInSocket);
675 if (Config.Addrs.udp_outgoing.s_addr != no_addr.s_addr) {
676 enter_suid();
677 htcpOutSocket = comm_open(SOCK_DGRAM,
678 0,
679 Config.Addrs.udp_outgoing,
680 Config.Port.htcp,
681 COMM_NONBLOCKING,
682 "Outgoing HTCP Socket");
683 leave_suid();
684 if (htcpOutSocket < 0)
685 fatal("Cannot open Outgoing HTCP Socket");
686 commSetSelect(htcpOutSocket, COMM_SELECT_READ, htcpRecv, NULL, 0);
ba3eec6b 687 debug(31, 1) ("Outgoing HTCP messages on port %d, FD %d.\n",
d5d466fc 688 (int) Config.Port.htcp, htcpOutSocket);
689 fd_note(htcpInSocket, "Incoming HTCP socket");
690 } else {
691 htcpOutSocket = htcpInSocket;
692 }
59c4d35b 693}
72549e05 694
56714a1a 695void
696htcpQuery(StoreEntry * e, request_t * req, peer * p)
697{
698 char *pkt;
699 ssize_t pktlen;
700 char vbuf[32];
701 htcpStuff stuff;
702 HttpHeader hdr;
703 Packer pa;
704 MemBuf mb;
705 snprintf(vbuf, sizeof(vbuf), "%3.1f", req->http_ver);
706 stuff.op = HTCP_TST;
707 stuff.rr = RR_REQUEST;
708 stuff.f1 = 1;
709 stuff.response = 0;
710 stuff.method = RequestMethodStr[req->method];
711 stuff.uri = storeUrl(e);
712 stuff.version = vbuf;
713 httpBuildRequestHeader(req, req, e, &hdr, -1, 0);
714 memBufDefInit(&mb);
715 packerToMemInit(&pa, &mb);
716 httpHeaderPackInto(&hdr, &pa);
717 httpHeaderClean(&hdr);
718 packerClean(&pa);
719 stuff.req_hdrs = mb.buf;
720 pkt = htcpBuildPacket(&stuff, &pktlen);
721 if (pkt == NULL) {
722 debug(31, 0) ("htcpQuery: htcpBuildPacket() failed\n");
723 return;
724 }
725 htcpSend(pkt, (int) pktlen, &p->in_addr);
726 xfree(pkt);
727}
728
72549e05 729/*
730 * htcpSocketShutdown only closes the 'in' socket if it is
731 * different than the 'out' socket.
1afe05c5 732 */
72549e05 733void
734htcpSocketShutdown(void)
1afe05c5 735{
72549e05 736 if (htcpInSocket < 0)
1afe05c5 737 return;
738 if (htcpInSocket != htcpOutSocket) {
739 debug(12, 1) ("FD %d Closing HTCP socket\n", htcpInSocket);
740 comm_close(htcpInSocket);
741 }
72549e05 742 /*
743 * Here we set 'htcpInSocket' to -1 even though the HTCP 'in'
744 * and 'out' sockets might be just one FD. This prevents this
745 * function from executing repeatedly. When we are really ready to
746 * exit or restart, main will comm_close the 'out' descriptor.
1afe05c5 747 */
72549e05 748 htcpInSocket = -1;
749 /*
750 * Normally we only write to the outgoing HTCP socket, but
751 * we also have a read handler there to catch messages sent
752 * to that specific interface. During shutdown, we must
753 * disable reading on the outgoing socket.
1afe05c5 754 */
72549e05 755 assert(htcpOutSocket > -1);
756 commSetSelect(htcpOutSocket, COMM_SELECT_READ, NULL, NULL, 0);
757}
758
1afe05c5 759void
72549e05 760htcpSocketClose(void)
761{
762 htcpSocketShutdown();
763 if (htcpOutSocket > -1) {
1afe05c5 764 debug(12, 1) ("FD %d Closing HTCP socket\n", htcpOutSocket);
765 comm_close(htcpOutSocket);
766 }
767}