]>
Commit | Line | Data |
---|---|---|
d5d466fc | 1 | |
2 | /* | |
b8def95f | 3 | * $Id: htcp.cc,v 1.72 2007/04/12 05:03:54 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" |
924f73bc | 37 | #include "htcp.h" |
5401aa8d | 38 | #include "ACLChecklist.h" |
39 | #include "ACL.h" | |
985c86bc | 40 | #include "SquidTime.h" |
e6ccf245 | 41 | #include "Store.h" |
42 | #include "StoreClient.h" | |
528b2c61 | 43 | #include "HttpRequest.h" |
402d6bec | 44 | #include "comm.h" |
0eb49b6d | 45 | #include "MemBuf.h" |
3b0d7130 | 46 | #include "http.h" |
c1b92ccb | 47 | |
48 | typedef struct _Countstr Countstr; | |
62e76326 | 49 | |
c1b92ccb | 50 | typedef struct _htcpHeader htcpHeader; |
62e76326 | 51 | |
c1b92ccb | 52 | typedef struct _htcpDataHeader htcpDataHeader; |
62e76326 | 53 | |
527ee50d | 54 | typedef struct _htcpDataHeaderSquid htcpDataHeaderSquid; |
55 | ||
c1b92ccb | 56 | typedef struct _htcpAuthHeader htcpAuthHeader; |
62e76326 | 57 | |
d5d466fc | 58 | typedef struct _htcpStuff htcpStuff; |
62e76326 | 59 | |
a2edf5dc | 60 | typedef struct _htcpDetail htcpDetail; |
c1b92ccb | 61 | |
62e76326 | 62 | struct _Countstr |
63 | { | |
a9245686 | 64 | u_int16_t length; |
59c4d35b | 65 | char *text; |
c1b92ccb | 66 | }; |
67 | ||
62e76326 | 68 | struct _htcpHeader |
69 | { | |
a9245686 | 70 | u_int16_t length; |
59c4d35b | 71 | u_char major; |
72 | u_char minor; | |
c1b92ccb | 73 | }; |
74 | ||
5401aa8d | 75 | struct _htcpDataHeaderSquid |
527ee50d | 76 | { |
77 | u_int16_t length; | |
5401aa8d | 78 | #if !WORDS_BIGENDIAN |
527ee50d | 79 | |
5401aa8d | 80 | unsigned int opcode: |
527ee50d | 81 | 4; |
82 | ||
5401aa8d | 83 | unsigned int response: |
527ee50d | 84 | 4; |
85 | #else | |
86 | ||
5401aa8d | 87 | unsigned int response: |
527ee50d | 88 | 4; |
89 | ||
5401aa8d | 90 | unsigned int opcode: |
527ee50d | 91 | 4; |
92 | #endif | |
5401aa8d | 93 | #if !WORDS_BIGENDIAN |
527ee50d | 94 | |
5401aa8d | 95 | unsigned int reserved: |
527ee50d | 96 | 6; |
97 | ||
5401aa8d | 98 | unsigned int F1: |
527ee50d | 99 | 1; |
100 | ||
5401aa8d | 101 | unsigned int RR: |
527ee50d | 102 | 1; |
103 | #else | |
104 | ||
5401aa8d | 105 | unsigned int RR: |
527ee50d | 106 | 1; |
107 | ||
5401aa8d | 108 | unsigned int F1: |
527ee50d | 109 | 1; |
110 | ||
5401aa8d | 111 | unsigned int reserved: |
527ee50d | 112 | 6; |
113 | #endif | |
114 | ||
115 | u_int32_t msg_id; | |
116 | }; | |
117 | ||
5401aa8d | 118 | struct _htcpDataHeader |
62e76326 | 119 | { |
a9245686 | 120 | u_int16_t length; |
5401aa8d | 121 | #if WORDS_BIGENDIAN |
62e76326 | 122 | |
5401aa8d | 123 | u_int8_t opcode: |
62e76326 | 124 | 4; |
125 | ||
5401aa8d | 126 | u_int8_t response: |
62e76326 | 127 | 4; |
eb9ae2f7 | 128 | #else |
62e76326 | 129 | |
5401aa8d | 130 | u_int8_t response: |
62e76326 | 131 | 4; |
132 | ||
5401aa8d | 133 | u_int8_t opcode: |
62e76326 | 134 | 4; |
eb9ae2f7 | 135 | #endif |
5401aa8d | 136 | #if WORDS_BIGENDIAN |
62e76326 | 137 | |
5401aa8d | 138 | u_int8_t reserved: |
62e76326 | 139 | 6; |
140 | ||
5401aa8d | 141 | u_int8_t F1: |
62e76326 | 142 | 1; |
143 | ||
5401aa8d | 144 | u_int8_t RR: |
62e76326 | 145 | 1; |
eb9ae2f7 | 146 | #else |
62e76326 | 147 | |
5401aa8d | 148 | u_int8_t RR: |
62e76326 | 149 | 1; |
150 | ||
5401aa8d | 151 | u_int8_t F1: |
62e76326 | 152 | 1; |
153 | ||
5401aa8d | 154 | u_int8_t reserved: |
62e76326 | 155 | 6; |
eb9ae2f7 | 156 | #endif |
62e76326 | 157 | |
a9245686 | 158 | u_int32_t msg_id; |
eb9ae2f7 | 159 | }; |
160 | ||
62e76326 | 161 | /* RR == 0 --> F1 = RESPONSE DESIRED FLAG */ |
162 | /* RR == 1 --> F1 = MESSAGE OVERALL FLAG */ | |
163 | /* RR == 0 --> REQUEST */ | |
164 | /* RR == 1 --> RESPONSE */ | |
c1b92ccb | 165 | |
62e76326 | 166 | struct _htcpAuthHeader |
167 | { | |
a9245686 | 168 | u_int16_t length; |
59c4d35b | 169 | time_t sig_time; |
170 | time_t sig_expire; | |
171 | Countstr key_name; | |
172 | Countstr signature; | |
c1b92ccb | 173 | }; |
174 | ||
62e76326 | 175 | class htcpSpecifier : public StoreClient |
176 | { | |
177 | ||
e6ccf245 | 178 | public: |
b001e822 | 179 | MEMPROXY_CLASS(htcpSpecifier); |
e6ccf245 | 180 | |
3b13a8fd | 181 | void created (StoreEntry *newEntry); |
e6ccf245 | 182 | void checkHit(); |
183 | void checkedHit(StoreEntry *e); | |
62e76326 | 184 | |
e6ccf245 | 185 | void setFrom (struct sockaddr_in *from); |
186 | void setDataHeader (htcpDataHeader *); | |
eb9ae2f7 | 187 | char *method; |
188 | char *uri; | |
189 | char *version; | |
190 | char *req_hdrs; | |
5401aa8d | 191 | HttpRequest *request; |
62e76326 | 192 | |
e6ccf245 | 193 | private: |
190154cf | 194 | HttpRequest *checkHitRequest; |
62e76326 | 195 | |
e6ccf245 | 196 | struct sockaddr_in *from; |
197 | htcpDataHeader *dhdr; | |
eb9ae2f7 | 198 | }; |
199 | ||
b001e822 | 200 | MEMPROXY_CLASS_INLINE(htcpSpecifier) |
201 | ||
62e76326 | 202 | struct _htcpDetail |
203 | { | |
a2edf5dc | 204 | char *resp_hdrs; |
205 | char *entity_hdrs; | |
206 | char *cache_hdrs; | |
207 | }; | |
208 | ||
62e76326 | 209 | struct _htcpStuff |
210 | { | |
d5d466fc | 211 | int op; |
212 | int rr; | |
213 | int f1; | |
214 | int response; | |
a9245686 | 215 | u_int32_t msg_id; |
a2edf5dc | 216 | htcpSpecifier S; |
217 | htcpDetail D; | |
c1b92ccb | 218 | }; |
219 | ||
220 | enum { | |
59c4d35b | 221 | HTCP_NOP, |
222 | HTCP_TST, | |
223 | HTCP_MON, | |
224 | HTCP_SET, | |
eb9ae2f7 | 225 | HTCP_CLR, |
226 | HTCP_END | |
227 | }; | |
228 | ||
1afe05c5 | 229 | static const char *const htcpOpcodeStr[] = |
62e76326 | 230 | { |
231 | "HTCP_NOP", | |
232 | "HTCP_TST", | |
233 | "HTCP_MON", | |
234 | "HTCP_SET", | |
235 | "HTCP_CLR", | |
236 | "HTCP_END" | |
237 | }; | |
c1b92ccb | 238 | |
239 | /* | |
240 | * values for htcpDataHeader->response | |
241 | */ | |
242 | enum { | |
59c4d35b | 243 | AUTH_REQUIRED, |
244 | AUTH_FAILURE, | |
245 | OPCODE_UNIMPLEMENTED, | |
246 | MAJOR_VERSION_UNSUPPORTED, | |
247 | MINOR_VERSION_UNSUPPORTED, | |
248 | INVALID_OPCODE | |
c1b92ccb | 249 | }; |
250 | ||
251 | /* | |
252 | * values for htcpDataHeader->RR | |
253 | */ | |
254 | enum { | |
59c4d35b | 255 | RR_REQUEST, |
256 | RR_RESPONSE | |
c1b92ccb | 257 | }; |
258 | ||
a9245686 | 259 | static u_int32_t msg_id_counter = 0; |
d5d466fc | 260 | static int htcpInSocket = -1; |
261 | static int htcpOutSocket = -1; | |
5401aa8d | 262 | #define N_QUERIED_KEYS 8192 |
263 | static u_int32_t queried_id[N_QUERIED_KEYS]; | |
26df9ec6 | 264 | static cache_key queried_keys[N_QUERIED_KEYS][MD5_DIGEST_CHARS]; |
5401aa8d | 265 | |
266 | static struct sockaddr_in queried_addr[N_QUERIED_KEYS]; | |
b001e822 | 267 | static MemAllocator *htcpDetailPool = NULL; |
675f3dff | 268 | |
527ee50d | 269 | static int old_squid_format = 0; |
270 | ||
59c4d35b | 271 | |
5401aa8d | 272 | static ssize_t htcpBuildPacket(char *buf, size_t buflen, htcpStuff * stuff); |
56714a1a | 273 | static htcpSpecifier *htcpUnpackSpecifier(char *buf, int sz); |
a2edf5dc | 274 | static htcpDetail *htcpUnpackDetail(char *buf, int sz); |
56714a1a | 275 | static ssize_t htcpBuildAuth(char *buf, size_t buflen); |
276 | static ssize_t htcpBuildCountstr(char *buf, size_t buflen, const char *s); | |
277 | static ssize_t htcpBuildData(char *buf, size_t buflen, htcpStuff * stuff); | |
278 | static ssize_t htcpBuildDetail(char *buf, size_t buflen, htcpStuff * stuff); | |
279 | static ssize_t htcpBuildOpData(char *buf, size_t buflen, htcpStuff * stuff); | |
280 | static ssize_t htcpBuildSpecifier(char *buf, size_t buflen, htcpStuff * stuff); | |
281 | static ssize_t htcpBuildTstOpData(char *buf, size_t buflen, htcpStuff * stuff); | |
282 | static void htcpFreeSpecifier(htcpSpecifier * s); | |
a2edf5dc | 283 | static void htcpFreeDetail(htcpDetail * s); |
62e76326 | 284 | |
56714a1a | 285 | static void htcpHandle(char *buf, int sz, struct sockaddr_in *from); |
62e76326 | 286 | |
56714a1a | 287 | static void htcpHandleData(char *buf, int sz, struct sockaddr_in *from); |
62e76326 | 288 | |
60fac9b5 | 289 | static void htcpHandleMon(htcpDataHeader *, char *buf, int sz, struct sockaddr_in *from); |
62e76326 | 290 | |
60fac9b5 | 291 | static void htcpHandleNop(htcpDataHeader *, char *buf, int sz, struct sockaddr_in *from); |
62e76326 | 292 | |
60fac9b5 | 293 | static void htcpHandleSet(htcpDataHeader *, char *buf, int sz, struct sockaddr_in *from); |
62e76326 | 294 | |
60fac9b5 | 295 | static void htcpHandleTst(htcpDataHeader *, char *buf, int sz, struct sockaddr_in *from); |
56714a1a | 296 | static void htcpRecv(int fd, void *data); |
62e76326 | 297 | |
56714a1a | 298 | static void htcpSend(const char *buf, int len, struct sockaddr_in *to); |
62e76326 | 299 | |
26df9ec6 | 300 | static void htcpTstReply(htcpDataHeader *, StoreEntry *, htcpSpecifier *, struct sockaddr_in *); |
62e76326 | 301 | |
26df9ec6 | 302 | static void htcpHandleTstRequest(htcpDataHeader *, char *buf, int sz, struct sockaddr_in *from); |
62e76326 | 303 | |
60fac9b5 | 304 | static void htcpHandleTstResponse(htcpDataHeader *, char *, int, struct sockaddr_in *); |
56714a1a | 305 | |
306 | static void | |
307 | htcpHexdump(const char *tag, const char *s, int sz) | |
308 | { | |
95eb77fe | 309 | #if USE_HEXDUMP |
60fac9b5 | 310 | int i; |
311 | int k; | |
312 | char hex[80]; | |
d87ebd78 | 313 | debug(31, 3) ("htcpHexdump %s\n", tag); |
60fac9b5 | 314 | memset(hex, '\0', 80); |
62e76326 | 315 | |
60fac9b5 | 316 | for (i = 0; i < sz; i++) { |
62e76326 | 317 | k = i % 16; |
318 | snprintf(&hex[k * 3], 4, " %02x", (int) *(s + i)); | |
319 | ||
320 | if (k < 15 && i < (sz - 1)) | |
321 | continue; | |
322 | ||
323 | debug(31, 3) ("\t%s\n", hex); | |
324 | ||
325 | memset(hex, '\0', 80); | |
60fac9b5 | 326 | } |
62e76326 | 327 | |
95eb77fe | 328 | #endif |
56714a1a | 329 | } |
d9f9d78b | 330 | |
eb9ae2f7 | 331 | /* |
332 | * STUFF FOR SENDING HTCP MESSAGES | |
333 | */ | |
334 | ||
56714a1a | 335 | static ssize_t |
d5d466fc | 336 | htcpBuildAuth(char *buf, size_t buflen) |
59c4d35b | 337 | { |
3340a3e6 | 338 | htcpAuthHeader auth; |
339 | size_t copy_sz = 0; | |
a9245686 | 340 | assert(2 == sizeof(u_int16_t)); |
3340a3e6 | 341 | auth.length = htons(2); |
342 | copy_sz += 2; | |
081cdbe3 | 343 | if (buflen < copy_sz) |
344 | return -1; | |
3340a3e6 | 345 | xmemcpy(buf, &auth, copy_sz); |
346 | return copy_sz; | |
347 | } | |
348 | ||
56714a1a | 349 | static ssize_t |
d5d466fc | 350 | htcpBuildCountstr(char *buf, size_t buflen, const char *s) |
351 | { | |
a9245686 | 352 | u_int16_t length; |
56714a1a | 353 | size_t len; |
5401aa8d | 354 | int off = 0; |
62e76326 | 355 | |
d5d466fc | 356 | if (buflen - off < 2) |
62e76326 | 357 | return -1; |
358 | ||
56714a1a | 359 | if (s) |
62e76326 | 360 | len = strlen(s); |
56714a1a | 361 | else |
62e76326 | 362 | len = 0; |
363 | ||
137a13ea | 364 | debugs(31, 3, "htcpBuildCountstr: LENGTH = " << len); |
62e76326 | 365 | |
d87ebd78 | 366 | debug(31, 3) ("htcpBuildCountstr: TEXT = {%s}\n", s ? s : "<NULL>"); |
62e76326 | 367 | |
a9245686 | 368 | length = htons((u_int16_t) len); |
62e76326 | 369 | |
d5d466fc | 370 | xmemcpy(buf + off, &length, 2); |
62e76326 | 371 | |
d5d466fc | 372 | off += 2; |
62e76326 | 373 | |
d5d466fc | 374 | if (buflen - off < len) |
62e76326 | 375 | return -1; |
376 | ||
56714a1a | 377 | if (len) |
62e76326 | 378 | xmemcpy(buf + off, s, len); |
379 | ||
d5d466fc | 380 | off += len; |
62e76326 | 381 | |
d5d466fc | 382 | return off; |
383 | } | |
384 | ||
56714a1a | 385 | static ssize_t |
d5d466fc | 386 | htcpBuildSpecifier(char *buf, size_t buflen, htcpStuff * stuff) |
387 | { | |
388 | ssize_t off = 0; | |
389 | ssize_t s; | |
a2edf5dc | 390 | s = htcpBuildCountstr(buf + off, buflen - off, stuff->S.method); |
62e76326 | 391 | |
d5d466fc | 392 | if (s < 0) |
62e76326 | 393 | return s; |
394 | ||
d5d466fc | 395 | off += s; |
62e76326 | 396 | |
a2edf5dc | 397 | s = htcpBuildCountstr(buf + off, buflen - off, stuff->S.uri); |
62e76326 | 398 | |
d5d466fc | 399 | if (s < 0) |
62e76326 | 400 | return s; |
401 | ||
d5d466fc | 402 | off += s; |
62e76326 | 403 | |
a2edf5dc | 404 | s = htcpBuildCountstr(buf + off, buflen - off, stuff->S.version); |
62e76326 | 405 | |
d5d466fc | 406 | if (s < 0) |
62e76326 | 407 | return s; |
408 | ||
d5d466fc | 409 | off += s; |
62e76326 | 410 | |
a2edf5dc | 411 | s = htcpBuildCountstr(buf + off, buflen - off, stuff->S.req_hdrs); |
62e76326 | 412 | |
d5d466fc | 413 | if (s < 0) |
62e76326 | 414 | return s; |
415 | ||
d5d466fc | 416 | off += s; |
62e76326 | 417 | |
d87ebd78 | 418 | debug(31, 3) ("htcpBuildSpecifier: size %d\n", (int) off); |
62e76326 | 419 | |
d5d466fc | 420 | return off; |
421 | } | |
422 | ||
56714a1a | 423 | static ssize_t |
424 | htcpBuildDetail(char *buf, size_t buflen, htcpStuff * stuff) | |
425 | { | |
426 | ssize_t off = 0; | |
427 | ssize_t s; | |
a2edf5dc | 428 | s = htcpBuildCountstr(buf + off, buflen - off, stuff->D.resp_hdrs); |
62e76326 | 429 | |
56714a1a | 430 | if (s < 0) |
62e76326 | 431 | return s; |
432 | ||
56714a1a | 433 | off += s; |
62e76326 | 434 | |
a2edf5dc | 435 | s = htcpBuildCountstr(buf + off, buflen - off, stuff->D.entity_hdrs); |
62e76326 | 436 | |
56714a1a | 437 | if (s < 0) |
62e76326 | 438 | return s; |
439 | ||
56714a1a | 440 | off += s; |
62e76326 | 441 | |
a2edf5dc | 442 | s = htcpBuildCountstr(buf + off, buflen - off, stuff->D.cache_hdrs); |
62e76326 | 443 | |
56714a1a | 444 | if (s < 0) |
62e76326 | 445 | return s; |
446 | ||
56714a1a | 447 | off += s; |
62e76326 | 448 | |
56714a1a | 449 | return off; |
450 | } | |
451 | ||
452 | static ssize_t | |
d5d466fc | 453 | htcpBuildTstOpData(char *buf, size_t buflen, htcpStuff * stuff) |
454 | { | |
0cdcddb9 | 455 | switch (stuff->rr) { |
62e76326 | 456 | |
d9f9d78b | 457 | case RR_REQUEST: |
62e76326 | 458 | debug(31, 3) ("htcpBuildTstOpData: RR_REQUEST\n"); |
459 | return htcpBuildSpecifier(buf, buflen, stuff); | |
460 | ||
d9f9d78b | 461 | case RR_RESPONSE: |
62e76326 | 462 | debug(31, 3) ("htcpBuildTstOpData: RR_RESPONSE\n"); |
463 | debug(31, 3) ("htcpBuildTstOpData: F1 = %d\n", stuff->f1); | |
464 | ||
465 | if (stuff->f1) /* cache miss */ | |
466 | return 0; | |
467 | else /* cache hit */ | |
468 | return htcpBuildDetail(buf, buflen, stuff); | |
469 | ||
d9f9d78b | 470 | default: |
62e76326 | 471 | fatal_dump("htcpBuildTstOpData: bad RR value"); |
0cdcddb9 | 472 | } |
62e76326 | 473 | |
0cdcddb9 | 474 | return 0; |
d5d466fc | 475 | } |
476 | ||
56714a1a | 477 | static ssize_t |
d5d466fc | 478 | htcpBuildOpData(char *buf, size_t buflen, htcpStuff * stuff) |
479 | { | |
480 | ssize_t off = 0; | |
d87ebd78 | 481 | debug(31, 3) ("htcpBuildOpData: opcode %s\n", |
62e76326 | 482 | htcpOpcodeStr[stuff->op]); |
483 | ||
d5d466fc | 484 | switch (stuff->op) { |
62e76326 | 485 | |
d5d466fc | 486 | case HTCP_TST: |
62e76326 | 487 | off = htcpBuildTstOpData(buf + off, buflen, stuff); |
488 | break; | |
489 | ||
5401aa8d | 490 | case HTCP_CLR: |
491 | /* nothing to be done */ | |
492 | break; | |
493 | ||
d5d466fc | 494 | default: |
62e76326 | 495 | assert(0); |
496 | break; | |
d5d466fc | 497 | } |
62e76326 | 498 | |
d5d466fc | 499 | return off; |
500 | } | |
501 | ||
56714a1a | 502 | static ssize_t |
d5d466fc | 503 | htcpBuildData(char *buf, size_t buflen, htcpStuff * stuff) |
504 | { | |
505 | ssize_t off = 0; | |
506 | ssize_t op_data_sz; | |
507 | size_t hdr_sz = sizeof(htcpDataHeader); | |
508 | htcpDataHeader hdr; | |
62e76326 | 509 | |
d5d466fc | 510 | if (buflen < hdr_sz) |
62e76326 | 511 | return -1; |
512 | ||
d5d466fc | 513 | off += hdr_sz; /* skip! */ |
62e76326 | 514 | |
d5d466fc | 515 | op_data_sz = htcpBuildOpData(buf + off, buflen - off, stuff); |
62e76326 | 516 | |
d5d466fc | 517 | if (op_data_sz < 0) |
62e76326 | 518 | return op_data_sz; |
519 | ||
d5d466fc | 520 | off += op_data_sz; |
62e76326 | 521 | |
d87ebd78 | 522 | debug(31, 3) ("htcpBuildData: hdr.length = %d\n", (int) off); |
62e76326 | 523 | |
a9245686 | 524 | hdr.length = (u_int16_t) off; |
62e76326 | 525 | |
d5d466fc | 526 | hdr.opcode = stuff->op; |
62e76326 | 527 | |
d5d466fc | 528 | hdr.response = stuff->response; |
62e76326 | 529 | |
d5d466fc | 530 | hdr.RR = stuff->rr; |
62e76326 | 531 | |
d5d466fc | 532 | hdr.F1 = stuff->f1; |
62e76326 | 533 | |
26df9ec6 | 534 | hdr.msg_id = stuff->msg_id; |
62e76326 | 535 | |
d5d466fc | 536 | /* convert multi-byte fields */ |
537 | hdr.length = htons(hdr.length); | |
62e76326 | 538 | |
eb9ae2f7 | 539 | hdr.msg_id = htonl(hdr.msg_id); |
62e76326 | 540 | |
527ee50d | 541 | if (!old_squid_format) { |
542 | xmemcpy(buf, &hdr, hdr_sz); | |
543 | } else { | |
544 | htcpDataHeaderSquid hdrSquid; | |
545 | memset(&hdrSquid, 0, sizeof(hdrSquid)); | |
546 | hdrSquid.length = hdr.length; | |
547 | hdrSquid.opcode = hdr.opcode; | |
548 | hdrSquid.response = hdr.response; | |
549 | hdrSquid.F1 = hdr.F1; | |
550 | hdrSquid.RR = hdr.RR; | |
551 | xmemcpy(buf, &hdrSquid, hdr_sz); | |
552 | } | |
62e76326 | 553 | |
d87ebd78 | 554 | debug(31, 3) ("htcpBuildData: size %d\n", (int) off); |
62e76326 | 555 | |
d5d466fc | 556 | return off; |
557 | } | |
558 | ||
5401aa8d | 559 | /* |
560 | * Build an HTCP packet into buf, maximum length buflen. | |
561 | * Returns the packet length, or zero on failure. | |
562 | */ | |
563 | static ssize_t | |
564 | htcpBuildPacket(char *buf, size_t buflen, htcpStuff * stuff) | |
3340a3e6 | 565 | { |
5401aa8d | 566 | ssize_t s; |
d5d466fc | 567 | ssize_t off = 0; |
568 | size_t hdr_sz = sizeof(htcpHeader); | |
569 | htcpHeader hdr; | |
d5d466fc | 570 | /* skip the header -- we don't know the overall length */ |
62e76326 | 571 | |
9bc73deb | 572 | if (buflen < hdr_sz) { |
5401aa8d | 573 | return 0; |
9bc73deb | 574 | } |
62e76326 | 575 | |
d5d466fc | 576 | off += hdr_sz; |
577 | s = htcpBuildData(buf + off, buflen - off, stuff); | |
62e76326 | 578 | |
9bc73deb | 579 | if (s < 0) { |
5401aa8d | 580 | return 0; |
9bc73deb | 581 | } |
62e76326 | 582 | |
d5d466fc | 583 | off += s; |
584 | s = htcpBuildAuth(buf + off, buflen - off); | |
62e76326 | 585 | |
9bc73deb | 586 | if (s < 0) { |
5401aa8d | 587 | return 0; |
9bc73deb | 588 | } |
62e76326 | 589 | |
d5d466fc | 590 | off += s; |
a9245686 | 591 | hdr.length = htons((u_int16_t) off); |
d5d466fc | 592 | hdr.major = 0; |
527ee50d | 593 | |
594 | if (old_squid_format) | |
595 | hdr.minor = 0; | |
596 | else | |
597 | hdr.minor = 1; | |
598 | ||
d5d466fc | 599 | xmemcpy(buf, &hdr, hdr_sz); |
527ee50d | 600 | |
d87ebd78 | 601 | debug(31, 3) ("htcpBuildPacket: size %d\n", (int) off); |
527ee50d | 602 | |
5401aa8d | 603 | return off; |
3340a3e6 | 604 | } |
605 | ||
56714a1a | 606 | static void |
62e76326 | 607 | |
56714a1a | 608 | htcpSend(const char *buf, int len, struct sockaddr_in *to) |
3340a3e6 | 609 | { |
d5d466fc | 610 | int x; |
5401aa8d | 611 | debugs(31, 3, "htcpSend: " << inet_ntoa(to->sin_addr) << "/" << ntohs(to->sin_port)); |
56714a1a | 612 | htcpHexdump("htcpSend", buf, len); |
d5d466fc | 613 | x = comm_udp_sendto(htcpOutSocket, |
62e76326 | 614 | to, |
615 | ||
616 | sizeof(struct sockaddr_in), | |
617 | buf, | |
618 | len); | |
619 | ||
d5d466fc | 620 | if (x < 0) |
5401aa8d | 621 | debug(31, 1) ("htcpSend: FD %d sendto: %s\n", htcpOutSocket, xstrerror()); |
c4ebc830 | 622 | else |
623 | statCounter.htcp.pkts_sent++; | |
3340a3e6 | 624 | } |
625 | ||
eb9ae2f7 | 626 | /* |
627 | * STUFF FOR RECEIVING HTCP MESSAGES | |
628 | */ | |
629 | ||
e6ccf245 | 630 | void |
62e76326 | 631 | |
e6ccf245 | 632 | htcpSpecifier::setFrom (struct sockaddr_in *aSocket) |
633 | { | |
634 | from = aSocket; | |
635 | } | |
636 | ||
637 | void | |
638 | htcpSpecifier::setDataHeader (htcpDataHeader *aDataHeader) | |
639 | { | |
640 | dhdr = aDataHeader; | |
641 | } | |
642 | ||
eb9ae2f7 | 643 | static void |
644 | htcpFreeSpecifier(htcpSpecifier * s) | |
645 | { | |
5401aa8d | 646 | HTTPMSGUNLOCK(s->request); |
647 | ||
e6ccf245 | 648 | delete s; |
eb9ae2f7 | 649 | } |
650 | ||
a2edf5dc | 651 | static void |
652 | htcpFreeDetail(htcpDetail * d) | |
653 | { | |
b001e822 | 654 | htcpDetailPool->free(d); |
a2edf5dc | 655 | } |
656 | ||
5401aa8d | 657 | /* |
658 | * Unpack an HTCP SPECIFIER in place | |
659 | * This will overwrite any following AUTH block | |
660 | */ | |
56714a1a | 661 | static htcpSpecifier * |
eb9ae2f7 | 662 | htcpUnpackSpecifier(char *buf, int sz) |
663 | { | |
e6ccf245 | 664 | htcpSpecifier *s = new htcpSpecifier; |
5401aa8d | 665 | method_t method; |
62e76326 | 666 | |
5401aa8d | 667 | /* Find length of METHOD */ |
668 | u_int16_t l = ntohs(*(u_int16_t *) buf); | |
669 | sz -= 2; | |
670 | buf += 2; | |
671 | ||
672 | if (l > sz) { | |
62e76326 | 673 | debug(31, 1) ("htcpUnpackSpecifier: failed to unpack METHOD\n"); |
674 | htcpFreeSpecifier(s); | |
675 | return NULL; | |
1afe05c5 | 676 | } |
62e76326 | 677 | |
5401aa8d | 678 | /* Set METHOD */ |
679 | s->method = buf; | |
680 | ||
681 | buf += l; | |
682 | ||
683 | sz -= l; | |
684 | ||
685 | /* Find length of URI */ | |
686 | l = ntohs(*(u_int16_t *) buf); | |
62e76326 | 687 | |
5401aa8d | 688 | sz -= 2; |
689 | ||
690 | if (l > sz) { | |
62e76326 | 691 | debug(31, 1) ("htcpUnpackSpecifier: failed to unpack URI\n"); |
692 | htcpFreeSpecifier(s); | |
693 | return NULL; | |
1afe05c5 | 694 | } |
62e76326 | 695 | |
5401aa8d | 696 | /* Add terminating null to METHOD */ |
697 | *buf = '\0'; | |
698 | ||
699 | /* Set URI */ | |
700 | buf += 2; | |
701 | ||
702 | s->uri = buf; | |
703 | ||
704 | buf += l; | |
705 | ||
706 | sz -= l; | |
707 | ||
708 | /* Find length of VERSION */ | |
709 | l = ntohs(*(u_int16_t *) buf); | |
710 | ||
711 | sz -= 2; | |
62e76326 | 712 | |
5401aa8d | 713 | if (l > sz) { |
62e76326 | 714 | debug(31, 1) ("htcpUnpackSpecifier: failed to unpack VERSION\n"); |
715 | htcpFreeSpecifier(s); | |
716 | return NULL; | |
1afe05c5 | 717 | } |
62e76326 | 718 | |
5401aa8d | 719 | /* Add terminating null to URI */ |
720 | *buf = '\0'; | |
721 | ||
722 | /* Set VERSION */ | |
723 | buf += 2; | |
724 | ||
725 | s->version = buf; | |
726 | ||
727 | buf += l; | |
728 | ||
729 | sz -= l; | |
730 | ||
731 | /* Find length of REQ-HDRS */ | |
732 | l = ntohs(*(u_int16_t *) buf); | |
733 | ||
734 | sz -= 2; | |
62e76326 | 735 | |
5401aa8d | 736 | if (l > sz) { |
62e76326 | 737 | debug(31, 1) ("htcpUnpackSpecifier: failed to unpack REQ-HDRS\n"); |
738 | htcpFreeSpecifier(s); | |
739 | return NULL; | |
1afe05c5 | 740 | } |
62e76326 | 741 | |
5401aa8d | 742 | /* Add terminating null to URI */ |
743 | *buf = '\0'; | |
744 | ||
745 | /* Set REQ-HDRS */ | |
746 | buf += 2; | |
747 | ||
748 | s->req_hdrs = buf; | |
749 | ||
750 | buf += l; | |
751 | ||
752 | sz -= l; | |
753 | ||
d87ebd78 | 754 | debug(31, 3) ("htcpUnpackSpecifier: %d bytes left\n", sz); |
5401aa8d | 755 | |
756 | /* | |
757 | * Add terminating null to REQ-HDRS. This is possible because we allocated | |
758 | * an extra byte when we received the packet. This will overwrite any following | |
759 | * AUTH block. | |
760 | */ | |
761 | *buf = '\0'; | |
762 | ||
763 | /* | |
764 | * Parse the request | |
765 | */ | |
766 | method = HttpRequestMethod(s->method); | |
767 | ||
768 | s->request = HttpRequest::CreateFromUrlAndMethod(s->uri, method == METHOD_NONE ? METHOD_GET : method); | |
769 | ||
b8def95f | 770 | if (s->request) |
771 | HTTPMSGLOCK(s->request); | |
772 | ||
1afe05c5 | 773 | return s; |
eb9ae2f7 | 774 | } |
775 | ||
5401aa8d | 776 | /* |
777 | * Unpack an HTCP DETAIL in place | |
778 | * This will overwrite any following AUTH block | |
779 | */ | |
a2edf5dc | 780 | static htcpDetail * |
781 | htcpUnpackDetail(char *buf, int sz) | |
782 | { | |
b001e822 | 783 | htcpDetail *d = static_cast<htcpDetail *>(htcpDetailPool->alloc()); |
62e76326 | 784 | |
5401aa8d | 785 | /* Find length of RESP-HDRS */ |
786 | u_int16_t l = ntohs(*(u_int16_t *) buf); | |
787 | sz -= 2; | |
788 | buf += 2; | |
789 | ||
790 | if (l > sz) { | |
62e76326 | 791 | debug(31, 1) ("htcpUnpackDetail: failed to unpack RESP_HDRS\n"); |
792 | htcpFreeDetail(d); | |
793 | return NULL; | |
a2edf5dc | 794 | } |
62e76326 | 795 | |
5401aa8d | 796 | /* Set RESP-HDRS */ |
797 | d->resp_hdrs = buf; | |
798 | ||
799 | buf += l; | |
800 | ||
801 | sz -= l; | |
62e76326 | 802 | |
5401aa8d | 803 | /* Find length of ENTITY-HDRS */ |
804 | l = ntohs(*(u_int16_t *) buf); | |
805 | ||
806 | sz -= 2; | |
807 | ||
808 | if (l > sz) { | |
62e76326 | 809 | debug(31, 1) ("htcpUnpackDetail: failed to unpack ENTITY_HDRS\n"); |
810 | htcpFreeDetail(d); | |
811 | return NULL; | |
a2edf5dc | 812 | } |
62e76326 | 813 | |
5401aa8d | 814 | /* Add terminating null to RESP-HDRS */ |
815 | *buf = '\0'; | |
816 | ||
817 | /* Set ENTITY-HDRS */ | |
818 | buf += 2; | |
819 | ||
820 | d->entity_hdrs = buf; | |
62e76326 | 821 | |
5401aa8d | 822 | buf += l; |
823 | ||
824 | sz -= l; | |
825 | ||
826 | /* Find length of CACHE-HDRS */ | |
827 | l = ntohs(*(u_int16_t *) buf); | |
828 | ||
829 | sz -= 2; | |
830 | ||
831 | if (l > sz) { | |
62e76326 | 832 | debug(31, 1) ("htcpUnpackDetail: failed to unpack CACHE_HDRS\n"); |
833 | htcpFreeDetail(d); | |
834 | return NULL; | |
a2edf5dc | 835 | } |
62e76326 | 836 | |
5401aa8d | 837 | /* Add terminating null to ENTITY-HDRS */ |
838 | *buf = '\0'; | |
839 | ||
840 | /* Set CACHE-HDRS */ | |
841 | buf += 2; | |
842 | ||
843 | d->cache_hdrs = buf; | |
844 | ||
845 | buf += l; | |
846 | ||
847 | sz -= l; | |
848 | ||
d87ebd78 | 849 | debug(31, 3) ("htcpUnpackDetail: %d bytes left\n", sz); |
5401aa8d | 850 | |
851 | /* | |
852 | * Add terminating null to CACHE-HDRS. This is possible because we allocated | |
853 | * an extra byte when we received the packet. This will overwrite any following | |
854 | * AUTH block. | |
855 | */ | |
856 | *buf = '\0'; | |
857 | ||
a2edf5dc | 858 | return d; |
859 | } | |
860 | ||
5401aa8d | 861 | static int |
862 | ||
863 | htcpAccessCheck(acl_access * acl, htcpSpecifier * s, struct sockaddr_in *from) | |
864 | { | |
865 | ACLChecklist checklist; | |
866 | checklist.src_addr = from->sin_addr; | |
867 | checklist.my_addr = no_addr; | |
b8def95f | 868 | checklist.request = HTTPMSGLOCK(s->request); |
5401aa8d | 869 | checklist.accessList = cbdataReference(acl); |
870 | /* cbdataReferenceDone() happens in either fastCheck() or ~ACLCheckList */ | |
871 | int result = checklist.fastCheck(); | |
872 | return result; | |
873 | } | |
874 | ||
eb9ae2f7 | 875 | static void |
62e76326 | 876 | |
886f2785 | 877 | htcpTstReply(htcpDataHeader * dhdr, StoreEntry * e, htcpSpecifier * spec, struct sockaddr_in *from) |
60fac9b5 | 878 | { |
879 | htcpStuff stuff; | |
5401aa8d | 880 | static char pkt[8192]; |
75faaa7a | 881 | HttpHeader hdr(hoHtcpReply); |
2dcc81d4 | 882 | MemBuf mb; |
883 | Packer p; | |
60fac9b5 | 884 | ssize_t pktlen; |
2dcc81d4 | 885 | char *host; |
886 | int rtt = 0; | |
887 | int hops = 0; | |
888 | int samp = 0; | |
889 | char cto_buf[128]; | |
9bc73deb | 890 | memset(&stuff, '\0', sizeof(stuff)); |
60fac9b5 | 891 | stuff.op = HTCP_TST; |
892 | stuff.rr = RR_RESPONSE; | |
44e237d0 | 893 | stuff.f1 = 0; |
894 | stuff.response = e ? 0 : 1; | |
7e3ce7b9 | 895 | debug(31, 3) ("htcpTstReply: response = %d\n", stuff.response); |
26df9ec6 | 896 | stuff.msg_id = dhdr->msg_id; |
62e76326 | 897 | |
898 | if (spec) | |
899 | { | |
2fe7eff9 | 900 | mb.init(); |
62e76326 | 901 | packerToMemInit(&p, &mb); |
62e76326 | 902 | stuff.S.method = spec->method; |
903 | stuff.S.uri = spec->uri; | |
904 | stuff.S.version = spec->version; | |
905 | stuff.S.req_hdrs = spec->req_hdrs; | |
61f4f11b | 906 | hdr.putInt(HDR_AGE, |
907 | e->timestamp <= squid_curtime ? | |
908 | squid_curtime - e->timestamp : 0); | |
909 | hdr.packInto(&p); | |
62e76326 | 910 | stuff.D.resp_hdrs = xstrdup(mb.buf); |
911 | debug(31, 3) ("htcpTstReply: resp_hdrs = {%s}\n", stuff.D.resp_hdrs); | |
2fe7eff9 | 912 | mb.reset(); |
61f4f11b | 913 | hdr.reset(); |
62e76326 | 914 | |
915 | if (e->expires > -1) | |
61f4f11b | 916 | hdr.putTime(HDR_EXPIRES, e->expires); |
62e76326 | 917 | |
918 | if (e->lastmod > -1) | |
61f4f11b | 919 | hdr.putTime(HDR_LAST_MODIFIED, e->lastmod); |
62e76326 | 920 | |
61f4f11b | 921 | hdr.packInto(&p); |
62e76326 | 922 | |
923 | stuff.D.entity_hdrs = xstrdup(mb.buf); | |
924 | ||
925 | debug(31, 3) ("htcpTstReply: entity_hdrs = {%s}\n", stuff.D.entity_hdrs); | |
926 | ||
2fe7eff9 | 927 | mb.reset(); |
62e76326 | 928 | |
61f4f11b | 929 | hdr.reset(); |
62e76326 | 930 | |
931 | if ((host = urlHostname(spec->uri))) { | |
932 | netdbHostData(host, &samp, &rtt, &hops); | |
933 | ||
934 | if (rtt || hops) { | |
935 | snprintf(cto_buf, 128, "%s %d %f %d", | |
936 | host, samp, 0.001 * rtt, hops); | |
61f4f11b | 937 | hdr.putExt("Cache-to-Origin", cto_buf); |
62e76326 | 938 | } |
939 | } | |
940 | ||
61f4f11b | 941 | hdr.packInto(&p); |
62e76326 | 942 | stuff.D.cache_hdrs = xstrdup(mb.buf); |
943 | debug(31, 3) ("htcpTstReply: cache_hdrs = {%s}\n", stuff.D.cache_hdrs); | |
2fe7eff9 | 944 | mb.clean(); |
519e0948 | 945 | hdr.clean(); |
62e76326 | 946 | packerClean(&p); |
60fac9b5 | 947 | } |
62e76326 | 948 | |
5401aa8d | 949 | pktlen = htcpBuildPacket(pkt, sizeof(pkt), &stuff); |
62e76326 | 950 | |
0203ca6d | 951 | safe_free(stuff.D.resp_hdrs); |
952 | safe_free(stuff.D.entity_hdrs); | |
953 | safe_free(stuff.D.cache_hdrs); | |
954 | ||
5401aa8d | 955 | if (!pktlen) |
956 | { | |
957 | debug(31, 1) ("htcpTstReply: htcpBuildPacket() failed\n"); | |
958 | return; | |
959 | } | |
960 | ||
961 | htcpSend(pkt, (int) pktlen, from); | |
962 | } | |
963 | ||
964 | static void | |
965 | ||
966 | htcpClrReply(htcpDataHeader * dhdr, int purgeSucceeded, struct sockaddr_in *from) | |
967 | { | |
968 | htcpStuff stuff; | |
969 | static char pkt[8192]; | |
970 | ssize_t pktlen; | |
971 | ||
972 | /* If dhdr->F1 == 0, no response desired */ | |
973 | ||
974 | if (dhdr->F1 == 0) | |
975 | return; | |
976 | ||
977 | memset(&stuff, '\0', sizeof(stuff)); | |
978 | ||
979 | stuff.op = HTCP_CLR; | |
980 | ||
981 | stuff.rr = RR_RESPONSE; | |
982 | ||
983 | stuff.f1 = 0; | |
984 | ||
985 | stuff.response = purgeSucceeded ? 0 : 2; | |
986 | ||
987 | debug(31, 3) ("htcpClrReply: response = %d\n", stuff.response); | |
988 | ||
989 | stuff.msg_id = dhdr->msg_id; | |
990 | ||
991 | pktlen = htcpBuildPacket(pkt, sizeof(pkt), &stuff); | |
992 | ||
993 | if (pktlen == 0) | |
62e76326 | 994 | { |
5401aa8d | 995 | debug(31, 1) ("htcpClrReply: htcpBuildPacket() failed\n"); |
62e76326 | 996 | return; |
60fac9b5 | 997 | } |
62e76326 | 998 | |
60fac9b5 | 999 | htcpSend(pkt, (int) pktlen, from); |
60fac9b5 | 1000 | } |
1001 | ||
1002 | static void | |
62e76326 | 1003 | |
60fac9b5 | 1004 | htcpHandleNop(htcpDataHeader * hdr, char *buf, int sz, struct sockaddr_in *from) |
eb9ae2f7 | 1005 | { |
d87ebd78 | 1006 | debug(31, 3) ("htcpHandleNop: Unimplemented\n"); |
eb9ae2f7 | 1007 | } |
1008 | ||
e6ccf245 | 1009 | void |
1010 | htcpSpecifier::checkHit() | |
32b3cf93 | 1011 | { |
7e3ce7b9 | 1012 | char *blk_end; |
5401aa8d | 1013 | checkHitRequest = request; |
62e76326 | 1014 | |
e6ccf245 | 1015 | if (NULL == checkHitRequest) { |
62e76326 | 1016 | debug(31, 3) ("htcpCheckHit: NO; failed to parse URL\n"); |
1017 | checkedHit(NullStoreEntry::getInstance()); | |
1018 | return; | |
7e3ce7b9 | 1019 | } |
62e76326 | 1020 | |
e6ccf245 | 1021 | blk_end = req_hdrs + strlen(req_hdrs); |
62e76326 | 1022 | |
61f4f11b | 1023 | if (!checkHitRequest->header.parse(req_hdrs, blk_end)) { |
62e76326 | 1024 | debug(31, 3) ("htcpCheckHit: NO; failed to parse request headers\n"); |
5cafad19 | 1025 | delete checkHitRequest; |
62e76326 | 1026 | checkHitRequest = NULL; |
1027 | checkedHit(NullStoreEntry::getInstance()); | |
1028 | return; | |
f66a9ef4 | 1029 | } |
62e76326 | 1030 | |
3b13a8fd | 1031 | StoreEntry::getPublicByRequest(this, checkHitRequest); |
e6ccf245 | 1032 | } |
1033 | ||
1034 | void | |
3b13a8fd | 1035 | htcpSpecifier::created (StoreEntry *e) |
e6ccf245 | 1036 | { |
1037 | StoreEntry *hit=NULL; | |
1038 | assert (e); | |
62e76326 | 1039 | |
e6ccf245 | 1040 | if (e->isNull()) { |
62e76326 | 1041 | debug(31, 3) ("htcpCheckHit: NO; public object not found\n"); |
1042 | goto miss; | |
f66a9ef4 | 1043 | } |
62e76326 | 1044 | |
f66a9ef4 | 1045 | if (!storeEntryValidToSend(e)) { |
62e76326 | 1046 | debug(31, 3) ("htcpCheckHit: NO; entry not valid to send\n"); |
1047 | goto miss; | |
f66a9ef4 | 1048 | } |
62e76326 | 1049 | |
e6ccf245 | 1050 | if (refreshCheckHTCP(e, checkHitRequest)) { |
62e76326 | 1051 | debug(31, 3) ("htcpCheckHit: NO; cached response is stale\n"); |
1052 | goto miss; | |
7e3ce7b9 | 1053 | } |
62e76326 | 1054 | |
f66a9ef4 | 1055 | debug(31, 3) ("htcpCheckHit: YES!?\n"); |
1056 | hit = e; | |
62e76326 | 1057 | |
1058 | miss: | |
e6ccf245 | 1059 | checkedHit (hit); |
32b3cf93 | 1060 | } |
1061 | ||
5401aa8d | 1062 | static void |
1063 | htcpClrStoreEntry(StoreEntry * e) | |
1064 | { | |
1065 | debug(31, 4) ("htcpClrStoreEntry: Clearing store for entry: %s\n", storeUrl(e)); | |
1066 | storeReleaseRequest(e); | |
1067 | } | |
1068 | ||
1069 | static int | |
1070 | htcpClrStore(const htcpSpecifier * s) | |
1071 | { | |
1072 | HttpRequest *request = s->request; | |
1073 | char *blk_end; | |
1074 | StoreEntry *e = NULL; | |
1075 | int released = 0; | |
1076 | ||
1077 | if (request == NULL) { | |
1078 | debug(31, 3) ("htcpClrStore: failed to parse URL\n"); | |
1079 | return -1; | |
1080 | } | |
1081 | ||
1082 | /* Parse request headers */ | |
1083 | blk_end = s->req_hdrs + strlen(s->req_hdrs); | |
1084 | ||
1085 | if (!request->header.parse(s->req_hdrs, blk_end)) { | |
1086 | debug(31, 2) ("htcpClrStore: failed to parse request headers\n"); | |
1087 | return -1; | |
1088 | } | |
1089 | ||
1090 | /* Lookup matching entries. This matches both GET and HEAD */ | |
1091 | while ((e = storeGetPublicByRequest(request)) != NULL) { | |
1092 | if (e != NULL) { | |
1093 | htcpClrStoreEntry(e); | |
1094 | released++; | |
1095 | } | |
1096 | } | |
1097 | ||
1098 | if (released) { | |
1099 | debug(31, 4) ("htcpClrStore: Cleared %d matching entries\n", released); | |
1100 | return 1; | |
1101 | } else { | |
1102 | debug(31, 4) ("htcpClrStore: No matching entry found\n"); | |
1103 | return 0; | |
1104 | } | |
1105 | } | |
1106 | ||
eb9ae2f7 | 1107 | static void |
62e76326 | 1108 | |
60fac9b5 | 1109 | htcpHandleTst(htcpDataHeader * hdr, char *buf, int sz, struct sockaddr_in *from) |
eb9ae2f7 | 1110 | { |
d87ebd78 | 1111 | debug(31, 3) ("htcpHandleTst: sz = %d\n", (int) sz); |
62e76326 | 1112 | |
60fac9b5 | 1113 | if (hdr->RR == RR_REQUEST) |
62e76326 | 1114 | htcpHandleTstRequest(hdr, buf, sz, from); |
60fac9b5 | 1115 | else |
62e76326 | 1116 | htcpHandleTstResponse(hdr, buf, sz, from); |
60fac9b5 | 1117 | } |
1118 | ||
75faaa7a | 1119 | HtcpReplyData::HtcpReplyData() : hdr(hoHtcpReply) |
1120 | {} | |
1121 | ||
60fac9b5 | 1122 | static void |
62e76326 | 1123 | |
60fac9b5 | 1124 | htcpHandleTstResponse(htcpDataHeader * hdr, char *buf, int sz, struct sockaddr_in *from) |
1125 | { | |
a2edf5dc | 1126 | htcpReplyData htcpReply; |
1127 | cache_key *key = NULL; | |
5401aa8d | 1128 | |
1129 | struct sockaddr_in *peer; | |
26df9ec6 | 1130 | htcpDetail *d = NULL; |
a2edf5dc | 1131 | char *t; |
62e76326 | 1132 | |
5401aa8d | 1133 | |
1134 | if (queried_id[hdr->msg_id % N_QUERIED_KEYS] != hdr->msg_id) | |
1135 | { | |
1136 | debug(31, 2) ("htcpHandleTstResponse: No matching query id '%d' (expected %d) from '%s'\n", hdr->msg_id, queried_id[hdr->msg_id % N_QUERIED_KEYS], inet_ntoa(from->sin_addr)); | |
1137 | return; | |
1138 | } | |
1139 | ||
1140 | key = queried_keys[hdr->msg_id % N_QUERIED_KEYS]; | |
1141 | ||
1142 | if (!key) | |
1143 | { | |
1144 | debug(31, 1) ("htcpHandleTstResponse: No query key for response id '%d' from '%s'\n", hdr->msg_id, inet_ntoa(from->sin_addr)); | |
1145 | return; | |
1146 | } | |
1147 | ||
1148 | peer = &queried_addr[hdr->msg_id % N_QUERIED_KEYS]; | |
1149 | ||
1150 | if (peer->sin_addr.s_addr != from->sin_addr.s_addr || peer->sin_port != from->sin_port) | |
1151 | { | |
1152 | debug(31, 1) ("htcpHandleTstResponse: Unexpected response source %s\n", inet_ntoa(from->sin_addr)); | |
1153 | return; | |
1154 | } | |
1155 | ||
62e76326 | 1156 | if (hdr->F1 == 1) |
1157 | { | |
5401aa8d | 1158 | debug(31, 2) ("htcpHandleTstResponse: error condition, F1/MO == 1\n"); |
62e76326 | 1159 | return; |
44e237d0 | 1160 | } |
62e76326 | 1161 | |
26df9ec6 | 1162 | htcpReply.msg_id = hdr->msg_id; |
d87ebd78 | 1163 | debug(31, 3) ("htcpHandleTstResponse: msg_id = %d\n", (int) htcpReply.msg_id); |
44e237d0 | 1164 | htcpReply.hit = hdr->response ? 0 : 1; |
62e76326 | 1165 | |
1166 | if (hdr->F1) | |
1167 | { | |
1168 | debug(31, 3) ("htcpHandleTstResponse: MISS\n"); | |
1169 | } else | |
1170 | { | |
1171 | debug(31, 3) ("htcpHandleTstResponse: HIT\n"); | |
1172 | d = htcpUnpackDetail(buf, sz); | |
1173 | ||
1174 | if (d == NULL) { | |
1175 | debug(31, 1) ("htcpHandleTstResponse: bad DETAIL\n"); | |
1176 | return; | |
1177 | } | |
1178 | ||
1179 | if ((t = d->resp_hdrs)) | |
61f4f11b | 1180 | htcpReply.hdr.parse(t, t + strlen(t)); |
62e76326 | 1181 | |
1182 | if ((t = d->entity_hdrs)) | |
61f4f11b | 1183 | htcpReply.hdr.parse(t, t + strlen(t)); |
62e76326 | 1184 | |
1185 | if ((t = d->cache_hdrs)) | |
61f4f11b | 1186 | htcpReply.hdr.parse(t, t + strlen(t)); |
a2edf5dc | 1187 | } |
62e76326 | 1188 | |
d87ebd78 | 1189 | debug(31, 3) ("htcpHandleTstResponse: key (%p) %s\n", key, storeKeyText(key)); |
a2edf5dc | 1190 | neighborsHtcpReply(key, &htcpReply, from); |
519e0948 | 1191 | htcpReply.hdr.clean(); |
62e76326 | 1192 | |
26df9ec6 | 1193 | if (d) |
62e76326 | 1194 | htcpFreeDetail(d); |
60fac9b5 | 1195 | } |
1196 | ||
1197 | static void | |
62e76326 | 1198 | |
886f2785 | 1199 | htcpHandleTstRequest(htcpDataHeader * dhdr, char *buf, int sz, struct sockaddr_in *from) |
60fac9b5 | 1200 | { |
1201 | /* buf should be a SPECIFIER */ | |
1202 | htcpSpecifier *s; | |
62e76326 | 1203 | |
1204 | if (sz == 0) | |
1205 | { | |
1206 | debug(31, 3) ("htcpHandleTst: nothing to do\n"); | |
1207 | return; | |
60fac9b5 | 1208 | } |
62e76326 | 1209 | |
44e237d0 | 1210 | if (dhdr->F1 == 0) |
62e76326 | 1211 | return; |
1212 | ||
e6ccf245 | 1213 | /* s is a new object */ |
60fac9b5 | 1214 | s = htcpUnpackSpecifier(buf, sz); |
62e76326 | 1215 | |
e6ccf245 | 1216 | s->setFrom (from); |
62e76326 | 1217 | |
e6ccf245 | 1218 | s->setDataHeader (dhdr); |
62e76326 | 1219 | |
1220 | if (NULL == s) | |
1221 | { | |
5401aa8d | 1222 | debug(31, 2) ("htcpHandleTstRequest: htcpUnpackSpecifier failed\n"); |
1223 | return; | |
1224 | } | |
1225 | ||
1226 | if (!s->request) | |
1227 | { | |
1228 | debug(31, 2) ("htcpHandleTstRequest: failed to parse request\n"); | |
1229 | htcpFreeSpecifier(s); | |
1230 | return; | |
1231 | } | |
1232 | ||
5401aa8d | 1233 | if (!htcpAccessCheck(Config.accessList.htcp, s, from)) |
1234 | { | |
1235 | debug(31, 2) ("htcpHandleTstRequest: Access denied\n"); | |
1236 | htcpFreeSpecifier(s); | |
62e76326 | 1237 | return; |
1afe05c5 | 1238 | } |
62e76326 | 1239 | |
d87ebd78 | 1240 | debug(31, 3) ("htcpHandleTstRequest: %s %s %s\n", |
62e76326 | 1241 | s->method, |
1242 | s->uri, | |
1243 | s->version); | |
d87ebd78 | 1244 | debug(31, 3) ("htcpHandleTstRequest: %s\n", s->req_hdrs); |
e6ccf245 | 1245 | s->checkHit(); |
1246 | } | |
1247 | ||
1248 | void | |
1249 | htcpSpecifier::checkedHit(StoreEntry *e) | |
1250 | { | |
1251 | if (e) | |
62e76326 | 1252 | htcpTstReply(dhdr, e, this, from); /* hit */ |
32b3cf93 | 1253 | else |
62e76326 | 1254 | htcpTstReply(dhdr, NULL, NULL, from); /* cache miss */ |
1255 | ||
e6ccf245 | 1256 | htcpFreeSpecifier(this); |
d9f9d78b | 1257 | } |
1258 | ||
1259 | static void | |
62e76326 | 1260 | |
60fac9b5 | 1261 | htcpHandleMon(htcpDataHeader * hdr, char *buf, int sz, struct sockaddr_in *from) |
eb9ae2f7 | 1262 | { |
d87ebd78 | 1263 | debug(31, 3) ("htcpHandleMon: Unimplemented\n"); |
eb9ae2f7 | 1264 | } |
1265 | ||
1266 | static void | |
62e76326 | 1267 | |
60fac9b5 | 1268 | htcpHandleSet(htcpDataHeader * hdr, char *buf, int sz, struct sockaddr_in *from) |
eb9ae2f7 | 1269 | { |
d87ebd78 | 1270 | debug(31, 3) ("htcpHandleSet: Unimplemented\n"); |
eb9ae2f7 | 1271 | } |
1272 | ||
1273 | static void | |
62e76326 | 1274 | |
5401aa8d | 1275 | htcpHandleClr(htcpDataHeader * hdr, char *buf, int sz, struct sockaddr_in *from) |
1276 | { | |
1277 | htcpSpecifier *s; | |
1278 | /* buf[0/1] is reserved and reason */ | |
1279 | int reason = buf[1] << 4; | |
1280 | debug(31, 3) ("htcpHandleClr: reason=%d\n", reason); | |
1281 | buf += 2; | |
1282 | sz -= 2; | |
1283 | ||
1284 | /* buf should be a SPECIFIER */ | |
1285 | ||
1286 | if (sz == 0) | |
1287 | { | |
1288 | debug(31, 4) ("htcpHandleClr: nothing to do\n"); | |
1289 | return; | |
1290 | } | |
1291 | ||
1292 | s = htcpUnpackSpecifier(buf, sz); | |
1293 | ||
1294 | if (NULL == s) | |
1295 | { | |
1296 | debug(31, 3) ("htcpHandleClr: htcpUnpackSpecifier failed\n"); | |
1297 | return; | |
1298 | } | |
1299 | ||
1300 | if (!htcpAccessCheck(Config.accessList.htcp_clr, s, from)) | |
1301 | { | |
1302 | debug(31, 2) ("htcpHandleClr: Access denied\n"); | |
1303 | htcpFreeSpecifier(s); | |
1304 | return; | |
1305 | } | |
1306 | ||
1307 | debug(31, 5) ("htcpHandleClr: %s %s %s\n", | |
1308 | s->method, | |
1309 | s->uri, | |
1310 | s->version); | |
1311 | debug(31, 5) ("htcpHandleClr: request headers: %s\n", s->req_hdrs); | |
1312 | ||
1313 | /* Release objects from cache | |
1314 | * analog to clientPurgeRequest in client_side.c | |
1315 | */ | |
1316 | ||
1317 | switch (htcpClrStore(s)) | |
1318 | { | |
1319 | ||
1320 | case 1: | |
1321 | htcpClrReply(hdr, 1, from); /* hit */ | |
1322 | break; | |
1323 | ||
1324 | case 0: | |
1325 | htcpClrReply(hdr, 0, from); /* miss */ | |
1326 | break; | |
1327 | ||
1328 | default: | |
1329 | break; | |
1330 | } | |
1331 | ||
1332 | htcpFreeSpecifier(s); | |
1333 | } | |
1334 | ||
1335 | static void | |
1336 | ||
56714a1a | 1337 | htcpHandleData(char *buf, int sz, struct sockaddr_in *from) |
eb9ae2f7 | 1338 | { |
1339 | htcpDataHeader hdr; | |
62e76326 | 1340 | |
1341 | if ((size_t)sz < sizeof(htcpDataHeader)) | |
1342 | { | |
5401aa8d | 1343 | debug(31, 1) ("htcpHandleData: msg size less than htcpDataHeader size\n"); |
62e76326 | 1344 | return; |
eb9ae2f7 | 1345 | } |
62e76326 | 1346 | |
527ee50d | 1347 | if (!old_squid_format) |
1348 | { | |
5401aa8d | 1349 | xmemcpy(&hdr, buf, sizeof(hdr)); |
527ee50d | 1350 | } else |
1351 | { | |
1352 | htcpDataHeaderSquid hdrSquid; | |
1353 | xmemcpy(&hdrSquid, buf, sizeof(hdrSquid)); | |
5401aa8d | 1354 | hdr.length = hdrSquid.length; |
527ee50d | 1355 | hdr.opcode = hdrSquid.opcode; |
1356 | hdr.response = hdrSquid.response; | |
1357 | hdr.F1 = hdrSquid.F1; | |
1358 | hdr.RR = hdrSquid.RR; | |
1359 | hdr.reserved = 0; | |
1360 | hdr.msg_id = hdrSquid.msg_id; | |
1361 | } | |
1362 | ||
eb9ae2f7 | 1363 | hdr.length = ntohs(hdr.length); |
26df9ec6 | 1364 | hdr.msg_id = ntohl(hdr.msg_id); |
d87ebd78 | 1365 | debug(31, 3) ("htcpHandleData: sz = %d\n", sz); |
1366 | debug(31, 3) ("htcpHandleData: length = %d\n", (int) hdr.length); | |
62e76326 | 1367 | |
1368 | if (hdr.opcode >= HTCP_END) | |
1369 | { | |
5401aa8d | 1370 | debug(31, 1) ("htcpHandleData: client %s, opcode %d out of range\n", |
62e76326 | 1371 | inet_ntoa(from->sin_addr), |
1372 | (int) hdr.opcode); | |
1373 | return; | |
eb9ae2f7 | 1374 | } |
62e76326 | 1375 | |
d87ebd78 | 1376 | debug(31, 3) ("htcpHandleData: opcode = %d %s\n", |
62e76326 | 1377 | (int) hdr.opcode, htcpOpcodeStr[hdr.opcode]); |
d87ebd78 | 1378 | debug(31, 3) ("htcpHandleData: response = %d\n", (int) hdr.response); |
1379 | debug(31, 3) ("htcpHandleData: F1 = %d\n", (int) hdr.F1); | |
1380 | debug(31, 3) ("htcpHandleData: RR = %d\n", (int) hdr.RR); | |
1381 | debug(31, 3) ("htcpHandleData: msg_id = %d\n", (int) hdr.msg_id); | |
62e76326 | 1382 | |
1383 | if (sz < hdr.length) | |
1384 | { | |
5401aa8d | 1385 | debug(31, 1) ("htcpHandleData: sz < hdr.length\n"); |
62e76326 | 1386 | return; |
eb9ae2f7 | 1387 | } |
62e76326 | 1388 | |
60fac9b5 | 1389 | /* |
1390 | * set sz = hdr.length so we ignore any AUTH fields following | |
1391 | * the DATA. | |
1392 | */ | |
1393 | sz = (int) hdr.length; | |
62e76326 | 1394 | |
eb9ae2f7 | 1395 | buf += sizeof(htcpDataHeader); |
62e76326 | 1396 | |
eb9ae2f7 | 1397 | sz -= sizeof(htcpDataHeader); |
62e76326 | 1398 | |
d87ebd78 | 1399 | debug(31, 3) ("htcpHandleData: sz = %d\n", sz); |
62e76326 | 1400 | |
56714a1a | 1401 | htcpHexdump("htcpHandleData", buf, sz); |
62e76326 | 1402 | |
1403 | switch (hdr.opcode) | |
1404 | { | |
1405 | ||
eb9ae2f7 | 1406 | case HTCP_NOP: |
62e76326 | 1407 | htcpHandleNop(&hdr, buf, sz, from); |
1408 | break; | |
1409 | ||
eb9ae2f7 | 1410 | case HTCP_TST: |
62e76326 | 1411 | htcpHandleTst(&hdr, buf, sz, from); |
1412 | break; | |
1413 | ||
eb9ae2f7 | 1414 | case HTCP_MON: |
62e76326 | 1415 | htcpHandleMon(&hdr, buf, sz, from); |
1416 | break; | |
1417 | ||
eb9ae2f7 | 1418 | case HTCP_SET: |
62e76326 | 1419 | htcpHandleSet(&hdr, buf, sz, from); |
1420 | break; | |
1421 | ||
2caa57ef | 1422 | case HTCP_CLR: |
5401aa8d | 1423 | htcpHandleClr(&hdr, buf, sz, from); |
62e76326 | 1424 | break; |
1425 | ||
eb9ae2f7 | 1426 | default: |
5401aa8d | 1427 | return; |
eb9ae2f7 | 1428 | } |
1429 | } | |
1430 | ||
1431 | static void | |
62e76326 | 1432 | |
eb9ae2f7 | 1433 | htcpHandle(char *buf, int sz, struct sockaddr_in *from) |
1434 | { | |
1435 | htcpHeader htcpHdr; | |
e6ccf245 | 1436 | assert (sz >= 0); |
62e76326 | 1437 | |
1438 | if ((size_t)sz < sizeof(htcpHeader)) | |
1439 | { | |
5401aa8d | 1440 | debug(31, 1) ("htcpHandle: msg size less than htcpHeader size\n"); |
62e76326 | 1441 | return; |
eb9ae2f7 | 1442 | } |
62e76326 | 1443 | |
56714a1a | 1444 | htcpHexdump("htcpHandle", buf, sz); |
eb9ae2f7 | 1445 | xmemcpy(&htcpHdr, buf, sizeof(htcpHeader)); |
1446 | htcpHdr.length = ntohs(htcpHdr.length); | |
527ee50d | 1447 | |
1448 | if (htcpHdr.minor == 0) | |
1449 | old_squid_format = 1; | |
1450 | else | |
1451 | old_squid_format = 0; | |
1452 | ||
d87ebd78 | 1453 | debug(31, 3) ("htcpHandle: htcpHdr.length = %d\n", (int) htcpHdr.length); |
527ee50d | 1454 | |
d87ebd78 | 1455 | debug(31, 3) ("htcpHandle: htcpHdr.major = %d\n", (int) htcpHdr.major); |
527ee50d | 1456 | |
d87ebd78 | 1457 | debug(31, 3) ("htcpHandle: htcpHdr.minor = %d\n", (int) htcpHdr.minor); |
62e76326 | 1458 | |
1459 | if (sz != htcpHdr.length) | |
1460 | { | |
1461 | debug(31, 1) ("htcpHandle: sz/%d != htcpHdr.length/%d from %s:%d\n", | |
1462 | sz, htcpHdr.length, | |
1463 | inet_ntoa(from->sin_addr), (int) ntohs(from->sin_port)); | |
1464 | return; | |
eb9ae2f7 | 1465 | } |
62e76326 | 1466 | |
527ee50d | 1467 | if (htcpHdr.major != 0) |
1468 | { | |
1469 | debug(31, 1) ("htcpHandle: Unknown major version %d from %s:%d\n", | |
1470 | htcpHdr.major, | |
1471 | inet_ntoa(from->sin_addr), (int) ntohs(from->sin_port)); | |
1472 | return; | |
1473 | } | |
1474 | ||
eb9ae2f7 | 1475 | buf += sizeof(htcpHeader); |
1476 | sz -= sizeof(htcpHeader); | |
56714a1a | 1477 | htcpHandleData(buf, sz, from); |
eb9ae2f7 | 1478 | } |
1479 | ||
56714a1a | 1480 | static void |
eb9ae2f7 | 1481 | htcpRecv(int fd, void *data) |
1482 | { | |
1483 | static char buf[8192]; | |
1484 | int len; | |
62e76326 | 1485 | |
eb9ae2f7 | 1486 | static struct sockaddr_in from; |
62e76326 | 1487 | |
e6ccf245 | 1488 | socklen_t flen = sizeof(struct sockaddr_in); |
eb9ae2f7 | 1489 | memset(&from, '\0', flen); |
62e76326 | 1490 | |
5401aa8d | 1491 | /* Receive up to 8191 bytes, leaving room for a null */ |
1492 | ||
1493 | len = comm_udp_recvfrom(fd, buf, sizeof(buf) - 1, 0, (struct sockaddr *) &from, &flen); | |
d87ebd78 | 1494 | debug(31, 3) ("htcpRecv: FD %d, %d bytes from %s:%d\n", |
62e76326 | 1495 | fd, len, inet_ntoa(from.sin_addr), ntohs(from.sin_port)); |
c4ebc830 | 1496 | |
1497 | if (len) | |
1498 | statCounter.htcp.pkts_recv++; | |
1499 | ||
eb9ae2f7 | 1500 | htcpHandle(buf, len, &from); |
c4ebc830 | 1501 | |
eb9ae2f7 | 1502 | commSetSelect(fd, COMM_SELECT_READ, htcpRecv, NULL, 0); |
1503 | } | |
1504 | ||
56714a1a | 1505 | /* |
1506 | * ====================================================================== | |
1507 | * PUBLIC FUNCTIONS | |
1508 | * ====================================================================== | |
1509 | */ | |
1510 | ||
d5d466fc | 1511 | void |
1512 | htcpInit(void) | |
3340a3e6 | 1513 | { |
775fa4ba | 1514 | if (Config.Port.htcp <= 0) { |
62e76326 | 1515 | debug(31, 1) ("HTCP Disabled.\n"); |
1516 | return; | |
775fa4ba | 1517 | } |
62e76326 | 1518 | |
d5d466fc | 1519 | enter_suid(); |
1520 | htcpInSocket = comm_open(SOCK_DGRAM, | |
bdb741f4 | 1521 | IPPROTO_UDP, |
62e76326 | 1522 | Config.Addrs.udp_incoming, |
1523 | Config.Port.htcp, | |
1524 | COMM_NONBLOCKING, | |
1525 | "HTCP Socket"); | |
d5d466fc | 1526 | leave_suid(); |
62e76326 | 1527 | |
d5d466fc | 1528 | if (htcpInSocket < 0) |
62e76326 | 1529 | fatal("Cannot open HTCP Socket"); |
1530 | ||
d5d466fc | 1531 | commSetSelect(htcpInSocket, COMM_SELECT_READ, htcpRecv, NULL, 0); |
62e76326 | 1532 | |
ba3eec6b | 1533 | debug(31, 1) ("Accepting HTCP messages on port %d, FD %d.\n", |
62e76326 | 1534 | (int) Config.Port.htcp, htcpInSocket); |
1535 | ||
d5d466fc | 1536 | if (Config.Addrs.udp_outgoing.s_addr != no_addr.s_addr) { |
62e76326 | 1537 | enter_suid(); |
1538 | htcpOutSocket = comm_open(SOCK_DGRAM, | |
bdb741f4 | 1539 | IPPROTO_UDP, |
62e76326 | 1540 | Config.Addrs.udp_outgoing, |
1541 | Config.Port.htcp, | |
1542 | COMM_NONBLOCKING, | |
1543 | "Outgoing HTCP Socket"); | |
1544 | leave_suid(); | |
1545 | ||
1546 | if (htcpOutSocket < 0) | |
1547 | fatal("Cannot open Outgoing HTCP Socket"); | |
1548 | ||
1549 | commSetSelect(htcpOutSocket, COMM_SELECT_READ, htcpRecv, NULL, 0); | |
1550 | ||
1551 | debug(31, 1) ("Outgoing HTCP messages on port %d, FD %d.\n", | |
1552 | (int) Config.Port.htcp, htcpOutSocket); | |
1553 | ||
1554 | fd_note(htcpInSocket, "Incoming HTCP socket"); | |
d5d466fc | 1555 | } else { |
62e76326 | 1556 | htcpOutSocket = htcpInSocket; |
d5d466fc | 1557 | } |
62e76326 | 1558 | |
e6ccf245 | 1559 | if (!htcpDetailPool) { |
04eb0689 | 1560 | htcpDetailPool = memPoolCreate("htcpDetail", sizeof(htcpDetail)); |
675f3dff | 1561 | } |
59c4d35b | 1562 | } |
72549e05 | 1563 | |
56714a1a | 1564 | void |
190154cf | 1565 | htcpQuery(StoreEntry * e, HttpRequest * req, peer * p) |
56714a1a | 1566 | { |
26df9ec6 | 1567 | cache_key *save_key; |
5401aa8d | 1568 | static char pkt[8192]; |
56714a1a | 1569 | ssize_t pktlen; |
1570 | char vbuf[32]; | |
1571 | htcpStuff stuff; | |
75faaa7a | 1572 | HttpHeader hdr(hoRequest); |
56714a1a | 1573 | Packer pa; |
1574 | MemBuf mb; | |
9c48373d | 1575 | http_state_flags flags; |
775fa4ba | 1576 | |
1577 | if (htcpInSocket < 0) | |
62e76326 | 1578 | return; |
775fa4ba | 1579 | |
527ee50d | 1580 | old_squid_format = p->options.htcp_oldsquid; |
1581 | ||
9c48373d | 1582 | memset(&flags, '\0', sizeof(flags)); |
62e76326 | 1583 | |
7af0a8e6 | 1584 | snprintf(vbuf, sizeof(vbuf), "%d/%d", |
62e76326 | 1585 | req->http_ver.major, req->http_ver.minor); |
1586 | ||
56714a1a | 1587 | stuff.op = HTCP_TST; |
62e76326 | 1588 | |
56714a1a | 1589 | stuff.rr = RR_REQUEST; |
62e76326 | 1590 | |
56714a1a | 1591 | stuff.f1 = 1; |
62e76326 | 1592 | |
56714a1a | 1593 | stuff.response = 0; |
62e76326 | 1594 | |
26df9ec6 | 1595 | stuff.msg_id = ++msg_id_counter; |
62e76326 | 1596 | |
9c48373d | 1597 | stuff.S.method = (char *) RequestMethodStr[req->method]; |
62e76326 | 1598 | |
9c48373d | 1599 | stuff.S.uri = (char *) storeUrl(e); |
62e76326 | 1600 | |
a2edf5dc | 1601 | stuff.S.version = vbuf; |
62e76326 | 1602 | |
3b0d7130 | 1603 | HttpStateData::httpBuildRequestHeader(req, req, e, &hdr, flags); |
62e76326 | 1604 | |
2fe7eff9 | 1605 | mb.init(); |
62e76326 | 1606 | |
56714a1a | 1607 | packerToMemInit(&pa, &mb); |
62e76326 | 1608 | |
61f4f11b | 1609 | hdr.packInto(&pa); |
62e76326 | 1610 | |
519e0948 | 1611 | hdr.clean(); |
62e76326 | 1612 | |
56714a1a | 1613 | packerClean(&pa); |
62e76326 | 1614 | |
a2edf5dc | 1615 | stuff.S.req_hdrs = mb.buf; |
62e76326 | 1616 | |
5401aa8d | 1617 | pktlen = htcpBuildPacket(pkt, sizeof(pkt), &stuff); |
62e76326 | 1618 | |
2fe7eff9 | 1619 | mb.clean(); |
62e76326 | 1620 | |
5401aa8d | 1621 | if (!pktlen) { |
1622 | debug(31, 1) ("htcpQuery: htcpBuildPacket() failed\n"); | |
62e76326 | 1623 | return; |
56714a1a | 1624 | } |
62e76326 | 1625 | |
56714a1a | 1626 | htcpSend(pkt, (int) pktlen, &p->in_addr); |
5401aa8d | 1627 | queried_id[stuff.msg_id % N_QUERIED_KEYS] = stuff.msg_id; |
26df9ec6 | 1628 | save_key = queried_keys[stuff.msg_id % N_QUERIED_KEYS]; |
332dafa2 | 1629 | storeKeyCopy(save_key, (const cache_key *)e->key); |
5401aa8d | 1630 | queried_addr[stuff.msg_id % N_QUERIED_KEYS] = p->in_addr; |
d87ebd78 | 1631 | debug(31, 3) ("htcpQuery: key (%p) %s\n", save_key, storeKeyText(save_key)); |
56714a1a | 1632 | } |
1633 | ||
62e76326 | 1634 | /* |
72549e05 | 1635 | * htcpSocketShutdown only closes the 'in' socket if it is |
1636 | * different than the 'out' socket. | |
1afe05c5 | 1637 | */ |
72549e05 | 1638 | void |
1639 | htcpSocketShutdown(void) | |
1afe05c5 | 1640 | { |
72549e05 | 1641 | if (htcpInSocket < 0) |
62e76326 | 1642 | return; |
1643 | ||
1afe05c5 | 1644 | if (htcpInSocket != htcpOutSocket) { |
62e76326 | 1645 | debug(12, 1) ("FD %d Closing HTCP socket\n", htcpInSocket); |
1646 | comm_close(htcpInSocket); | |
1afe05c5 | 1647 | } |
62e76326 | 1648 | |
1649 | /* | |
72549e05 | 1650 | * Here we set 'htcpInSocket' to -1 even though the HTCP 'in' |
1651 | * and 'out' sockets might be just one FD. This prevents this | |
1652 | * function from executing repeatedly. When we are really ready to | |
1653 | * exit or restart, main will comm_close the 'out' descriptor. | |
1afe05c5 | 1654 | */ |
72549e05 | 1655 | htcpInSocket = -1; |
62e76326 | 1656 | |
1657 | /* | |
72549e05 | 1658 | * Normally we only write to the outgoing HTCP socket, but |
1659 | * we also have a read handler there to catch messages sent | |
1660 | * to that specific interface. During shutdown, we must | |
1661 | * disable reading on the outgoing socket. | |
1afe05c5 | 1662 | */ |
675f3dff | 1663 | /* XXX Don't we need this handler to read replies while shutting down? |
1664 | * I think there should be a separate hander for reading replies.. | |
1665 | */ | |
72549e05 | 1666 | assert(htcpOutSocket > -1); |
62e76326 | 1667 | |
72549e05 | 1668 | commSetSelect(htcpOutSocket, COMM_SELECT_READ, NULL, NULL, 0); |
1669 | } | |
1670 | ||
1afe05c5 | 1671 | void |
72549e05 | 1672 | htcpSocketClose(void) |
1673 | { | |
1674 | htcpSocketShutdown(); | |
62e76326 | 1675 | |
72549e05 | 1676 | if (htcpOutSocket > -1) { |
62e76326 | 1677 | debug(12, 1) ("FD %d Closing HTCP socket\n", htcpOutSocket); |
1678 | comm_close(htcpOutSocket); | |
1679 | htcpOutSocket = -1; | |
1afe05c5 | 1680 | } |
1681 | } |