]>
Commit | Line | Data |
---|---|---|
d5d466fc | 1 | |
2 | /* | |
8ec13096 | 3 | * $Id: htcp.cc,v 1.35 2001/04/01 16:33:37 wessels Exp $ |
9cef6668 | 4 | * |
5 | * DEBUG: section 31 Hypertext Caching Protocol | |
6 | * AUTHOR: Duane Wesssels | |
7 | * | |
2b6662ba | 8 | * SQUID Web Proxy Cache http://www.squid-cache.org/ |
9cef6668 | 9 | * ---------------------------------------------------------- |
10 | * | |
2b6662ba | 11 | * Squid is the result of efforts by numerous individuals from |
12 | * the Internet community; see the CONTRIBUTORS file for full | |
13 | * details. Many organizations have provided support for Squid's | |
14 | * development; see the SPONSORS file for full details. Squid is | |
15 | * Copyrighted (C) 2001 by the Regents of the University of | |
16 | * California; see the COPYRIGHT file for full details. Squid | |
17 | * incorporates software developed and/or copyrighted by other | |
18 | * sources; see the 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 | ||
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; |
a2edf5dc | 44 | typedef struct _htcpDetail htcpDetail; |
c1b92ccb | 45 | |
46 | struct _Countstr { | |
59c4d35b | 47 | u_short length; |
48 | char *text; | |
c1b92ccb | 49 | }; |
50 | ||
51 | struct _htcpHeader { | |
59c4d35b | 52 | u_short length; |
53 | u_char major; | |
54 | u_char minor; | |
c1b92ccb | 55 | }; |
56 | ||
57 | struct _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 | |
83 | struct _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 | 91 | struct _htcpSpecifier { |
92 | char *method; | |
93 | char *uri; | |
94 | char *version; | |
95 | char *req_hdrs; | |
96 | }; | |
97 | ||
a2edf5dc | 98 | struct _htcpDetail { |
99 | char *resp_hdrs; | |
100 | char *entity_hdrs; | |
101 | char *cache_hdrs; | |
102 | }; | |
103 | ||
d5d466fc | 104 | struct _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 | ||
114 | enum { | |
59c4d35b | 115 | HTCP_NOP, |
116 | HTCP_TST, | |
117 | HTCP_MON, | |
118 | HTCP_SET, | |
eb9ae2f7 | 119 | HTCP_CLR, |
120 | HTCP_END | |
121 | }; | |
122 | ||
1afe05c5 | 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" | |
c1b92ccb | 131 | }; |
132 | ||
133 | /* | |
134 | * values for htcpDataHeader->response | |
135 | */ | |
136 | enum { | |
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 | */ | |
148 | enum { | |
59c4d35b | 149 | RR_REQUEST, |
150 | RR_RESPONSE | |
c1b92ccb | 151 | }; |
152 | ||
d5d466fc | 153 | static u_num32 msg_id_counter = 0; |
154 | static int htcpInSocket = -1; | |
155 | static int htcpOutSocket = -1; | |
26df9ec6 | 156 | #define N_QUERIED_KEYS 256 |
157 | static cache_key queried_keys[N_QUERIED_KEYS][MD5_DIGEST_CHARS]; | |
59c4d35b | 158 | |
56714a1a | 159 | static char *htcpBuildPacket(htcpStuff * stuff, ssize_t * len); |
160 | static htcpSpecifier *htcpUnpackSpecifier(char *buf, int sz); | |
a2edf5dc | 161 | static htcpDetail *htcpUnpackDetail(char *buf, int sz); |
56714a1a | 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); | |
a2edf5dc | 171 | static void htcpFreeDetail(htcpDetail * s); |
56714a1a | 172 | static void htcpHandle(char *buf, int sz, struct sockaddr_in *from); |
173 | static void htcpHandleData(char *buf, int sz, struct sockaddr_in *from); | |
60fac9b5 | 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); | |
56714a1a | 178 | static void htcpRecv(int fd, void *data); |
179 | static void htcpSend(const char *buf, int len, struct sockaddr_in *to); | |
26df9ec6 | 180 | static void htcpTstReply(htcpDataHeader *, StoreEntry *, htcpSpecifier *, struct sockaddr_in *); |
181 | static void htcpHandleTstRequest(htcpDataHeader *, char *buf, int sz, struct sockaddr_in *from); | |
60fac9b5 | 182 | static void htcpHandleTstResponse(htcpDataHeader *, char *, int, struct sockaddr_in *); |
32b3cf93 | 183 | static StoreEntry *htcpCheckHit(const htcpSpecifier *); |
56714a1a | 184 | |
185 | static void | |
186 | htcpHexdump(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 | 209 | static ssize_t |
d5d466fc | 210 | htcpBuildAuth(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 | 222 | static ssize_t |
d5d466fc | 223 | htcpBuildCountstr(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 | 247 | static ssize_t |
d5d466fc | 248 | htcpBuildSpecifier(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 | 272 | static ssize_t |
273 | htcpBuildDetail(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 | ||
292 | static ssize_t | |
d5d466fc | 293 | htcpBuildTstOpData(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 | 312 | static ssize_t |
d5d466fc | 313 | htcpBuildOpData(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 | 329 | static ssize_t |
d5d466fc | 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; | |
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 | 358 | static char * |
d5d466fc | 359 | htcpBuildPacket(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 | 394 | static void |
395 | htcpSend(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 | ||
414 | static void | |
415 | htcpFreeSpecifier(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 | 424 | static void |
425 | htcpFreeDetail(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 | 433 | static int |
eb9ae2f7 | 434 | htcpUnpackCountstr(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 | 460 | static htcpSpecifier * |
eb9ae2f7 | 461 | htcpUnpackSpecifier(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 | 502 | static htcpDetail * |
503 | htcpUnpackDetail(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 | 536 | static void |
886f2785 | 537 | htcpTstReply(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 | ||
606 | static void | |
607 | htcpHandleNop(htcpDataHeader * hdr, char *buf, int sz, struct sockaddr_in *from) | |
eb9ae2f7 | 608 | { |
d87ebd78 | 609 | debug(31, 3) ("htcpHandleNop: Unimplemented\n"); |
eb9ae2f7 | 610 | } |
611 | ||
32b3cf93 | 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); | |
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 | 646 | static void |
60fac9b5 | 647 | htcpHandleTst(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 | ||
656 | static void | |
657 | htcpHandleTstResponse(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 | ||
696 | static void | |
886f2785 | 697 | htcpHandleTstRequest(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 | ||
725 | static void | |
60fac9b5 | 726 | htcpHandleMon(htcpDataHeader * hdr, char *buf, int sz, struct sockaddr_in *from) |
eb9ae2f7 | 727 | { |
d87ebd78 | 728 | debug(31, 3) ("htcpHandleMon: Unimplemented\n"); |
eb9ae2f7 | 729 | } |
730 | ||
731 | static void | |
60fac9b5 | 732 | htcpHandleSet(htcpDataHeader * hdr, char *buf, int sz, struct sockaddr_in *from) |
eb9ae2f7 | 733 | { |
d87ebd78 | 734 | debug(31, 3) ("htcpHandleSet: Unimplemented\n"); |
eb9ae2f7 | 735 | } |
736 | ||
737 | static void | |
56714a1a | 738 | htcpHandleData(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); | |
8ec13096 | 750 | if (hdr.opcode >= HTCP_END) { |
751 | debug(31, 0) ("htcpHandleData: client %s, opcode %d out of range\n", | |
752 | inet_ntoa(from->sin_addr), | |
eb9ae2f7 | 753 | (int) hdr.opcode); |
754 | return; | |
755 | } | |
d87ebd78 | 756 | debug(31, 3) ("htcpHandleData: opcode = %d %s\n", |
eb9ae2f7 | 757 | (int) hdr.opcode, htcpOpcodeStr[hdr.opcode]); |
d87ebd78 | 758 | debug(31, 3) ("htcpHandleData: response = %d\n", (int) hdr.response); |
759 | debug(31, 3) ("htcpHandleData: F1 = %d\n", (int) hdr.F1); | |
760 | debug(31, 3) ("htcpHandleData: RR = %d\n", (int) hdr.RR); | |
761 | debug(31, 3) ("htcpHandleData: msg_id = %d\n", (int) hdr.msg_id); | |
eb9ae2f7 | 762 | if (sz < hdr.length) { |
1afe05c5 | 763 | debug(31, 0) ("htcpHandle: sz < hdr.length\n"); |
eb9ae2f7 | 764 | return; |
765 | } | |
60fac9b5 | 766 | /* |
767 | * set sz = hdr.length so we ignore any AUTH fields following | |
768 | * the DATA. | |
769 | */ | |
770 | sz = (int) hdr.length; | |
eb9ae2f7 | 771 | buf += sizeof(htcpDataHeader); |
772 | sz -= sizeof(htcpDataHeader); | |
d87ebd78 | 773 | debug(31, 3) ("htcpHandleData: sz = %d\n", sz); |
56714a1a | 774 | htcpHexdump("htcpHandleData", buf, sz); |
1afe05c5 | 775 | switch (hdr.opcode) { |
eb9ae2f7 | 776 | case HTCP_NOP: |
60fac9b5 | 777 | htcpHandleNop(&hdr, buf, sz, from); |
eb9ae2f7 | 778 | break; |
779 | case HTCP_TST: | |
60fac9b5 | 780 | htcpHandleTst(&hdr, buf, sz, from); |
eb9ae2f7 | 781 | break; |
782 | case HTCP_MON: | |
60fac9b5 | 783 | htcpHandleMon(&hdr, buf, sz, from); |
eb9ae2f7 | 784 | break; |
785 | case HTCP_SET: | |
60fac9b5 | 786 | htcpHandleSet(&hdr, buf, sz, from); |
eb9ae2f7 | 787 | break; |
788 | default: | |
789 | assert(0); | |
790 | break; | |
791 | } | |
792 | } | |
793 | ||
794 | static void | |
795 | htcpHandle(char *buf, int sz, struct sockaddr_in *from) | |
796 | { | |
797 | htcpHeader htcpHdr; | |
798 | if (sz < sizeof(htcpHeader)) { | |
1afe05c5 | 799 | debug(31, 0) ("htcpHandle: msg size less than htcpHeader size\n"); |
eb9ae2f7 | 800 | return; |
801 | } | |
56714a1a | 802 | htcpHexdump("htcpHandle", buf, sz); |
eb9ae2f7 | 803 | xmemcpy(&htcpHdr, buf, sizeof(htcpHeader)); |
804 | htcpHdr.length = ntohs(htcpHdr.length); | |
d87ebd78 | 805 | debug(31, 3) ("htcpHandle: htcpHdr.length = %d\n", (int) htcpHdr.length); |
806 | debug(31, 3) ("htcpHandle: htcpHdr.major = %d\n", (int) htcpHdr.major); | |
807 | debug(31, 3) ("htcpHandle: htcpHdr.minor = %d\n", (int) htcpHdr.minor); | |
eb9ae2f7 | 808 | if (sz != htcpHdr.length) { |
efd900cb | 809 | debug(31, 1) ("htcpHandle: sz != htcpHdr.length\n"); |
eb9ae2f7 | 810 | return; |
811 | } | |
812 | buf += sizeof(htcpHeader); | |
813 | sz -= sizeof(htcpHeader); | |
56714a1a | 814 | htcpHandleData(buf, sz, from); |
eb9ae2f7 | 815 | } |
816 | ||
56714a1a | 817 | static void |
eb9ae2f7 | 818 | htcpRecv(int fd, void *data) |
819 | { | |
820 | static char buf[8192]; | |
821 | int len; | |
822 | static struct sockaddr_in from; | |
823 | int flen = sizeof(struct sockaddr_in); | |
824 | memset(&from, '\0', flen); | |
83704487 | 825 | statCounter.syscalls.sock.recvfroms++; |
eb9ae2f7 | 826 | len = recvfrom(fd, buf, 8192, 0, (struct sockaddr *) &from, &flen); |
d87ebd78 | 827 | debug(31, 3) ("htcpRecv: FD %d, %d bytes from %s:%d\n", |
eb9ae2f7 | 828 | fd, len, inet_ntoa(from.sin_addr), ntohs(from.sin_port)); |
829 | htcpHandle(buf, len, &from); | |
830 | commSetSelect(fd, COMM_SELECT_READ, htcpRecv, NULL, 0); | |
831 | } | |
832 | ||
56714a1a | 833 | /* |
834 | * ====================================================================== | |
835 | * PUBLIC FUNCTIONS | |
836 | * ====================================================================== | |
837 | */ | |
838 | ||
d5d466fc | 839 | void |
840 | htcpInit(void) | |
3340a3e6 | 841 | { |
d5d466fc | 842 | enter_suid(); |
843 | htcpInSocket = comm_open(SOCK_DGRAM, | |
844 | 0, | |
845 | Config.Addrs.udp_incoming, | |
846 | Config.Port.htcp, | |
847 | COMM_NONBLOCKING, | |
848 | "HTCP Socket"); | |
849 | leave_suid(); | |
850 | if (htcpInSocket < 0) | |
851 | fatal("Cannot open HTCP Socket"); | |
852 | commSetSelect(htcpInSocket, COMM_SELECT_READ, htcpRecv, NULL, 0); | |
ba3eec6b | 853 | debug(31, 1) ("Accepting HTCP messages on port %d, FD %d.\n", |
d5d466fc | 854 | (int) Config.Port.htcp, htcpInSocket); |
855 | if (Config.Addrs.udp_outgoing.s_addr != no_addr.s_addr) { | |
856 | enter_suid(); | |
857 | htcpOutSocket = comm_open(SOCK_DGRAM, | |
858 | 0, | |
859 | Config.Addrs.udp_outgoing, | |
860 | Config.Port.htcp, | |
861 | COMM_NONBLOCKING, | |
862 | "Outgoing HTCP Socket"); | |
863 | leave_suid(); | |
864 | if (htcpOutSocket < 0) | |
865 | fatal("Cannot open Outgoing HTCP Socket"); | |
866 | commSetSelect(htcpOutSocket, COMM_SELECT_READ, htcpRecv, NULL, 0); | |
ba3eec6b | 867 | debug(31, 1) ("Outgoing HTCP messages on port %d, FD %d.\n", |
d5d466fc | 868 | (int) Config.Port.htcp, htcpOutSocket); |
869 | fd_note(htcpInSocket, "Incoming HTCP socket"); | |
870 | } else { | |
871 | htcpOutSocket = htcpInSocket; | |
872 | } | |
9bc73deb | 873 | memDataInit(MEM_HTCP_SPECIFIER, "htcpSpecifier", sizeof(htcpSpecifier), 0); |
874 | memDataInit(MEM_HTCP_DETAIL, "htcpDetail", sizeof(htcpDetail), 0); | |
59c4d35b | 875 | } |
72549e05 | 876 | |
56714a1a | 877 | void |
878 | htcpQuery(StoreEntry * e, request_t * req, peer * p) | |
879 | { | |
26df9ec6 | 880 | cache_key *save_key; |
56714a1a | 881 | char *pkt; |
882 | ssize_t pktlen; | |
883 | char vbuf[32]; | |
884 | htcpStuff stuff; | |
885 | HttpHeader hdr; | |
886 | Packer pa; | |
887 | MemBuf mb; | |
9c48373d | 888 | http_state_flags flags; |
889 | memset(&flags, '\0', sizeof(flags)); | |
7af0a8e6 | 890 | snprintf(vbuf, sizeof(vbuf), "%d/%d", |
891 | req->http_ver.major, req->http_ver.minor); | |
56714a1a | 892 | stuff.op = HTCP_TST; |
893 | stuff.rr = RR_REQUEST; | |
894 | stuff.f1 = 1; | |
895 | stuff.response = 0; | |
26df9ec6 | 896 | stuff.msg_id = ++msg_id_counter; |
9c48373d | 897 | stuff.S.method = (char *) RequestMethodStr[req->method]; |
898 | stuff.S.uri = (char *) storeUrl(e); | |
a2edf5dc | 899 | stuff.S.version = vbuf; |
9c48373d | 900 | httpBuildRequestHeader(req, req, e, &hdr, -1, flags); |
56714a1a | 901 | memBufDefInit(&mb); |
902 | packerToMemInit(&pa, &mb); | |
903 | httpHeaderPackInto(&hdr, &pa); | |
904 | httpHeaderClean(&hdr); | |
905 | packerClean(&pa); | |
a2edf5dc | 906 | stuff.S.req_hdrs = mb.buf; |
56714a1a | 907 | pkt = htcpBuildPacket(&stuff, &pktlen); |
9bc73deb | 908 | memBufClean(&mb); |
56714a1a | 909 | if (pkt == NULL) { |
910 | debug(31, 0) ("htcpQuery: htcpBuildPacket() failed\n"); | |
911 | return; | |
912 | } | |
913 | htcpSend(pkt, (int) pktlen, &p->in_addr); | |
26df9ec6 | 914 | save_key = queried_keys[stuff.msg_id % N_QUERIED_KEYS]; |
6c40d272 | 915 | storeKeyCopy(save_key, e->hash.key); |
d87ebd78 | 916 | debug(31, 3) ("htcpQuery: key (%p) %s\n", save_key, storeKeyText(save_key)); |
3a3c723d | 917 | xfree(pkt); |
56714a1a | 918 | } |
919 | ||
72549e05 | 920 | /* |
921 | * htcpSocketShutdown only closes the 'in' socket if it is | |
922 | * different than the 'out' socket. | |
1afe05c5 | 923 | */ |
72549e05 | 924 | void |
925 | htcpSocketShutdown(void) | |
1afe05c5 | 926 | { |
72549e05 | 927 | if (htcpInSocket < 0) |
1afe05c5 | 928 | return; |
929 | if (htcpInSocket != htcpOutSocket) { | |
930 | debug(12, 1) ("FD %d Closing HTCP socket\n", htcpInSocket); | |
931 | comm_close(htcpInSocket); | |
932 | } | |
72549e05 | 933 | /* |
934 | * Here we set 'htcpInSocket' to -1 even though the HTCP 'in' | |
935 | * and 'out' sockets might be just one FD. This prevents this | |
936 | * function from executing repeatedly. When we are really ready to | |
937 | * exit or restart, main will comm_close the 'out' descriptor. | |
1afe05c5 | 938 | */ |
72549e05 | 939 | htcpInSocket = -1; |
940 | /* | |
941 | * Normally we only write to the outgoing HTCP socket, but | |
942 | * we also have a read handler there to catch messages sent | |
943 | * to that specific interface. During shutdown, we must | |
944 | * disable reading on the outgoing socket. | |
1afe05c5 | 945 | */ |
72549e05 | 946 | assert(htcpOutSocket > -1); |
947 | commSetSelect(htcpOutSocket, COMM_SELECT_READ, NULL, NULL, 0); | |
948 | } | |
949 | ||
1afe05c5 | 950 | void |
72549e05 | 951 | htcpSocketClose(void) |
952 | { | |
953 | htcpSocketShutdown(); | |
954 | if (htcpOutSocket > -1) { | |
1afe05c5 | 955 | debug(12, 1) ("FD %d Closing HTCP socket\n", htcpOutSocket); |
956 | comm_close(htcpOutSocket); | |
957 | } | |
958 | } |