static void storeClientReadBody(void *data, const char *buf, ssize_t len) { store_client *sc = data; MemObject *mem = sc->entry->mem_obj; assert(sc->flags.disk_io_pending); sc->flags.disk_io_pending = 0; assert(sc->callback != NULL); debug(20, 3) ("storeClientReadBody: len %d\n", (int) len); if (sc->copy_offset == 0 && len > 0 && memHaveHeaders(mem) == 0) httpReplyParse(mem->reply, sc->copy_buf, headersEnd(sc->copy_buf, len)); storeClientCallback(sc, len); }
static void storeClientReadBody(void *data, const char *buf_unused, ssize_t len) { char *cbuf = NULL; store_client *sc = data; assert(sc->flags.disk_io_pending); sc->flags.disk_io_pending = 0; assert(sc->new_callback); assert(sc->node_ref.node); cbuf = sc->node_ref.node->data; /* XXX update how much data in that mem page is active; argh this should be done in a storage layer */ sc->node_ref.node->len = len; debug(20, 3) ("storeClientReadBody: len %d\n", (int) len); (void) storeClientParseHeader(sc, cbuf, len); storeClientCallback(sc, len); }
/* * This routine hasn't been optimised to take advantage of the * passed sc. Yet. */ int storeUnregister(store_client * sc, StoreEntry * e, void *data) { MemObject *mem = e->mem_obj; #if STORE_CLIENT_LIST_DEBUG assert(sc == storeClientListSearch(e->mem_obj, data)); #endif if (mem == NULL) return 0; debug(20, 3) ("storeUnregister: called for '%s'\n", storeKeyText(e->hash.key)); if (sc == NULL) return 0; if (mem->clients.head == NULL) return 0; dlinkDelete(&sc->node, &mem->clients); mem->nclients--; if (e->store_status == STORE_OK && e->swap_status != SWAPOUT_DONE) storeSwapOut(e); if (sc->swapin_sio) { storeClose(sc->swapin_sio); cbdataUnlock(sc->swapin_sio); sc->swapin_sio = NULL; statCounter.swap.ins++; } if (NULL != sc->callback) { /* callback with ssize = -1 to indicate unexpected termination */ debug(20, 3) ("storeUnregister: store_client for %s has a callback\n", mem->url); storeClientCallback(sc, -1); } #if DELAY_POOLS delayUnregisterDelayIdPtr(&sc->delay_id); #endif cbdataUnlock(sc->callback_data); /* we're done with it now */ /*assert(!sc->flags.disk_io_pending); */ cbdataFree(sc); assert(e->lock_count > 0); storeSwapOutMaintainMemObject(e); if (mem->nclients == 0) CheckQuickAbort(e); return 1; }
/* * This routine hasn't been optimised to take advantage of the * passed sc. Yet. */ int storeClientUnregister(store_client * sc, StoreEntry * e, void *owner) { MemObject *mem = e->mem_obj; if (sc == NULL) return 0; debug(20, 3) ("storeClientUnregister: called for '%s'\n", storeKeyText(e->hash.key)); #if STORE_CLIENT_LIST_DEBUG assert(sc == storeClientListSearch(e->mem_obj, owner)); #endif assert(sc->entry == e); if (mem->clients.head == NULL) return 0; dlinkDelete(&sc->node, &mem->clients); mem->nclients--; if (e->store_status == STORE_OK && e->swap_status != SWAPOUT_DONE) storeSwapOut(e); if (sc->swapin_sio) { storeClose(sc->swapin_sio); cbdataUnlock(sc->swapin_sio); sc->swapin_sio = NULL; statCounter.swap.ins++; } if (NULL != sc->new_callback) { /* callback with ssize = -1 to indicate unexpected termination */ debug(20, 3) ("storeClientUnregister: store_client for %s has a callback\n", mem->url); storeClientCallback(sc, -1); } stmemNodeUnref(&sc->node_ref); #if DELAY_POOLS delayUnregisterDelayIdPtr(&sc->delay_id); #endif storeSwapOutMaintainMemObject(e); if (mem->nclients == 0) CheckQuickAbort(e); storeUnlockObject(sc->entry); sc->entry = NULL; cbdataFree(sc); return 1; }
static void storeClientReadHeader(void *data, const char *buf, ssize_t len) { static int md5_mismatches = 0; store_client *sc = data; StoreEntry *e = sc->entry; MemObject *mem = e->mem_obj; int swap_hdr_sz = 0; size_t body_sz; size_t copy_sz; tlv *tlv_list; tlv *t; int swap_object_ok = 1; char *new_url = NULL; char *new_store_url = NULL; assert(sc->flags.disk_io_pending); sc->flags.disk_io_pending = 0; assert(sc->callback != NULL); debug(20, 3) ("storeClientReadHeader: len %d\n", (int) len); if (len < 0) { debug(20, 3) ("storeClientReadHeader: %s\n", xstrerror()); storeClientCallback(sc, len); return; } tlv_list = storeSwapMetaUnpack(buf, &swap_hdr_sz); if (swap_hdr_sz > len) { /* oops, bad disk file? */ debug(20, 1) ("WARNING: swapfile header too small\n"); storeClientCallback(sc, -1); return; } if (tlv_list == NULL) { debug(20, 1) ("WARNING: failed to unpack meta data\n"); storeClientCallback(sc, -1); return; } /* * Check the meta data and make sure we got the right object. */ for (t = tlv_list; t && swap_object_ok; t = t->next) { switch (t->type) { case STORE_META_KEY: assert(t->length == SQUID_MD5_DIGEST_LENGTH); if (!EBIT_TEST(e->flags, KEY_PRIVATE) && memcmp(t->value, e->hash.key, SQUID_MD5_DIGEST_LENGTH)) { debug(20, 2) ("storeClientReadHeader: swapin MD5 mismatch\n"); debug(20, 2) ("\t%s\n", storeKeyText(t->value)); debug(20, 2) ("\t%s\n", storeKeyText(e->hash.key)); if (isPowTen(++md5_mismatches)) debug(20, 1) ("WARNING: %d swapin MD5 mismatches\n", md5_mismatches); swap_object_ok = 0; } break; case STORE_META_URL: new_url = xstrdup(t->value); break; case STORE_META_STOREURL: new_store_url = xstrdup(t->value); break; case STORE_META_OBJSIZE: break; case STORE_META_STD: case STORE_META_STD_LFS: break; case STORE_META_VARY_HEADERS: if (mem->vary_headers) { if (strcmp(mem->vary_headers, t->value) != 0) swap_object_ok = 0; } else { /* Assume the object is OK.. remember the vary request headers */ mem->vary_headers = xstrdup(t->value); } break; default: debug(20, 2) ("WARNING: got unused STORE_META type %d\n", t->type); break; } } /* Check url / store_url */ do { if (new_url == NULL) { debug(20, 1) ("storeClientReadHeader: no URL!\n"); swap_object_ok = 0; break; } /* * If we have a store URL then it must match the requested object URL. * The theory is that objects with a store URL have been normalised * and thus a direct access which didn't go via the rewrite framework * are illegal! */ if (new_store_url) { if (NULL == mem->store_url) mem->store_url = new_store_url; else if (0 == strcasecmp(mem->store_url, new_store_url)) (void) 0; /* a match! */ else { debug(20, 1) ("storeClientReadHeader: store URL mismatch\n"); debug(20, 1) ("\t{%s} != {%s}\n", (char *) new_store_url, mem->store_url); swap_object_ok = 0; break; } } /* If we have no store URL then the request and the memory URL must match */ /* if ((!new_store_url) && mem->url && strcasecmp(mem->url, new_url) != 0) { debug(20, 1) ("storeClientReadHeader: URL mismatch\n"); debug(20, 1) ("\t{%s} != {%s}\n", (char *) new_url, mem->url); swap_object_ok = 0; break; } */ } while (0); storeSwapTLVFree(tlv_list); xfree(new_url); /* don't free new_store_url if its owned by the mem object now */ if (mem->store_url != new_store_url) xfree(new_store_url); if (!swap_object_ok) { storeClientCallback(sc, -1); return; } mem->swap_hdr_sz = swap_hdr_sz; mem->object_sz = e->swap_file_sz - swap_hdr_sz; /* * If our last read got some data the client wants, then give * it to them, otherwise schedule another read. */ body_sz = len - swap_hdr_sz; if (sc->copy_offset < body_sz) { /* * we have (part of) what they want */ copy_sz = XMIN(sc->copy_size, body_sz); debug(20, 3) ("storeClientReadHeader: copying %d bytes of body\n", (int) copy_sz); xmemmove(sc->copy_buf, sc->copy_buf + swap_hdr_sz, copy_sz); if (sc->copy_offset == 0 && len > 0 && memHaveHeaders(mem) == 0) httpReplyParse(mem->reply, sc->copy_buf, headersEnd(sc->copy_buf, copy_sz)); storeClientCallback(sc, copy_sz); return; } /* * we don't have what the client wants, but at least we now * know the swap header size. */ storeClientFileRead(sc); }
static void storeClientCopy3(StoreEntry * e, store_client * sc) { MemObject *mem = e->mem_obj; ssize_t sz; if (storeClientNoMoreToSend(e, sc)) { /* There is no more to send! */ storeClientCallback(sc, 0); return; } if (e->store_status == STORE_PENDING && sc->seen_offset >= mem->inmem_hi) { /* client has already seen this, wait for more */ debug(20, 3) ("storeClientCopy3: Waiting for more\n"); /* If the read is backed off and all clients have seen all the data in * memory, re-poll the fd */ if ((EBIT_TEST(e->flags, ENTRY_DEFER_READ)) && (storeLowestMemReaderOffset(e) == mem->inmem_hi)) { debug(20, 3) ("storeClientCopy3: %s - clearing ENTRY_DEFER_READ\n", e->mem_obj->url); /* Clear the flag and re-poll the fd */ storeResumeRead(e); } return; } /* * Slight weirdness here. We open a swapin file for any * STORE_DISK_CLIENT, even if we can copy the requested chunk * from memory in the next block. We must try to open the * swapin file before sending any data to the client side. If * we postpone the open, and then can not open the file later * on, the client loses big time. Its transfer just gets cut * off. Better to open it early (while the client side handler * is clientCacheHit) so that we can fall back to a cache miss * if needed. */ if (STORE_DISK_CLIENT == sc->type && NULL == sc->swapin_sio) { debug(20, 3) ("storeClientCopy3: Need to open swap in file\n"); /* gotta open the swapin file */ if (storeTooManyDiskFilesOpen()) { /* yuck -- this causes a TCP_SWAPFAIL_MISS on the client side */ storeClientCallback(sc, -1); return; } else if (!sc->flags.disk_io_pending) { /* Don't set store_io_pending here */ storeSwapInStart(sc); if (NULL == sc->swapin_sio) { storeClientCallback(sc, -1); return; } /* * If the open succeeds we either copy from memory, or * schedule a disk read in the next block. */ } else { debug(20, 1) ("WARNING: Averted multiple fd operation (1)\n"); return; } } if (sc->copy_offset >= mem->inmem_lo && sc->copy_offset < mem->inmem_hi) { /* What the client wants is in memory */ debug(20, 3) ("storeClientCopy3: Copying from memory\n"); sz = stmemCopy(&mem->data_hdr, sc->copy_offset, sc->copy_buf, sc->copy_size); if (EBIT_TEST(e->flags, RELEASE_REQUEST)) storeSwapOutMaintainMemObject(e); storeClientCallback(sc, sz); return; } /* What the client wants is not in memory. Schedule a disk read */ assert(STORE_DISK_CLIENT == sc->type); assert(!sc->flags.disk_io_pending); debug(20, 3) ("storeClientCopy3: reading from STORE\n"); storeClientFileRead(sc); }
static void storeClientReadHeader(void *data, const char *buf, ssize_t len) { static int md5_mismatches = 0; store_client *sc = data; StoreEntry *e = sc->entry; MemObject *mem = e->mem_obj; int swap_hdr_sz = 0; size_t body_sz; size_t copy_sz; tlv *tlv_list; tlv *t; int swap_object_ok = 1; assert(sc->flags.disk_io_pending); sc->flags.disk_io_pending = 0; assert(sc->callback != NULL); debug(20, 3) ("storeClientReadHeader: len %d\n", (int) len); if (len < 0) { debug(20, 3) ("storeClientReadHeader: %s\n", xstrerror()); storeClientCallback(sc, len); return; } tlv_list = storeSwapMetaUnpack(buf, &swap_hdr_sz); if (swap_hdr_sz > len) { /* oops, bad disk file? */ debug(20, 1) ("WARNING: swapfile header too small\n"); storeClientCallback(sc, -1); return; } if (tlv_list == NULL) { debug(20, 1) ("WARNING: failed to unpack meta data\n"); storeClientCallback(sc, -1); return; } /* * Check the meta data and make sure we got the right object. */ for (t = tlv_list; t && swap_object_ok; t = t->next) { switch (t->type) { case STORE_META_KEY: assert(t->length == MD5_DIGEST_CHARS); if (!EBIT_TEST(e->flags, KEY_PRIVATE) && memcmp(t->value, e->hash.key, MD5_DIGEST_CHARS)) { debug(20, 2) ("storeClientReadHeader: swapin MD5 mismatch\n"); debug(20, 2) ("\t%s\n", storeKeyText(t->value)); debug(20, 2) ("\t%s\n", storeKeyText(e->hash.key)); if (isPowTen(++md5_mismatches)) debug(20, 1) ("WARNING: %d swapin MD5 mismatches\n", md5_mismatches); swap_object_ok = 0; } break; case STORE_META_URL: if (NULL == mem->url) (void) 0; /* can't check */ else if (0 == strcasecmp(mem->url, t->value)) (void) 0; /* a match! */ else { debug(20, 1) ("storeClientReadHeader: URL mismatch\n"); debug(20, 1) ("\t{%s} != {%s}\n", (char *) t->value, mem->url); swap_object_ok = 0; break; } break; case STORE_META_STD: case STORE_META_STD_LFS: break; case STORE_META_VARY_HEADERS: if (mem->vary_headers) { if (strcmp(mem->vary_headers, t->value) != 0) swap_object_ok = 0; } else { /* Assume the object is OK.. remember the vary request headers */ mem->vary_headers = xstrdup(t->value); } break; default: debug(20, 2) ("WARNING: got unused STORE_META type %d\n", t->type); break; } } storeSwapTLVFree(tlv_list); if (!swap_object_ok) { storeClientCallback(sc, -1); return; } mem->swap_hdr_sz = swap_hdr_sz; mem->object_sz = e->swap_file_sz - swap_hdr_sz; /* * If our last read got some data the client wants, then give * it to them, otherwise schedule another read. */ body_sz = len - swap_hdr_sz; if (sc->copy_offset < body_sz) { /* * we have (part of) what they want */ copy_sz = XMIN(sc->copy_size, body_sz); debug(20, 3) ("storeClientReadHeader: copying %d bytes of body\n", (int) copy_sz); xmemmove(sc->copy_buf, sc->copy_buf + swap_hdr_sz, copy_sz); if (sc->copy_offset == 0 && len > 0 && mem->reply->sline.status == 0) httpReplyParse(mem->reply, sc->copy_buf, headersEnd(sc->copy_buf, copy_sz)); storeClientCallback(sc, copy_sz); return; } /* * we don't have what the client wants, but at least we now * know the swap header size. */ storeClientFileRead(sc); }