/* Return TRUE if it is okay to send an ICP request to this peer. */ static int peerWouldBePinged(const peer * p, request_t * request) { if (!peerAllowedToUse(p, request)) return 0; if (p->options.no_query) return 0; if (p->options.mcast_responder) return 0; if (p->n_addresses == 0) return 0; if (p->icp.port == 0) return 0; /* the case below seems strange, but can happen if the * URL host is on the other side of a firewall */ if (p->type == PEER_SIBLING) if (!request->flags.hierarchical) return 0; /* Ping dead peers every timeout interval */ if (squid_curtime - p->stats.last_query > Config.Timeout.deadPeer) return 1; if (!neighborUp(p)) return 0; return 1; }
/* Return TRUE if it is okay to send an HTTP request to this peer. */ int peerHTTPOkay(const peer * p, request_t * request) { if (!peerAllowedToUse(p, request)) return 0; if (!neighborUp(p)) return 0; if (p->max_conn) if (p->stats.conn_open >= p->max_conn) return 0; return 1; }
peer * getFirstUpParent(request_t * request) { peer *p = NULL; for (p = Config.peers; p; p = p->next) { if (!neighborUp(p)) continue; if (neighborType(p, request) != PEER_PARENT) continue; if (!peerHTTPOkay(p, request)) continue; break; } debug(15, 3) ("getFirstUpParent: returning %s\n", p ? p->name : "NULL"); return p; }
peer * carpSelectParent(request_t * request) { #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> ((sizeof(u_long)*8)-(n)))) const char *c; peer *p = NULL; peer *tp; unsigned long url_hash = 0; unsigned long combined_hash; unsigned long high_score = 0; const char *url = urlCanonical(request); /* calculate url hash */ debug(39, 2) ("carpSelectParent: CARP Calculating hash for %s\n", url); for (c = url; *c != 0; c++) url_hash += ROTATE_LEFT(url_hash, 19) + *c; /* select peer */ for (tp = Config.peers; tp; tp = tp->next) { if (0.0 == tp->carp.load_factor) continue; if (tp->tcp_up != PEER_TCP_MAGIC_COUNT) continue; assert(tp->type == PEER_PARENT); combined_hash = (url_hash ^ tp->carp.hash); combined_hash += combined_hash * 0x62531965; combined_hash = ROTATE_LEFT(combined_hash, 21); combined_hash = combined_hash * tp->carp.load_multiplier; debug(39, 3) ("carpSelectParent: %s combined_hash %d\n", tp->host, combined_hash); if ((combined_hash > high_score) && neighborUp(tp)) { p = tp; high_score = combined_hash; } } if (p) debug(39, 3) ("carpSelectParent: selected CARP %s\n", p->host); return p; }
int neighborsUdpPing(request_t * request, StoreEntry * entry, IRCB * callback, void *callback_data, int *exprep, int *timeout) { const char *url = storeUrl(entry); MemObject *mem = entry->mem_obj; peer *p = NULL; int i; int reqnum = 0; int flags; icp_common_t *query; int queries_sent = 0; int peers_pinged = 0; int parent_timeout = 0, parent_exprep = 0; int sibling_timeout = 0, sibling_exprep = 0; int mcast_timeout = 0, mcast_exprep = 0; if (Config.peers == NULL) return 0; if (theOutIcpConnection < 0) fatal("neighborsUdpPing: There is no ICP socket!"); assert(entry->swap_status == SWAPOUT_NONE); mem->start_ping = current_time; mem->ping_reply_callback = callback; mem->ircb_data = callback_data; reqnum = icpSetCacheKey(entry->hash.key); for (i = 0, p = first_ping; i++ < Config.npeers; p = p->next) { if (p == NULL) p = Config.peers; debug(15, 5) ("neighborsUdpPing: Peer %s\n", p->name); if (!peerWouldBePinged(p, request)) continue; /* next peer */ peers_pinged++; debug(15, 4) ("neighborsUdpPing: pinging peer %s for '%s'\n", p->name, url); if (p->type == PEER_MULTICAST) mcastSetTtl(theOutIcpConnection, p->mcast.ttl); debug(15, 3) ("neighborsUdpPing: key = '%s'\n", storeKeyText(entry->hash.key)); debug(15, 3) ("neighborsUdpPing: reqnum = %d\n", reqnum); #if USE_HTCP if (p->options.htcp && !p->options.htcp_only_clr) { debug(15, 3) ("neighborsUdpPing: sending HTCP query\n"); htcpQuery(entry, request, p); } else #endif if (p->icp.port == echo_port) { debug(15, 4) ("neighborsUdpPing: Looks like a dumb cache, send DECHO ping\n"); echo_hdr.reqnum = reqnum; query = icpCreateMessage(ICP_DECHO, 0, url, reqnum, 0); icpUdpSend(theOutIcpConnection, &p->in_addr, query, LOG_ICP_QUERY, 0); } else { flags = 0; if (Config.onoff.query_icmp) if (p->icp.version == ICP_VERSION_2) flags |= ICP_FLAG_SRC_RTT; query = icpCreateMessage(ICP_QUERY, flags, url, reqnum, 0); icpUdpSend(theOutIcpConnection, &p->in_addr, query, LOG_ICP_QUERY, 0); } queries_sent++; p->stats.pings_sent++; if (p->type == PEER_MULTICAST) { mcast_exprep += p->mcast.n_replies_expected; mcast_timeout += (p->stats.rtt * p->mcast.n_replies_expected); } else if (neighborUp(p)) { /* its alive, expect a reply from it */ if (neighborType(p, request) == PEER_PARENT) { parent_exprep++; parent_timeout += p->stats.rtt; } else { sibling_exprep++; sibling_timeout += p->stats.rtt; } } else { /* Neighbor is dead; ping it anyway, but don't expect a reply */ /* log it once at the threshold */ if (p->stats.logged_state == PEER_ALIVE) { debug(15, 1) ("Detected DEAD %s: %s\n", neighborTypeStr(p), p->name); p->stats.logged_state = PEER_DEAD; } } p->stats.last_query = squid_curtime; /* * keep probe_start == 0 for a multicast peer, * so neighborUp() never says this peer is dead. */ if ((p->type != PEER_MULTICAST) && (p->stats.probe_start == 0)) p->stats.probe_start = squid_curtime; } if ((first_ping = first_ping->next) == NULL) first_ping = Config.peers; #if ALLOW_SOURCE_PING /* only do source_ping if we have neighbors */ if (Config.npeers) { const ipcache_addrs *ia = NULL; struct sockaddr_in to_addr; char *host = request->host; if (!Config.onoff.source_ping) { debug(15, 6) ("neighborsUdpPing: Source Ping is disabled.\n"); } else if ((ia = ipcache_gethostbyname(host, 0))) { debug(15, 6) ("neighborsUdpPing: Source Ping: to %s for '%s'\n", host, url); echo_hdr.reqnum = reqnum; if (icmp_sock != -1) { icmpSourcePing(ia->in_addrs[ia->cur], &echo_hdr, url); } else { to_addr.sin_family = AF_INET; to_addr.sin_addr = ia->in_addrs[ia->cur]; to_addr.sin_port = htons(echo_port); query = icpCreateMessage(ICP_SECHO, 0, url, reqnum, 0); icpUdpSend(theOutIcpConnection, &to_addr, query, LOG_ICP_QUERY, 0); } } else { debug(15, 6) ("neighborsUdpPing: Source Ping: unknown host: %s\n", host); } } #endif /* * How many replies to expect? */ *exprep = parent_exprep + sibling_exprep + mcast_exprep; /* * If there is a configured timeout, use it */ if (Config.Timeout.icp_query) *timeout = Config.Timeout.icp_query; else { if (*exprep > 0) { if (parent_exprep) *timeout = 2 * parent_timeout / parent_exprep; else if (mcast_exprep) *timeout = 2 * mcast_timeout / mcast_exprep; else *timeout = 2 * sibling_timeout / sibling_exprep; } else *timeout = 2000; /* 2 seconds */ if (Config.Timeout.icp_query_max) if (*timeout > Config.Timeout.icp_query_max) *timeout = Config.Timeout.icp_query_max; if (*timeout < Config.Timeout.icp_query_min) *timeout = Config.Timeout.icp_query_min; } return peers_pinged; }
static void dump_peers(StoreEntry * sentry, peer * peers) { peer *e = NULL; struct _domain_ping *d = NULL; icp_opcode op; int i; if (peers == NULL) storeAppendPrintf(sentry, "There are no neighbors installed.\n"); for (e = peers; e; e = e->next) { assert(e->host != NULL); storeAppendPrintf(sentry, "\n%-11.11s: %s\n", neighborTypeStr(e), e->name); storeAppendPrintf(sentry, "Host : %s/%d/%d\n", e->host, e->http_port, e->icp.port); storeAppendPrintf(sentry, "Flags :"); dump_peer_options(sentry, e); for (i = 0; i < e->n_addresses; i++) { storeAppendPrintf(sentry, "Address[%d] : %s\n", i, inet_ntoa(e->addresses[i])); } storeAppendPrintf(sentry, "Status : %s\n", neighborUp(e) ? "Up" : "Down"); storeAppendPrintf(sentry, "AVG RTT : %d msec\n", e->stats.rtt); storeAppendPrintf(sentry, "OPEN CONNS : %d\n", e->stats.conn_open); if (!e->options.no_query) { storeAppendPrintf(sentry, "LAST QUERY : %8d seconds ago\n", (int) (squid_curtime - e->stats.last_query)); if (e->stats.last_reply > 0) storeAppendPrintf(sentry, "LAST REPLY : %8d seconds ago\n", (int) (squid_curtime - e->stats.last_reply)); else storeAppendPrintf(sentry, "LAST REPLY : none received\n"); storeAppendPrintf(sentry, "PINGS SENT : %8d\n", e->stats.pings_sent); storeAppendPrintf(sentry, "PINGS ACKED: %8d %3d%%\n", e->stats.pings_acked, percent(e->stats.pings_acked, e->stats.pings_sent)); } storeAppendPrintf(sentry, "FETCHES : %8d %3d%%\n", e->stats.fetches, percent(e->stats.fetches, e->stats.pings_acked)); storeAppendPrintf(sentry, "IGNORED : %8d %3d%%\n", e->stats.ignored_replies, percent(e->stats.ignored_replies, e->stats.pings_acked)); if (!e->options.no_query) { storeAppendPrintf(sentry, "Histogram of PINGS ACKED:\n"); #if USE_HTCP if (e->options.htcp) { storeAppendPrintf(sentry, "\tMisses\t%8d %3d%%\n", e->htcp.counts[0], percent(e->htcp.counts[0], e->stats.pings_acked)); storeAppendPrintf(sentry, "\tHits\t%8d %3d%%\n", e->htcp.counts[1], percent(e->htcp.counts[1], e->stats.pings_acked)); } else { #endif for (op = ICP_INVALID; op < ICP_END; op++) { if (e->icp.counts[op] == 0) continue; storeAppendPrintf(sentry, " %12.12s : %8d %3d%%\n", icp_opcode_str[op], e->icp.counts[op], percent(e->icp.counts[op], e->stats.pings_acked)); } #if USE_HTCP } #endif } if (e->stats.last_connect_failure) { storeAppendPrintf(sentry, "Last failed connect() at: %s\n", mkhttpdlogtime(&(e->stats.last_connect_failure))); } if (e->peer_domain != NULL) { storeAppendPrintf(sentry, "DOMAIN LIST: "); for (d = e->peer_domain; d; d = d->next) { storeAppendPrintf(sentry, "%s%s ", d->do_ping ? null_string : "!", d->domain); } storeAppendPrintf(sentry, "\n"); } storeAppendPrintf(sentry, "keep-alive ratio: %d%%\n", percent(e->stats.n_keepalives_recv, e->stats.n_keepalives_sent)); } }
variable_list * snmp_meshPtblFn(variable_list * Var, snint * ErrP) { variable_list *Answer = NULL; struct in_addr *laddr; char *cp = NULL; peer *p = NULL; int cnt = 0; debug(49, 5) ("snmp_meshPtblFn: peer %d requested!\n", Var->name[LEN_SQ_MESH + 3]); *ErrP = SNMP_ERR_NOERROR; laddr = oid2addr(&Var->name[LEN_SQ_MESH + 3]); for (p = Config.peers; p != NULL; p = p->next, cnt++) if (p->in_addr.sin_addr.s_addr == laddr->s_addr) break; if (p == NULL) { *ErrP = SNMP_ERR_NOSUCHNAME; return NULL; } switch (Var->name[LEN_SQ_MESH + 2]) { case MESH_PTBL_NAME: cp = p->host; Answer = snmp_var_new(Var->name, Var->name_length); Answer->type = ASN_OCTET_STR; Answer->val_len = strlen(cp); Answer->val.string = (u_char *) xstrdup(cp); break; case MESH_PTBL_IP: Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) p->in_addr.sin_addr.s_addr, SMI_IPADDRESS); break; case MESH_PTBL_HTTP: Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) p->http_port, ASN_INTEGER); break; case MESH_PTBL_ICP: Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) p->icp.port, ASN_INTEGER); break; case MESH_PTBL_TYPE: Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) p->type, ASN_INTEGER); break; case MESH_PTBL_STATE: Answer = snmp_var_new_integer(Var->name, Var->name_length, (snint) neighborUp(p), ASN_INTEGER); break; case MESH_PTBL_SENT: Answer = snmp_var_new_integer(Var->name, Var->name_length, p->stats.pings_sent, SMI_COUNTER32); break; case MESH_PTBL_PACKED: Answer = snmp_var_new_integer(Var->name, Var->name_length, p->stats.pings_acked, SMI_COUNTER32); break; case MESH_PTBL_FETCHES: Answer = snmp_var_new_integer(Var->name, Var->name_length, p->stats.fetches, SMI_COUNTER32); break; case MESH_PTBL_RTT: Answer = snmp_var_new_integer(Var->name, Var->name_length, p->stats.rtt, ASN_INTEGER); break; case MESH_PTBL_IGN: Answer = snmp_var_new_integer(Var->name, Var->name_length, p->stats.ignored_replies, SMI_COUNTER32); break; case MESH_PTBL_KEEPAL_S: Answer = snmp_var_new_integer(Var->name, Var->name_length, p->stats.n_keepalives_sent, SMI_COUNTER32); break; case MESH_PTBL_KEEPAL_R: Answer = snmp_var_new_integer(Var->name, Var->name_length, p->stats.n_keepalives_recv, SMI_COUNTER32); break; default: *ErrP = SNMP_ERR_NOSUCHNAME; break; } return Answer; }