]> git.ipfire.org Git - thirdparty/squid.git/blob - src/wais.cc
Luyers finished delay pools patch
[thirdparty/squid.git] / src / wais.cc
1
2 /*
3 * $Id: wais.cc,v 1.116 1998/08/14 09:22:43 wessels Exp $
4 *
5 * DEBUG: section 24 WAIS Relay
6 * AUTHOR: Harvest Derived
7 *
8 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
9 * ----------------------------------------------------------
10 *
11 * Squid is the result of efforts by numerous individuals from the
12 * Internet community. Development is led by Duane Wessels of the
13 * National Laboratory for Applied Network Research and funded by the
14 * National Science Foundation. Squid is Copyrighted (C) 1998 by
15 * Duane Wessels and the University of California San Diego. Please
16 * see the COPYRIGHT file for full details. Squid incorporates
17 * software developed and/or copyrighted by other sources. Please see
18 * the CREDITS file for full details.
19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 *
34 */
35
36 #include "squid.h"
37
38 typedef struct {
39 int fd;
40 StoreEntry *entry;
41 method_t method;
42 char *relayhost;
43 int relayport;
44 const HttpHeader *request_hdr;
45 char request[MAX_URL];
46 } WaisStateData;
47
48 static PF waisStateFree;
49 static PF waisTimeout;
50 static PF waisReadReply;
51 static CWCB waisSendComplete;
52 static PF waisSendRequest;
53
54 static void
55 waisStateFree(int fdnotused, void *data)
56 {
57 WaisStateData *waisState = data;
58 if (waisState == NULL)
59 return;
60 storeUnlockObject(waisState->entry);
61 cbdataFree(waisState);
62 }
63
64 /* This will be called when socket lifetime is expired. */
65 static void
66 waisTimeout(int fd, void *data)
67 {
68 WaisStateData *waisState = data;
69 ErrorState *err;
70 StoreEntry *entry = waisState->entry;
71 debug(24, 4) ("waisTimeout: FD %d: '%s'\n", fd, storeUrl(entry));
72 err = errorCon(ERR_READ_TIMEOUT, HTTP_GATEWAY_TIMEOUT);
73 err->request = urlParse(METHOD_CONNECT, waisState->request);
74 errorAppendEntry(entry, err);
75 comm_close(fd);
76 }
77
78 /* This will be called when data is ready to be read from fd. Read until
79 * error or connection closed. */
80 static void
81 waisReadReply(int fd, void *data)
82 {
83 WaisStateData *waisState = data;
84 LOCAL_ARRAY(char, buf, 4096);
85 StoreEntry *entry = waisState->entry;
86 int len;
87 int clen;
88 int bin;
89 size_t read_sz;
90 #if DELAY_POOLS
91 delay_id delay_id = delayMostBytesAllowed(entry->mem_obj);
92 #endif
93 if (fwdAbortFetch(entry)) {
94 ErrorState *err;
95 err = errorCon(ERR_CLIENT_ABORT, HTTP_INTERNAL_SERVER_ERROR);
96 err->request = urlParse(METHOD_CONNECT, waisState->request);
97 errorAppendEntry(entry, err);
98 comm_close(fd);
99 return;
100 }
101 errno = 0;
102 read_sz = 4096;
103 #if DELAY_POOLS
104 read_sz = delayBytesWanted(delay_id, read_sz);
105 assert(read_sz > 0);
106 #endif
107 len = read(fd, buf, read_sz);
108 if (len > 0) {
109 fd_bytes(fd, len, FD_READ);
110 #if DELAY_POOLS
111 delayBytesIn(delay_id, len);
112 #endif
113 kb_incr(&Counter.server.all.kbytes_in, len);
114 kb_incr(&Counter.server.other.kbytes_in, len);
115 }
116 debug(24, 5) ("waisReadReply: FD %d read len:%d\n", fd, len);
117 if (len > 0) {
118 commSetTimeout(fd, Config.Timeout.read, NULL, NULL);
119 IOStats.Wais.reads++;
120 for (clen = len - 1, bin = 0; clen; bin++)
121 clen >>= 1;
122 IOStats.Wais.read_hist[bin]++;
123 }
124 if (len < 0) {
125 debug(50, 1) ("waisReadReply: FD %d: read failure: %s.\n",
126 fd, xstrerror());
127 if (ignoreErrno(errno)) {
128 /* reinstall handlers */
129 /* XXX This may loop forever */
130 commSetSelect(fd, COMM_SELECT_READ,
131 waisReadReply, waisState, 0);
132 } else {
133 ErrorState *err;
134 EBIT_CLR(entry->flag, ENTRY_CACHABLE);
135 storeReleaseRequest(entry);
136 err = errorCon(ERR_READ_ERROR, HTTP_INTERNAL_SERVER_ERROR);
137 err->xerrno = errno;
138 err->request = urlParse(METHOD_CONNECT, waisState->request);
139 errorAppendEntry(entry, err);
140 comm_close(fd);
141 }
142 } else if (len == 0 && entry->mem_obj->inmem_hi == 0) {
143 ErrorState *err;
144 err = errorCon(ERR_ZERO_SIZE_OBJECT, HTTP_SERVICE_UNAVAILABLE);
145 err->xerrno = errno;
146 err->request = urlParse(METHOD_CONNECT, waisState->request);
147 errorAppendEntry(entry, err);
148 comm_close(fd);
149 } else if (len == 0) {
150 /* Connection closed; retrieval done. */
151 entry->expires = squid_curtime;
152 storeComplete(entry);
153 comm_close(fd);
154 } else {
155 storeAppend(entry, buf, len);
156 commSetSelect(fd,
157 COMM_SELECT_READ,
158 waisReadReply,
159 waisState, 0);
160 }
161 }
162
163 /* This will be called when request write is complete. Schedule read of
164 * reply. */
165 static void
166 waisSendComplete(int fd, char *bufnotused, size_t size, int errflag, void *data)
167 {
168 WaisStateData *waisState = data;
169 StoreEntry *entry = waisState->entry;
170 debug(24, 5) ("waisSendComplete: FD %d size: %d errflag: %d\n",
171 fd, size, errflag);
172 if (size > 0) {
173 fd_bytes(fd, size, FD_WRITE);
174 kb_incr(&Counter.server.all.kbytes_out, size);
175 kb_incr(&Counter.server.other.kbytes_out, size);
176 }
177 if (errflag == COMM_ERR_CLOSING)
178 return;
179 if (errflag) {
180 ErrorState *err;
181 err = errorCon(ERR_CONNECT_FAIL, HTTP_SERVICE_UNAVAILABLE);
182 err->xerrno = errno;
183 err->host = xstrdup(waisState->relayhost);
184 err->port = waisState->relayport;
185 err->request = urlParse(METHOD_CONNECT, waisState->request);
186 errorAppendEntry(entry, err);
187 comm_close(fd);
188 } else {
189 /* Schedule read reply. */
190 commSetSelect(fd,
191 COMM_SELECT_READ,
192 waisReadReply,
193 waisState, 0);
194 commSetDefer(fd, fwdCheckDeferRead, entry);
195 }
196 }
197
198 /* This will be called when connect completes. Write request. */
199 static void
200 waisSendRequest(int fd, void *data)
201 {
202 WaisStateData *waisState = data;
203 MemBuf mb;
204 const char *Method = RequestMethodStr[waisState->method];
205 debug(24, 5) ("waisSendRequest: FD %d\n", fd);
206 memBufPrintf(&mb, "%s %s", Method, waisState->request);
207 if (waisState->request_hdr) {
208 Packer p;
209 packerToMemInit(&p, &mb);
210 httpHeaderPackInto(waisState->request_hdr, &p);
211 packerClean(&p);
212 }
213 memBufPrintf(&mb, "\r\n");
214 debug(24, 6) ("waisSendRequest: buf: %s\n", mb.buf);
215 comm_write_mbuf(fd, mb, waisSendComplete, waisState);
216 if (EBIT_TEST(waisState->entry->flag, ENTRY_CACHABLE))
217 storeSetPublicKey(waisState->entry); /* Make it public */
218 }
219
220 void
221 waisStart(request_t * request, StoreEntry * entry, int fd)
222 {
223 WaisStateData *waisState = NULL;
224 const char *url = storeUrl(entry);
225 method_t method = request->method;
226 debug(24, 3) ("waisStart: \"%s %s\"\n", RequestMethodStr[method], url);
227 Counter.server.all.requests++;
228 Counter.server.other.requests++;
229 if (!Config.Wais.relayHost) {
230 ErrorState *err;
231 debug(24, 0) ("waisStart: Failed because no relay host defined!\n");
232 err = errorCon(ERR_NO_RELAY, HTTP_INTERNAL_SERVER_ERROR);
233 err->request = urlParse(METHOD_CONNECT, waisState->request);
234 errorAppendEntry(entry, err);
235 return;
236 }
237 waisState = xcalloc(1, sizeof(WaisStateData));
238 cbdataAdd(waisState, MEM_NONE);
239 waisState->method = method;
240 waisState->relayhost = Config.Wais.relayHost;
241 waisState->relayport = Config.Wais.relayPort;
242 waisState->request_hdr = &request->header;
243 waisState->fd = fd;
244 waisState->entry = entry;
245 xstrncpy(waisState->request, url, MAX_URL);
246 comm_add_close_handler(waisState->fd, waisStateFree, waisState);
247 storeLockObject(entry);
248 commSetSelect(fd, COMM_SELECT_WRITE, waisSendRequest, waisState, 0);
249 commSetTimeout(fd, Config.Timeout.read, waisTimeout, waisState);
250 }