]> git.ipfire.org Git - thirdparty/squid.git/blame - src/store_client.cc
formatting
[thirdparty/squid.git] / src / store_client.cc
CommitLineData
f09f5b26 1#include "squid.h"
2
e3ef2b09 3/*
4 * NOTE: 'Header' refers to the swapfile metadata header.
5 * 'Body' refers to the swapfile body, which is the full
6 * HTTP reply (including HTTP headers and body).
7 */
8static DRCB storeClientReadBody;
9static DRCB storeClientReadHeader;
10static SIH storeClientFileOpened;
f09f5b26 11static void storeClientCopy2(StoreEntry * e, store_client * sc);
e3ef2b09 12static void storeClientFileRead(store_client * sc);
f09f5b26 13
14/* check if there is any client waiting for this object at all */
15/* return 1 if there is at least one client */
16int
17storeClientWaiting(const StoreEntry * e)
18{
19 MemObject *mem = e->mem_obj;
20 store_client *sc;
21 for (sc = mem->clients; sc; sc = sc->next) {
22 if (sc->callback_data != NULL)
23 return 1;
24 }
25 return 0;
26}
27
28store_client *
29storeClientListSearch(const MemObject * mem, void *data)
30{
31 store_client *sc;
32 for (sc = mem->clients; sc; sc = sc->next) {
33 if (sc->callback_data == data)
34 break;
35 }
36 return sc;
37}
38
39/* add client with fd to client list */
40void
41storeClientListAdd(StoreEntry * e, void *data)
42{
43 MemObject *mem = e->mem_obj;
44 store_client **T;
45 store_client *sc;
46 assert(mem);
47 if (storeClientListSearch(mem, data) != NULL)
48 return;
49 mem->nclients++;
50 sc = memAllocate(MEM_STORE_CLIENT, 1);
51 cbdataAdd(sc, MEM_STORE_CLIENT); /* sc is callback_data for file_read */
52 sc->callback_data = data;
53 sc->seen_offset = 0;
54 sc->copy_offset = 0;
55 sc->swapin_fd = -1;
56 sc->disk_op_in_progress = 0;
57 sc->mem = mem;
58 if (e->store_status == STORE_PENDING && mem->swapout.fd == -1)
59 sc->type = STORE_MEM_CLIENT;
60 else
61 sc->type = STORE_DISK_CLIENT;
62 for (T = &mem->clients; *T; T = &(*T)->next);
63 *T = sc;
64}
65
66/* copy bytes requested by the client */
67void
68storeClientCopy(StoreEntry * e,
69 off_t seen_offset,
70 off_t copy_offset,
71 size_t size,
72 char *buf,
73 STCB * callback,
74 void *data)
75{
76 store_client *sc;
77 static int recurse_detect = 0;
78 assert(e->store_status != STORE_ABORTED);
79 assert(recurse_detect < 3); /* could == 1 for IMS not modified's */
80 debug(20, 3) ("storeClientCopy: %s, seen %d, want %d, size %d, cb %p, cbdata %p\n",
81 storeKeyText(e->key),
82 (int) seen_offset,
83 (int) copy_offset,
84 (int) size,
85 callback,
86 data);
87 sc = storeClientListSearch(e->mem_obj, data);
88 assert(sc != NULL);
89 assert(sc->callback == NULL);
90 sc->copy_offset = copy_offset;
91 sc->seen_offset = seen_offset;
92 sc->callback = callback;
93 sc->copy_buf = buf;
94 sc->copy_size = size;
95 sc->copy_offset = copy_offset;
96 storeClientCopy2(e, sc);
97 recurse_detect--;
98}
99
100static void
101storeClientCopy2(StoreEntry * e, store_client * sc)
102{
103 STCB *callback = sc->callback;
104 MemObject *mem = e->mem_obj;
105 size_t sz;
106 static int loopdetect = 0;
107 assert(++loopdetect < 10);
108 debug(20, 3) ("storeClientCopy2: %s\n", storeKeyText(e->key));
109 assert(callback != NULL);
110 if (e->store_status == STORE_ABORTED) {
111#if USE_ASYNC_IO
112 if (sc->disk_op_in_progress == 1) {
113 if (sc->swapin_fd >= 0)
114 aioCancel(sc->swapin_fd, NULL);
115 else
116 aioCancel(-1, sc);
117 }
118#endif
119 sc->disk_op_in_progress = 0;
120 sc->callback = NULL;
121 callback(sc->callback_data, sc->copy_buf, 0);
122 } else if (e->store_status == STORE_OK && sc->copy_offset == e->object_len) {
123 /* There is no more to send! */
124#if USE_ASYNC_IO
125 if (sc->disk_op_in_progress == 1) {
126 if (sc->swapin_fd >= 0)
127 aioCancel(sc->swapin_fd, NULL);
128 else
129 aioCancel(-1, sc);
130 }
131#endif
132 sc->disk_op_in_progress = 0;
133 sc->callback = NULL;
134 callback(sc->callback_data, sc->copy_buf, 0);
135 } else if (e->store_status == STORE_PENDING && sc->seen_offset == mem->inmem_hi) {
136 /* client has already seen this, wait for more */
137 debug(20, 3) ("storeClientCopy2: Waiting for more\n");
138 } else if (sc->copy_offset >= mem->inmem_lo && mem->inmem_lo < mem->inmem_hi) {
139 /* What the client wants is in memory */
140 debug(20, 3) ("storeClientCopy2: Copying from memory\n");
141 sz = stmemCopy(mem->data, sc->copy_offset, sc->copy_buf, sc->copy_size);
142#if USE_ASYNC_IO
143 if (sc->disk_op_in_progress == 1) {
144 if (sc->swapin_fd >= 0)
145 aioCancel(sc->swapin_fd, NULL);
146 else
147 aioCancel(-1, sc);
148 }
149#endif
150 sc->disk_op_in_progress = 0;
151 sc->callback = NULL;
152 callback(sc->callback_data, sc->copy_buf, sz);
153 } else if (sc->swapin_fd < 0) {
154 debug(20, 3) ("storeClientCopy2: Need to open swap in file\n");
155 assert(sc->type == STORE_DISK_CLIENT);
156 /* gotta open the swapin file */
157 /* assert(sc->copy_offset == 0); */
158 if (sc->disk_op_in_progress == 0) {
159 sc->disk_op_in_progress = 1;
e3ef2b09 160 storeSwapInStart(e, storeClientFileOpened, sc);
f09f5b26 161 } else {
162 debug(20, 2) ("storeClientCopy2: Averted multiple fd operation\n");
163 }
164 } else {
165 debug(20, 3) ("storeClientCopy: reading from disk FD %d\n",
166 sc->swapin_fd);
167 assert(sc->type == STORE_DISK_CLIENT);
168 if (sc->disk_op_in_progress == 0) {
169 sc->disk_op_in_progress = 1;
e3ef2b09 170 storeClientFileRead(sc);
f09f5b26 171 } else {
172 debug(20, 2) ("storeClientCopy2: Averted multiple fd operation\n");
173 }
174 }
175 --loopdetect;
176}
177
178static void
e3ef2b09 179storeClientFileOpened(int fd, void *data)
f09f5b26 180{
181 store_client *sc = data;
182 STCB *callback = sc->callback;
183 if (fd < 0) {
e3ef2b09 184 debug(20, 3) ("storeClientFileOpened: failed\n");
f09f5b26 185 sc->disk_op_in_progress = 0;
186 sc->callback = NULL;
187 callback(sc->callback_data, sc->copy_buf, -1);
188 return;
189 }
190 sc->swapin_fd = fd;
e3ef2b09 191 storeClientFileRead(sc);
f09f5b26 192}
193
194static void
e3ef2b09 195storeClientFileRead(store_client * sc)
f09f5b26 196{
e3ef2b09 197 MemObject *mem = sc->mem;
f09f5b26 198 assert(sc->callback != NULL);
e3ef2b09 199 if (mem->swap_hdr_sz == 0)
200 file_read(sc->swapin_fd,
201 memAllocate(MEM_DISK_BUF, 1),
202 DISK_PAGE_SIZE,
203 0,
204 storeClientReadHeader,
205 sc);
206 else
207 file_read(sc->swapin_fd,
208 sc->copy_buf,
209 sc->copy_size,
210 sc->copy_offset + mem->swap_hdr_sz,
211 storeClientReadBody,
212 sc);
f09f5b26 213}
214
215static void
e3ef2b09 216storeClientReadBody(int fd, const char *buf, int len, int flagnotused, void *data)
f09f5b26 217{
218 store_client *sc = data;
25535cbe 219 MemObject *mem = sc->mem;
f09f5b26 220 STCB *callback = sc->callback;
f09f5b26 221 assert(sc->disk_op_in_progress != 0);
222 sc->disk_op_in_progress = 0;
223 assert(sc->callback != NULL);
e3ef2b09 224 debug(20, 3) ("storeClientReadBody: FD %d, len %d\n", fd, len);
25535cbe 225 if (sc->copy_offset == 0 && len > 0 && mem->reply->code == 0)
226 httpParseReplyHeaders(sc->copy_buf, mem->reply);
f09f5b26 227 sc->callback = NULL;
228 callback(sc->callback_data, sc->copy_buf, len);
229}
230
e3ef2b09 231static void
232storeClientReadHeader(int fd, const char *buf, int len, int flagnotused, void *data)
233{
234 /*
235 * 'buf' should have been allocated by memAllocate(MEM_DISK_BUF)
236 */
237 store_client *sc = data;
238 MemObject *mem = sc->mem;
239 STCB *callback = sc->callback;
240 int swap_hdr_sz = 0;
241 size_t body_sz;
242 size_t copy_sz;
243 tlv *tlv_list;
244 assert(sc->disk_op_in_progress != 0);
245 sc->disk_op_in_progress = 0;
246 assert(sc->callback != NULL);
247 debug(20, 3) ("storeClientReadHeader: FD %d, len %d\n", fd, len);
248 if (len < 0) {
25535cbe 249 debug(20, 3) ("storeClientReadHeader: FD %d: %s\n", fd, xstrerror());
e3ef2b09 250 memFree(MEM_DISK_BUF, (void *) buf);
25535cbe 251 sc->callback = NULL;
252 callback(sc->callback_data, sc->copy_buf, len);
e3ef2b09 253 return;
254 }
255 tlv_list = storeSwapMetaUnpack(buf, &swap_hdr_sz);
256 if (tlv_list == NULL) {
25535cbe 257 debug(20, 1) ("storeClientReadHeader: failed to unpack meta data\n");
e3ef2b09 258 memFree(MEM_DISK_BUF, (void *) buf);
25535cbe 259 sc->callback = NULL;
260 callback(sc->callback_data, sc->copy_buf, -1);
e3ef2b09 261 return;
262 }
263 /*
264 * XXX Here we should check the meta data and make sure we got
265 * the right object.
266 */
267 mem->swap_hdr_sz = swap_hdr_sz;
268 /*
269 * If our last read got some data the client wants, then give
270 * it to them, otherwise schedule another read.
271 */
272 body_sz = len - swap_hdr_sz;
273 if (sc->copy_offset < body_sz) {
274 /*
25535cbe 275 * we have (part of) what they want
e3ef2b09 276 */
277 copy_sz = XMIN(sc->copy_size, body_sz);
25535cbe 278 debug(20, 3) ("storeClientReadHeader: copying %d bytes of body\n",
279 copy_sz);
280 xmemcpy(sc->copy_buf, buf + swap_hdr_sz, copy_sz);
e3ef2b09 281 memFree(MEM_DISK_BUF, (void *) buf);
25535cbe 282 if (sc->copy_offset == 0 && len > 0 && mem->reply->code == 0)
283 httpParseReplyHeaders(sc->copy_buf, mem->reply);
e3ef2b09 284 sc->callback = NULL;
25535cbe 285 callback(sc->callback_data, sc->copy_buf, copy_sz);
e3ef2b09 286 return;
287 }
288 /*
289 * we don't have what the client wants, but at least we now
290 * know the swap header size.
291 */
292 memFree(MEM_DISK_BUF, (void *) buf);
293 storeClientFileRead(sc);
294}
295
f09f5b26 296int
297storeClientCopyPending(StoreEntry * e, void *data)
298{
299 /* return 1 if there is a callback registered for this client */
300 store_client *sc = storeClientListSearch(e->mem_obj, data);
301 if (sc == NULL)
302 return 0;
303 if (sc->callback == NULL)
304 return 0;
305 return 1;
306}
307
308int
309storeUnregister(StoreEntry * e, void *data)
310{
311 MemObject *mem = e->mem_obj;
312 store_client *sc;
313 store_client **S;
314 STCB *callback;
315 if (mem == NULL)
316 return 0;
317 debug(20, 3) ("storeUnregister: called for '%s'\n", storeKeyText(e->key));
318 for (S = &mem->clients; (sc = *S) != NULL; S = &(*S)->next) {
319 if (sc->callback_data == data)
320 break;
321 }
322 if (sc == NULL)
323 return 0;
324 *S = sc->next;
325 mem->nclients--;
326 sc->disk_op_in_progress = 0;
327 if (e->store_status == STORE_OK && e->swap_status != SWAPOUT_DONE)
328 storeCheckSwapOut(e);
329 if (sc->swapin_fd > -1) {
330 commSetSelect(sc->swapin_fd, COMM_SELECT_READ, NULL, NULL, 0);
331 file_close(sc->swapin_fd);
332 }
333#if USE_ASYNC_IO
334 else
335 aioCancel(-1, sc);
336#endif
337 if ((callback = sc->callback) != NULL) {
338 /* callback with ssize = -1 to indicate unexpected termination */
339 debug(20, 3) ("storeUnregister: store_client for %s has a callback\n",
340 mem->url);
341 sc->callback = NULL;
342 callback(sc->callback_data, sc->copy_buf, -1);
343 }
344 cbdataFree(sc);
345 return 1;
346}
347
348off_t
349storeLowestMemReaderOffset(const StoreEntry * entry)
350{
351 const MemObject *mem = entry->mem_obj;
352 off_t lowest = mem->inmem_hi;
353 store_client *sc;
354 store_client *nx = NULL;
355 for (sc = mem->clients; sc; sc = nx) {
356 nx = sc->next;
357 if (sc->callback_data == NULL) /* open slot */
358 continue;
359 if (sc->type != STORE_MEM_CLIENT)
360 continue;
361 if (sc->copy_offset < lowest)
362 lowest = sc->copy_offset;
363 }
364 return lowest;
365}
366
367/* Call handlers waiting for data to be appended to E. */
368void
369InvokeHandlers(StoreEntry * e)
370{
371 int i = 0;
372 MemObject *mem = e->mem_obj;
373 store_client *sc;
374 store_client *nx = NULL;
375 assert(mem->clients != NULL || mem->nclients == 0);
376 debug(20, 3) ("InvokeHandlers: %s\n", storeKeyText(e->key));
377 /* walk the entire list looking for valid callbacks */
378 for (sc = mem->clients; sc; sc = nx) {
379 nx = sc->next;
380 debug(20, 3) ("InvokeHandlers: checking client #%d\n", i++);
381 if (sc->callback_data == NULL)
382 continue;
383 if (sc->callback == NULL)
384 continue;
385 storeClientCopy2(e, sc);
386 }
387}
388
389int
390storePendingNClients(const StoreEntry * e)
391{
392 int npend = 0;
393 MemObject *mem = e->mem_obj;
394 store_client *sc;
395 store_client *nx = NULL;
396 if (mem == NULL)
397 return 0;
398 for (sc = mem->clients; sc; sc = nx) {
399 nx = sc->next;
400 /* Changed from callback_data to just callback. There can be no use */
401 /* for callback_data without a callback, and sc->callback we know */
402 /* gets reset, but not necessarily sc->callback_data */
403 if (sc->callback == NULL)
404 continue;
405 npend++;
406 }
407 return npend;
408}