]>
Commit | Line | Data |
---|---|---|
f900607e | 1 | |
30a4f2a8 | 2 | /* |
bfcaf585 | 3 | * $Id: wais.cc,v 1.74 1997/06/02 05:39:51 wessels Exp $ |
30a4f2a8 | 4 | * |
5 | * DEBUG: section 24 WAIS Relay | |
6 | * AUTHOR: Harvest Derived | |
7 | * | |
42c04c16 | 8 | * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ |
30a4f2a8 | 9 | * -------------------------------------------------------- |
10 | * | |
11 | * Squid is the result of efforts by numerous individuals from the | |
12 | * Internet community. Development is led by Duane Wessels of the | |
13 | * National Laboratory for Applied Network Research and funded by | |
14 | * the National Science Foundation. | |
15 | * | |
16 | * This program is free software; you can redistribute it and/or modify | |
17 | * it under the terms of the GNU General Public License as published by | |
18 | * the Free Software Foundation; either version 2 of the License, or | |
19 | * (at your option) any later version. | |
20 | * | |
21 | * This program is distributed in the hope that it will be useful, | |
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
24 | * GNU General Public License for more details. | |
25 | * | |
26 | * You should have received a copy of the GNU General Public License | |
27 | * along with this program; if not, write to the Free Software | |
28 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
29 | * | |
30 | */ | |
7528fc90 | 31 | |
32 | /* | |
30a4f2a8 | 33 | * Copyright (c) 1994, 1995. All rights reserved. |
34 | * | |
35 | * The Harvest software was developed by the Internet Research Task | |
36 | * Force Research Group on Resource Discovery (IRTF-RD): | |
37 | * | |
38 | * Mic Bowman of Transarc Corporation. | |
39 | * Peter Danzig of the University of Southern California. | |
40 | * Darren R. Hardy of the University of Colorado at Boulder. | |
41 | * Udi Manber of the University of Arizona. | |
42 | * Michael F. Schwartz of the University of Colorado at Boulder. | |
43 | * Duane Wessels of the University of Colorado at Boulder. | |
44 | * | |
45 | * This copyright notice applies to software in the Harvest | |
46 | * ``src/'' directory only. Users should consult the individual | |
47 | * copyright notices in the ``components/'' subdirectories for | |
48 | * copyright information about other software bundled with the | |
49 | * Harvest source code distribution. | |
50 | * | |
51 | * TERMS OF USE | |
52 | * | |
53 | * The Harvest software may be used and re-distributed without | |
54 | * charge, provided that the software origin and research team are | |
55 | * cited in any use of the system. Most commonly this is | |
56 | * accomplished by including a link to the Harvest Home Page | |
57 | * (http://harvest.cs.colorado.edu/) from the query page of any | |
58 | * Broker you deploy, as well as in the query result pages. These | |
59 | * links are generated automatically by the standard Broker | |
60 | * software distribution. | |
61 | * | |
62 | * The Harvest software is provided ``as is'', without express or | |
63 | * implied warranty, and with no support nor obligation to assist | |
64 | * in its use, correction, modification or enhancement. We assume | |
65 | * no liability with respect to the infringement of copyrights, | |
66 | * trade secrets, or any patents, and are not responsible for | |
67 | * consequential damages. Proper use of the Harvest software is | |
68 | * entirely the responsibility of the user. | |
69 | * | |
70 | * DERIVATIVE WORKS | |
71 | * | |
72 | * Users may make derivative works from the Harvest software, subject | |
73 | * to the following constraints: | |
74 | * | |
75 | * - You must include the above copyright notice and these | |
76 | * accompanying paragraphs in all forms of derivative works, | |
77 | * and any documentation and other materials related to such | |
78 | * distribution and use acknowledge that the software was | |
79 | * developed at the above institutions. | |
80 | * | |
81 | * - You must notify IRTF-RD regarding your distribution of | |
82 | * the derivative work. | |
83 | * | |
84 | * - You must clearly notify users that your are distributing | |
85 | * a modified version and not the original Harvest software. | |
86 | * | |
87 | * - Any derivative product is also subject to these copyright | |
88 | * and use restrictions. | |
89 | * | |
90 | * Note that the Harvest software is NOT in the public domain. We | |
91 | * retain copyright, as specified above. | |
92 | * | |
93 | * HISTORY OF FREE SOFTWARE STATUS | |
94 | * | |
95 | * Originally we required sites to license the software in cases | |
96 | * where they were going to build commercial products/services | |
97 | * around Harvest. In June 1995 we changed this policy. We now | |
98 | * allow people to use the core Harvest software (the code found in | |
99 | * the Harvest ``src/'' directory) for free. We made this change | |
100 | * in the interest of encouraging the widest possible deployment of | |
101 | * the technology. The Harvest software is really a reference | |
102 | * implementation of a set of protocols and formats, some of which | |
103 | * we intend to standardize. We encourage commercial | |
104 | * re-implementations of code complying to this set of standards. | |
7528fc90 | 105 | */ |
44a47c6e | 106 | |
107 | #include "squid.h" | |
ed43818f | 108 | |
090089c4 | 109 | #define WAIS_DELETE_GAP (64*1024) |
110 | ||
30a4f2a8 | 111 | typedef struct { |
112 | int fd; | |
090089c4 | 113 | StoreEntry *entry; |
7111c86a | 114 | method_t method; |
115 | char *relayhost; | |
116 | int relayport; | |
3a1c3e2f | 117 | char *request_hdr; |
f2052513 | 118 | char request[MAX_URL]; |
30a4f2a8 | 119 | } WaisStateData; |
120 | ||
582b6456 | 121 | static PF waisStateFree; |
5c5783a2 | 122 | static PF waisTimeout; |
582b6456 | 123 | static PF waisReadReply; |
f17936ab | 124 | static CWCB waisSendComplete; |
582b6456 | 125 | static PF waisSendRequest; |
4f92c80c | 126 | static CNCB waisConnectDone; |
bfcaf585 | 127 | static STABH waisAbort; |
090089c4 | 128 | |
582b6456 | 129 | static void |
130 | waisStateFree(int fd, void *data) | |
ba718c8f | 131 | { |
582b6456 | 132 | WaisStateData *waisState = data; |
51fa90db | 133 | if (waisState == NULL) |
582b6456 | 134 | return; |
30a4f2a8 | 135 | storeUnlockObject(waisState->entry); |
bfcaf585 | 136 | storeUnregisterAbort(waisState->entry); |
51fa90db | 137 | xfree(waisState); |
ba718c8f | 138 | } |
139 | ||
090089c4 | 140 | /* This will be called when socket lifetime is expired. */ |
b8d8561b | 141 | static void |
5c5783a2 | 142 | waisTimeout(int fd, void *data) |
090089c4 | 143 | { |
582b6456 | 144 | WaisStateData *waisState = data; |
145 | StoreEntry *entry = waisState->entry; | |
5c5783a2 | 146 | debug(24, 4, "waisTimeout: FD %d: '%s'\n", fd, entry->url); |
147 | squid_error_entry(entry, ERR_READ_TIMEOUT, NULL); | |
51fa90db | 148 | comm_close(fd); |
090089c4 | 149 | } |
150 | ||
151 | ||
152 | ||
090089c4 | 153 | /* This will be called when data is ready to be read from fd. Read until |
154 | * error or connection closed. */ | |
b8d8561b | 155 | static void |
582b6456 | 156 | waisReadReply(int fd, void *data) |
090089c4 | 157 | { |
582b6456 | 158 | WaisStateData *waisState = data; |
95d659f0 | 159 | LOCAL_ARRAY(char, buf, 4096); |
582b6456 | 160 | StoreEntry *entry = waisState->entry; |
bfcaf585 | 161 | int len; |
56fa4cad | 162 | int clen; |
163 | int off; | |
164 | int bin; | |
bfcaf585 | 165 | if (protoAbortFetch(entry)) { |
166 | squid_error_entry(entry, ERR_CLIENT_ABORT, NULL); | |
167 | comm_close(fd); | |
168 | return; | |
169 | } | |
56fa4cad | 170 | if (entry->flag & DELETE_BEHIND && !storeClientWaiting(entry)) { |
171 | /* we can terminate connection right now */ | |
172 | squid_error_entry(entry, ERR_NO_CLIENTS_BIG_OBJ, NULL); | |
173 | comm_close(fd); | |
174 | return; | |
175 | } | |
176 | /* check if we want to defer reading */ | |
177 | clen = entry->mem_obj->e_current_len; | |
178 | off = storeGetLowestReaderOffset(entry); | |
179 | if ((clen - off) > WAIS_DELETE_GAP) { | |
56fa4cad | 180 | IOStats.Wais.reads_deferred++; |
181 | debug(24, 3, "waisReadReply: Read deferred for Object: %s\n", | |
182 | entry->url); | |
183 | debug(24, 3, " Current Gap: %d bytes\n", clen - off); | |
184 | /* reschedule, so it will automatically reactivated | |
185 | * when Gap is big enough. */ | |
b177367b | 186 | commSetSelect(fd, |
56fa4cad | 187 | COMM_SELECT_READ, |
cd1fb0eb | 188 | waisReadReply, |
189 | waisState, 0); | |
56fa4cad | 190 | /* don't install read handler while we're above the gap */ |
56fa4cad | 191 | if (!BIT_TEST(entry->flag, READ_DEFERRED)) { |
5c5783a2 | 192 | commSetTimeout(fd, Config.Timeout.defer, NULL, NULL); |
56fa4cad | 193 | BIT_SET(entry->flag, READ_DEFERRED); |
194 | } | |
195 | /* dont try reading again for a while */ | |
196 | comm_set_stall(fd, Config.stallDelay); | |
197 | return; | |
198 | } else { | |
199 | BIT_RESET(entry->flag, READ_DEFERRED); | |
090089c4 | 200 | } |
201 | len = read(fd, buf, 4096); | |
4f92c80c | 202 | fd_bytes(fd, len, FD_READ); |
56fa4cad | 203 | debug(24, 5, "waisReadReply: FD %d read len:%d\n", fd, len); |
204 | if (len > 0) { | |
5c5783a2 | 205 | commSetTimeout(fd, Config.Timeout.read, NULL, NULL); |
fedac7e5 | 206 | IOStats.Wais.reads++; |
207 | for (clen = len - 1, bin = 0; clen; bin++) | |
208 | clen >>= 1; | |
209 | IOStats.Wais.read_hist[bin]++; | |
56fa4cad | 210 | } |
ba718c8f | 211 | if (len < 0) { |
881f7a6c | 212 | debug(50, 1, "waisReadReply: FD %d: read failure: %s.\n", xstrerror()); |
0a0bf5db | 213 | if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) { |
6fe6313d | 214 | /* reinstall handlers */ |
215 | /* XXX This may loop forever */ | |
b177367b | 216 | commSetSelect(fd, COMM_SELECT_READ, |
cd1fb0eb | 217 | waisReadReply, waisState, 0); |
090089c4 | 218 | } else { |
1c481e00 | 219 | BIT_RESET(entry->flag, ENTRY_CACHABLE); |
2daae136 | 220 | storeReleaseRequest(entry); |
b8de7ebe | 221 | squid_error_entry(entry, ERR_READ_ERROR, xstrerror()); |
51fa90db | 222 | comm_close(fd); |
090089c4 | 223 | } |
ba718c8f | 224 | } else if (len == 0 && entry->mem_obj->e_current_len == 0) { |
b8de7ebe | 225 | squid_error_entry(entry, |
ba718c8f | 226 | ERR_ZERO_SIZE_OBJECT, |
227 | errno ? xstrerror() : NULL); | |
51fa90db | 228 | comm_close(fd); |
090089c4 | 229 | } else if (len == 0) { |
230 | /* Connection closed; retrieval done. */ | |
b8de7ebe | 231 | entry->expires = squid_curtime; |
090089c4 | 232 | storeComplete(entry); |
51fa90db | 233 | comm_close(fd); |
090089c4 | 234 | } else { |
235 | storeAppend(entry, buf, len); | |
b177367b | 236 | commSetSelect(fd, |
6fe6313d | 237 | COMM_SELECT_READ, |
cd1fb0eb | 238 | waisReadReply, |
239 | waisState, 0); | |
090089c4 | 240 | } |
241 | } | |
242 | ||
243 | /* This will be called when request write is complete. Schedule read of | |
244 | * reply. */ | |
b8d8561b | 245 | static void |
246 | waisSendComplete(int fd, char *buf, int size, int errflag, void *data) | |
090089c4 | 247 | { |
30a4f2a8 | 248 | WaisStateData *waisState = data; |
582b6456 | 249 | StoreEntry *entry = waisState->entry; |
56fa4cad | 250 | debug(24, 5, "waisSendComplete: FD %d size: %d errflag: %d\n", |
090089c4 | 251 | fd, size, errflag); |
252 | if (errflag) { | |
b8de7ebe | 253 | squid_error_entry(entry, ERR_CONNECT_FAIL, xstrerror()); |
51fa90db | 254 | comm_close(fd); |
090089c4 | 255 | } else { |
256 | /* Schedule read reply. */ | |
b177367b | 257 | commSetSelect(fd, |
6fe6313d | 258 | COMM_SELECT_READ, |
cd1fb0eb | 259 | waisReadReply, |
260 | waisState, 0); | |
090089c4 | 261 | } |
090089c4 | 262 | } |
263 | ||
264 | /* This will be called when connect completes. Write request. */ | |
b8d8561b | 265 | static void |
582b6456 | 266 | waisSendRequest(int fd, void *data) |
090089c4 | 267 | { |
582b6456 | 268 | WaisStateData *waisState = data; |
30a4f2a8 | 269 | int len = strlen(waisState->request) + 4; |
2285407f | 270 | char *buf = NULL; |
0ee4272b | 271 | const char *Method = RequestMethodStr[waisState->method]; |
090089c4 | 272 | |
56fa4cad | 273 | debug(24, 5, "waisSendRequest: FD %d\n", fd); |
090089c4 | 274 | |
8e352276 | 275 | if (Method) |
276 | len += strlen(Method); | |
3a1c3e2f | 277 | if (waisState->request_hdr) |
278 | len += strlen(waisState->request_hdr); | |
090089c4 | 279 | |
30a4f2a8 | 280 | buf = xcalloc(1, len + 1); |
090089c4 | 281 | |
3a1c3e2f | 282 | if (waisState->request_hdr) |
30a4f2a8 | 283 | sprintf(buf, "%s %s %s\r\n", Method, waisState->request, |
3a1c3e2f | 284 | waisState->request_hdr); |
090089c4 | 285 | else |
30a4f2a8 | 286 | sprintf(buf, "%s %s\r\n", Method, waisState->request); |
56fa4cad | 287 | debug(24, 6, "waisSendRequest: buf: %s\n", buf); |
30a4f2a8 | 288 | comm_write(fd, |
2285407f | 289 | buf, |
290 | len, | |
2285407f | 291 | waisSendComplete, |
9864ee44 | 292 | (void *) waisState, |
293 | xfree); | |
1c481e00 | 294 | if (BIT_TEST(waisState->entry->flag, ENTRY_CACHABLE)) |
30a4f2a8 | 295 | storeSetPublicKey(waisState->entry); /* Make it public */ |
296 | } | |
297 | ||
770f051d | 298 | void |
f182d1c5 | 299 | waisStart(request_t *request, StoreEntry * entry) |
090089c4 | 300 | { |
30a4f2a8 | 301 | WaisStateData *waisState = NULL; |
302 | int fd; | |
75e88d56 | 303 | char *url = entry->url; |
f182d1c5 | 304 | method_t method = request->method; |
30a4f2a8 | 305 | debug(24, 3, "waisStart: \"%s %s\"\n", RequestMethodStr[method], url); |
b6f794d6 | 306 | if (!Config.Wais.relayHost) { |
7528fc90 | 307 | debug(24, 0, "waisStart: Failed because no relay host defined!\n"); |
b8de7ebe | 308 | squid_error_entry(entry, ERR_NO_RELAY, NULL); |
770f051d | 309 | return; |
090089c4 | 310 | } |
16b204c4 | 311 | fd = comm_open(SOCK_STREAM, |
312 | 0, | |
313 | Config.Addrs.tcp_outgoing, | |
314 | 0, | |
315 | COMM_NONBLOCKING, | |
316 | url); | |
30a4f2a8 | 317 | if (fd == COMM_ERROR) { |
7528fc90 | 318 | debug(24, 4, "waisStart: Failed because we're out of sockets.\n"); |
b8de7ebe | 319 | squid_error_entry(entry, ERR_NO_FDS, xstrerror()); |
770f051d | 320 | return; |
090089c4 | 321 | } |
30a4f2a8 | 322 | waisState = xcalloc(1, sizeof(WaisStateData)); |
30a4f2a8 | 323 | waisState->method = method; |
b6f794d6 | 324 | waisState->relayhost = Config.Wais.relayHost; |
325 | waisState->relayport = Config.Wais.relayPort; | |
f182d1c5 | 326 | waisState->request_hdr = request->headers; |
30a4f2a8 | 327 | waisState->fd = fd; |
0a0bf5db | 328 | waisState->entry = entry; |
d5aa0e3b | 329 | xstrncpy(waisState->request, url, MAX_URL); |
bfcaf585 | 330 | comm_add_close_handler(waisState->fd, waisStateFree, waisState); |
331 | storeRegisterAbort(entry, waisAbort, waisState); | |
5c5783a2 | 332 | commSetTimeout(fd, Config.Timeout.read, waisTimeout, waisState); |
770f051d | 333 | storeLockObject(entry); |
edeb28fd | 334 | commConnectStart(waisState->fd, |
e924600d | 335 | waisState->relayhost, |
336 | waisState->relayport, | |
337 | waisConnectDone, | |
338 | waisState); | |
e5f6c5c2 | 339 | } |
340 | ||
341 | static void | |
342 | waisConnectDone(int fd, int status, void *data) | |
343 | { | |
344 | WaisStateData *waisState = data; | |
edeb28fd | 345 | if (status == COMM_ERR_DNS) { |
346 | squid_error_entry(waisState->entry, ERR_DNS_FAIL, dns_error_message); | |
347 | comm_close(fd); | |
348 | return; | |
349 | } else if (status != COMM_OK) { | |
e5f6c5c2 | 350 | squid_error_entry(waisState->entry, ERR_CONNECT_FAIL, xstrerror()); |
351 | comm_close(fd); | |
352 | return; | |
090089c4 | 353 | } |
f900607e | 354 | if (opt_no_ipcache) |
e5f6c5c2 | 355 | ipcacheInvalidate(waisState->relayhost); |
b177367b | 356 | commSetSelect(fd, |
30a4f2a8 | 357 | COMM_SELECT_WRITE, |
cd1fb0eb | 358 | waisSendRequest, |
359 | waisState, 0); | |
090089c4 | 360 | } |
bfcaf585 | 361 | |
362 | static void | |
363 | waisAbort(void *data) | |
364 | { | |
365 | HttpStateData *waisState = data; | |
366 | debug(24, 1, "waisAbort: %s\n", waisState->entry->url); | |
367 | comm_close(waisState->fd); | |
368 | } |