net_db.c
上传用户:liugui
上传日期:2007-01-04
资源大小:822k
文件大小:25k
源码类别:

代理服务器

开发平台:

Unix_Linux

  1. /*
  2.  * $Id: net_db.c,v 1.136 1999/01/29 21:28:16 wessels Exp $
  3.  *
  4.  * DEBUG: section 38    Network Measurement Database
  5.  * AUTHOR: Duane Wessels
  6.  *
  7.  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
  8.  * ----------------------------------------------------------
  9.  *
  10.  *  Squid is the result of efforts by numerous individuals from the
  11.  *  Internet community.  Development is led by Duane Wessels of the
  12.  *  National Laboratory for Applied Network Research and funded by the
  13.  *  National Science Foundation.  Squid is Copyrighted (C) 1998 by
  14.  *  Duane Wessels and the University of California San Diego.  Please
  15.  *  see the COPYRIGHT file for full details.  Squid incorporates
  16.  *  software developed and/or copyrighted by other sources.  Please see
  17.  *  the CREDITS file for full details.
  18.  *
  19.  *  This program is free software; you can redistribute it and/or modify
  20.  *  it under the terms of the GNU General Public License as published by
  21.  *  the Free Software Foundation; either version 2 of the License, or
  22.  *  (at your option) any later version.
  23.  *  
  24.  *  This program is distributed in the hope that it will be useful,
  25.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  26.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  27.  *  GNU General Public License for more details.
  28.  *  
  29.  *  You should have received a copy of the GNU General Public License
  30.  *  along with this program; if not, write to the Free Software
  31.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  32.  *
  33.  */
  34. #include "squid.h"
  35. #if USE_ICMP
  36. typedef struct {
  37.     peer *p;
  38.     StoreEntry *e;
  39.     request_t *r;
  40.     off_t seen;
  41.     off_t used;
  42.     size_t buf_sz;
  43.     char *buf;
  44. } netdbExchangeState;
  45. static hash_table *addr_table = NULL;
  46. static hash_table *host_table = NULL;
  47. static struct in_addr networkFromInaddr(struct in_addr a);
  48. static void netdbRelease(netdbEntry * n);
  49. static void netdbHashInsert(netdbEntry * n, struct in_addr addr);
  50. static void netdbHashDelete(const char *key);
  51. static void netdbHostInsert(netdbEntry * n, const char *hostname);
  52. static void netdbHostDelete(const net_db_name * x);
  53. static void netdbPurgeLRU(void);
  54. static netdbEntry *netdbLookupHost(const char *key);
  55. static net_db_peer *netdbPeerByName(const netdbEntry * n, const char *);
  56. static net_db_peer *netdbPeerAdd(netdbEntry * n, peer * e);
  57. static char *netdbPeerName(const char *name);
  58. static IPH netdbSendPing;
  59. static QS sortPeerByRtt;
  60. static QS sortByRtt;
  61. static QS netdbLRU;
  62. static FREE netdbFreeNameEntry;
  63. static FREE netdbFreeNetdbEntry;
  64. static STCB netdbExchangeHandleReply;
  65. static void netdbExchangeDone(void *);
  66. /* We have to keep a local list of peer names.  The Peers structure
  67.  * gets freed during a reconfigure.  We want this database to
  68.  * remain persisitent, so _net_db_peer->peername points into this
  69.  * linked list */
  70. static wordlist *peer_names = NULL;
  71. static void
  72. netdbHashInsert(netdbEntry * n, struct in_addr addr)
  73. {
  74.     xstrncpy(n->network, inet_ntoa(networkFromInaddr(addr)), 16);
  75.     n->key = n->network;
  76.     assert(hash_lookup(addr_table, n->network) == NULL);
  77.     hash_join(addr_table, (hash_link *) n);
  78. }
  79. static void
  80. netdbHashDelete(const char *key)
  81. {
  82.     hash_link *hptr = hash_lookup(addr_table, key);
  83.     if (hptr == NULL) {
  84. debug_trap("netdbHashDelete: key not found");
  85. return;
  86.     }
  87.     hash_remove_link(addr_table, hptr);
  88. }
  89. static void
  90. netdbHostInsert(netdbEntry * n, const char *hostname)
  91. {
  92.     net_db_name *x = memAllocate(MEM_NET_DB_NAME);
  93.     x->name = xstrdup(hostname);
  94.     x->next = n->hosts;
  95.     n->hosts = x;
  96.     x->net_db_entry = n;
  97.     assert(hash_lookup(host_table, hostname) == NULL);
  98.     hash_join(host_table, (hash_link *) x);
  99.     n->link_count++;
  100. }
  101. static void
  102. netdbHostDelete(const net_db_name * x)
  103. {
  104.     netdbEntry *n;
  105.     net_db_name **X;
  106.     assert(x != NULL);
  107.     assert(x->net_db_entry != NULL);
  108.     n = x->net_db_entry;
  109.     n->link_count--;
  110.     for (X = &n->hosts; *X; X = &(*X)->next) {
  111. if (*X == x) {
  112.     *X = x->next;
  113.     break;
  114. }
  115.     }
  116.     hash_remove_link(host_table, (hash_link *) x);
  117.     xfree(x->name);
  118.     memFree((void *) x, MEM_NET_DB_NAME);
  119. }
  120. static netdbEntry *
  121. netdbLookupHost(const char *key)
  122. {
  123.     net_db_name *x = (net_db_name *) hash_lookup(host_table, key);
  124.     return x ? x->net_db_entry : NULL;
  125. }
  126. static void
  127. netdbRelease(netdbEntry * n)
  128. {
  129.     net_db_name *x;
  130.     net_db_name *next;
  131.     for (x = n->hosts; x; x = next) {
  132. next = x->next;
  133. netdbHostDelete(x);
  134.     }
  135.     n->hosts = NULL;
  136.     safe_free(n->peers);
  137.     n->peers = NULL;
  138.     n->n_peers = 0;
  139.     n->n_peers_alloc = 0;
  140.     if (n->link_count == 0) {
  141. netdbHashDelete(n->network);
  142. memFree(n, MEM_NETDBENTRY);
  143.     }
  144. }
  145. static int
  146. netdbLRU(const void *A, const void *B)
  147. {
  148.     const netdbEntry *const *n1 = A;
  149.     const netdbEntry *const *n2 = B;
  150.     if ((*n1)->last_use_time > (*n2)->last_use_time)
  151. return (1);
  152.     if ((*n1)->last_use_time < (*n2)->last_use_time)
  153. return (-1);
  154.     return (0);
  155. }
  156. static void
  157. netdbPurgeLRU(void)
  158. {
  159.     netdbEntry *n;
  160.     netdbEntry **list;
  161.     int k = 0;
  162.     int list_count = 0;
  163.     int removed = 0;
  164.     list = xcalloc(memInUse(MEM_NETDBENTRY), sizeof(netdbEntry *));
  165.     hash_first(addr_table);
  166.     while ((n = (netdbEntry *) hash_next(addr_table))) {
  167. assert(list_count < memInUse(MEM_NETDBENTRY));
  168. *(list + list_count) = n;
  169. list_count++;
  170.     }
  171.     qsort((char *) list,
  172. list_count,
  173. sizeof(netdbEntry *),
  174. netdbLRU);
  175.     for (k = 0; k < list_count; k++) {
  176. if (memInUse(MEM_NETDBENTRY) < Config.Netdb.low)
  177.     break;
  178. netdbRelease(*(list + k));
  179. removed++;
  180.     }
  181.     xfree(list);
  182. }
  183. static netdbEntry *
  184. netdbLookupAddr(struct in_addr addr)
  185. {
  186.     netdbEntry *n;
  187.     char *key = inet_ntoa(networkFromInaddr(addr));
  188.     n = (netdbEntry *) hash_lookup(addr_table, key);
  189.     return n;
  190. }
  191. static netdbEntry *
  192. netdbAdd(struct in_addr addr)
  193. {
  194.     netdbEntry *n;
  195.     if (memInUse(MEM_NETDBENTRY) > Config.Netdb.high)
  196. netdbPurgeLRU();
  197.     if ((n = netdbLookupAddr(addr)) == NULL) {
  198. n = memAllocate(MEM_NETDBENTRY);
  199. netdbHashInsert(n, addr);
  200.     }
  201.     return n;
  202. }
  203. static void
  204. netdbSendPing(const ipcache_addrs * ia, void *data)
  205. {
  206.     struct in_addr addr;
  207.     char *hostname = data;
  208.     netdbEntry *n;
  209.     netdbEntry *na;
  210.     net_db_name *x;
  211.     net_db_name **X;
  212.     cbdataUnlock(hostname);
  213.     if (ia == NULL) {
  214. cbdataFree(hostname);
  215. return;
  216.     }
  217.     addr = ia->in_addrs[ia->cur];
  218.     if ((n = netdbLookupHost(hostname)) == NULL) {
  219. n = netdbAdd(addr);
  220. netdbHostInsert(n, hostname);
  221.     } else if ((na = netdbLookupAddr(addr)) != n) {
  222. /*
  223.  *hostname moved from 'network n' to 'network na'!
  224.  */
  225. if (na == NULL)
  226.     na = netdbAdd(addr);
  227. debug(38, 3) ("netdbSendPing: %s moved from %s to %sn",
  228.     hostname, n->network, na->network);
  229. x = (net_db_name *) hash_lookup(host_table, hostname);
  230. if (x == NULL) {
  231.     debug(38, 1) ("netdbSendPing: net_db_name list bug: %s not found", hostname);
  232.     cbdataFree(hostname);
  233.     return;
  234. }
  235. /* remove net_db_name from 'network n' linked list */
  236. for (X = &n->hosts; *X; X = &(*X)->next) {
  237.     if (*X == x) {
  238. *X = x->next;
  239. break;
  240.     }
  241. }
  242. n->link_count--;
  243. /* point to 'network na' from host entry */
  244. x->net_db_entry = na;
  245. /* link net_db_name to 'network na' */
  246. x->next = na->hosts;
  247. na->hosts = x;
  248. na->link_count++;
  249. n = na;
  250.     }
  251.     if (n->next_ping_time <= squid_curtime) {
  252. debug(38, 3) ("netdbSendPing: pinging %sn", hostname);
  253. icmpDomainPing(addr, hostname);
  254. n->pings_sent++;
  255. n->next_ping_time = squid_curtime + Config.Netdb.period;
  256. n->last_use_time = squid_curtime;
  257.     }
  258.     cbdataFree(hostname);
  259. }
  260. static struct in_addr
  261. networkFromInaddr(struct in_addr a)
  262. {
  263.     struct in_addr b;
  264.     b.s_addr = ntohl(a.s_addr);
  265. #if USE_CLASSFUL
  266.     if (IN_CLASSC(b.s_addr))
  267. b.s_addr &= IN_CLASSC_NET;
  268.     else if (IN_CLASSB(b.s_addr))
  269. b.s_addr &= IN_CLASSB_NET;
  270.     else if (IN_CLASSA(b.s_addr))
  271. b.s_addr &= IN_CLASSA_NET;
  272. #else
  273.     /* use /24 for everything */
  274.     b.s_addr &= IN_CLASSC_NET;
  275. #endif
  276.     b.s_addr = htonl(b.s_addr);
  277.     return b;
  278. }
  279. static int
  280. sortByRtt(const void *A, const void *B)
  281. {
  282.     const netdbEntry *const *n1 = A;
  283.     const netdbEntry *const *n2 = B;
  284.     if ((*n1)->rtt > (*n2)->rtt)
  285. return 1;
  286.     else if ((*n1)->rtt < (*n2)->rtt)
  287. return -1;
  288.     else
  289. return 0;
  290. }
  291. static net_db_peer *
  292. netdbPeerByName(const netdbEntry * n, const char *peername)
  293. {
  294.     int i;
  295.     net_db_peer *p = n->peers;
  296.     for (i = 0; i < n->n_peers; i++, p++) {
  297. if (!strcmp(p->peername, peername))
  298.     return p;
  299.     }
  300.     return NULL;
  301. }
  302. static net_db_peer *
  303. netdbPeerAdd(netdbEntry * n, peer * e)
  304. {
  305.     net_db_peer *p;
  306.     net_db_peer *o;
  307.     int osize;
  308.     int i;
  309.     if (n->n_peers == n->n_peers_alloc) {
  310. o = n->peers;
  311. osize = n->n_peers_alloc;
  312. if (n->n_peers_alloc == 0)
  313.     n->n_peers_alloc = 2;
  314. else
  315.     n->n_peers_alloc <<= 1;
  316. debug(38, 3) ("netdbPeerAdd: Growing peer list for '%s' to %dn",
  317.     n->network, n->n_peers_alloc);
  318. n->peers = xcalloc(n->n_peers_alloc, sizeof(net_db_peer));
  319. for (i = 0; i < osize; i++)
  320.     *(n->peers + i) = *(o + i);
  321. if (osize) {
  322.     safe_free(o);
  323. }
  324.     }
  325.     p = n->peers + n->n_peers;
  326.     p->peername = netdbPeerName(e->host);
  327.     n->n_peers++;
  328.     return p;
  329. }
  330. static int
  331. sortPeerByRtt(const void *A, const void *B)
  332. {
  333.     const net_db_peer *p1 = A;
  334.     const net_db_peer *p2 = B;
  335.     if (p1->rtt > p2->rtt)
  336. return 1;
  337.     else if (p1->rtt < p2->rtt)
  338. return -1;
  339.     else
  340. return 0;
  341. }
  342. static void
  343. netdbSaveState(void *foo)
  344. {
  345.     LOCAL_ARRAY(char, path, SQUID_MAXPATHLEN);
  346.     FILE *fp;
  347.     netdbEntry *n;
  348.     net_db_name *x;
  349.     struct timeval start = current_time;
  350.     int count = 0;
  351.     snprintf(path, SQUID_MAXPATHLEN, "%s/netdb_state", storeSwapDir(0));
  352.     fp = fopen(path, "w");
  353.     if (fp == NULL) {
  354. debug(50, 1) ("netdbSaveState: %s: %sn", path, xstrerror());
  355. return;
  356.     }
  357.     hash_first(addr_table);
  358.     while ((n = (netdbEntry *) hash_next(addr_table))) {
  359. if (n->pings_recv == 0)
  360.     continue;
  361. fprintf(fp, "%s %d %d %10.5f %10.5f %d %d",
  362.     n->network,
  363.     n->pings_sent,
  364.     n->pings_recv,
  365.     n->hops,
  366.     n->rtt,
  367.     (int) n->next_ping_time,
  368.     (int) n->last_use_time);
  369. for (x = n->hosts; x; x = x->next)
  370.     fprintf(fp, " %s", x->name);
  371. fprintf(fp, "n");
  372. count++;
  373.     }
  374.     fclose(fp);
  375.     getCurrentTime();
  376.     debug(38, 1) ("NETDB state saved; %d entries, %d msecn",
  377. count, tvSubMsec(start, current_time));
  378.     eventAddIsh("netdbSaveState", netdbSaveState, NULL, 3600.0, 1);
  379. }
  380. static void
  381. netdbReloadState(void)
  382. {
  383.     LOCAL_ARRAY(char, path, SQUID_MAXPATHLEN);
  384.     char *buf;
  385.     char *t;
  386.     FILE *fp;
  387.     netdbEntry *n;
  388.     netdbEntry N;
  389.     struct in_addr addr;
  390.     int count = 0;
  391.     struct timeval start = current_time;
  392.     snprintf(path, SQUID_MAXPATHLEN, "%s/netdb_state", storeSwapDir(0));
  393.     fp = fopen(path, "r");
  394.     if (fp == NULL)
  395. return;
  396.     buf = memAllocate(MEM_4K_BUF);
  397.     while (fgets(buf, 4095, fp)) {
  398. memset(&N, '', sizeof(netdbEntry));
  399. if ((t = strtok(buf, w_space)) == NULL)
  400.     continue;
  401. if (!safe_inet_addr(t, &addr))
  402.     continue;
  403. if (netdbLookupAddr(addr) != NULL) /* no dups! */
  404.     continue;
  405. if ((t = strtok(NULL, w_space)) == NULL)
  406.     continue;
  407. N.pings_sent = atoi(t);
  408. if ((t = strtok(NULL, w_space)) == NULL)
  409.     continue;
  410. N.pings_recv = atoi(t);
  411. if (N.pings_recv == 0)
  412.     continue;
  413. /* give this measurement low weight */
  414. N.pings_sent = 1;
  415. N.pings_recv = 1;
  416. if ((t = strtok(NULL, w_space)) == NULL)
  417.     continue;
  418. N.hops = atof(t);
  419. if ((t = strtok(NULL, w_space)) == NULL)
  420.     continue;
  421. N.rtt = atof(t);
  422. if ((t = strtok(NULL, w_space)) == NULL)
  423.     continue;
  424. N.next_ping_time = (time_t) atoi(t);
  425. if ((t = strtok(NULL, w_space)) == NULL)
  426.     continue;
  427. N.last_use_time = (time_t) atoi(t);
  428. n = memAllocate(MEM_NETDBENTRY);
  429. xmemcpy(n, &N, sizeof(netdbEntry));
  430. netdbHashInsert(n, addr);
  431. while ((t = strtok(NULL, w_space)) != NULL) {
  432.     if (netdbLookupHost(t) != NULL) /* no dups! */
  433. continue;
  434.     netdbHostInsert(n, t);
  435. }
  436. count++;
  437.     }
  438.     memFree(buf, MEM_4K_BUF);
  439.     fclose(fp);
  440.     getCurrentTime();
  441.     debug(38, 1) ("NETDB state reloaded; %d entries, %d msecn",
  442. count, tvSubMsec(start, current_time));
  443. }
  444. static char *
  445. netdbPeerName(const char *name)
  446. {
  447.     wordlist *w;
  448.     for (w = peer_names; w; w = w->next) {
  449. if (!strcmp(w->key, name))
  450.     return w->key;
  451.     }
  452.     w = wordlistAdd(&peer_names, name);
  453.     return w->key;
  454. }
  455. static void
  456. netdbFreeNetdbEntry(void *data)
  457. {
  458.     netdbEntry *n = data;
  459.     safe_free(n->peers);
  460.     memFree(n, MEM_NETDBENTRY);
  461. }
  462. static void
  463. netdbFreeNameEntry(void *data)
  464. {
  465.     net_db_name *x = data;
  466.     xfree(x->name);
  467.     memFree(x, MEM_NET_DB_NAME);
  468. }
  469. static void
  470. netdbExchangeHandleReply(void *data, char *buf, ssize_t size)
  471. {
  472.     netdbExchangeState *ex = data;
  473.     int rec_sz = 0;
  474.     off_t o;
  475.     struct in_addr addr;
  476.     double rtt;
  477.     double hops;
  478.     char *p;
  479.     int j;
  480.     HttpReply *rep;
  481.     size_t hdr_sz;
  482.     int nused = 0;
  483.     rec_sz = 0;
  484.     rec_sz += 1 + sizeof(addr.s_addr);
  485.     rec_sz += 1 + sizeof(int);
  486.     rec_sz += 1 + sizeof(int);
  487.     ex->seen = ex->used + size;
  488.     debug(38, 3) ("netdbExchangeHandleReply: %d bytesn", (int) size);
  489.     if (!cbdataValid(ex->p)) {
  490. debug(38, 3) ("netdbExchangeHandleReply: Peer became invalidn");
  491. netdbExchangeDone(ex);
  492. return;
  493.     }
  494.     debug(38, 3) ("netdbExchangeHandleReply: for '%s:%d'n", ex->p->host, ex->p->http_port);
  495.     p = buf;
  496.     if (0 == ex->used) {
  497. /* skip reply headers */
  498. if ((hdr_sz = headersEnd(p, size))) {
  499.     debug(38, 5) ("netdbExchangeHandleReply: hdr_sz = %dn", hdr_sz);
  500.     rep = ex->e->mem_obj->reply;
  501.     if (0 == rep->sline.status)
  502. httpReplyParse(rep, buf);
  503.     debug(38, 3) ("netdbExchangeHandleReply: reply status %dn",
  504. rep->sline.status);
  505.     if (HTTP_OK != rep->sline.status) {
  506. netdbExchangeDone(ex);
  507. return;
  508.     }
  509.     assert(size >= hdr_sz);
  510.     ex->used += hdr_sz;
  511.     size -= hdr_sz;
  512.     p += hdr_sz;
  513. } else {
  514.     size = 0;
  515. }
  516.     }
  517.     debug(38, 5) ("netdbExchangeHandleReply: start parsing loop, size = %dn",
  518. size);
  519.     while (size >= rec_sz) {
  520. debug(38, 5) ("netdbExchangeHandleReply: in parsing loop, size = %dn",
  521.     size);
  522. addr.s_addr = any_addr.s_addr;
  523. hops = rtt = 0.0;
  524. for (o = 0; o < rec_sz;) {
  525.     switch ((int) *(p + o)) {
  526.     case NETDB_EX_NETWORK:
  527. o++;
  528. xmemcpy(&addr.s_addr, p + o, sizeof(addr.s_addr));
  529. o += sizeof(addr.s_addr);
  530. break;
  531.     case NETDB_EX_RTT:
  532. o++;
  533. xmemcpy(&j, p + o, sizeof(int));
  534. o += sizeof(int);
  535. rtt = (double) ntohl(j) / 1000.0;
  536. break;
  537.     case NETDB_EX_HOPS:
  538. o++;
  539. xmemcpy(&j, p + o, sizeof(int));
  540. o += sizeof(int);
  541. hops = (double) ntohl(j) / 1000.0;
  542. break;
  543.     }
  544. }
  545. if (addr.s_addr != any_addr.s_addr && rtt > 0)
  546.     netdbExchangeUpdatePeer(addr, ex->p, rtt, hops);
  547. assert(o == rec_sz);
  548. ex->used += rec_sz;
  549. size -= rec_sz;
  550. p += rec_sz;
  551. /*
  552.  * This is a fairly cpu-intensive loop, break after adding
  553.  * just a few
  554.  */
  555. if (++nused == 20)
  556.     break;
  557.     }
  558.     debug(38, 3) ("netdbExchangeHandleReply: used %d entries, (x %d bytes) == %d bytes totaln",
  559. nused, rec_sz, nused * rec_sz);
  560.     debug(38, 3) ("netdbExchangeHandleReply: seen %d, used %dn", ex->seen, ex->used);
  561.     if (EBIT_TEST(ex->e->flags, ENTRY_ABORTED)) {
  562. debug(38, 3) ("netdbExchangeHandleReply: ENTRY_ABORTEDn");
  563. netdbExchangeDone(ex);
  564.     } else if (ex->e->store_status == STORE_PENDING) {
  565. debug(38, 3) ("netdbExchangeHandleReply: STORE_PENDINGn");
  566. storeClientCopy(ex->e, ex->seen, ex->used, ex->buf_sz,
  567.     ex->buf, netdbExchangeHandleReply, ex);
  568.     } else if (ex->seen < ex->e->mem_obj->inmem_hi) {
  569. debug(38, 3) ("netdbExchangeHandleReply: ex->e->mem_obj->inmem_hin");
  570. storeClientCopy(ex->e, ex->seen, ex->used, ex->buf_sz,
  571.     ex->buf, netdbExchangeHandleReply, ex);
  572.     } else {
  573. debug(38, 3) ("netdbExchangeHandleReply: Donen");
  574. netdbExchangeDone(ex);
  575.     }
  576. }
  577. static void
  578. netdbExchangeDone(void *data)
  579. {
  580.     netdbExchangeState *ex = data;
  581.     debug(38, 3) ("netdbExchangeDone: %sn", storeUrl(ex->e));
  582.     memFree(ex->buf, MEM_4K_BUF);
  583.     requestUnlink(ex->r);
  584.     storeUnregister(ex->e, ex);
  585.     storeUnlockObject(ex->e);
  586.     cbdataUnlock(ex->p);
  587.     cbdataFree(ex);
  588. }
  589. #endif /* USE_ICMP */
  590. /* PUBLIC FUNCTIONS */
  591. void
  592. netdbInit(void)
  593. {
  594. #if USE_ICMP
  595.     int n;
  596.     if (addr_table)
  597. return;
  598.     n = hashPrime(Config.Netdb.high / 4);
  599.     addr_table = hash_create((HASHCMP *) strcmp, n, hash_string);
  600.     n = hashPrime(3 * Config.Netdb.high / 4);
  601.     host_table = hash_create((HASHCMP *) strcmp, n, hash_string);
  602.     eventAddIsh("netdbSaveState", netdbSaveState, NULL, 3600.0, 1);
  603.     netdbReloadState();
  604.     cachemgrRegister("netdb",
  605. "Network Measurement Database",
  606. netdbDump, 0, 1);
  607. #endif
  608. }
  609. void
  610. netdbPingSite(const char *hostname)
  611. {
  612. #if USE_ICMP
  613.     netdbEntry *n;
  614.     char *h;
  615.     if ((n = netdbLookupHost(hostname)) != NULL)
  616. if (n->next_ping_time > squid_curtime)
  617.     return;
  618.     h = xstrdup(hostname);
  619.     cbdataAdd(h, cbdataXfree, 0);
  620.     cbdataLock(h);
  621.     ipcache_nbgethostbyname(hostname, netdbSendPing, h);
  622. #endif
  623. }
  624. void
  625. netdbHandlePingReply(const struct sockaddr_in *from, int hops, int rtt)
  626. {
  627. #if USE_ICMP
  628.     netdbEntry *n;
  629.     int N;
  630.     debug(38, 3) ("netdbHandlePingReply: from %sn", inet_ntoa(from->sin_addr));
  631.     if ((n = netdbLookupAddr(from->sin_addr)) == NULL)
  632. return;
  633.     N = ++n->pings_recv;
  634.     if (N > 5)
  635. N = 5;
  636.     n->hops = ((n->hops * (N - 1)) + hops) / N;
  637.     n->rtt = ((n->rtt * (N - 1)) + rtt) / N;
  638.     debug(38, 3) ("netdbHandlePingReply: %s; rtt=%5.1f  hops=%4.1fn",
  639. n->network,
  640. n->rtt,
  641. n->hops);
  642. #endif
  643. }
  644. void
  645. netdbFreeMemory(void)
  646. {
  647. #if USE_ICMP
  648.     hashFreeItems(addr_table, netdbFreeNetdbEntry);
  649.     hashFreeMemory(addr_table);
  650.     addr_table = NULL;
  651.     hashFreeItems(host_table, netdbFreeNameEntry);
  652.     hashFreeMemory(host_table);
  653.     host_table = NULL;
  654.     wordlistDestroy(&peer_names);
  655.     peer_names = NULL;
  656. #endif
  657. }
  658. int
  659. netdbHops(struct in_addr addr)
  660. {
  661. #if USE_ICMP
  662.     netdbEntry *n = netdbLookupAddr(addr);
  663.     if (n && n->pings_recv) {
  664. n->last_use_time = squid_curtime;
  665. return (int) (n->hops + 0.5);
  666.     }
  667. #endif
  668.     return 256;
  669. }
  670. void
  671. netdbDump(StoreEntry * sentry)
  672. {
  673. #if USE_ICMP
  674.     netdbEntry *n;
  675.     netdbEntry **list;
  676.     net_db_name *x;
  677.     int k;
  678.     int i;
  679.     int j;
  680.     net_db_peer *p;
  681.     storeAppendPrintf(sentry, "Network DB Statistics:n");
  682.     storeAppendPrintf(sentry, "%-16.16s %9s %7s %5s %sn",
  683. "Network",
  684. "recv/sent",
  685. "RTT",
  686. "Hops",
  687. "Hostnames");
  688.     list = xcalloc(memInUse(MEM_NETDBENTRY), sizeof(netdbEntry *));
  689.     i = 0;
  690.     hash_first(addr_table);
  691.     while ((n = (netdbEntry *) hash_next(addr_table)))
  692. *(list + i++) = n;
  693.     if (i != memInUse(MEM_NETDBENTRY))
  694. debug(38, 0) ("WARNING: netdb_addrs count off, found %d, expected %dn",
  695.     i, memInUse(MEM_NETDBENTRY));
  696.     qsort((char *) list,
  697. i,
  698. sizeof(netdbEntry *),
  699. sortByRtt);
  700.     for (k = 0; k < i; k++) {
  701. n = *(list + k);
  702. storeAppendPrintf(sentry, "%-16.16s %4d/%4d %7.1f %5.1f",
  703.     n->network,
  704.     n->pings_recv,
  705.     n->pings_sent,
  706.     n->rtt,
  707.     n->hops);
  708. for (x = n->hosts; x; x = x->next)
  709.     storeAppendPrintf(sentry, " %s", x->name);
  710. storeAppendPrintf(sentry, "n");
  711. p = n->peers;
  712. for (j = 0; j < n->n_peers; j++, p++) {
  713.     storeAppendPrintf(sentry, "    %-22.22s %7.1f %5.1fn",
  714. p->peername,
  715. p->rtt,
  716. p->hops);
  717. }
  718.     }
  719.     xfree(list);
  720. #else
  721.     storeAppendPrintf(sentry,
  722. "NETDB support not compiled into this Squid cache.n");
  723. #endif
  724. }
  725. int
  726. netdbHostHops(const char *host)
  727. {
  728. #if USE_ICMP
  729.     netdbEntry *n = netdbLookupHost(host);
  730.     if (n) {
  731. n->last_use_time = squid_curtime;
  732. return (int) (n->hops + 0.5);
  733.     }
  734. #endif
  735.     return 0;
  736. }
  737. int
  738. netdbHostRtt(const char *host)
  739. {
  740. #if USE_ICMP
  741.     netdbEntry *n = netdbLookupHost(host);
  742.     if (n) {
  743. n->last_use_time = squid_curtime;
  744. return (int) (n->rtt + 0.5);
  745.     }
  746. #endif
  747.     return 0;
  748. }
  749. void
  750. netdbHostData(const char *host, int *samp, int *rtt, int *hops)
  751. {
  752. #if USE_ICMP
  753.     netdbEntry *n = netdbLookupHost(host);
  754.     if (n == NULL)
  755. return;
  756.     *samp = n->pings_recv;
  757.     *rtt = (int) (n->rtt + 0.5);
  758.     *hops = (int) (n->hops + 0.5);
  759. #endif
  760. }
  761. int
  762. netdbHostPeerRtt(const char *host, peer * p)
  763. {
  764. #if USE_ICMP
  765.     const netdbEntry *n = netdbLookupHost(host);
  766.     if (n) {
  767. const net_db_peer *np = netdbPeerByName(n, p->host);
  768. if (np && np->expires >= squid_curtime)
  769.     return (int) (np->rtt + 0.5);
  770.     }
  771. #endif
  772.     return 0;
  773. }
  774. void
  775. netdbUpdatePeer(request_t * r, peer * e, int irtt, int ihops)
  776. {
  777. #if USE_ICMP
  778.     netdbEntry *n;
  779.     double rtt = (double) irtt;
  780.     double hops = (double) ihops;
  781.     net_db_peer *p;
  782.     debug(38, 3) ("netdbUpdatePeer: '%s', %d hops, %d rttn", r->host, ihops, irtt);
  783.     n = netdbLookupHost(r->host);
  784.     if (n == NULL) {
  785. debug(38, 3) ("netdbUpdatePeer: host '%s' not foundn", r->host);
  786. return;
  787.     }
  788.     if ((p = netdbPeerByName(n, e->host)) == NULL)
  789. p = netdbPeerAdd(n, e);
  790.     p->rtt = rtt;
  791.     p->hops = hops;
  792.     p->expires = squid_curtime + 3600;
  793.     if (n->n_peers < 2)
  794. return;
  795.     qsort((char *) n->peers,
  796. n->n_peers,
  797. sizeof(net_db_peer),
  798. sortPeerByRtt);
  799. #endif
  800. }
  801. void
  802. netdbExchangeUpdatePeer(struct in_addr addr, peer * e, double rtt, double hops)
  803. {
  804. #if USE_ICMP
  805.     netdbEntry *n;
  806.     net_db_peer *p;
  807.     debug(38, 5) ("netdbExchangeUpdatePeer: '%s', %0.1f hops, %0.1f rttn",
  808. inet_ntoa(addr), hops, rtt);
  809.     n = netdbLookupAddr(addr);
  810.     if (n == NULL)
  811. n = netdbAdd(addr);
  812.     assert(NULL != n);
  813.     if ((p = netdbPeerByName(n, e->host)) == NULL)
  814. p = netdbPeerAdd(n, e);
  815.     p->rtt = rtt;
  816.     p->hops = hops;
  817.     p->expires = squid_curtime + 3600; /* XXX ? */
  818.     if (n->n_peers < 2)
  819. return;
  820.     qsort((char *) n->peers,
  821. n->n_peers,
  822. sizeof(net_db_peer),
  823. sortPeerByRtt);
  824. #endif
  825. }
  826. void
  827. netdbDeleteAddrNetwork(struct in_addr addr)
  828. {
  829. #if USE_ICMP
  830.     netdbEntry *n = netdbLookupAddr(addr);
  831.     if (n == NULL)
  832. return;
  833.     debug(38, 3) ("netdbDeleteAddrNetwork: %sn", n->network);
  834.     netdbRelease(n);
  835. #endif
  836. }
  837. void
  838. netdbBinaryExchange(StoreEntry * s)
  839. {
  840.     http_reply *reply = s->mem_obj->reply;
  841. #if USE_ICMP
  842.     netdbEntry *n;
  843.     int i;
  844.     int j;
  845.     int rec_sz;
  846.     char *buf;
  847.     struct in_addr addr;
  848.     storeBuffer(s);
  849.     httpReplyReset(reply);
  850.     httpReplySetHeaders(reply, 1.0, HTTP_OK, "OK",
  851. NULL, -1, squid_curtime, -2);
  852.     httpReplySwapOut(reply, s);
  853.     rec_sz = 0;
  854.     rec_sz += 1 + sizeof(addr.s_addr);
  855.     rec_sz += 1 + sizeof(int);
  856.     rec_sz += 1 + sizeof(int);
  857.     buf = memAllocate(MEM_4K_BUF);
  858.     i = 0;
  859.     hash_first(addr_table);
  860.     while ((n = (netdbEntry *) hash_next(addr_table))) {
  861. if (0.0 == n->rtt)
  862.     continue;
  863. if (n->rtt > 60000) /* RTT > 1 MIN probably bogus */
  864.     continue;
  865. if (!safe_inet_addr(n->network, &addr))
  866.     continue;
  867. buf[i++] = (char) NETDB_EX_NETWORK;
  868. xmemcpy(&buf[i], &addr.s_addr, sizeof(addr.s_addr));
  869. i += sizeof(addr.s_addr);
  870. buf[i++] = (char) NETDB_EX_RTT;
  871. j = htonl((int) (n->rtt * 1000));
  872. xmemcpy(&buf[i], &j, sizeof(int));
  873. i += sizeof(int);
  874. buf[i++] = (char) NETDB_EX_HOPS;
  875. j = htonl((int) (n->hops * 1000));
  876. xmemcpy(&buf[i], &j, sizeof(int));
  877. i += sizeof(int);
  878. if (i + rec_sz > 4096) {
  879.     storeAppend(s, buf, i);
  880.     i = 0;
  881. }
  882.     }
  883.     if (i > 0) {
  884. storeAppend(s, buf, i);
  885. i = 0;
  886.     }
  887.     assert(0 == i);
  888.     storeBufferFlush(s);
  889.     memFree(buf, MEM_4K_BUF);
  890. #else
  891.     httpReplyReset(reply);
  892.     httpReplySetHeaders(reply, 1.0, HTTP_BAD_REQUEST, "Bad Request",
  893. NULL, -1, squid_curtime, -2);
  894.     storeAppendPrintf(s, "NETDB support not compiled into this Squid cache.n");
  895. #endif
  896.     storeComplete(s);
  897. }
  898. void
  899. netdbExchangeStart(void *data)
  900. {
  901. #if USE_ICMP
  902.     peer *p = data;
  903.     char *uri;
  904.     netdbExchangeState *ex = xcalloc(1, sizeof(*ex));
  905.     cbdataAdd(ex, cbdataXfree, 0);
  906.     cbdataLock(p);
  907.     ex->p = p;
  908.     uri = internalRemoteUri(p->host, p->http_port, "/squid-internal-dynamic/", "netdb");
  909.     debug(38, 3) ("netdbExchangeStart: Requesting '%s'n", uri);
  910.     assert(NULL != uri);
  911.     ex->r = urlParse(METHOD_GET, uri);
  912.     if (NULL == ex->r) {
  913. debug(38, 1) ("netdbExchangeStart: Bad URI %sn", uri);
  914. return;
  915.     }
  916.     requestLink(ex->r);
  917.     assert(NULL != ex->r);
  918.     ex->r->http_ver = 1.0;
  919.     ex->e = storeCreateEntry(uri, uri, null_request_flags, METHOD_GET);
  920.     ex->buf_sz = 4096;;
  921.     ex->buf = memAllocate(MEM_4K_BUF);
  922.     assert(NULL != ex->e);
  923.     storeClientListAdd(ex->e, ex);
  924.     storeClientCopy(ex->e, ex->seen, ex->used, ex->buf_sz,
  925. ex->buf, netdbExchangeHandleReply, ex);
  926.     ex->r->flags.loopdetect = 1; /* cheat! -- force direct */
  927.     fwdStart(-1, ex->e, ex->r, no_addr, no_addr);
  928. #endif
  929. }
  930. peer *
  931. netdbClosestParent(request_t * request)
  932. {
  933. #if USE_ICMP
  934.     peer *p = NULL;
  935.     netdbEntry *n;
  936.     const ipcache_addrs *ia;
  937.     net_db_peer *h;
  938.     int i;
  939.     n = netdbLookupHost(request->host);
  940.     if (NULL == n) {
  941. /* try IP addr */
  942. ia = ipcache_gethostbyname(request->host, 0);
  943. if (NULL != ia)
  944.     n = netdbLookupAddr(ia->in_addrs[ia->cur]);
  945.     }
  946.     if (NULL == n)
  947. return NULL;
  948.     if (0 == n->n_peers)
  949. return NULL;
  950.     /* 
  951.      * Find the parent with the least RTT to the origin server.
  952.      * Make sure we don't return a parent who is farther away than
  953.      * we are.  Note, the n->peers list is pre-sorted by RTT.
  954.      */
  955.     for (i = 0; i < n->n_peers; i++) {
  956. h = &n->peers[i];
  957. if (n->rtt > 0)
  958.     if (n->rtt < h->rtt)
  959. break;
  960. p = peerFindByName(h->peername);
  961. if (NULL == p) /* not found */
  962.     continue;
  963. if (neighborType(p, request) != PEER_PARENT)
  964.     continue;
  965. if (!peerHTTPOkay(p, request)) /* not allowed */
  966.     continue;
  967. return p;
  968.     }
  969. #endif
  970.     return NULL;
  971. }