static int peerCheckNetdbDirect(ps_state * psstate) { peer *p; int myrtt; int myhops; if (psstate->direct == DIRECT_NO) return 0; myrtt = netdbHostRtt(psstate->request->host); debug(44, 3) ("peerCheckNetdbDirect: MY RTT = %d msec\n", myrtt); debug(44, 3) ("peerCheckNetdbDirect: minimum_direct_rtt = %d msec\n", Config.minDirectRtt); if (myrtt && myrtt <= Config.minDirectRtt) return 1; myhops = netdbHostHops(psstate->request->host); debug(44, 3) ("peerCheckNetdbDirect: MY hops = %d\n", myhops); debug(44, 3) ("peerCheckNetdbDirect: minimum_direct_hops = %d\n", Config.minDirectHops); if (myhops && myhops <= Config.minDirectHops) return 1; p = whichPeer(&psstate->closest_parent_miss); if (p == NULL) return 0; debug(44, 3) ("peerCheckNetdbDirect: closest_parent_miss RTT = %d msec\n", psstate->ping.p_rtt); if (myrtt && myrtt <= psstate->ping.p_rtt) return 1; return 0; }
/* select best peer based on cache digests */ peer * neighborsDigestSelect(request_t * request) { peer *best_p = NULL; #if USE_CACHE_DIGESTS const cache_key *key; int best_rtt = 0; int choice_count = 0; int ichoice_count = 0; peer *p; int p_rtt; int i; if (!request->flags.hierarchical) return NULL; key = storeKeyPublicByRequest(request); for (i = 0, p = first_ping; i++ < Config.npeers; p = p->next) { lookup_t lookup; if (!p) p = Config.peers; if (i == 1) first_ping = p; lookup = peerDigestLookup(p, request); if (lookup == LOOKUP_NONE) continue; choice_count++; if (lookup == LOOKUP_MISS) continue; p_rtt = netdbHostRtt(p->host); debug(15, 5) ("neighborsDigestSelect: peer %s rtt: %d\n", p->name, p_rtt); /* is this peer better than others in terms of rtt ? */ if (!best_p || (p_rtt && p_rtt < best_rtt)) { best_p = p; best_rtt = p_rtt; if (p_rtt) /* informative choice (aka educated guess) */ ichoice_count++; debug(15, 4) ("neighborsDigestSelect: peer %s leads with rtt %d\n", p->name, best_rtt); } } debug(15, 4) ("neighborsDigestSelect: choices: %d (%d)\n", choice_count, ichoice_count); peerNoteDigestLookup(request, best_p, best_p ? LOOKUP_HIT : (choice_count ? LOOKUP_MISS : LOOKUP_NONE)); request->hier.n_choices = choice_count; request->hier.n_ichoices = ichoice_count; #endif return best_p; }
static url_entry * urnParseReply(const char *inbuf, method_t m) { char *buf = xstrdup(inbuf); char *token; char *url; char *host; int rtt; url_entry *list; url_entry *old; int n = 32; int i = 0; debug(52, 3) ("urnParseReply\n"); list = xcalloc(n + 1, sizeof(*list)); for (token = strtok(buf, crlf); token; token = strtok(NULL, crlf)) { debug(52, 3) ("urnParseReply: got '%s'\n", token); if (i == n) { old = list; n <<= 2; list = xcalloc(n + 1, sizeof(*list)); xmemcpy(list, old, i * sizeof(*list)); safe_free(old); } url = xstrdup(token); host = urlHostname(url); if (NULL == host) continue; rtt = netdbHostRtt(host); if (0 == rtt) { debug(52, 3) ("urnParseReply: Pinging %s\n", host); netdbPingSite(host); } list[i].url = url; list[i].host = xstrdup(host); list[i].rtt = rtt; list[i].flags.cached = storeGetPublic(url, m) ? 1 : 0; i++; } debug(52, 3) ("urnParseReply: Found %d URLs\n", i); return list; }
static void icpHandleIcpV2(int fd, struct sockaddr_in from, char *buf, int len) { icp_common_t header; StoreEntry *entry = NULL; char *url = NULL; const cache_key *key; request_t *icp_request = NULL; int allow = 0; aclCheck_t checklist; icp_common_t *reply; int src_rtt = 0; u_num32 flags = 0; int rtt = 0; int hops = 0; xmemcpy(&header, buf, sizeof(icp_common_t)); /* * Only these fields need to be converted */ header.length = ntohs(header.length); header.reqnum = ntohl(header.reqnum); header.flags = ntohl(header.flags); header.pad = ntohl(header.pad); /* * Length field should match the number of bytes read */ if (len != header.length) { debug(12, 3) ("icpHandleIcpV2: ICP message is too small\n"); return; } switch (header.opcode) { case ICP_QUERY: /* We have a valid packet */ url = buf + sizeof(icp_common_t) + sizeof(u_num32); if (strpbrk(url, w_space)) { url = rfc1738_escape(url); reply = icpCreateMessage(ICP_ERR, 0, url, header.reqnum, 0); icpUdpSend(fd, &from, reply, LOG_UDP_INVALID, 0); break; } if ((icp_request = urlParse(METHOD_GET, url)) == NULL) { reply = icpCreateMessage(ICP_ERR, 0, url, header.reqnum, 0); icpUdpSend(fd, &from, reply, LOG_UDP_INVALID, 0); break; } memset(&checklist, '\0', sizeof(checklist)); checklist.src_addr = from.sin_addr; checklist.my_addr = no_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 (clientdbCutoffDenied(from.sin_addr)) { /* * count this DENIED query in the clientdb, even though * we're not sending an ICP reply... */ clientdbUpdate(from.sin_addr, LOG_UDP_DENIED, PROTO_ICP, 0); } else { reply = icpCreateMessage(ICP_DENIED, 0, url, header.reqnum, 0); icpUdpSend(fd, &from, reply, LOG_UDP_DENIED, 0); } break; } if (header.flags & ICP_FLAG_SRC_RTT) { rtt = netdbHostRtt(icp_request->host); 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 */ entry = storeGetPublic(url, METHOD_GET); debug(12, 5) ("icpHandleIcpV2: OPCODE %s\n", icp_opcode_str[header.opcode]); if (icpCheckUdpHit(entry, icp_request)) { reply = icpCreateMessage(ICP_HIT, flags, url, header.reqnum, src_rtt); icpUdpSend(fd, &from, reply, LOG_UDP_HIT, 0); break; } if (Config.onoff.test_reachability && rtt == 0) { if ((rtt = netdbHostRtt(icp_request->host)) == 0) netdbPingSite(icp_request->host); } /* if store is rebuilding, return a UDP_HIT, but not a MISS */ if (store_dirs_rebuilding && opt_reload_hit_only) { reply = icpCreateMessage(ICP_MISS_NOFETCH, flags, url, header.reqnum, src_rtt); icpUdpSend(fd, &from, reply, LOG_UDP_MISS_NOFETCH, 0); } else if (hit_only_mode_until > squid_curtime) { reply = icpCreateMessage(ICP_MISS_NOFETCH, flags, url, header.reqnum, src_rtt); icpUdpSend(fd, &from, reply, LOG_UDP_MISS_NOFETCH, 0); } else if (Config.onoff.test_reachability && rtt == 0) { reply = icpCreateMessage(ICP_MISS_NOFETCH, flags, url, header.reqnum, src_rtt); icpUdpSend(fd, &from, reply, LOG_UDP_MISS_NOFETCH, 0); } else { reply = icpCreateMessage(ICP_MISS, flags, url, header.reqnum, src_rtt); icpUdpSend(fd, &from, reply, LOG_UDP_MISS, 0); } break; case ICP_HIT: #if ALLOW_SOURCE_PING case ICP_SECHO: #endif case ICP_DECHO: case ICP_MISS: case ICP_DENIED: case ICP_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(icp_common_t); debug(12, 3) ("icpHandleIcpV2: %s from %s for '%s'\n", icp_opcode_str[header.opcode], inet_ntoa(from.sin_addr), url); key = icpGetCacheKey(url, (int) header.reqnum); /* call neighborsUdpAck even if ping_status != PING_WAITING */ neighborsUdpAck(key, &header, &from); break; case ICP_INVALID: case ICP_ERR: break; default: debug(12, 0) ("icpHandleIcpV2: UNKNOWN OPCODE: %d from %s\n", header.opcode, inet_ntoa(from.sin_addr)); break; } if (icp_request) requestDestroy(icp_request); }