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