]>
Commit | Line | Data |
---|---|---|
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 | ||
38 | typedef struct _Countstr Countstr; | |
39 | typedef struct _htcpHeader htcpHeader; | |
40 | typedef struct _htcpDataHeader htcpDataHeader; | |
41 | typedef struct _htcpAuthHeader htcpAuthHeader; | |
d5d466fc | 42 | typedef struct _htcpStuff htcpStuff; |
eb9ae2f7 | 43 | typedef struct _htcpSpecifier htcpSpecifier; |
c1b92ccb | 44 | |
45 | struct _Countstr { | |
59c4d35b | 46 | u_short length; |
47 | char *text; | |
c1b92ccb | 48 | }; |
49 | ||
50 | struct _htcpHeader { | |
59c4d35b | 51 | u_short length; |
52 | u_char major; | |
53 | u_char minor; | |
c1b92ccb | 54 | }; |
55 | ||
56 | struct _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 | |
82 | struct _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 | 90 | struct _htcpSpecifier { |
91 | char *method; | |
92 | char *uri; | |
93 | char *version; | |
94 | char *req_hdrs; | |
95 | }; | |
96 | ||
d5d466fc | 97 | struct _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 | ||
111 | enum { | |
59c4d35b | 112 | HTCP_NOP, |
113 | HTCP_TST, | |
114 | HTCP_MON, | |
115 | HTCP_SET, | |
eb9ae2f7 | 116 | HTCP_CLR, |
117 | HTCP_END | |
118 | }; | |
119 | ||
1afe05c5 | 120 | static 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 | */ | |
133 | enum { | |
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 | */ | |
145 | enum { | |
59c4d35b | 146 | RR_REQUEST, |
147 | RR_RESPONSE | |
c1b92ccb | 148 | }; |
149 | ||
d5d466fc | 150 | static u_num32 msg_id_counter = 0; |
151 | static int htcpInSocket = -1; | |
152 | static int htcpOutSocket = -1; | |
59c4d35b | 153 | |
56714a1a | 154 | static char *htcpBuildPacket(htcpStuff * stuff, ssize_t * len); |
155 | static htcpSpecifier *htcpUnpackSpecifier(char *buf, int sz); | |
156 | static int htcpUnpackCountstr(char *buf, int sz, char **str); | |
157 | static ssize_t htcpBuildAuth(char *buf, size_t buflen); | |
158 | static ssize_t htcpBuildCountstr(char *buf, size_t buflen, const char *s); | |
159 | static ssize_t htcpBuildData(char *buf, size_t buflen, htcpStuff * stuff); | |
160 | static ssize_t htcpBuildDetail(char *buf, size_t buflen, htcpStuff * stuff); | |
161 | static ssize_t htcpBuildOpData(char *buf, size_t buflen, htcpStuff * stuff); | |
162 | static ssize_t htcpBuildSpecifier(char *buf, size_t buflen, htcpStuff * stuff); | |
163 | static ssize_t htcpBuildTstOpData(char *buf, size_t buflen, htcpStuff * stuff); | |
164 | static void htcpFreeSpecifier(htcpSpecifier * s); | |
165 | static void htcpHandle(char *buf, int sz, struct sockaddr_in *from); | |
166 | static void htcpHandleData(char *buf, int sz, struct sockaddr_in *from); | |
167 | static void htcpHandleMon(char *buf, int sz, struct sockaddr_in *from); | |
168 | static void htcpHandleNop(char *buf, int sz, struct sockaddr_in *from); | |
169 | static void htcpHandleSet(char *buf, int sz, struct sockaddr_in *from); | |
170 | static void htcpHandleTst(char *buf, int sz, struct sockaddr_in *from); | |
171 | static void htcpRecv(int fd, void *data); | |
172 | static void htcpSend(const char *buf, int len, struct sockaddr_in *to); | |
173 | static void htcpTstReply(StoreEntry *, htcpSpecifier *, struct sockaddr_in *); | |
174 | ||
175 | static void | |
176 | htcpHexdump(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 | 197 | static ssize_t |
d5d466fc | 198 | htcpBuildAuth(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 | 210 | static ssize_t |
d5d466fc | 211 | htcpBuildCountstr(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 | 235 | static ssize_t |
d5d466fc | 236 | htcpBuildSpecifier(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 | 260 | static ssize_t |
261 | htcpBuildDetail(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 | ||
280 | static ssize_t | |
d5d466fc | 281 | htcpBuildTstOpData(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 | 296 | static ssize_t |
d5d466fc | 297 | htcpBuildOpData(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 | 313 | static ssize_t |
d5d466fc | 314 | htcpBuildData(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 | 342 | static char * |
d5d466fc | 343 | htcpBuildPacket(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 | 372 | static void |
373 | htcpSend(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 | ||
392 | static void | |
393 | htcpFreeSpecifier(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 | 402 | static int |
eb9ae2f7 | 403 | htcpUnpackCountstr(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 | 429 | static htcpSpecifier * |
eb9ae2f7 | 430 | htcpUnpackSpecifier(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 | ||
475 | static void | |
56714a1a | 476 | htcpHandleNop(char *buf, int sz, struct sockaddr_in *from) |
eb9ae2f7 | 477 | { |
1afe05c5 | 478 | debug(31, 1) ("htcpHandleNop: Unimplemented\n"); |
eb9ae2f7 | 479 | } |
480 | ||
481 | static void | |
56714a1a | 482 | htcpHandleTst(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 | ||
526 | static void | |
56714a1a | 527 | htcpTstReply(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 | ||
552 | static void | |
56714a1a | 553 | htcpHandleMon(char *buf, int sz, struct sockaddr_in *from) |
eb9ae2f7 | 554 | { |
1afe05c5 | 555 | debug(31, 1) ("htcpHandleMon: Unimplemented\n"); |
eb9ae2f7 | 556 | } |
557 | ||
558 | static void | |
56714a1a | 559 | htcpHandleSet(char *buf, int sz, struct sockaddr_in *from) |
eb9ae2f7 | 560 | { |
1afe05c5 | 561 | debug(31, 1) ("htcpHandleSet: Unimplemented\n"); |
eb9ae2f7 | 562 | } |
563 | ||
564 | static void | |
56714a1a | 565 | htcpHandleData(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 | ||
615 | static void | |
616 | htcpHandle(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 | 638 | static void |
eb9ae2f7 | 639 | htcpRecv(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 | 659 | void |
660 | htcpInit(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 | 695 | void |
696 | htcpQuery(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 | 733 | void |
734 | htcpSocketShutdown(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 | 759 | void |
72549e05 | 760 | htcpSocketClose(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 | } |