--------------------- PatchSet 6465 Date: 2005/03/03 03:47:08 Author: hno Branch: lfs-2_5 Tag: (none) Log: Restored corrupt file Members: src/htcp.c:1.9.2.5.2.2->1.9.2.5.2.3 Index: squid/src/htcp.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/htcp.c,v retrieving revision 1.9.2.5.2.2 retrieving revision 1.9.2.5.2.3 diff -u -r1.9.2.5.2.2 -r1.9.2.5.2.3 --- squid/src/htcp.c 3 Mar 2005 03:44:04 -0000 1.9.2.5.2.2 +++ squid/src/htcp.c 3 Mar 2005 03:47:08 -0000 1.9.2.5.2.3 @@ -1,6 +1,6 @@ /* - * $Id: htcp.c,v 1.9.2.5.2.2 2005/03/03 03:44:04 hno Exp $ + * $Id: htcp.c,v 1.9.2.5.2.3 2005/03/03 03:47:08 hno Exp $ * * DEBUG: section 31 Hypertext Caching Protocol * AUTHOR: Duane Wesssels @@ -596,4 +596,389 @@ memBufClean(&mb); httpHeaderClean(&hdr); packerClean(&p); - \ No newline at end of file + } + pkt = htcpBuildPacket(&stuff, &pktlen); + if (pkt == NULL) { + debug(31, 0) ("htcpTstReply: htcpBuildPacket() failed\n"); + return; + } + htcpSend(pkt, (int) pktlen, from); + xfree(pkt); +} + +static void +htcpHandleNop(htcpDataHeader * hdr, char *buf, int sz, struct sockaddr_in *from) +{ + debug(31, 3) ("htcpHandleNop: Unimplemented\n"); +} + +static StoreEntry * +htcpCheckHit(const htcpSpecifier * s) +{ + request_t *request; + method_t m = urlParseMethod(s->method); + StoreEntry *e = NULL, *hit = NULL; + char *blk_end; + request = urlParse(m, s->uri); + if (NULL == request) { + debug(31, 3) ("htcpCheckHit: NO; failed to parse URL\n"); + return NULL; + } + blk_end = s->req_hdrs + strlen(s->req_hdrs); + if (!httpHeaderParse(&request->header, s->req_hdrs, blk_end)) { + debug(31, 3) ("htcpCheckHit: NO; failed to parse request headers\n"); + goto miss; + } + e = storeGetPublicByRequest(request); + if (NULL == e) { + debug(31, 3) ("htcpCheckHit: NO; public object not found\n"); + goto miss; + } + if (!storeEntryValidToSend(e)) { + debug(31, 3) ("htcpCheckHit: NO; entry not valid to send\n"); + goto miss; + } + if (refreshCheckHTCP(e, request)) { + debug(31, 3) ("htcpCheckHit: NO; cached response is stale\n"); + goto miss; + } + debug(31, 3) ("htcpCheckHit: YES!?\n"); + hit = e; + miss: + requestDestroy(request); + return hit; +} + +static void +htcpHandleTst(htcpDataHeader * hdr, char *buf, int sz, struct sockaddr_in *from) +{ + debug(31, 3) ("htcpHandleTst: sz = %d\n", (int) sz); + if (hdr->RR == RR_REQUEST) + htcpHandleTstRequest(hdr, buf, sz, from); + else + htcpHandleTstResponse(hdr, buf, sz, from); +} + +static void +htcpHandleTstResponse(htcpDataHeader * hdr, char *buf, int sz, struct sockaddr_in *from) +{ + htcpReplyData htcpReply; + cache_key *key = NULL; + htcpDetail *d = NULL; + char *t; + if (hdr->F1 == 1) { + debug(31, 1) ("htcpHandleTstResponse: error condition, F1/MO == 1\n"); + return; + } + memset(&htcpReply, '\0', sizeof(htcpReply)); + httpHeaderInit(&htcpReply.hdr, hoHtcpReply); + htcpReply.msg_id = hdr->msg_id; + debug(31, 3) ("htcpHandleTstResponse: msg_id = %d\n", (int) htcpReply.msg_id); + htcpReply.hit = hdr->response ? 0 : 1; + if (hdr->F1) { + debug(31, 3) ("htcpHandleTstResponse: MISS\n"); + } else { + debug(31, 3) ("htcpHandleTstResponse: HIT\n"); + d = htcpUnpackDetail(buf, sz); + if (d == NULL) { + debug(31, 1) ("htcpHandleTstResponse: bad DETAIL\n"); + return; + } + if ((t = d->resp_hdrs)) + httpHeaderParse(&htcpReply.hdr, t, t + strlen(t)); + if ((t = d->entity_hdrs)) + httpHeaderParse(&htcpReply.hdr, t, t + strlen(t)); + if ((t = d->cache_hdrs)) + httpHeaderParse(&htcpReply.hdr, t, t + strlen(t)); + } + key = queried_keys[htcpReply.msg_id % N_QUERIED_KEYS]; + debug(31, 3) ("htcpHandleTstResponse: key (%p) %s\n", key, storeKeyText(key)); + neighborsHtcpReply(key, &htcpReply, from); + httpHeaderClean(&htcpReply.hdr); + if (d) + htcpFreeDetail(d); +} + +static void +htcpHandleTstRequest(htcpDataHeader * dhdr, char *buf, int sz, struct sockaddr_in *from) +{ + /* buf should be a SPECIFIER */ + htcpSpecifier *s; + StoreEntry *e; + if (sz == 0) { + debug(31, 3) ("htcpHandleTst: nothing to do\n"); + return; + } + if (dhdr->F1 == 0) + return; + s = htcpUnpackSpecifier(buf, sz); + if (NULL == s) { + debug(31, 3) ("htcpHandleTstRequest: htcpUnpackSpecifier failed\n"); + return; + } + debug(31, 3) ("htcpHandleTstRequest: %s %s %s\n", + s->method, + s->uri, + s->version); + debug(31, 3) ("htcpHandleTstRequest: %s\n", s->req_hdrs); + if ((e = htcpCheckHit(s))) + htcpTstReply(dhdr, e, s, from); /* hit */ + else + htcpTstReply(dhdr, NULL, NULL, from); /* cache miss */ + htcpFreeSpecifier(s); +} + +static void +htcpHandleMon(htcpDataHeader * hdr, char *buf, int sz, struct sockaddr_in *from) +{ + debug(31, 3) ("htcpHandleMon: Unimplemented\n"); +} + +static void +htcpHandleSet(htcpDataHeader * hdr, char *buf, int sz, struct sockaddr_in *from) +{ + debug(31, 3) ("htcpHandleSet: Unimplemented\n"); +} + +static void +htcpHandleData(char *buf, int sz, struct sockaddr_in *from) +{ + htcpDataHeader hdr; + if (sz < sizeof(htcpDataHeader)) { + debug(31, 0) ("htcpHandleData: msg size less than htcpDataHeader size\n"); + return; + } + xmemcpy(&hdr, buf, sizeof(htcpDataHeader)); + hdr.length = ntohs(hdr.length); + hdr.msg_id = ntohl(hdr.msg_id); + debug(31, 3) ("htcpHandleData: sz = %d\n", sz); + debug(31, 3) ("htcpHandleData: length = %d\n", (int) hdr.length); + if (hdr.opcode >= HTCP_END) { + debug(31, 0) ("htcpHandleData: client %s, opcode %d out of range\n", + inet_ntoa(from->sin_addr), + (int) hdr.opcode); + return; + } + debug(31, 3) ("htcpHandleData: opcode = %d %s\n", + (int) hdr.opcode, htcpOpcodeStr[hdr.opcode]); + debug(31, 3) ("htcpHandleData: response = %d\n", (int) hdr.response); + debug(31, 3) ("htcpHandleData: F1 = %d\n", (int) hdr.F1); + debug(31, 3) ("htcpHandleData: RR = %d\n", (int) hdr.RR); + debug(31, 3) ("htcpHandleData: msg_id = %d\n", (int) hdr.msg_id); + if (sz < hdr.length) { + debug(31, 0) ("htcpHandle: sz < hdr.length\n"); + return; + } + /* + * set sz = hdr.length so we ignore any AUTH fields following + * the DATA. + */ + sz = (int) hdr.length; + buf += sizeof(htcpDataHeader); + sz -= sizeof(htcpDataHeader); + debug(31, 3) ("htcpHandleData: sz = %d\n", sz); + htcpHexdump("htcpHandleData", buf, sz); + switch (hdr.opcode) { + case HTCP_NOP: + htcpHandleNop(&hdr, buf, sz, from); + break; + case HTCP_TST: + htcpHandleTst(&hdr, buf, sz, from); + break; + case HTCP_MON: + htcpHandleMon(&hdr, buf, sz, from); + break; + case HTCP_SET: + htcpHandleSet(&hdr, buf, sz, from); + break; + case HTCP_CLR: + debug(31, 1) ("htcpHandleData: client %s, CLR not supported\n", + inet_ntoa(from->sin_addr)); + break; + default: + assert(0); + break; + } +} + +static void +htcpHandle(char *buf, int sz, struct sockaddr_in *from) +{ + htcpHeader htcpHdr; + if (sz < sizeof(htcpHeader)) { + debug(31, 0) ("htcpHandle: msg size less than htcpHeader size\n"); + return; + } + htcpHexdump("htcpHandle", buf, sz); + xmemcpy(&htcpHdr, buf, sizeof(htcpHeader)); + htcpHdr.length = ntohs(htcpHdr.length); + debug(31, 3) ("htcpHandle: htcpHdr.length = %d\n", (int) htcpHdr.length); + debug(31, 3) ("htcpHandle: htcpHdr.major = %d\n", (int) htcpHdr.major); + debug(31, 3) ("htcpHandle: htcpHdr.minor = %d\n", (int) htcpHdr.minor); + if (sz != htcpHdr.length) { + debug(31, 1) ("htcpHandle: sz/%d != htcpHdr.length/%d from %s:%d\n", + sz, htcpHdr.length, + inet_ntoa(from->sin_addr), (int) ntohs(from->sin_port)); + return; + } + buf += sizeof(htcpHeader); + sz -= sizeof(htcpHeader); + htcpHandleData(buf, sz, from); +} + +static void +htcpRecv(int fd, void *data) +{ + static char buf[8192]; + int len; + static struct sockaddr_in from; + socklen_t flen = sizeof(struct sockaddr_in); + memset(&from, '\0', flen); + statCounter.syscalls.sock.recvfroms++; + len = recvfrom(fd, buf, 8192, 0, (struct sockaddr *) &from, &flen); + debug(31, 3) ("htcpRecv: FD %d, %d bytes from %s:%d\n", + fd, len, inet_ntoa(from.sin_addr), ntohs(from.sin_port)); + htcpHandle(buf, len, &from); + commSetSelect(fd, COMM_SELECT_READ, htcpRecv, NULL, 0); +} + +/* + * ====================================================================== + * PUBLIC FUNCTIONS + * ====================================================================== + */ + +void +htcpInit(void) +{ + if (Config.Port.htcp <= 0) { + debug(31, 1) ("HTCP Disabled.\n"); + return; + } + enter_suid(); + htcpInSocket = comm_open(SOCK_DGRAM, + 0, + Config.Addrs.udp_incoming, + Config.Port.htcp, + COMM_NONBLOCKING, + "HTCP Socket"); + leave_suid(); + if (htcpInSocket < 0) + fatal("Cannot open HTCP Socket"); + commSetSelect(htcpInSocket, COMM_SELECT_READ, htcpRecv, NULL, 0); + debug(31, 1) ("Accepting HTCP messages on port %d, FD %d.\n", + (int) Config.Port.htcp, htcpInSocket); + if (Config.Addrs.udp_outgoing.s_addr != no_addr.s_addr) { + enter_suid(); + htcpOutSocket = comm_open(SOCK_DGRAM, + 0, + Config.Addrs.udp_outgoing, + Config.Port.htcp, + COMM_NONBLOCKING, + "Outgoing HTCP Socket"); + leave_suid(); + if (htcpOutSocket < 0) + fatal("Cannot open Outgoing HTCP Socket"); + commSetSelect(htcpOutSocket, COMM_SELECT_READ, htcpRecv, NULL, 0); + debug(31, 1) ("Outgoing HTCP messages on port %d, FD %d.\n", + (int) Config.Port.htcp, htcpOutSocket); + fd_note(htcpInSocket, "Incoming HTCP socket"); + } else { + htcpOutSocket = htcpInSocket; + } + if (!htcpSpecifierPool) { + htcpSpecifierPool = memPoolCreate("htcpSpecifier", sizeof(htcpSpecifier)); + htcpDetailPool = memPoolCreate("htcpDetail", sizeof(htcpDetail)); + } +} + +void +htcpQuery(StoreEntry * e, request_t * req, peer * p) +{ + cache_key *save_key; + char *pkt; + squid_off_t pktlen; + char vbuf[32]; + htcpStuff stuff; + HttpHeader hdr; + Packer pa; + MemBuf mb; + http_state_flags flags; + + if (htcpInSocket < 0) + return; + + memset(&flags, '\0', sizeof(flags)); + snprintf(vbuf, sizeof(vbuf), "%d/%d", + req->http_ver.major, req->http_ver.minor); + stuff.op = HTCP_TST; + stuff.rr = RR_REQUEST; + stuff.f1 = 1; + stuff.response = 0; + stuff.msg_id = ++msg_id_counter; + stuff.S.method = (char *) RequestMethodStr[req->method]; + stuff.S.uri = (char *) storeUrl(e); + stuff.S.version = vbuf; + httpBuildRequestHeader(req, req, e, &hdr, flags); + memBufDefInit(&mb); + packerToMemInit(&pa, &mb); + httpHeaderPackInto(&hdr, &pa); + httpHeaderClean(&hdr); + packerClean(&pa); + stuff.S.req_hdrs = mb.buf; + pkt = htcpBuildPacket(&stuff, &pktlen); + memBufClean(&mb); + if (pkt == NULL) { + debug(31, 0) ("htcpQuery: htcpBuildPacket() failed\n"); + return; + } + htcpSend(pkt, (int) pktlen, &p->in_addr); + save_key = queried_keys[stuff.msg_id % N_QUERIED_KEYS]; + storeKeyCopy(save_key, e->hash.key); + debug(31, 3) ("htcpQuery: key (%p) %s\n", save_key, storeKeyText(save_key)); + xfree(pkt); +} + +/* + * htcpSocketShutdown only closes the 'in' socket if it is + * different than the 'out' socket. + */ +void +htcpSocketShutdown(void) +{ + if (htcpInSocket < 0) + return; + if (htcpInSocket != htcpOutSocket) { + debug(12, 1) ("FD %d Closing HTCP socket\n", htcpInSocket); + comm_close(htcpInSocket); + } + /* + * Here we set 'htcpInSocket' to -1 even though the HTCP 'in' + * and 'out' sockets might be just one FD. This prevents this + * function from executing repeatedly. When we are really ready to + * exit or restart, main will comm_close the 'out' descriptor. + */ + htcpInSocket = -1; + /* + * Normally we only write to the outgoing HTCP socket, but + * we also have a read handler there to catch messages sent + * to that specific interface. During shutdown, we must + * disable reading on the outgoing socket. + */ + /* XXX Don't we need this handler to read replies while shutting down? + * I think there should be a separate hander for reading replies.. + */ + assert(htcpOutSocket > -1); + commSetSelect(htcpOutSocket, COMM_SELECT_READ, NULL, NULL, 0); +} + +void +htcpSocketClose(void) +{ + htcpSocketShutdown(); + if (htcpOutSocket > -1) { + debug(12, 1) ("FD %d Closing HTCP socket\n", htcpOutSocket); + comm_close(htcpOutSocket); + htcpOutSocket = -1; + } +}