From: wessels <> Date: Wed, 5 Nov 1997 07:39:48 +0000 (+0000) Subject: trying to rearrange file names so they make more sense. X-Git-Tag: SQUID_3_0_PRE1~4571 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=7a2f978b6f6c399c7582369d81fa9649b27be1b9;p=thirdparty%2Fsquid.git trying to rearrange file names so they make more sense. --- diff --git a/src/Makefile.in b/src/Makefile.in index c633ed0fc2..5bc6bf4c9b 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -1,7 +1,7 @@ # # Makefile for the Squid Object Cache server # -# $Id: Makefile.in,v 1.92 1997/11/04 19:39:44 wessels Exp $ +# $Id: Makefile.in,v 1.93 1997/11/05 00:39:48 wessels Exp $ # # Uncomment and customize the following to suit your needs: # @@ -106,7 +106,8 @@ OBJS = \ http.o \ http-anon.o \ icmp.o \ - icp.o \ + icp_v2.o \ + icp_v3.o \ ident.o \ ipcache.o \ main.o \ diff --git a/src/access_log.cc b/src/access_log.cc index 54159a9477..9ddf820243 100644 --- a/src/access_log.cc +++ b/src/access_log.cc @@ -1,6 +1,6 @@ /* - * $Id: access_log.cc,v 1.6 1997/10/17 15:44:32 wessels Exp $ + * $Id: access_log.cc,v 1.7 1997/11/05 00:39:49 wessels Exp $ * * DEBUG: section 46 Access Log * AUTHOR: Duane Wessels @@ -32,6 +32,29 @@ #include "squid.h" +const char *log_tags[] = +{ + "NONE", + "TCP_HIT", + "TCP_MISS", + "TCP_REFRESH_HIT", + "TCP_REF_FAIL_HIT", + "TCP_REFRESH_MISS", + "TCP_CLIENT_REFRESH", + "TCP_IMS_HIT", + "TCP_IMS_MISS", + "TCP_SWAPFAIL_MISS", + "TCP_NEGATIVE_HIT", + "TCP_MEM_HIT", + "UDP_HIT", + "UDP_HIT_OBJ", + "UDP_MISS", + "UDP_DENIED", + "UDP_INVALID", + "UDP_MISS_NOFETCH", + "LOG_TYPE_MAX" +}; + #define MAX_LINELEN (4096) #define max(a,b) ((a)>(b)? (a): (b)) @@ -270,3 +293,9 @@ hierarchyNote(HierarchyLogEntry * hl, xstrncpy(hl->host, cache_peer, SQUIDHOSTNAMELEN); hl->icp.stop = current_time; } + +void +accessLogInit(void) +{ + assert(sizeof(log_tags) == (LOG_TYPE_MAX + 1) * sizeof(char *)); +} diff --git a/src/client_side.cc b/src/client_side.cc index c5f5d27d2a..30f823ca09 100644 --- a/src/client_side.cc +++ b/src/client_side.cc @@ -1,6 +1,6 @@ /* - * $Id: client_side.cc,v 1.139 1997/11/03 22:43:08 wessels Exp $ + * $Id: client_side.cc,v 1.140 1997/11/05 00:39:50 wessels Exp $ * * DEBUG: section 33 Client-side Routines * AUTHOR: Duane Wessels @@ -31,10 +31,38 @@ #include "squid.h" +static const char *const crlf = "\r\n"; + +#define REQUEST_BUF_SIZE 4096 +#define FAILURE_MODE_TIME 300 + +/* Local functions */ + +static CWCB icpHandleIMSComplete; +static PF clientReadRequest; +static PF connStateFree; +static PF requestTimeout; +static STCB icpGetHeadersForIMS; +static char *icpConstruct304reply(struct _http_reply *); +static int CheckQuickAbort2(const clientHttpRequest *); +static int icpCheckTransferDone(clientHttpRequest *); +static void CheckQuickAbort(clientHttpRequest *); +static void checkFailureRatio(log_type, hier_code); +static void clientProcessMISS(int, clientHttpRequest *); +static void clientAppendReplyHeader(char *, const char *, size_t *, size_t); +size_t clientBuildReplyHeader(clientHttpRequest *, char *, size_t *, char *, size_t); +static clientHttpRequest *parseHttpRequest(ConnStateData *, method_t *, int *, char **, size_t *); static RH clientRedirectDone; static STCB icpHandleIMSReply; static int clientGetsOldEntry(StoreEntry * new, StoreEntry * old, request_t * request); static int checkAccelOnly(clientHttpRequest *); +static ERCB clientErrorComplete; +static STCB clientSendMoreData; +static STCB clientCacheHit; +static void icpParseRequestHeaders(clientHttpRequest *); +static void icpProcessRequest(int, clientHttpRequest *); + + static int checkAccelOnly(clientHttpRequest * http) @@ -209,7 +237,6 @@ clientGetsOldEntry(StoreEntry * new_entry, StoreEntry * old_entry, request_t * r } - static void icpHandleIMSReply(void *data, char *buf, ssize_t size) { @@ -388,3 +415,1378 @@ checkNegativeHit(StoreEntry * e) return 0; return 1; } + +static void +httpRequestFree(void *data) +{ + clientHttpRequest *http = data; + clientHttpRequest **H; + ConnStateData *conn = http->conn; + StoreEntry *entry = http->entry; + request_t *request = http->request; + MemObject *mem = NULL; + debug(12, 3) ("httpRequestFree: %s\n", storeUrl(entry)); + if (!icpCheckTransferDone(http)) { + if (entry) + storeUnregister(entry, http); /* unregister BEFORE abort */ + CheckQuickAbort(http); + entry = http->entry; /* reset, IMS might have changed it */ + if (entry && entry->ping_status == PING_WAITING) + storeReleaseRequest(entry); + protoUnregister(entry, request, conn->peer.sin_addr); + } + assert(http->log_type < LOG_TYPE_MAX); + if (entry) + mem = entry->mem_obj; + if (http->out.size || http->log_type) { + http->al.icp.opcode = 0; + http->al.url = http->url; + if (mem) { + http->al.http.code = mem->reply->code; + http->al.http.content_type = mem->reply->content_type; + } + http->al.cache.caddr = conn->log_addr; + http->al.cache.size = http->out.size; + http->al.cache.code = http->log_type; + http->al.cache.msec = tvSubMsec(http->start, current_time); + http->al.cache.ident = conn->ident.ident; + if (request) { + http->al.http.method = request->method; + http->al.headers.request = request->headers; + http->al.hier = request->hier; + } + accessLogLog(&http->al); + HTTPCacheInfo->proto_count(HTTPCacheInfo, + request ? request->protocol : PROTO_NONE, + http->log_type); + clientdbUpdate(conn->peer.sin_addr, http->log_type, PROTO_HTTP); + } + if (http->redirect_state == REDIRECT_PENDING) + redirectUnregister(http->url, http); + if (http->acl_checklist) + aclChecklistFree(http->acl_checklist); + checkFailureRatio(http->log_type, http->al.hier.code); + safe_free(http->url); + safe_free(http->log_url); + safe_free(http->al.headers.reply); + if (entry) { + http->entry = NULL; + storeUnregister(entry, http); + storeUnlockObject(entry); + } + /* old_entry might still be set if we didn't yet get the reply + * code in icpHandleIMSReply() */ + if (http->old_entry) { + storeUnregister(http->old_entry, http); + storeUnlockObject(http->old_entry); + http->old_entry = NULL; + } + requestUnlink(http->request); + assert(http != http->next); + assert(http->conn->chr != NULL); + H = &http->conn->chr; + while (*H) { + if (*H == http) + break; + H = &(*H)->next; + } + assert(*H != NULL); + *H = http->next; + http->next = NULL; + cbdataFree(http); +} + +/* This is a handler normally called by comm_close() */ +static void +connStateFree(int fd, void *data) +{ + ConnStateData *connState = data; + clientHttpRequest *http; + debug(12, 3) ("connStateFree: FD %d\n", fd); + assert(connState != NULL); + while ((http = connState->chr)) { + assert(http->conn == connState); + assert(connState->chr != connState->chr->next); + httpRequestFree(http); + } + if (connState->ident.fd > -1) + comm_close(connState->ident.fd); + safe_free(connState->in.buf); + meta_data.misc -= connState->in.size; + pconnHistCount(0, connState->nrequests); + cbdataFree(connState); +} + +static void +icpParseRequestHeaders(clientHttpRequest * http) +{ + request_t *request = http->request; + char *request_hdr = request->headers; + char *t = NULL; + request->ims = -2; + request->imslen = -1; + if ((t = mime_get_header(request_hdr, "If-Modified-Since"))) { + BIT_SET(request->flags, REQ_IMS); + request->ims = parse_rfc1123(t); + while ((t = strchr(t, ';'))) { + for (t++; isspace(*t); t++); + if (strncasecmp(t, "length=", 7) == 0) + request->imslen = atoi(t + 7); + } + } + if ((t = mime_get_header(request_hdr, "Pragma"))) { + if (!strcasecmp(t, "no-cache")) + BIT_SET(request->flags, REQ_NOCACHE); + } + if (mime_get_header(request_hdr, "Range")) { + BIT_SET(request->flags, REQ_NOCACHE); + BIT_SET(request->flags, REQ_RANGE); + } else if (mime_get_header(request_hdr, "Request-Range")) { + BIT_SET(request->flags, REQ_NOCACHE); + BIT_SET(request->flags, REQ_RANGE); + } + if (mime_get_header(request_hdr, "Authorization")) + BIT_SET(request->flags, REQ_AUTH); + if (request->login[0] != '\0') + BIT_SET(request->flags, REQ_AUTH); + if ((t = mime_get_header(request_hdr, "Proxy-Connection"))) { + if (!strcasecmp(t, "Keep-Alive")) + BIT_SET(request->flags, REQ_PROXY_KEEPALIVE); + } + if ((t = mime_get_header(request_hdr, "Via"))) + if (strstr(t, ThisCache)) { + if (!http->accel) { + debug(12, 1) ("WARNING: Forwarding loop detected for '%s'\n", + http->url); + debug(12, 1) ("--> %s\n", t); + } + BIT_SET(request->flags, REQ_LOOPDETECT); + } +#if USE_USERAGENT_LOG + if ((t = mime_get_header(request_hdr, "User-Agent"))) + logUserAgent(fqdnFromAddr(http->conn->peer.sin_addr), t); +#endif + request->max_age = -1; + if ((t = mime_get_header(request_hdr, "Cache-control"))) { + if (!strncasecmp(t, "Max-age=", 8)) + request->max_age = atoi(t + 8); + } + if (request->method == METHOD_TRACE) { + if ((t = mime_get_header(request_hdr, "Max-Forwards"))) + request->max_forwards = atoi(t); + } +} + +static int +icpCachable(clientHttpRequest * http) +{ + const char *url = http->url; + request_t *req = http->request; + method_t method = req->method; + const wordlist *p; + for (p = Config.cache_stoplist; p; p = p->next) { + if (strstr(url, p->key)) + return 0; + } + if (Config.cache_stop_relist) + if (aclMatchRegex(Config.cache_stop_relist, url)) + return 0; + if (req->protocol == PROTO_HTTP) + return httpCachable(method); + /* FTP is always cachable */ + if (req->protocol == PROTO_GOPHER) + return gopherCachable(url); + if (req->protocol == PROTO_WAIS) + return 0; + if (method == METHOD_CONNECT) + return 0; + if (method == METHOD_TRACE) + return 0; + if (req->protocol == PROTO_CACHEOBJ) + return 0; + return 1; +} + +/* Return true if we can query our neighbors for this object */ +static int +icpHierarchical(clientHttpRequest * http) +{ + const char *url = http->url; + request_t *request = http->request; + method_t method = request->method; + const wordlist *p = NULL; + + /* IMS needs a private key, so we can use the hierarchy for IMS only + * if our neighbors support private keys */ + if (BIT_TEST(request->flags, REQ_IMS) && !neighbors_do_private_keys) + return 0; + if (BIT_TEST(request->flags, REQ_AUTH)) + return 0; + if (method == METHOD_TRACE) + return 1; + if (method != METHOD_GET) + return 0; + /* scan hierarchy_stoplist */ + for (p = Config.hierarchy_stoplist; p; p = p->next) + if (strstr(url, p->key)) + return 0; + if (BIT_TEST(request->flags, REQ_LOOPDETECT)) + return 0; + if (request->protocol == PROTO_HTTP) + return httpCachable(method); + if (request->protocol == PROTO_GOPHER) + return gopherCachable(url); + if (request->protocol == PROTO_WAIS) + return 0; + if (request->protocol == PROTO_CACHEOBJ) + return 0; + return 1; +} + +static void +clientErrorComplete(int fd, void *data, int size) +{ + clientHttpRequest *http = data; + if (http) + http->out.size += size; + comm_close(fd); +} + +int +isTcpHit(log_type code) +{ + /* this should be a bitmap for better optimization */ + if (code == LOG_TCP_HIT) + return 1; + if (code == LOG_TCP_IMS_HIT) + return 1; + if (code == LOG_TCP_REFRESH_FAIL_HIT) + return 1; + if (code == LOG_TCP_REFRESH_HIT) + return 1; + if (code == LOG_TCP_NEGATIVE_HIT) + return 1; + if (code == LOG_TCP_MEM_HIT) + return 1; + return 0; +} + +static void +clientAppendReplyHeader(char *hdr, const char *line, size_t * sz, size_t max) +{ + size_t n = *sz + strlen(line) + 2; + if (n >= max) + return; + strcpy(hdr + (*sz), line); + strcat(hdr + (*sz), crlf); + *sz = n; +} + +size_t +clientBuildReplyHeader(clientHttpRequest * http, + char *hdr_in, + size_t * in_len, + char *hdr_out, + size_t out_sz) +{ + char *xbuf; + char *ybuf; + char *t = NULL; + char *end = NULL; + size_t len = 0; + size_t hdr_len = 0; + size_t l; + end = mime_headers_end(hdr_in); + if (end == NULL) { + debug(12, 3) ("clientBuildReplyHeader: DIDN'T FIND END-OF-HEADERS\n"); + debug(12, 3) ("\n%s", hdr_in); + return 0; + } + xbuf = get_free_4k_page(); + ybuf = get_free_4k_page(); + for (t = hdr_in; t < end; t += strcspn(t, crlf), t += strspn(t, crlf)) { + hdr_len = t - hdr_in; + l = strcspn(t, crlf) + 1; + xstrncpy(xbuf, t, l > 4096 ? 4096 : l); + debug(12, 5) ("clientBuildReplyHeader: %s\n", xbuf); +#if 0 + if (strncasecmp(xbuf, "Accept-Ranges:", 14) == 0) + continue; + if (strncasecmp(xbuf, "Etag:", 5) == 0) + continue; +#endif + if (strncasecmp(xbuf, "Proxy-Connection:", 17) == 0) + continue; + if (strncasecmp(xbuf, "Connection:", 11) == 0) + continue; + if (strncasecmp(xbuf, "Keep-Alive:", 11) == 0) + continue; + if (strncasecmp(xbuf, "Set-Cookie:", 11) == 0) + if (isTcpHit(http->log_type)) + continue; + clientAppendReplyHeader(hdr_out, xbuf, &len, out_sz - 512); + } + hdr_len = end - hdr_in; + /* Append X-Cache: */ + snprintf(ybuf, 4096, "X-Cache: %s", isTcpHit(http->log_type) ? "HIT" : "MISS"); + clientAppendReplyHeader(hdr_out, ybuf, &len, out_sz); + /* Append Proxy-Connection: */ + if (BIT_TEST(http->request->flags, REQ_PROXY_KEEPALIVE)) { + snprintf(ybuf, 4096, "Proxy-Connection: Keep-Alive"); + clientAppendReplyHeader(hdr_out, ybuf, &len, out_sz); + } + clientAppendReplyHeader(hdr_out, null_string, &len, out_sz); + if (in_len) + *in_len = hdr_len; + if ((l = strlen(hdr_out)) != len) { + debug_trap("clientBuildReplyHeader: size mismatch"); + len = l; + } + debug(12, 3) ("clientBuildReplyHeader: OUTPUT:\n%s\n", hdr_out); + put_free_4k_page(xbuf); + put_free_4k_page(ybuf); + return len; +} + +void +clientCacheHit(void *data, char *buf, ssize_t size) +{ + clientHttpRequest *http = data; + if (size >= 0) { + clientSendMoreData(data, buf, size); + } else if (http->entry == NULL) { + debug(12, 3) ("clientCacheHit: request aborted\n"); + } else { + /* swap in failure */ + http->log_type = LOG_TCP_SWAPFAIL_MISS; + clientProcessMISS(http->conn->fd, http); + } +} + +void +clientSendMoreData(void *data, char *buf, ssize_t size) +{ + clientHttpRequest *http = data; + StoreEntry *entry = http->entry; + ConnStateData *conn = http->conn; + int fd = conn->fd; + char *p = NULL; + size_t hdrlen; + size_t l = 0; + size_t writelen; + char *newbuf; + FREE *freefunc = put_free_4k_page; + int hack = 0; + char C = '\0'; + assert(size <= SM_PAGE_SIZE); + debug(12, 5) ("clientSendMoreData: FD %d '%s', out.offset=%d\n", + fd, storeUrl(entry), http->out.offset); + if (conn->chr != http) { + /* there is another object in progress, defer this one */ + debug(0, 0) ("clientSendMoreData: Deferring delivery of\n"); + debug(0, 0) ("--> %s\n", storeUrl(entry)); + debug(0, 0) ("--> because other requests are in front\n"); + freefunc(buf); + return; + } else if (entry->store_status == STORE_ABORTED) { + freefunc(buf); + return; + } else if (size < 0) { + freefunc(buf); + return; + } else if (size == 0) { + clientWriteComplete(fd, NULL, 0, DISK_OK, http); + freefunc(buf); + return; + } + writelen = size; + if (http->out.offset == 0 && http->request->protocol != PROTO_CACHEOBJ) { + if (Config.onoff.log_mime_hdrs) { + if ((p = mime_headers_end(buf))) { + safe_free(http->al.headers.reply); + http->al.headers.reply = xcalloc(1 + p - buf, 1); + xstrncpy(http->al.headers.reply, buf, p - buf); + } + } + /* make sure 'buf' is null terminated somewhere */ + if (size == SM_PAGE_SIZE) { + hack = 1; + size--; + C = *(buf + size); + } + *(buf + size) = '\0'; + newbuf = get_free_8k_page(); + hdrlen = 0; + l = clientBuildReplyHeader(http, buf, &hdrlen, newbuf, 8192); + if (hack) + *(buf + size++) = C; + if (l != 0) { + writelen = l + size - hdrlen; + assert(writelen <= 8192); + /* + * l is the length of the new headers in newbuf + * hdrlen is the length of the old headers in buf + * size - hdrlen is the amount of body in buf + */ + debug(12, 3) ("clientSendMoreData: Appending %d bytes after headers\n", + (int) (size - hdrlen)); + xmemcpy(newbuf + l, buf + hdrlen, size - hdrlen); + /* replace buf with newbuf */ + freefunc(buf); + buf = newbuf; + freefunc = put_free_8k_page; + newbuf = NULL; + } else { + put_free_8k_page(newbuf); + newbuf = NULL; + if (size < SM_PAGE_SIZE && entry->store_status == STORE_PENDING) { + /* wait for more to arrive */ + storeClientCopy(entry, + http->out.offset + size, + http->out.offset, + SM_PAGE_SIZE, + buf, + clientSendMoreData, + http); + return; + } + } + } + http->out.offset += size; + if (http->request->method == METHOD_HEAD) { + if ((p = mime_headers_end(buf))) { + *p = '\0'; + writelen = p - buf; + /* force end */ + http->out.offset = entry->mem_obj->inmem_hi; + } + } + comm_write(fd, buf, writelen, clientWriteComplete, http, freefunc); +} + +void +clientWriteComplete(int fd, char *buf, int size, int errflag, void *data) +{ + clientHttpRequest *http = data; + ConnStateData *conn; + StoreEntry *entry = http->entry; + http->out.size += size; + debug(12, 5) ("clientWriteComplete: FD %d, sz %d, err %d, off %d, len %d\n", + fd, size, errflag, http->out.offset, entry->object_len); + if (errflag) { + CheckQuickAbort(http); + /* Log the number of bytes that we managed to read */ + HTTPCacheInfo->proto_touchobject(HTTPCacheInfo, + urlParseProtocol(storeUrl(entry)), + http->out.size); + comm_close(fd); + } else if (entry->store_status == STORE_ABORTED) { + HTTPCacheInfo->proto_touchobject(HTTPCacheInfo, + urlParseProtocol(storeUrl(entry)), + http->out.size); + comm_close(fd); + } else if (icpCheckTransferDone(http) || size == 0) { + debug(12, 5) ("clientWriteComplete: FD %d transfer is DONE\n", fd); + /* We're finished case */ + HTTPCacheInfo->proto_touchobject(HTTPCacheInfo, + http->request->protocol, + http->out.size); + if (http->entry->mem_obj->reply->content_length <= 0) { + comm_close(fd); + } else if (BIT_TEST(http->request->flags, REQ_PROXY_KEEPALIVE)) { + debug(12, 5) ("clientWriteComplete: FD %d Keeping Alive\n", fd); + conn = http->conn; + httpRequestFree(http); + if ((http = conn->chr)) { + debug(12, 1) ("clientWriteComplete: FD %d Sending next request\n", fd); + storeClientCopy(entry, + http->out.offset, + http->out.offset, + SM_PAGE_SIZE, + get_free_4k_page(), + clientSendMoreData, + http); + } else { + debug(12, 5) ("clientWriteComplete: FD %d Setting read handler for next request\n", fd); + fd_note(fd, "Reading next request"); + commSetSelect(fd, COMM_SELECT_READ, clientReadRequest, conn, 0); + commSetTimeout(fd, 15, requestTimeout, conn); + } + } else { + comm_close(fd); + } + } else { + /* More data will be coming from primary server; register with + * storage manager. */ + storeClientCopy(entry, + http->out.offset, + http->out.offset, + SM_PAGE_SIZE, + get_free_4k_page(), + clientSendMoreData, + http); + } +} + +static void +icpGetHeadersForIMS(void *data, char *buf, ssize_t size) +{ + clientHttpRequest *http = data; + int fd = http->conn->fd; + StoreEntry *entry = http->entry; + MemObject *mem = entry->mem_obj; + char *reply = NULL; + assert(size <= SM_PAGE_SIZE); + if (size < 0) { + debug(12, 1) ("icpGetHeadersForIMS: storeClientCopy failed for '%s'\n", + storeKeyText(entry->key)); + put_free_4k_page(buf); + clientProcessMISS(fd, http); + return; + } + if (mem->reply->code == 0) { + if (entry->mem_status == IN_MEMORY) { + put_free_4k_page(buf); + clientProcessMISS(fd, http); + return; + } + /* All headers are not yet available, wait for more data */ + storeClientCopy(entry, + http->out.offset + size, + http->out.offset, + SM_PAGE_SIZE, + buf, + icpGetHeadersForIMS, + http); + return; + } + /* All headers are available, check if object is modified or not */ + /* --------------------------------------------------------------- + * Removed check for reply->code != 200 because of a potential + * problem with ICP. We will return a HIT for any public, cached + * object. This includes other responses like 301, 410, as coded in + * http.c. It is Bad(tm) to return UDP_HIT and then, if the reply + * code is not 200, hand off to clientProcessMISS(), which may disallow + * the request based on 'miss_access' rules. Alternatively, we might + * consider requiring returning UDP_HIT only for 200's. This + * problably means an entry->flag bit, which would be lost during + * restart because the flags aren't preserved across restarts. + * --DW 3/11/96. + * ---------------------------------------------------------------- */ +#ifdef CHECK_REPLY_CODE_NOTEQUAL_200 + /* Only objects with statuscode==200 can be "Not modified" */ + if (mem->reply->code != 200) { + debug(12, 4) ("icpGetHeadersForIMS: Reply code %d!=200\n", + mem->reply->code); + put_free_4k_page(buf); + clientProcessMISS(fd, http); + return; + } + + +#endif + http->log_type = LOG_TCP_IMS_HIT; + entry->refcount++; + if (modifiedSince(entry, http->request)) { + storeClientCopy(entry, + http->out.offset, + http->out.offset, + SM_PAGE_SIZE, + buf, + clientSendMoreData, + http); + return; + } + debug(12, 4) ("icpGetHeadersForIMS: Not modified '%s'\n", storeUrl(entry)); + reply = icpConstruct304reply(mem->reply); + comm_write(fd, + xstrdup(reply), + strlen(reply), + icpHandleIMSComplete, + http, + xfree); +} + +static void +icpHandleIMSComplete(int fd, char *buf_unused, int size, int errflag, void *data) +{ + clientHttpRequest *http = data; + StoreEntry *entry = http->entry; + debug(12, 5) ("icpHandleIMSComplete: Not Modified sent '%s'\n", storeUrl(entry)); + HTTPCacheInfo->proto_touchobject(HTTPCacheInfo, + http->request->protocol, + size); + /* Set up everything for the logging */ + storeUnregister(entry, http); + storeUnlockObject(entry); + http->entry = NULL; + http->out.size += size; + http->al.http.code = 304; + if (errflag != COMM_ERR_CLOSING) + comm_close(fd); +} + +/* + * Below, we check whether the object is a hit or a miss. If it's a hit, + * we check whether the object is still valid or whether it is a MISS_TTL. + */ +void +icpProcessRequest(int fd, clientHttpRequest * http) +{ + char *url = http->url; + const cache_key *pubkey; + StoreEntry *entry = NULL; + request_t *request = http->request; + char *reply; + debug(12, 4) ("icpProcessRequest: %s '%s'\n", + RequestMethodStr[http->request->method], + url); + if (http->request->method == METHOD_CONNECT) { + http->log_type = LOG_TCP_MISS; + sslStart(fd, url, http->request, &http->out.size); + return; + } else if (request->method == METHOD_PURGE) { + clientPurgeRequest(http); + return; + } else if (request->method == METHOD_TRACE) { + if (request->max_forwards == 0) { + reply = clientConstructTraceEcho(http); + comm_write(fd, + xstrdup(reply), + strlen(reply), + clientWriteComplete, + http, + xfree); + return; + } + /* yes, continue */ + } else if (request->method != METHOD_GET) { + http->log_type = LOG_TCP_MISS; + passStart(fd, url, http->request, &http->out.size); + return; + } + if (icpCachable(http)) + BIT_SET(request->flags, REQ_CACHABLE); + if (icpHierarchical(http)) + BIT_SET(request->flags, REQ_HIERARCHICAL); + debug(12, 5) ("icpProcessRequest: REQ_NOCACHE = %s\n", + BIT_TEST(request->flags, REQ_NOCACHE) ? "SET" : "NOT SET"); + debug(12, 5) ("icpProcessRequest: REQ_CACHABLE = %s\n", + BIT_TEST(request->flags, REQ_CACHABLE) ? "SET" : "NOT SET"); + debug(12, 5) ("icpProcessRequest: REQ_HIERARCHICAL = %s\n", + BIT_TEST(request->flags, REQ_HIERARCHICAL) ? "SET" : "NOT SET"); + + /* NOTE on HEAD requests: We currently don't cache HEAD reqeusts + * at all, so look for the corresponding GET object, or just go + * directly. The only way to get a TCP_HIT on a HEAD reqeust is + * if someone already did a GET. Maybe we should turn HEAD + * misses into full GET's? */ + if (http->request->method == METHOD_HEAD) + pubkey = storeKeyPublic(http->url, METHOD_GET); + else + pubkey = storeKeyPublic(http->url, http->request->method); + + if ((entry = storeGet(pubkey)) == NULL) { + /* this object isn't in the cache */ + http->log_type = LOG_TCP_MISS; + } else if (BIT_TEST(entry->flag, ENTRY_SPECIAL)) { + if (entry->mem_status == IN_MEMORY) + http->log_type = LOG_TCP_MEM_HIT; + else + http->log_type = LOG_TCP_HIT; + } else if (!storeEntryValidToSend(entry)) { + http->log_type = LOG_TCP_MISS; + storeRelease(entry); + entry = NULL; + } else if (BIT_TEST(request->flags, REQ_NOCACHE)) { + /* NOCACHE should always eject a negative cached object */ + if (BIT_TEST(entry->flag, ENTRY_NEGCACHED)) + storeRelease(entry); + /* NOCACHE+IMS should not eject a valid object */ + else if (BIT_TEST(request->flags, REQ_IMS)) + (void) 0; + /* Request-Range should not eject a valid object */ + else if (BIT_TEST(request->flags, REQ_RANGE)) + (void) 0; + else + storeRelease(entry); + ipcacheReleaseInvalid(http->request->host); + entry = NULL; + http->log_type = LOG_TCP_CLIENT_REFRESH; + } else if (checkNegativeHit(entry)) { + http->log_type = LOG_TCP_NEGATIVE_HIT; + } else if (refreshCheck(entry, request, 0)) { + /* The object is in the cache, but it needs to be validated. Use + * LOG_TCP_REFRESH_MISS for the time being, maybe change it to + * _HIT later in icpHandleIMSReply() */ + if (request->protocol == PROTO_HTTP) + http->log_type = LOG_TCP_REFRESH_MISS; + else + http->log_type = LOG_TCP_MISS; /* XXX zoinks */ + } else if (BIT_TEST(request->flags, REQ_IMS)) { + /* User-initiated IMS request for something we think is valid */ + http->log_type = LOG_TCP_IMS_MISS; + } else { + if (entry->mem_status == IN_MEMORY) + http->log_type = LOG_TCP_MEM_HIT; + else + http->log_type = LOG_TCP_HIT; + } + debug(12, 4) ("icpProcessRequest: %s for '%s'\n", + log_tags[http->log_type], + http->url); + if (entry) { + storeLockObject(entry); + storeCreateMemObject(entry, http->url, http->log_url); + storeClientListAdd(entry, http); + } + http->entry = entry; /* Save a reference to the object */ + http->out.offset = 0; + switch (http->log_type) { + case LOG_TCP_HIT: + case LOG_TCP_NEGATIVE_HIT: + case LOG_TCP_MEM_HIT: + entry->refcount++; /* HIT CASE */ + storeClientCopy(entry, + http->out.offset, + http->out.offset, + SM_PAGE_SIZE, + get_free_4k_page(), + clientCacheHit, + http); + break; + case LOG_TCP_IMS_MISS: + storeClientCopy(entry, + http->out.offset, + http->out.offset, + SM_PAGE_SIZE, + get_free_4k_page(), + icpGetHeadersForIMS, + http); + break; + case LOG_TCP_REFRESH_MISS: + icpProcessExpired(fd, http); + break; + default: + clientProcessMISS(fd, http); + break; + } +} + +/* + * Prepare to fetch the object as it's a cache miss of some kind. + */ +static void +clientProcessMISS(int fd, clientHttpRequest * http) +{ + char *url = http->url; + char *request_hdr = http->request->headers; + StoreEntry *entry = NULL; + aclCheck_t ch; + int answer; + ErrorState *err = NULL; + debug(12, 4) ("clientProcessMISS: '%s %s'\n", + RequestMethodStr[http->request->method], url); + debug(12, 10) ("clientProcessMISS: request_hdr:\n%s\n", request_hdr); + + /* Check if this host is allowed to fetch MISSES from us */ + memset(&ch, '\0', sizeof(aclCheck_t)); + ch.src_addr = http->conn->peer.sin_addr; + ch.request = http->request; + answer = aclCheckFast(Config.accessList.miss, &ch); + if (answer == 0) { + http->al.http.code = HTTP_FORBIDDEN; + err = errorCon(ERR_CANNOT_FORWARD, HTTP_FORBIDDEN); + err->request = requestLink(http->request); + err->src_addr = http->conn->peer.sin_addr; + err->callback = clientErrorComplete; + err->callback_data = http; + errorSend(fd, err); + return; + } + /* Get rid of any references to a StoreEntry (if any) */ + if (http->entry) { + storeUnregister(http->entry, http); + storeUnlockObject(http->entry); + http->entry = NULL; + } + entry = storeCreateEntry(url, + http->log_url, + http->request->flags, + http->request->method); + /* NOTE, don't call storeLockObject(), storeCreateEntry() does it */ + storeClientListAdd(entry, http); + entry->mem_obj->fd = fd; + entry->refcount++; /* MISS CASE */ + http->entry = entry; + http->out.offset = 0; + /* Register with storage manager to receive updates when data comes in. */ + storeClientCopy(entry, + http->out.offset, + http->out.offset, + SM_PAGE_SIZE, + get_free_4k_page(), + clientSendMoreData, + http); + /* protoDispatch() needs to go after storeClientCopy() at least + * for OBJCACHE requests */ + protoDispatch(fd, http->entry, http->request); + return; +} + +/* + * parseHttpRequest() + * + * Returns + * NULL on error or incomplete request + * a clientHttpRequest structure on success + */ +static clientHttpRequest * +parseHttpRequest(ConnStateData * conn, method_t * method_p, int *status, + char **headers_p, size_t * headers_sz_p) +{ + char *inbuf = NULL; + char *mstr = NULL; + char *url = NULL; + char *req_hdr = NULL; + LOCAL_ARRAY(char, http_ver_s, 32); + float http_ver; + char *token = NULL; + char *t = NULL; + char *end = NULL; + int free_request = 0; + size_t header_sz; /* size of headers, not including first line */ + size_t req_sz; /* size of whole request */ + size_t url_sz; + method_t method; + clientHttpRequest *http = NULL; + + /* Make sure a complete line has been received */ + if (strchr(conn->in.buf, '\n') == NULL) { + debug(12, 5) ("Incomplete request line, waiting for more data\n"); + *status = 0; + return NULL; + } + /* Use xmalloc/xmemcpy instead of xstrdup because inbuf might + * contain NULL bytes; especially for POST data */ + inbuf = xmalloc(conn->in.offset + 1); + xmemcpy(inbuf, conn->in.buf, conn->in.offset); + *(inbuf + conn->in.offset) = '\0'; + + /* Look for request method */ + if ((mstr = strtok(inbuf, "\t ")) == NULL) { + debug(12, 1) ("parseHttpRequest: Can't get request method\n"); + xfree(inbuf); + *status = -1; + return NULL; + } + method = urlParseMethod(mstr); + if (method == METHOD_NONE) { + debug(12, 1) ("parseHttpRequest: Unsupported method '%s'\n", mstr); + xfree(inbuf); + *status = -1; + return NULL; + } + debug(12, 5) ("parseHttpRequest: Method is '%s'\n", mstr); + + /* look for URL */ + if ((url = strtok(NULL, "\r\n\t ")) == NULL) { + debug(12, 1) ("parseHttpRequest: Missing URL\n"); + xfree(inbuf); + *status = -1; + return NULL; + } + debug(12, 5) ("parseHttpRequest: Request is '%s'\n", url); + + token = strtok(NULL, null_string); + for (t = token; t && *t && *t != '\n' && *t != '\r'; t++); + if (t == NULL || *t == '\0' || t == token) { + debug(12, 3) ("parseHttpRequest: Missing HTTP identifier\n"); + xfree(inbuf); + *status = -1; + return NULL; + } + memset(http_ver_s, '\0', 32); + xstrncpy(http_ver_s, token, 32); + sscanf(http_ver_s, "HTTP/%f", &http_ver); + debug(12, 5) ("parseHttpRequest: HTTP version is '%3.1f'\n", http_ver); + + /* Check if headers are received */ + if ((end = mime_headers_end(t)) == NULL) { + xfree(inbuf); + *status = 0; + return NULL; + } + while (isspace(*t)) + t++; + req_hdr = t; + header_sz = end - req_hdr; + req_sz = end - inbuf; + + /* Ok, all headers are received */ + http = xcalloc(1, sizeof(clientHttpRequest)); + cbdataAdd(http); + http->http_ver = http_ver; + http->conn = conn; + http->start = current_time; + http->req_sz = req_sz; + *headers_sz_p = header_sz; + *headers_p = xmalloc(header_sz + 1); + xmemcpy(*headers_p, req_hdr, header_sz); + *(*headers_p + header_sz) = '\0'; + + debug(12, 5) ("parseHttpRequest: Request Header is\n%s\n", *headers_p); + + /* Assign http->url */ + if ((t = strchr(url, '\n'))) /* remove NL */ + *t = '\0'; + if ((t = strchr(url, '\r'))) /* remove CR */ + *t = '\0'; + if ((t = strchr(url, '#'))) /* remove HTML anchors */ + *t = '\0'; + + /* see if we running in Config2.Accel.on, if so got to convert it to URL */ + if (Config2.Accel.on && *url == '/') { + /* prepend the accel prefix */ + if (vhost_mode) { + /* Put the local socket IP address as the hostname */ + url_sz = strlen(url) + 32 + Config.appendDomainLen; + http->url = xcalloc(url_sz, 1); + snprintf(http->url, url_sz, "http://%s:%d%s", + inet_ntoa(http->conn->me.sin_addr), + (int) Config.Accel.port, + url); + debug(12, 5) ("VHOST REWRITE: '%s'\n", http->url); + } else if (opt_accel_uses_host && (t = mime_get_header(req_hdr, "Host"))) { + /* If a Host: header was specified, use it to build the URL + * instead of the one in the Config file. */ + /* + * XXX Use of the Host: header here opens a potential + * security hole. There are no checks that the Host: value + * corresponds to one of your servers. It might, for example, + * refer to www.playboy.com. The 'dst' and/or 'dst_domain' ACL + * types should be used to prevent httpd-accelerators + * handling requests for non-local servers */ + strtok(t, " :/;@"); + url_sz = strlen(url) + 32 + Config.appendDomainLen; + http->url = xcalloc(url_sz, 1); + snprintf(http->url, url_sz, "http://%s:%d%s", + t, (int) Config.Accel.port, url); + } else { + url_sz = strlen(Config2.Accel.prefix) + strlen(url) + + Config.appendDomainLen + 1; + http->url = xcalloc(url_sz, 1); + snprintf(http->url, url_sz, "%s%s", Config2.Accel.prefix, url); + } + http->accel = 1; + } else { + /* URL may be rewritten later, so make extra room */ + url_sz = strlen(url) + Config.appendDomainLen + 5; + http->url = xcalloc(url_sz, 1); + strcpy(http->url, url); + http->accel = 0; + } + http->log_url = xstrdup(http->url); + debug(12, 5) ("parseHttpRequest: Complete request received\n"); + if (free_request) + safe_free(url); + xfree(inbuf); + *method_p = method; + *status = 1; + return http; +} + +static int +clientReadDefer(int fd, void *data) +{ + ConnStateData *conn = data; + return conn->defer.until > squid_curtime; +} + +static void +clientReadRequest(int fd, void *data) +{ + ConnStateData *conn = data; + int parser_return_code = 0; + int k; + request_t *request = NULL; + char *tmp; + int size; + int len; + method_t method; + clientHttpRequest *http = NULL; + clientHttpRequest **H = NULL; + char *headers; + size_t headers_sz; + ErrorState *err = NULL; + fde *F = &fd_table[fd]; + + len = conn->in.size - conn->in.offset - 1; + debug(12, 4) ("clientReadRequest: FD %d: reading request...\n", fd); + size = read(fd, conn->in.buf + conn->in.offset, len); + fd_bytes(fd, size, FD_READ); + + if (size == 0) { + if (conn->chr == NULL) { + /* no current or pending requests */ + comm_close(fd); + return; + } + /* It might be half-closed, we can't tell */ + debug(12, 5) ("clientReadRequest: FD %d closed?\n", fd); + BIT_SET(F->flags, FD_SOCKET_EOF); + conn->defer.until = squid_curtime + 1; + conn->defer.n++; + commSetSelect(fd, COMM_SELECT_READ, clientReadRequest, conn, 0); + return; + } else if (size < 0) { + if (errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR) { + commSetSelect(fd, COMM_SELECT_READ, clientReadRequest, conn, 0); + } else { + debug(50, 2) ("clientReadRequest: FD %d: %s\n", fd, xstrerror()); + comm_close(fd); + } + return; + } + conn->in.offset += size; + conn->in.buf[conn->in.offset] = '\0'; /* Terminate the string */ + + while (conn->in.offset > 0) { + http = parseHttpRequest(conn, + &method, + &parser_return_code, + &headers, + &headers_sz); + if (http) { + assert(http->req_sz > 0); + conn->in.offset -= http->req_sz; + assert(conn->in.offset >= 0); + if (conn->in.offset > 0) { + tmp = xstrdup(conn->in.buf + http->req_sz); + xstrncpy(conn->in.buf, tmp, conn->in.size); + safe_free(tmp); + } + /* link */ + for (H = &conn->chr; *H; H = &(*H)->next); + *H = http; + conn->nrequests++; + commSetTimeout(fd, Config.Timeout.lifetime, NULL, NULL); + if ((request = urlParse(method, http->url)) == NULL) { + debug(12, 5) ("Invalid URL: %s\n", http->url); + err = errorCon(ERR_INVALID_URL, HTTP_BAD_REQUEST); + err->src_addr = conn->peer.sin_addr; + err->callback = clientErrorComplete; + err->callback_data = http; + err->url = xstrdup(http->url); + http->al.http.code = err->http_status; + errorSend(fd, err); + safe_free(headers); + break; + } + safe_free(http->log_url); + http->log_url = xstrdup(urlCanonicalClean(request)); + request->client_addr = conn->peer.sin_addr; + request->http_ver = http->http_ver; + request->headers = headers; + request->headers_sz = headers_sz; + if (!urlCheckRequest(request)) { + err = errorCon(ERR_UNSUP_REQ, HTTP_NOT_IMPLEMENTED); + err->src_addr = conn->peer.sin_addr; + err->callback = clientErrorComplete; + err->callback_data = http; + err->request = requestLink(request); + http->al.http.code = err->http_status; + errorSend(fd, err); + return; + } + http->request = requestLink(request); + clientAccessCheck(http); + /* break here for NON-GET because most likely there is a + * reqeust body following and we don't want to parse it + * as though it was new request */ + if (request->method != METHOD_GET) { + if (conn->in.offset) { + request->body_sz = conn->in.offset; + request->body = xmalloc(request->body_sz); + xmemcpy(request->body, conn->in.buf, request->body_sz); + conn->in.offset = 0; + } + break; + } + commSetSelect(fd, COMM_SELECT_READ, clientReadRequest, conn, 0); + continue; /* while offset > 0 */ + } else if (parser_return_code == 0) { + /* + * Partial request received; reschedule until parseHttpRequest() + * is happy with the input + */ + k = conn->in.size - 1 - conn->in.offset; + if (k == 0) { + if (conn->in.offset >= Config.maxRequestSize) { + /* The request is too large to handle */ + debug(12, 0) ("Request won't fit in buffer.\n"); + debug(12, 0) ("Config 'request_size'= %d bytes.\n", + Config.maxRequestSize); + debug(12, 0) ("This request = %d bytes.\n", + conn->in.offset); + err = errorCon(ERR_INVALID_REQ, HTTP_REQUEST_ENTITY_TOO_LARGE); + err->callback = clientErrorComplete; + err->callback_data = NULL; + errorSend(fd, err); + return; + } + /* Grow the request memory area to accomodate for a large request */ + conn->in.size += REQUEST_BUF_SIZE; + conn->in.buf = xrealloc(conn->in.buf, conn->in.size); + meta_data.misc += REQUEST_BUF_SIZE; + debug(12, 2) ("Handling a large request, offset=%d inbufsize=%d\n", + conn->in.offset, conn->in.size); + k = conn->in.size - 1 - conn->in.offset; + } + commSetSelect(fd, COMM_SELECT_READ, clientReadRequest, conn, 0); + break; + } else { + /* parser returned -1 */ + debug(12, 1) ("clientReadRequest: FD %d Invalid Request\n", fd); + err = errorCon(ERR_INVALID_REQ, HTTP_BAD_REQUEST); + err->callback = clientErrorComplete; + err->callback_data = NULL; + errorSend(fd, err); + return; + } + } +} + +/* general lifetime handler for HTTP requests */ +static void +requestTimeout(int fd, void *data) +{ + ConnStateData *conn = data; + ErrorState *err; + debug(12, 2) ("requestTimeout: FD %d: lifetime is expired.\n", fd); + if (fd_table[fd].rwstate) { + /* Some data has been sent to the client, just close the FD */ + comm_close(fd); + } else if (conn->nrequests) { + /* assume its a persistent connection; just close it */ + comm_close(fd); + } else { + /* Generate an error */ + err = errorCon(ERR_LIFETIME_EXP, HTTP_REQUEST_TIMEOUT); + err->callback = clientErrorComplete; + err->url = xstrdup("N/A"); + errorSend(fd, err); + /* if we don't close() here, we still need a timeout handler! */ + commSetTimeout(fd, 30, requestTimeout, conn); + } +} + +int +httpAcceptDefer(int fd, void *notused) +{ + return !fdstat_are_n_free_fd(RESERVED_FD); +} + +/* Handle a new connection on ascii input socket. */ +void +httpAccept(int sock, void *notused) +{ + int fd = -1; + ConnStateData *connState = NULL; + struct sockaddr_in peer; + struct sockaddr_in me; + memset(&peer, '\0', sizeof(struct sockaddr_in)); + memset(&me, '\0', sizeof(struct sockaddr_in)); + commSetSelect(sock, COMM_SELECT_READ, httpAccept, NULL, 0); + if ((fd = comm_accept(sock, &peer, &me)) < 0) { + debug(50, 1) ("httpAccept: FD %d: accept failure: %s\n", + sock, xstrerror()); + return; + } + ntcpconn++; + debug(12, 4) ("httpAccept: FD %d: accepted\n", fd); + connState = xcalloc(1, sizeof(ConnStateData)); + connState->peer = peer; + connState->log_addr = peer.sin_addr; + connState->log_addr.s_addr &= Config.Addrs.client_netmask.s_addr; + connState->me = me; + connState->fd = fd; + connState->ident.fd = -1; + connState->in.size = REQUEST_BUF_SIZE; + connState->in.buf = xcalloc(connState->in.size, 1); + cbdataAdd(connState); + meta_data.misc += connState->in.size; + comm_add_close_handler(fd, connStateFree, connState); + if (Config.onoff.log_fqdn) + fqdncache_gethostbyaddr(peer.sin_addr, FQDN_LOOKUP_IF_MISS); + commSetTimeout(fd, Config.Timeout.request, requestTimeout, connState); + commSetSelect(fd, COMM_SELECT_READ, clientReadRequest, connState, 0); + commSetDefer(fd, clientReadDefer, connState); +} + +void +AppendUdp(icpUdpData * item) +{ + item->next = NULL; + if (UdpQueueHead == NULL) { + UdpQueueHead = item; + UdpQueueTail = item; + } else if (UdpQueueTail == UdpQueueHead) { + UdpQueueTail = item; + UdpQueueHead->next = item; + } else { + UdpQueueTail->next = item; + UdpQueueTail = item; + } +} + +/* return 1 if the request should be aborted */ +static int +CheckQuickAbort2(const clientHttpRequest * http) +{ + long curlen; + long minlen; + long expectlen; + + if (!BIT_TEST(http->request->flags, REQ_CACHABLE)) + return 1; + if (BIT_TEST(http->entry->flag, KEY_PRIVATE)) + return 1; + if (http->entry->mem_obj == NULL) + return 1; + expectlen = http->entry->mem_obj->reply->content_length; + curlen = http->entry->mem_obj->inmem_hi; + minlen = Config.quickAbort.min; + if (minlen < 0) + /* disabled */ + return 0; + if (curlen > expectlen) + /* bad content length */ + return 1; + if ((expectlen - curlen) < minlen) + /* only little more left */ + return 0; + if ((expectlen - curlen) > Config.quickAbort.max) + /* too much left to go */ + return 1; + if ((curlen / (expectlen / 128U)) > Config.quickAbort.pct) + /* past point of no return */ + return 0; + return 1; +} + + +static void +CheckQuickAbort(clientHttpRequest * http) +{ + StoreEntry *entry = http->entry; + /* Note, set entry here because http->entry might get changed (for IMS + * requests) during the storeAbort() call */ + if (entry == NULL) + return; + if (storePendingNClients(entry) > 1) + return; + if (entry->store_status != STORE_PENDING) + return; + if (CheckQuickAbort2(http) == 0) + return; + debug(12, 3) ("CheckQuickAbort: ABORTING %s\n", storeUrl(entry)); + storeAbort(entry, 1); +} + +static int +icpCheckTransferDone(clientHttpRequest * http) +{ + StoreEntry *entry = http->entry; + MemObject *mem = NULL; + + if (entry == NULL) + return 0; + if (entry->store_status != STORE_PENDING) + if (http->out.offset >= entry->object_len) + return 1; + if ((mem = entry->mem_obj) == NULL) + return 0; + if (mem->reply->content_length == 0) + return 0; + if (http->out.offset >= mem->reply->content_length + mem->reply->hdr_sz) + return 1; + return 0; +} + +static char * +icpConstruct304reply(struct _http_reply *source) +{ + LOCAL_ARRAY(char, line, 256); + LOCAL_ARRAY(char, reply, 8192); + + memset(reply, '\0', 8192); + strcpy(reply, "HTTP/1.0 304 Not Modified\r\n"); + if (source->date > -1) { + snprintf(line, 256, "Date: %s\r\n", mkrfc1123(source->date)); + strcat(reply, line); + } + if ((int) strlen(source->content_type) > 0) { + snprintf(line, 256, "Content-type: %s\r\n", source->content_type); + strcat(reply, line); + } + if (source->content_length) { + snprintf(line, 256, "Content-length: %d\r\n", source->content_length); + strcat(reply, line); + } + if (source->expires > -1) { + snprintf(line, 256, "Expires: %s\r\n", mkrfc1123(source->expires)); + strcat(reply, line); + } + if (source->last_modified > -1) { + snprintf(line, 256, "Last-modified: %s\r\n", + mkrfc1123(source->last_modified)); + strcat(reply, line); + } + strcat(reply, "\r\n"); + return reply; +} + +/* + * This function is designed to serve a fairly specific purpose. + * Occasionally our vBNS-connected caches can talk to each other, but not + * the rest of the world. Here we try to detect frequent failures which + * make the cache unusable (e.g. DNS lookup and connect() failures). If + * the failure:success ratio goes above 1.0 then we go into "hit only" + * mode where we only return UDP_HIT or UDP_MISS_NOFETCH. Neighbors + * will only fetch HITs from us if they are using the ICP protocol. We + * stay in this mode for 5 minutes. + * + * Duane W., Sept 16, 1996 + */ + +static void +checkFailureRatio(log_type rcode, hier_code hcode) +{ + static double fail_ratio = 0.0; + static double magic_factor = 100; + double n_good; + double n_bad; + if (hcode == HIER_NONE) + return; + n_good = magic_factor / (1.0 + fail_ratio); + n_bad = magic_factor - n_good; + switch (rcode) { + case ERR_DNS_FAIL: + case ERR_CONNECT_FAIL: + case ERR_READ_ERROR: + n_bad++; + break; + default: + n_good++; + } + fail_ratio = n_bad / n_good; + if (hit_only_mode_until > squid_curtime) + return; + if (fail_ratio < 1.0) + return; + debug(12, 0) ("Failure Ratio at %4.2f\n", fail_ratio); + debug(12, 0) ("Going into hit-only-mode for %d minutes...\n", + FAILURE_MODE_TIME / 60); + hit_only_mode_until = squid_curtime + FAILURE_MODE_TIME; + fail_ratio = 0.8; /* reset to something less than 1.0 */ +} diff --git a/src/globals.h b/src/globals.h index b3c5c4d961..233d0494c7 100644 --- a/src/globals.h +++ b/src/globals.h @@ -1,6 +1,6 @@ /* - * $Id: globals.h,v 1.15 1997/11/03 22:43:10 wessels Exp $ + * $Id: globals.h,v 1.16 1997/11/05 00:39:51 wessels Exp $ */ extern FILE *debug_log; /* NULL */ @@ -94,6 +94,9 @@ extern int store_rebuilding; /* 1 */ extern int store_swap_size; /* 0 */ extern int client_info_sz; /* 0 */ extern unsigned long store_mem_size; /* 0 */ +extern icpUdpData *UdpQueueHead; /* NULL */ +extern icpUdpData *UdpQueueTail; /* NULL */ +extern time_t hit_only_mode_until; /* 0 */ #ifdef HAVE_SYSLOG extern int _db_level; diff --git a/src/icp_v2.cc b/src/icp_v2.cc new file mode 100644 index 0000000000..1fd371599b --- /dev/null +++ b/src/icp_v2.cc @@ -0,0 +1,434 @@ +#include "squid.h" + +static void icpLogIcp(icpUdpData *); +static void icpHandleIcpV2(int, struct sockaddr_in, char *, int); + +static void +icpLogIcp(icpUdpData * queue) +{ + icp_common_t *header = (icp_common_t *) (void *) queue->msg; + char *url = (char *) header + sizeof(icp_common_t); + AccessLogEntry al; + ICPCacheInfo->proto_touchobject(ICPCacheInfo, + queue->proto, + queue->len); + ICPCacheInfo->proto_count(ICPCacheInfo, + queue->proto, + queue->logcode); + clientdbUpdate(queue->address.sin_addr, queue->logcode, PROTO_ICP); + if (!Config.onoff.log_udp) + return; + memset(&al, '\0', sizeof(AccessLogEntry)); + al.icp.opcode = ICP_OP_QUERY; + al.url = url; + al.cache.caddr = queue->address.sin_addr; + al.cache.size = queue->len; + al.cache.code = queue->logcode; + al.cache.msec = tvSubMsec(queue->start, current_time); + accessLogLog(&al); +} + +void +icpUdpReply(int fd, void *data) +{ + icpUdpData *queue = data; + int x; + /* Disable handler, in case of errors. */ + commSetSelect(fd, COMM_SELECT_WRITE, NULL, NULL, 0); + while ((queue = UdpQueueHead)) { + debug(12, 5) ("icpUdpReply: FD %d sending %d bytes to %s port %d\n", + fd, + queue->len, + inet_ntoa(queue->address.sin_addr), + ntohs(queue->address.sin_port)); + x = comm_udp_sendto(fd, + &queue->address, + sizeof(struct sockaddr_in), + queue->msg, + queue->len); + if (x < 0) { + if (errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR) + break; /* don't de-queue */ + } + UdpQueueHead = queue->next; + if (queue->logcode) + icpLogIcp(queue); + safe_free(queue->msg); + safe_free(queue); + } + /* Reinstate handler if needed */ + if (UdpQueueHead) { + commSetSelect(fd, COMM_SELECT_WRITE, icpUdpReply, UdpQueueHead, 0); + } +} + +void * +icpCreateMessage( + icp_opcode opcode, + int flags, + const char *url, + int reqnum, + int pad) +{ + char *buf = NULL; + icp_common_t *headerp = NULL; + char *urloffset = NULL; + int buf_len; + buf_len = sizeof(icp_common_t) + strlen(url) + 1; + assert(reqnum); + if (opcode == ICP_OP_QUERY) + buf_len += sizeof(u_num32); + buf = xcalloc(buf_len, 1); + headerp = (icp_common_t *) (void *) buf; + headerp->opcode = opcode; + headerp->version = ICP_VERSION_CURRENT; + headerp->length = htons(buf_len); + headerp->reqnum = htonl(reqnum); + headerp->flags = htonl(flags); + headerp->pad = htonl(pad); + headerp->shostid = htonl(theOutICPAddr.s_addr); + urloffset = buf + sizeof(icp_common_t); + if (opcode == ICP_OP_QUERY) + urloffset += sizeof(u_num32); + xmemcpy(urloffset, url, strlen(url)); + return buf; +} + +#if USE_ICP_HIT_OBJ +static void * +icpCreateHitObjMessage( + icp_opcode opcode, + int flags, + const char *url, + int reqnum, + int pad, + StoreEntry * entry) +{ + char *buf = NULL; + char *entryoffset = NULL; + char *urloffset = NULL; + icp_common_t *headerp = NULL; + int buf_len; + u_short data_sz; + int size; + MemObject *m = entry->mem_obj; + assert(m != NULL); + buf_len = sizeof(icp_common_t) + strlen(url) + 1 + 2 + entry->object_len; + if (opcode == ICP_OP_QUERY) + buf_len += sizeof(u_num32); + buf = xcalloc(buf_len, 1); + headerp = (icp_common_t *) (void *) buf; + headerp->opcode = opcode; + headerp->version = ICP_VERSION_CURRENT; + headerp->length = htons(buf_len); + headerp->reqnum = htonl(reqnum); + headerp->flags = htonl(flags); + headerp->pad = htonl(pad); + headerp->shostid = htonl(theOutICPAddr.s_addr); + urloffset = buf + sizeof(icp_common_t); + xmemcpy(urloffset, url, strlen(url)); + data_sz = htons((u_short) entry->object_len); + entryoffset = urloffset + strlen(url) + 1; + xmemcpy(entryoffset, &data_sz, sizeof(u_short)); + entryoffset += sizeof(u_short); + assert(m->data != NULL); + size = memCopy(m->data, 0, entryoffset, entry->object_len); + if (size < 0 || size != entry->object_len) { + debug(12, 1) ("icpCreateHitObjMessage: copy failed, wanted %d got %d bytes\n", + entry->object_len, size); + safe_free(buf); + return NULL; + } + return buf; +} +#endif + +void +icpUdpSend(int fd, + const struct sockaddr_in *to, + icp_common_t * msg, + log_type logcode, + protocol_t proto) +{ + icpUdpData *data = xcalloc(1, sizeof(icpUdpData)); + debug(12, 4) ("icpUdpSend: Queueing %s for %s\n", + IcpOpcodeStr[msg->opcode], + inet_ntoa(to->sin_addr)); + data->address = *to; + data->msg = msg; + data->len = (int) ntohs(msg->length); +#ifndef LESS_TIMING + data->start = current_time; /* wrong for HIT_OBJ */ +#endif + data->logcode = logcode; + data->proto = proto; + AppendUdp(data); + commSetSelect(fd, COMM_SELECT_WRITE, icpUdpReply, UdpQueueHead, 0); +} + +int +icpCheckUdpHit(StoreEntry * e, request_t * request) +{ + if (e == NULL) + return 0; + if (!storeEntryValidToSend(e)) + return 0; + if (Config.onoff.icp_hit_stale) + return 1; + if (refreshCheck(e, request, 30)) + return 0; + /* MUST NOT do UDP_HIT_OBJ if object is not in memory with async_io. The */ + /* icpHandleV2 code has not been written to support it - squid will die! */ +#if USE_ASYNC_IO || defined(MEM_UDP_HIT_OBJ) + if (e->mem_status != IN_MEMORY) + return 0; +#endif + return 1; +} + +#if USE_ICP_HIT_OBJ +int +icpCheckUdpHitObj(StoreEntry * e, request_t * r, icp_common_t * h, int len) +{ + if (!BIT_TEST(h->flags, ICP_FLAG_HIT_OBJ)) /* not requested */ + return 0; + if (len > Config.udpMaxHitObjsz) /* too big */ + return 0; + if (refreshCheck(e, r, 0)) /* stale */ + return 0; +#ifdef MEM_UDP_HIT_OBJ + if (e->mem_status != IN_MEMORY) + return 0; +#endif + return 1; +} +#endif + +static void +icpHandleIcpV2(int fd, struct sockaddr_in from, char *buf, int len) +{ + icp_common_t header; + icp_common_t *headerp = (icp_common_t *) (void *) buf; + StoreEntry *entry = NULL; + char *url = NULL; + const cache_key *key; + request_t *icp_request = NULL; + int allow = 0; + char *data = NULL; + u_short data_sz = 0; + u_short u; + int pkt_len; + aclCheck_t checklist; + icp_common_t *reply; + int src_rtt = 0; + u_num32 flags = 0; + header.opcode = headerp->opcode; + header.version = headerp->version; + header.length = ntohs(headerp->length); + header.reqnum = ntohl(headerp->reqnum); + header.flags = ntohl(headerp->flags); + header.shostid = ntohl(headerp->shostid); + header.pad = ntohl(headerp->pad); + + switch (header.opcode) { + case ICP_OP_QUERY: + nudpconn++; + /* We have a valid packet */ + url = buf + sizeof(header) + sizeof(u_num32); + if ((icp_request = urlParse(METHOD_GET, url)) == NULL) { + reply = icpCreateMessage(ICP_OP_ERR, 0, url, header.reqnum, 0); + icpUdpSend(fd, &from, reply, LOG_UDP_INVALID, PROTO_NONE); + break; + } + checklist.src_addr = from.sin_addr; + checklist.request = icp_request; + allow = aclCheckFast(Config.accessList.icp, &checklist); + if (!allow) { + debug(12, 2) ("icpHandleIcpV2: Access Denied for %s by %s.\n", + inet_ntoa(from.sin_addr), AclMatchedName); + if (clientdbDeniedPercent(from.sin_addr) < 95) { + reply = icpCreateMessage(ICP_OP_DENIED, 0, url, header.reqnum, 0); + icpUdpSend(fd, &from, reply, LOG_UDP_DENIED, icp_request->protocol); + } + break; + } + if (header.flags & ICP_FLAG_SRC_RTT) { + int rtt = netdbHostRtt(icp_request->host); + int hops = netdbHostHops(icp_request->host); + src_rtt = ((hops & 0xFFFF) << 16) | (rtt & 0xFFFF); + if (rtt) + flags |= ICP_FLAG_SRC_RTT; + } + /* The peer is allowed to use this cache */ + key = storeKeyPublic(url, METHOD_GET); + entry = storeGet(key); + debug(12, 5) ("icpHandleIcpV2: OPCODE %s\n", IcpOpcodeStr[header.opcode]); + if (icpCheckUdpHit(entry, icp_request)) { + pkt_len = sizeof(icp_common_t) + strlen(url) + 1 + 2 + entry->object_len; +#if USE_ICP_HIT_OBJ + if (icpCheckUdpHitObj(entry, icp_request, &header, pkt_len)) { + reply = icpCreateHitObjMessage(ICP_OP_HIT_OBJ, + flags, + url, + header.reqnum, + src_rtt, + entry); + icpUdpSend(fd, &from, reply, LOG_UDP_HIT, icp_request->protocol); + break; + } else { +#endif + reply = icpCreateMessage(ICP_OP_HIT, flags, url, header.reqnum, src_rtt); + icpUdpSend(fd, &from, reply, LOG_UDP_HIT, icp_request->protocol); + break; +#if USE_ICP_HIT_OBJ + } +#endif + } + /* if store is rebuilding, return a UDP_HIT, but not a MISS */ + if (store_rebuilding && opt_reload_hit_only) { + reply = icpCreateMessage(ICP_OP_MISS_NOFETCH, flags, url, header.reqnum, src_rtt); + icpUdpSend(fd, &from, reply, LOG_UDP_MISS_NOFETCH, icp_request->protocol); + } else if (hit_only_mode_until > squid_curtime) { + reply = icpCreateMessage(ICP_OP_MISS_NOFETCH, flags, url, header.reqnum, src_rtt); + icpUdpSend(fd, &from, reply, LOG_UDP_MISS_NOFETCH, icp_request->protocol); + } else { + reply = icpCreateMessage(ICP_OP_MISS, flags, url, header.reqnum, src_rtt); + icpUdpSend(fd, &from, reply, LOG_UDP_MISS, icp_request->protocol); + } + break; + + case ICP_OP_HIT_OBJ: + case ICP_OP_HIT: + case ICP_OP_SECHO: + case ICP_OP_DECHO: + case ICP_OP_MISS: + case ICP_OP_DENIED: + case ICP_OP_MISS_NOFETCH: + if (neighbors_do_private_keys && header.reqnum == 0) { + debug(12, 0) ("icpHandleIcpV2: Neighbor %s returned reqnum = 0\n", + inet_ntoa(from.sin_addr)); + debug(12, 0) ("icpHandleIcpV2: Disabling use of private keys\n"); + neighbors_do_private_keys = 0; + } + url = buf + sizeof(header); + if (header.opcode == ICP_OP_HIT_OBJ) { + data = url + strlen(url) + 1; + xmemcpy((char *) &u, data, sizeof(u_short)); + data += sizeof(u_short); + data_sz = ntohs(u); + if ((int) data_sz > (len - (data - buf))) { + debug(12, 0) ("icpHandleIcpV2: ICP_OP_HIT_OBJ object too small\n"); + break; + } + } + debug(12, 3) ("icpHandleIcpV2: %s from %s for '%s'\n", + IcpOpcodeStr[header.opcode], + inet_ntoa(from.sin_addr), + url); + if (neighbors_do_private_keys && header.reqnum) + key = storeKeyPrivate(url, METHOD_GET, header.reqnum); + else + key = storeKeyPublic(url, METHOD_GET); + debug(12, 3) ("icpHandleIcpV2: Looking for key '%s'\n", + storeKeyText(key)); + if ((entry = storeGet(key)) == NULL) { + debug(12, 3) ("icpHandleIcpV2: Ignoring %s for NULL Entry.\n", + IcpOpcodeStr[header.opcode]); + } else { + /* call neighborsUdpAck even if ping_status != PING_WAITING */ + neighborsUdpAck(fd, + url, + &header, + &from, + entry, + data, + (int) data_sz); + } + break; + + case ICP_OP_INVALID: + case ICP_OP_ERR: + break; + + default: + debug(12, 0) ("icpHandleIcpV2: UNKNOWN OPCODE: %d from %s\n", + header.opcode, inet_ntoa(from.sin_addr)); + break; + } + if (icp_request) + put_free_request_t(icp_request); +} + +#ifdef ICP_PKT_DUMP +static void +icpPktDump(icp_common_t * pkt) +{ + struct in_addr a; + + debug(12, 9) ("opcode: %3d %s\n", + (int) pkt->opcode, + IcpOpcodeStr[pkt->opcode]); + debug(12, 9) ("version: %-8d\n", (int) pkt->version); + debug(12, 9) ("length: %-8d\n", (int) ntohs(pkt->length)); + debug(12, 9) ("reqnum: %-8d\n", ntohl(pkt->reqnum)); + debug(12, 9) ("flags: %-8x\n", ntohl(pkt->flags)); + a.s_addr = ntohl(pkt->shostid); + debug(12, 9) ("shostid: %s\n", inet_ntoa(a)); + debug(12, 9) ("payload: %s\n", (char *) pkt + sizeof(icp_common_t)); +} +#endif + +void +icpHandleUdp(int sock, void *not_used) +{ + struct sockaddr_in from; + int from_len; + LOCAL_ARRAY(char, buf, SQUID_UDP_SO_RCVBUF); + int len; + icp_common_t *headerp = NULL; + int icp_version; + + commSetSelect(sock, COMM_SELECT_READ, icpHandleUdp, NULL, 0); + from_len = sizeof(from); + memset(&from, '\0', from_len); + len = recvfrom(sock, + buf, + SQUID_UDP_SO_RCVBUF - 1, + 0, + (struct sockaddr *) &from, + &from_len); + if (len < 0) { +#ifdef _SQUID_LINUX_ + /* Some Linux systems seem to set the FD for reading and then + * return ECONNREFUSED when sendto() fails and generates an ICMP + * port unreachable message. */ + /* or maybe an EHOSTUNREACH "No route to host" message */ + if (errno != ECONNREFUSED && errno != EHOSTUNREACH) +#endif + debug(50, 1) ("icpHandleUdp: FD %d recvfrom: %s\n", + sock, xstrerror()); + return; + } + buf[len] = '\0'; + debug(12, 4) ("icpHandleUdp: FD %d: received %d bytes from %s.\n", + sock, + len, + inet_ntoa(from.sin_addr)); +#ifdef ICP_PACKET_DUMP + icpPktDump(buf); +#endif + if (len < sizeof(icp_common_t)) { + debug(12, 4) ("icpHandleUdp: Ignoring too-small UDP packet\n"); + return; + } + headerp = (icp_common_t *) (void *) buf; + if ((icp_version = (int) headerp->version) == ICP_VERSION_2) + icpHandleIcpV2(sock, from, buf, len); + else if (icp_version == ICP_VERSION_3) + icpHandleIcpV3(sock, from, buf, len); + else + debug(12, 0) ("WARNING: Unused ICP version %d received from %s:%d\n", + icp_version, + inet_ntoa(from.sin_addr), + ntohs(from.sin_port)); +} diff --git a/src/icp_v3.cc b/src/icp_v3.cc new file mode 100644 index 0000000000..a6cd0b8ac5 --- /dev/null +++ b/src/icp_v3.cc @@ -0,0 +1,132 @@ +#include "squid.h" + +/* Currently Harvest cached-2.x uses ICP_VERSION_3 */ +void +icpHandleIcpV3(int fd, struct sockaddr_in from, char *buf, int len) +{ + icp_common_t header; + icp_common_t *reply; + icp_common_t *headerp = (icp_common_t *) (void *) buf; + StoreEntry *entry = NULL; + char *url = NULL; + const cache_key *key; + request_t *icp_request = NULL; + int allow = 0; + char *data = NULL; + u_short data_sz = 0; + u_short u; + aclCheck_t checklist; + + header.opcode = headerp->opcode; + header.version = headerp->version; + header.length = ntohs(headerp->length); + header.reqnum = ntohl(headerp->reqnum); + header.flags = ntohl(headerp->flags); + header.shostid = ntohl(headerp->shostid); + + switch (header.opcode) { + case ICP_OP_QUERY: + nudpconn++; + /* We have a valid packet */ + url = buf + sizeof(header) + sizeof(u_num32); + if ((icp_request = urlParse(METHOD_GET, url)) == NULL) { + reply = icpCreateMessage(ICP_OP_ERR, 0, url, header.reqnum, 0); + icpUdpSend(fd, &from, reply, LOG_UDP_INVALID, PROTO_NONE); + break; + } + checklist.src_addr = from.sin_addr; + checklist.request = icp_request; + allow = aclCheckFast(Config.accessList.icp, &checklist); + if (!allow) { + debug(12, 2) ("icpHandleIcpV3: Access Denied for %s by %s.\n", + inet_ntoa(from.sin_addr), AclMatchedName); + if (clientdbDeniedPercent(from.sin_addr) < 95) { + reply = icpCreateMessage(ICP_OP_DENIED, 0, url, header.reqnum, 0); + icpUdpSend(fd, &from, reply, LOG_UDP_DENIED, icp_request->protocol); + } + break; + } + /* The peer is allowed to use this cache */ + key = storeKeyPublic(url, METHOD_GET); + storeGet(key); + debug(12, 5) ("icpHandleIcpV3: OPCODE %s\n", + IcpOpcodeStr[header.opcode]); + if (icpCheckUdpHit(entry, icp_request)) { + reply = icpCreateMessage(ICP_OP_HIT, 0, url, header.reqnum, 0); + icpUdpSend(fd, &from, reply, LOG_UDP_HIT, icp_request->protocol); + break; + } + /* if store is rebuilding, return a UDP_HIT, but not a MISS */ + if (opt_reload_hit_only && store_rebuilding) { + reply = icpCreateMessage(ICP_OP_MISS_NOFETCH, 0, url, header.reqnum, 0); + icpUdpSend(fd, &from, reply, LOG_UDP_MISS_NOFETCH, icp_request->protocol); + } else if (hit_only_mode_until > squid_curtime) { + reply = icpCreateMessage(ICP_OP_MISS_NOFETCH, 0, url, header.reqnum, 0); + icpUdpSend(fd, &from, reply, LOG_UDP_MISS_NOFETCH, icp_request->protocol); + } else { + reply = icpCreateMessage(ICP_OP_MISS, 0, url, header.reqnum, 0); + icpUdpSend(fd, &from, reply, LOG_UDP_MISS, icp_request->protocol); + } + break; + + case ICP_OP_HIT_OBJ: + case ICP_OP_HIT: + case ICP_OP_SECHO: + case ICP_OP_DECHO: + case ICP_OP_MISS: + case ICP_OP_DENIED: + case ICP_OP_MISS_NOFETCH: + if (neighbors_do_private_keys && header.reqnum == 0) { + debug(12, 0) ("icpHandleIcpV3: Neighbor %s returned reqnum = 0\n", + inet_ntoa(from.sin_addr)); + debug(12, 0) ("icpHandleIcpV3: Disabling use of private keys\n"); + neighbors_do_private_keys = 0; + } + url = buf + sizeof(header); + if (header.opcode == ICP_OP_HIT_OBJ) { + data = url + strlen(url) + 1; + xmemcpy((char *) &u, data, sizeof(u_short)); + data += sizeof(u_short); + data_sz = ntohs(u); + if ((int) data_sz > (len - (data - buf))) { + debug(12, 0) ("icpHandleIcpV3: ICP_OP_HIT_OBJ object too small\n"); + break; + } + } + debug(12, 3) ("icpHandleIcpV3: %s from %s for '%s'\n", + IcpOpcodeStr[header.opcode], + inet_ntoa(from.sin_addr), + url); + if (neighbors_do_private_keys && header.reqnum) + key = storeKeyPrivate(url, METHOD_GET, header.reqnum); + else + key = storeKeyPublic(url, METHOD_GET); + debug(12, 3) ("icpHandleIcpV3: Looking for key '%s'\n", + storeKeyText(key)); + if ((entry = storeGet(key)) == NULL) { + debug(12, 3) ("icpHandleIcpV3: Ignoring %s for NULL Entry.\n", + IcpOpcodeStr[header.opcode]); + } else { + /* call neighborsUdpAck even if ping_status != PING_WAITING */ + neighborsUdpAck(fd, + url, + &header, + &from, + entry, + data, + (int) data_sz); + } + break; + + case ICP_OP_INVALID: + case ICP_OP_ERR: + break; + + default: + debug(12, 0) ("icpHandleIcpV3: UNKNOWN OPCODE: %d from %s\n", + header.opcode, inet_ntoa(from.sin_addr)); + break; + } + if (icp_request) + put_free_request_t(icp_request); +} diff --git a/src/main.cc b/src/main.cc index 08ce9dd0d6..bfbbdf06ff 100644 --- a/src/main.cc +++ b/src/main.cc @@ -1,6 +1,6 @@ /* - * $Id: main.cc,v 1.188 1997/11/04 23:29:36 wessels Exp $ + * $Id: main.cc,v 1.189 1997/11/05 00:39:55 wessels Exp $ * * DEBUG: section 1 Startup and Main Loop * AUTHOR: Harvest Derived @@ -256,6 +256,7 @@ mainParseOptions(int argc, char *argv[]) } } +/* ARGSUSED */ static void rotate_logs(int sig) { @@ -279,6 +280,7 @@ time_tick(int sig) #endif +/* ARGSUSED */ static void reconfigure(int sig) { @@ -525,6 +527,7 @@ mainInitialize(void) redirectOpenServers(); useragentOpenLog(); errorInitialize(); + accessLogInit(); #if MALLOC_DBG malloc_debug(0, malloc_debug_level); diff --git a/src/protos.h b/src/protos.h index 5da113aec0..b2af4def35 100644 --- a/src/protos.h +++ b/src/protos.h @@ -4,6 +4,7 @@ extern void accessLogLog(AccessLogEntry *); extern void accessLogRotate(void); extern void accessLogClose(void); extern void accessLogOpen(const char *); +extern void accessLogInit(void); extern void hierarchyNote(HierarchyLogEntry *, hier_code, icp_ping_data *, const char *); extern aclCheck_t *aclChecklistCreate(const struct _acl_access *, @@ -241,7 +242,6 @@ extern void icmpPing(struct in_addr to); extern void icmpSourcePing(struct in_addr to, const icp_common_t *, const char *url); extern void icmpDomainPing(struct in_addr to, const char *domain); - extern void *icpCreateMessage(icp_opcode opcode, int flags, const char *url, @@ -264,13 +264,13 @@ extern void icpSendERROR(int fd, clientHttpRequest *, int httpCode); extern void AppendUdp(icpUdpData *); -extern void icpParseRequestHeaders(clientHttpRequest *); -extern void icpProcessRequest(int, clientHttpRequest *); extern PF icpUdpReply; -extern ERCB icpErrorComplete; -extern STCB icpSendMoreData; -extern STCB clientCacheHit; - +extern void icpHandleIcpV3(int, struct sockaddr_in, char *, int); +extern int icpCheckUdpHit(StoreEntry *, request_t * request); +#if USE_ICP_HIT_OBJ +extern int icpCheckUdpHitObj(StoreEntry * e, request_t * r, icp_common_t * h, int len); +extern void *icpCreateHitObjMessage(icp_opcode, int, const char *, int, int, StoreEntry *); +#endif extern void ipcache_nbgethostbyname(const char *name, IPH * handler,