--------------------- PatchSet 5315 Date: 2002/10/09 05:21:28 Author: rbcollins Branch: rbcollins_cxxtest Tag: (none) Log: still more -> .cc Members: src/Makefile.am:1.29.2.19->1.29.2.20 src/fd.c:1.8->1.8.28.1(DEAD) src/fd.cc:1.1->1.1.2.1 src/net_db.c:1.16.2.1->1.16.2.2(DEAD) src/net_db.cc:1.1->1.1.2.1 src/store_dir.c:1.20.22.3->1.20.22.4(DEAD) src/store_dir.cc:1.1->1.1.2.1 src/whois.c:1.9.10.1->1.9.10.2(DEAD) src/whois.cc:1.1->1.1.2.1 Index: squid/src/Makefile.am =================================================================== RCS file: /cvsroot/squid-sf//squid/src/Makefile.am,v retrieving revision 1.29.2.19 retrieving revision 1.29.2.20 diff -u -r1.29.2.19 -r1.29.2.20 --- squid/src/Makefile.am 9 Oct 2002 04:52:02 -0000 1.29.2.19 +++ squid/src/Makefile.am 9 Oct 2002 05:21:28 -0000 1.29.2.20 @@ -146,7 +146,7 @@ ETag.cc \ event.c \ external_acl.cc \ - fd.c \ + fd.cc \ filemap.cc \ forward.c \ fqdncache.c \ @@ -183,7 +183,7 @@ mime.cc \ multicast.cc \ neighbors.c \ - net_db.c \ + net_db.cc \ Packer.cc \ $(XPROF_STATS_SOURCE) \ pconn.cc \ @@ -208,7 +208,7 @@ store_client.cc \ StoreClient.h \ store_digest.c \ - store_dir.c \ + store_dir.cc \ store_key_md5.c \ store_log.c \ store_rebuild.c \ @@ -224,7 +224,7 @@ useragent.c \ wais.cc \ wccp.c \ - whois.c \ + whois.cc \ $(WIN32SOURCE) nodist_squid_SOURCES = \ --- squid/src/fd.c Wed Feb 14 01:07:37 2007 +++ /dev/null Wed Feb 14 01:07:22 2007 @@ -1,208 +0,0 @@ - -/* - * $Id: fd.c,v 1.8 2001/12/25 12:38:51 squidadm Exp $ - * - * DEBUG: section 51 Filedescriptor Functions - * AUTHOR: Duane Wessels - * - * SQUID Web Proxy Cache http://www.squid-cache.org/ - * ---------------------------------------------------------- - * - * Squid is the result of efforts by numerous individuals from - * the Internet community; see the CONTRIBUTORS file for full - * details. Many organizations have provided support for Squid's - * development; see the SPONSORS file for full details. Squid is - * Copyrighted (C) 2001 by the Regents of the University of - * California; see the COPYRIGHT file for full details. Squid - * incorporates software developed and/or copyrighted by other - * sources; see the CREDITS file for full details. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. - * - */ - -#include "squid.h" - -int default_read_method(int, char *, int); -int default_write_method(int, const char *, int); - -const char *fdTypeStr[] = -{ - "None", - "Log", - "File", - "Socket", - "Pipe", - "Unknown" -}; - -static void fdUpdateBiggest(int fd, int); - -static void -fdUpdateBiggest(int fd, int opening) -{ - if (fd < Biggest_FD) - return; - assert(fd < Squid_MaxFD); - if (fd > Biggest_FD) { - /* - * assert that we are not closing a FD bigger than - * our known biggest FD - */ - assert(opening); - Biggest_FD = fd; - return; - } - /* if we are here, then fd == Biggest_FD */ - /* - * assert that we are closing the biggest FD; we can't be - * re-opening it - */ - assert(!opening); - while (!fd_table[Biggest_FD].flags.open) - Biggest_FD--; -} - -void -fd_close(int fd) -{ - fde *F = &fd_table[fd]; - if (F->type == FD_FILE) { - assert(F->read_handler == NULL); - assert(F->write_handler == NULL); - } - debug(51, 3) ("fd_close FD %d %s\n", fd, F->desc); - commSetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0); - commSetSelect(fd, COMM_SELECT_WRITE, NULL, NULL, 0); - F->flags.open = 0; - fdUpdateBiggest(fd, 0); - Number_FD--; - memset(F, '\0', sizeof(fde)); - F->timeout = 0; -} - -int -default_read_method(int fd, char *buf, int len) -{ - return (read(fd, buf, len)); -} - -int -default_write_method(int fd, const char *buf, int len) -{ - return (write(fd, buf, len)); -} - -void -fd_open(int fd, unsigned int type, const char *desc) -{ - fde *F; - assert(fd >= 0); - F = &fd_table[fd]; - if (F->flags.open) { - debug(51, 1) ("WARNING: Closing open FD %4d\n", fd); - fd_close(fd); - } - assert(!F->flags.open); - debug(51, 3) ("fd_open FD %d %s\n", fd, desc); - F->type = type; - F->flags.open = 1; - F->read_method = &default_read_method; - F->write_method = &default_write_method; - fdUpdateBiggest(fd, 1); - if (desc) - xstrncpy(F->desc, desc, FD_DESC_SZ); - Number_FD++; -} - -void -fd_note(int fd, const char *s) -{ - fde *F = &fd_table[fd]; - xstrncpy(F->desc, s, FD_DESC_SZ); -} - -void -fd_bytes(int fd, int len, unsigned int type) -{ - fde *F = &fd_table[fd]; - if (len < 0) - return; - assert(type == FD_READ || type == FD_WRITE); - if (type == FD_READ) - F->bytes_read += len; - else - F->bytes_written += len; -} - -void -fdFreeMemory(void) -{ - safe_free(fd_table); -} - -void -fdDumpOpen(void) -{ - int i; - fde *F; - for (i = 0; i < Squid_MaxFD; i++) { - F = &fd_table[i]; - if (!F->flags.open) - continue; - if (i == fileno(debug_log)) - continue; - debug(51, 1) ("Open FD %-10s %4d %s\n", - F->bytes_read && F->bytes_written ? "READ/WRITE" : - F->bytes_read ? "READING" : - F->bytes_written ? "WRITING" : null_string, - i, F->desc); - } -} - -int -fdNFree(void) -{ - return Squid_MaxFD - Number_FD - Opening_FD; -} - -/* Called when we runs out of file descriptors */ -void -fdAdjustReserved(void) -{ - int new; - int x; - static time_t last = 0; - /* - * don't update too frequently - */ - if (last + 5 > squid_curtime) - return; - /* - * Calculate a new reserve, based on current usage and a small extra - */ - new = Squid_MaxFD - Number_FD + XMIN(25, Squid_MaxFD / 16); - if (new <= RESERVED_FD) - return; - x = Squid_MaxFD - 20 - XMIN(25, Squid_MaxFD / 16); - if (new > x) { - /* perhaps this should be fatal()? -DW */ - debug(51, 0) ("WARNING: This machine has a serious shortage of filedescriptors.\n"); - new = x; - } - debug(51, 0) ("Reserved FD adjusted from %d to %d due to failures\n", - RESERVED_FD, new); - RESERVED_FD = new; -} --- /dev/null Wed Feb 14 01:07:22 2007 +++ squid/src/fd.cc Wed Feb 14 01:07:37 2007 @@ -0,0 +1,208 @@ + +/* + * $Id: fd.cc,v 1.1.2.1 2002/10/09 05:21:29 rbcollins Exp $ + * + * DEBUG: section 51 Filedescriptor Functions + * AUTHOR: Duane Wessels + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#include "squid.h" + +int default_read_method(int, char *, int); +int default_write_method(int, const char *, int); + +const char *fdTypeStr[] = +{ + "None", + "Log", + "File", + "Socket", + "Pipe", + "Unknown" +}; + +static void fdUpdateBiggest(int fd, int); + +static void +fdUpdateBiggest(int fd, int opening) +{ + if (fd < Biggest_FD) + return; + assert(fd < Squid_MaxFD); + if (fd > Biggest_FD) { + /* + * assert that we are not closing a FD bigger than + * our known biggest FD + */ + assert(opening); + Biggest_FD = fd; + return; + } + /* if we are here, then fd == Biggest_FD */ + /* + * assert that we are closing the biggest FD; we can't be + * re-opening it + */ + assert(!opening); + while (!fd_table[Biggest_FD].flags.open) + Biggest_FD--; +} + +void +fd_close(int fd) +{ + fde *F = &fd_table[fd]; + if (F->type == FD_FILE) { + assert(F->read_handler == NULL); + assert(F->write_handler == NULL); + } + debug(51, 3) ("fd_close FD %d %s\n", fd, F->desc); + commSetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0); + commSetSelect(fd, COMM_SELECT_WRITE, NULL, NULL, 0); + F->flags.open = 0; + fdUpdateBiggest(fd, 0); + Number_FD--; + memset(F, '\0', sizeof(fde)); + F->timeout = 0; +} + +int +default_read_method(int fd, char *buf, int len) +{ + return (read(fd, buf, len)); +} + +int +default_write_method(int fd, const char *buf, int len) +{ + return (write(fd, buf, len)); +} + +void +fd_open(int fd, unsigned int type, const char *desc) +{ + fde *F; + assert(fd >= 0); + F = &fd_table[fd]; + if (F->flags.open) { + debug(51, 1) ("WARNING: Closing open FD %4d\n", fd); + fd_close(fd); + } + assert(!F->flags.open); + debug(51, 3) ("fd_open FD %d %s\n", fd, desc); + F->type = type; + F->flags.open = 1; + F->read_method = &default_read_method; + F->write_method = &default_write_method; + fdUpdateBiggest(fd, 1); + if (desc) + xstrncpy(F->desc, desc, FD_DESC_SZ); + Number_FD++; +} + +void +fd_note(int fd, const char *s) +{ + fde *F = &fd_table[fd]; + xstrncpy(F->desc, s, FD_DESC_SZ); +} + +void +fd_bytes(int fd, int len, unsigned int type) +{ + fde *F = &fd_table[fd]; + if (len < 0) + return; + assert(type == FD_READ || type == FD_WRITE); + if (type == FD_READ) + F->bytes_read += len; + else + F->bytes_written += len; +} + +void +fdFreeMemory(void) +{ + safe_free(fd_table); +} + +void +fdDumpOpen(void) +{ + int i; + fde *F; + for (i = 0; i < Squid_MaxFD; i++) { + F = &fd_table[i]; + if (!F->flags.open) + continue; + if (i == fileno(debug_log)) + continue; + debug(51, 1) ("Open FD %-10s %4d %s\n", + F->bytes_read && F->bytes_written ? "READ/WRITE" : + F->bytes_read ? "READING" : + F->bytes_written ? "WRITING" : null_string, + i, F->desc); + } +} + +int +fdNFree(void) +{ + return Squid_MaxFD - Number_FD - Opening_FD; +} + +/* Called when we runs out of file descriptors */ +void +fdAdjustReserved(void) +{ + int newReserve; + int x; + static time_t last = 0; + /* + * don't update too frequently + */ + if (last + 5 > squid_curtime) + return; + /* + * Calculate a new reserve, based on current usage and a small extra + */ + newReserve = Squid_MaxFD - Number_FD + XMIN(25, Squid_MaxFD / 16); + if (newReserve <= RESERVED_FD) + return; + x = Squid_MaxFD - 20 - XMIN(25, Squid_MaxFD / 16); + if (newReserve > x) { + /* perhaps this should be fatal()? -DW */ + debug(51, 0) ("WARNING: This machine has a serious shortage of filedescriptors.\n"); + newReserve = x; + } + debug(51, 0) ("Reserved FD adjusted from %d to %d due to failures\n", + RESERVED_FD, newReserve); + RESERVED_FD = newReserve; +} --- squid/src/net_db.c Wed Feb 14 01:07:37 2007 +++ /dev/null Wed Feb 14 01:07:22 2007 @@ -1,1150 +0,0 @@ - -/* - * $Id: net_db.c,v 1.16.2.1 2002/10/04 07:07:27 rbcollins Exp $ - * - * DEBUG: section 38 Network Measurement Database - * AUTHOR: Duane Wessels - * - * SQUID Web Proxy Cache http://www.squid-cache.org/ - * ---------------------------------------------------------- - * - * Squid is the result of efforts by numerous individuals from - * the Internet community; see the CONTRIBUTORS file for full - * details. Many organizations have provided support for Squid's - * development; see the SPONSORS file for full details. Squid is - * Copyrighted (C) 2001 by the Regents of the University of - * California; see the COPYRIGHT file for full details. Squid - * incorporates software developed and/or copyrighted by other - * sources; see the CREDITS file for full details. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. - * - */ - -/* - * XXX XXX XXX - * - * This code may be slightly broken now. If you're getting consistent - * (sometimes working) corrupt data exchanges, please contact adrian - * (adrian@squid-cache.org) to sort them out. - */ - -#include "squid.h" -#include "Store.h" - - -#if USE_ICMP -#include "StoreClient.h" - -#define NETDB_REQBUF_SZ 4096 - -typedef enum { - STATE_NONE, - STATE_HEADER, - STATE_BODY -} netdb_conn_state_t; - -typedef struct { - peer *p; - StoreEntry *e; - store_client *sc; - request_t *r; - off_t used; - size_t buf_sz; - char buf[NETDB_REQBUF_SZ]; - int buf_ofs; - netdb_conn_state_t connstate; -} netdbExchangeState; - -static hash_table *addr_table = NULL; -static hash_table *host_table = NULL; - -static struct in_addr networkFromInaddr(struct in_addr a); -static void netdbRelease(netdbEntry * n); -static void netdbHashInsert(netdbEntry * n, struct in_addr addr); -static void netdbHashDelete(const char *key); -static void netdbHostInsert(netdbEntry * n, const char *hostname); -static void netdbHostDelete(const net_db_name * x); -static void netdbPurgeLRU(void); -static netdbEntry *netdbLookupHost(const char *key); -static net_db_peer *netdbPeerByName(const netdbEntry * n, const char *); -static net_db_peer *netdbPeerAdd(netdbEntry * n, peer * e); -static const char *netdbPeerName(const char *name); -static IPH netdbSendPing; -static QS sortPeerByRtt; -static QS sortByRtt; -static QS netdbLRU; -static FREE netdbFreeNameEntry; -static FREE netdbFreeNetdbEntry; -static STCB netdbExchangeHandleReply; -static void netdbExchangeDone(void *); - -/* We have to keep a local list of peer names. The Peers structure - * gets freed during a reconfigure. We want this database to - * remain persisitent, so _net_db_peer->peername points into this - * linked list */ -static wordlist *peer_names = NULL; - -static void -netdbHashInsert(netdbEntry * n, struct in_addr addr) -{ - xstrncpy(n->network, inet_ntoa(networkFromInaddr(addr)), 16); - n->hash.key = n->network; - assert(hash_lookup(addr_table, n->network) == NULL); - hash_join(addr_table, &n->hash); -} - -static void -netdbHashDelete(const char *key) -{ - hash_link *hptr = hash_lookup(addr_table, key); - if (hptr == NULL) { - debug_trap("netdbHashDelete: key not found"); - return; - } - hash_remove_link(addr_table, hptr); -} - -static void -netdbHostInsert(netdbEntry * n, const char *hostname) -{ - net_db_name *x = memAllocate(MEM_NET_DB_NAME); - x->hash.key = xstrdup(hostname); - x->next = n->hosts; - n->hosts = x; - x->net_db_entry = n; - assert(hash_lookup(host_table, hostname) == NULL); - hash_join(host_table, &x->hash); - n->link_count++; -} - -static void -netdbHostDelete(const net_db_name * x) -{ - netdbEntry *n; - net_db_name **X; - assert(x != NULL); - assert(x->net_db_entry != NULL); - n = x->net_db_entry; - n->link_count--; - for (X = &n->hosts; *X; X = &(*X)->next) { - if (*X == x) { - *X = x->next; - break; - } - } - hash_remove_link(host_table, (hash_link *) x); - xfree(x->hash.key); - memFree((void *) x, MEM_NET_DB_NAME); -} - -static netdbEntry * -netdbLookupHost(const char *key) -{ - net_db_name *x = (net_db_name *) hash_lookup(host_table, key); - return x ? x->net_db_entry : NULL; -} - -static void -netdbRelease(netdbEntry * n) -{ - net_db_name *x; - net_db_name *next; - for (x = n->hosts; x; x = next) { - next = x->next; - netdbHostDelete(x); - } - n->hosts = NULL; - safe_free(n->peers); - n->peers = NULL; - n->n_peers = 0; - n->n_peers_alloc = 0; - if (n->link_count == 0) { - netdbHashDelete(n->network); - memFree(n, MEM_NETDBENTRY); - } -} - -static int -netdbLRU(const void *A, const void *B) -{ - const netdbEntry *const *n1 = A; - const netdbEntry *const *n2 = B; - if ((*n1)->last_use_time > (*n2)->last_use_time) - return (1); - if ((*n1)->last_use_time < (*n2)->last_use_time) - return (-1); - return (0); -} - -static void -netdbPurgeLRU(void) -{ - netdbEntry *n; - netdbEntry **list; - int k = 0; - int list_count = 0; - int removed = 0; - list = xcalloc(memInUse(MEM_NETDBENTRY), sizeof(netdbEntry *)); - hash_first(addr_table); - while ((n = (netdbEntry *) hash_next(addr_table))) { - assert(list_count < memInUse(MEM_NETDBENTRY)); - *(list + list_count) = n; - list_count++; - } - qsort((char *) list, - list_count, - sizeof(netdbEntry *), - netdbLRU); - for (k = 0; k < list_count; k++) { - if (memInUse(MEM_NETDBENTRY) < Config.Netdb.low) - break; - netdbRelease(*(list + k)); - removed++; - } - xfree(list); -} - -static netdbEntry * -netdbLookupAddr(struct in_addr addr) -{ - netdbEntry *n; - char *key = inet_ntoa(networkFromInaddr(addr)); - n = (netdbEntry *) hash_lookup(addr_table, key); - return n; -} - -static netdbEntry * -netdbAdd(struct in_addr addr) -{ - netdbEntry *n; - if (memInUse(MEM_NETDBENTRY) > Config.Netdb.high) - netdbPurgeLRU(); - if ((n = netdbLookupAddr(addr)) == NULL) { - n = memAllocate(MEM_NETDBENTRY); - netdbHashInsert(n, addr); - } - return n; -} - -static void -netdbSendPing(const ipcache_addrs * ia, void *data) -{ - struct in_addr addr; - char *hostname = ((generic_cbdata *) data)->data; - netdbEntry *n; - netdbEntry *na; - net_db_name *x; - net_db_name **X; - cbdataFree(data); - if (ia == NULL) { - xfree(hostname); - return; - } - addr = ia->in_addrs[ia->cur]; - if ((n = netdbLookupHost(hostname)) == NULL) { - n = netdbAdd(addr); - netdbHostInsert(n, hostname); - } else if ((na = netdbLookupAddr(addr)) != n) { - /* - *hostname moved from 'network n' to 'network na'! - */ - if (na == NULL) - na = netdbAdd(addr); - debug(38, 3) ("netdbSendPing: %s moved from %s to %s\n", - hostname, n->network, na->network); - x = (net_db_name *) hash_lookup(host_table, hostname); - if (x == NULL) { - debug(38, 1) ("netdbSendPing: net_db_name list bug: %s not found", hostname); - xfree(hostname); - return; - } - /* remove net_db_name from 'network n' linked list */ - for (X = &n->hosts; *X; X = &(*X)->next) { - if (*X == x) { - *X = x->next; - break; - } - } - n->link_count--; - /* point to 'network na' from host entry */ - x->net_db_entry = na; - /* link net_db_name to 'network na' */ - x->next = na->hosts; - na->hosts = x; - na->link_count++; - n = na; - } - if (n->next_ping_time <= squid_curtime) { - debug(38, 3) ("netdbSendPing: pinging %s\n", hostname); - icmpDomainPing(addr, hostname); - n->pings_sent++; - n->next_ping_time = squid_curtime + Config.Netdb.period; - n->last_use_time = squid_curtime; - } - xfree(hostname); -} - -static struct in_addr -networkFromInaddr(struct in_addr a) -{ - struct in_addr b; - b.s_addr = ntohl(a.s_addr); -#if USE_CLASSFUL - if (IN_CLASSC(b.s_addr)) - b.s_addr &= IN_CLASSC_NET; - else if (IN_CLASSB(b.s_addr)) - b.s_addr &= IN_CLASSB_NET; - else if (IN_CLASSA(b.s_addr)) - b.s_addr &= IN_CLASSA_NET; -#else - /* use /24 for everything */ - b.s_addr &= IN_CLASSC_NET; -#endif - b.s_addr = htonl(b.s_addr); - return b; -} - -static int -sortByRtt(const void *A, const void *B) -{ - const netdbEntry *const *n1 = A; - const netdbEntry *const *n2 = B; - if ((*n1)->rtt > (*n2)->rtt) - return 1; - else if ((*n1)->rtt < (*n2)->rtt) - return -1; - else - return 0; -} - -static net_db_peer * -netdbPeerByName(const netdbEntry * n, const char *peername) -{ - int i; - net_db_peer *p = n->peers; - for (i = 0; i < n->n_peers; i++, p++) { - if (!strcmp(p->peername, peername)) - return p; - } - return NULL; -} - -static net_db_peer * -netdbPeerAdd(netdbEntry * n, peer * e) -{ - net_db_peer *p; - net_db_peer *o; - int osize; - int i; - if (n->n_peers == n->n_peers_alloc) { - o = n->peers; - osize = n->n_peers_alloc; - if (n->n_peers_alloc == 0) - n->n_peers_alloc = 2; - else - n->n_peers_alloc <<= 1; - debug(38, 3) ("netdbPeerAdd: Growing peer list for '%s' to %d\n", - n->network, n->n_peers_alloc); - n->peers = xcalloc(n->n_peers_alloc, sizeof(net_db_peer)); - for (i = 0; i < osize; i++) - *(n->peers + i) = *(o + i); - if (osize) { - safe_free(o); - } - } - p = n->peers + n->n_peers; - p->peername = netdbPeerName(e->host); - n->n_peers++; - return p; -} - -static int -sortPeerByRtt(const void *A, const void *B) -{ - const net_db_peer *p1 = A; - const net_db_peer *p2 = B; - if (p1->rtt > p2->rtt) - return 1; - else if (p1->rtt < p2->rtt) - return -1; - else - return 0; -} - -static void -netdbSaveState(void *foo) -{ - LOCAL_ARRAY(char, path, SQUID_MAXPATHLEN); - Logfile *lf; - netdbEntry *n; - net_db_name *x; - struct timeval start = current_time; - int count = 0; - snprintf(path, SQUID_MAXPATHLEN, "%s/netdb_state", storeSwapDir(0)); - /* - * This was nicer when we were using stdio, but thanks to - * Solaris bugs, its a bad idea. fopen can fail if more than - * 256 FDs are open. - */ - /* - * unlink() is here because there is currently no way to make - * logfileOpen() use O_TRUNC. - */ - unlink(path); - lf = logfileOpen(path, 4096, 0); - if (NULL == lf) { - debug(50, 1) ("netdbSaveState: %s: %s\n", path, xstrerror()); - return; - } - hash_first(addr_table); - while ((n = (netdbEntry *) hash_next(addr_table))) { - if (n->pings_recv == 0) - continue; - logfilePrintf(lf, "%s %d %d %10.5f %10.5f %d %d", - n->network, - n->pings_sent, - n->pings_recv, - n->hops, - n->rtt, - (int) n->next_ping_time, - (int) n->last_use_time); - for (x = n->hosts; x; x = x->next) - logfilePrintf(lf, " %s", hashKeyStr(&x->hash)); - logfilePrintf(lf, "\n"); - count++; -#undef RBUF_SZ - } - logfileClose(lf); - getCurrentTime(); - debug(38, 1) ("NETDB state saved; %d entries, %d msec\n", - count, tvSubMsec(start, current_time)); - eventAddIsh("netdbSaveState", netdbSaveState, NULL, 3600.0, 1); -} - -static void -netdbReloadState(void) -{ - LOCAL_ARRAY(char, path, SQUID_MAXPATHLEN); - char *buf; - char *t; - char *s; - int fd; - int l; - struct stat sb; - netdbEntry *n; - netdbEntry N; - struct in_addr addr; - int count = 0; - struct timeval start = current_time; - snprintf(path, SQUID_MAXPATHLEN, "%s/netdb_state", storeSwapDir(0)); - /* - * This was nicer when we were using stdio, but thanks to - * Solaris bugs, its a bad idea. fopen can fail if more than - * 256 FDs are open. - */ - fd = file_open(path, O_RDONLY | O_TEXT); - if (fd < 0) - return; - if (fstat(fd, &sb) < 0) { - file_close(fd); - return; - } - t = buf = xcalloc(1, sb.st_size + 1); - l = FD_READ_METHOD(fd, buf, sb.st_size); - file_close(fd); - if (l <= 0) - return; - while ((s = strchr(t, '\n'))) { - char *q; - assert(s - buf < l); - *s = '\0'; - memset(&N, '\0', sizeof(netdbEntry)); - q = strtok(t, w_space); - t = s + 1; - if (NULL == q) - continue; - if (!safe_inet_addr(q, &addr)) - continue; - if (netdbLookupAddr(addr) != NULL) /* no dups! */ - continue; - if ((q = strtok(NULL, w_space)) == NULL) - continue; - N.pings_sent = atoi(q); - if ((q = strtok(NULL, w_space)) == NULL) - continue; - N.pings_recv = atoi(q); - if (N.pings_recv == 0) - continue; - /* give this measurement low weight */ - N.pings_sent = 1; - N.pings_recv = 1; - if ((q = strtok(NULL, w_space)) == NULL) - continue; - N.hops = atof(q); - if ((q = strtok(NULL, w_space)) == NULL) - continue; - N.rtt = atof(q); - if ((q = strtok(NULL, w_space)) == NULL) - continue; - N.next_ping_time = (time_t) atoi(q); - if ((q = strtok(NULL, w_space)) == NULL) - continue; - N.last_use_time = (time_t) atoi(q); - n = memAllocate(MEM_NETDBENTRY); - xmemcpy(n, &N, sizeof(netdbEntry)); - netdbHashInsert(n, addr); - while ((q = strtok(NULL, w_space)) != NULL) { - if (netdbLookupHost(q) != NULL) /* no dups! */ - continue; - netdbHostInsert(n, q); - } - count++; - } - xfree(buf); - getCurrentTime(); - debug(38, 1) ("NETDB state reloaded; %d entries, %d msec\n", - count, tvSubMsec(start, current_time)); -} - -static const char * -netdbPeerName(const char *name) -{ - const wordlist *w; - for (w = peer_names; w; w = w->next) { - if (!strcmp(w->key, name)) - return w->key; - } - return wordlistAdd(&peer_names, name); -} - -static void -netdbFreeNetdbEntry(void *data) -{ - netdbEntry *n = data; - safe_free(n->peers); - memFree(n, MEM_NETDBENTRY); -} - -static void -netdbFreeNameEntry(void *data) -{ - net_db_name *x = data; - xfree(x->hash.key); - memFree(x, MEM_NET_DB_NAME); -} - - -static void -netdbExchangeHandleReply(void *data, StoreIOBuffer recievedData) -{ - netdbExchangeState *ex = data; - int rec_sz = 0; - off_t o; - struct in_addr addr; - double rtt; - double hops; - char *p; - int j; - HttpReply *rep; - size_t hdr_sz; - int nused = 0; - int size; - int oldbufofs = ex->buf_ofs; - - rec_sz = 0; - rec_sz += 1 + sizeof(addr.s_addr); - rec_sz += 1 + sizeof(int); - rec_sz += 1 + sizeof(int); - debug(38, 3) ("netdbExchangeHandleReply: %d read bytes\n", (int) recievedData.length); - if (!cbdataReferenceValid(ex->p)) { - debug(38, 3) ("netdbExchangeHandleReply: Peer became invalid\n"); - netdbExchangeDone(ex); - return; - } - debug(38, 3) ("netdbExchangeHandleReply: for '%s:%d'\n", ex->p->host, ex->p->http_port); - p = ex->buf; - - /* Get the size of the buffer now */ - size = ex->buf_ofs + recievedData.length; - debug(38, 3) ("netdbExchangeHandleReply: %d bytes buf\n", (int) size); - - /* Check if we're still doing headers */ - if (ex->connstate == STATE_HEADER) { - - ex->buf_ofs += recievedData.length; - - /* skip reply headers */ - if ((hdr_sz = headersEnd(p, ex->buf_ofs))) { - debug(38, 5) ("netdbExchangeHandleReply: hdr_sz = %d\n", hdr_sz); - rep = ex->e->mem_obj->reply; - if (0 == rep->sline.status) - httpReplyParse(rep, ex->buf, hdr_sz); - debug(38, 3) ("netdbExchangeHandleReply: reply status %d\n", - rep->sline.status); - if (HTTP_OK != rep->sline.status) { - netdbExchangeDone(ex); - return; - } - assert(ex->buf_ofs >= hdr_sz); - - /* - * Now, point p to the part of the buffer where the data - * starts, and update the size accordingly - */ - assert(ex->used == 0); - ex->used = hdr_sz; - size = ex->buf_ofs - hdr_sz; - p += hdr_sz; - - /* Finally, set the conn state mode to STATE_BODY */ - ex->connstate = STATE_BODY; - } else { - StoreIOBuffer tempBuffer = EMPTYIOBUFFER; - tempBuffer.offset = ex->buf_ofs; - tempBuffer.length = ex->buf_sz - ex->buf_ofs; - tempBuffer.data = ex->buf + ex->buf_ofs; - /* Have more headers .. */ - storeClientCopy(ex->sc, ex->e, tempBuffer, - netdbExchangeHandleReply, ex); - return; - } - } - assert(ex->connstate == STATE_BODY); - - /* If we get here, we have some body to parse .. */ - debug(38, 5) ("netdbExchangeHandleReply: start parsing loop, size = %d\n", - size); - while (size >= rec_sz) { - debug(38, 5) ("netdbExchangeHandleReply: in parsing loop, size = %d\n", - size); - addr.s_addr = any_addr.s_addr; - hops = rtt = 0.0; - for (o = 0; o < rec_sz;) { - switch ((int) *(p + o)) { - case NETDB_EX_NETWORK: - o++; - xmemcpy(&addr.s_addr, p + o, sizeof(addr.s_addr)); - o += sizeof(addr.s_addr); - break; - case NETDB_EX_RTT: - o++; - xmemcpy(&j, p + o, sizeof(int)); - o += sizeof(int); - rtt = (double) ntohl(j) / 1000.0; - break; - case NETDB_EX_HOPS: - o++; - xmemcpy(&j, p + o, sizeof(int)); - o += sizeof(int); - hops = (double) ntohl(j) / 1000.0; - break; - default: - debug(38, 1) ("netdbExchangeHandleReply: corrupt data, aborting\n"); - netdbExchangeDone(ex); - return; - } - } - if (addr.s_addr != any_addr.s_addr && rtt > 0) - netdbExchangeUpdatePeer(addr, ex->p, rtt, hops); - assert(o == rec_sz); - ex->used += rec_sz; - size -= rec_sz; - p += rec_sz; - nused++; - } - - /* - * Copy anything that is left over to the beginning of the buffer, - * and adjust buf_ofs accordingly - */ - - /* - * Evilly, size refers to the buf size left now, - * ex->buf_ofs is the original buffer size, so just copy that - * much data over - */ - memmove(ex->buf, ex->buf + (ex->buf_ofs - size), size); - ex->buf_ofs = size; - - /* - * And don't re-copy the remaining data .. - */ - ex->used += size; - - /* - * Now the tricky bit - size _included_ the leftover bit from the _last_ - * storeClientCopy. We don't want to include that, or our offset will be wrong. - * So, don't count the size of the leftover buffer we began with. - * This can _disappear_ when we're not tracking offsets .. - */ - ex->used -= oldbufofs; - - debug(38, 3) ("netdbExchangeHandleReply: size left over in this buffer: %d bytes\n", size); - - debug(38, 3) ("netdbExchangeHandleReply: used %d entries, (x %d bytes) == %d bytes total\n", - nused, rec_sz, nused * rec_sz); - debug(38, 3) ("netdbExchangeHandleReply: used %ld\n", (long int) ex->used); - if (EBIT_TEST(ex->e->flags, ENTRY_ABORTED)) { - debug(38, 3) ("netdbExchangeHandleReply: ENTRY_ABORTED\n"); - netdbExchangeDone(ex); - } else if (ex->e->store_status == STORE_PENDING) { - StoreIOBuffer tempBuffer = EMPTYIOBUFFER; - tempBuffer.offset = ex->used; - tempBuffer.length = ex->buf_sz - ex->buf_ofs; - tempBuffer.data = ex->buf + ex->buf_ofs; - debug(38, 3) ("netdbExchangeHandleReply: STORE_PENDING\n"); - storeClientCopy(ex->sc, ex->e, tempBuffer, - netdbExchangeHandleReply, ex); - } else if (ex->used < ex->e->mem_obj->inmem_hi) { - StoreIOBuffer tempBuffer = EMPTYIOBUFFER; - tempBuffer.offset = ex->used; - tempBuffer.length = ex->buf_sz - ex->buf_ofs; - tempBuffer.data = ex->buf + ex->buf_ofs; - debug(38, 3) ("netdbExchangeHandleReply: ex->e->mem_obj->inmem_hi\n"); - storeClientCopy(ex->sc, ex->e, tempBuffer, - netdbExchangeHandleReply, ex); - } else { - debug(38, 3) ("netdbExchangeHandleReply: Done\n"); - netdbExchangeDone(ex); - } -} - -static void -netdbExchangeDone(void *data) -{ - netdbExchangeState *ex = data; - debug(38, 3) ("netdbExchangeDone: %s\n", storeUrl(ex->e)); - requestUnlink(ex->r); - storeUnregister(ex->sc, ex->e, ex); - storeUnlockObject(ex->e); - cbdataReferenceDone(ex->p); - cbdataFree(ex); -} - -#endif /* USE_ICMP */ - -/* PUBLIC FUNCTIONS */ - -void -netdbInit(void) -{ -#if USE_ICMP - int n; - if (addr_table) - return; - n = hashPrime(Config.Netdb.high / 4); - addr_table = hash_create((HASHCMP *) strcmp, n, hash_string); - n = hashPrime(3 * Config.Netdb.high / 4); - host_table = hash_create((HASHCMP *) strcmp, n, hash_string); - eventAddIsh("netdbSaveState", netdbSaveState, NULL, 3600.0, 1); - netdbReloadState(); - cachemgrRegister("netdb", - "Network Measurement Database", - netdbDump, 0, 1); -#endif -} - -void -netdbPingSite(const char *hostname) -{ -#if USE_ICMP - netdbEntry *n; - generic_cbdata *h; - if ((n = netdbLookupHost(hostname)) != NULL) - if (n->next_ping_time > squid_curtime) - return; - h = cbdataAlloc(generic_cbdata); - h->data = xstrdup(hostname); - ipcache_nbgethostbyname(hostname, netdbSendPing, h); -#endif -} - -void -netdbHandlePingReply(const struct sockaddr_in *from, int hops, int rtt) -{ -#if USE_ICMP - netdbEntry *n; - int N; - debug(38, 3) ("netdbHandlePingReply: from %s\n", inet_ntoa(from->sin_addr)); - if ((n = netdbLookupAddr(from->sin_addr)) == NULL) - return; - N = ++n->pings_recv; - if (N > 5) - N = 5; - if (rtt < 1.0) - rtt = 1.0; - n->hops = ((n->hops * (N - 1)) + hops) / N; - n->rtt = ((n->rtt * (N - 1)) + rtt) / N; - debug(38, 3) ("netdbHandlePingReply: %s; rtt=%5.1f hops=%4.1f\n", - n->network, - n->rtt, - n->hops); -#endif -} - -void -netdbFreeMemory(void) -{ -#if USE_ICMP - hashFreeItems(addr_table, netdbFreeNetdbEntry); - hashFreeMemory(addr_table); - addr_table = NULL; - hashFreeItems(host_table, netdbFreeNameEntry); - hashFreeMemory(host_table); - host_table = NULL; - wordlistDestroy(&peer_names); - peer_names = NULL; -#endif -} - -int -netdbHops(struct in_addr addr) -{ -#if USE_ICMP - netdbEntry *n = netdbLookupAddr(addr); - if (n && n->pings_recv) { - n->last_use_time = squid_curtime; - return (int) (n->hops + 0.5); - } -#endif - return 256; -} - -void -netdbDump(StoreEntry * sentry) -{ -#if USE_ICMP - netdbEntry *n; - netdbEntry **list; - net_db_name *x; - int k; - int i; - int j; - net_db_peer *p; - storeAppendPrintf(sentry, "Network DB Statistics:\n"); - storeAppendPrintf(sentry, "%-16.16s %9s %7s %5s %s\n", - "Network", - "recv/sent", - "RTT", - "Hops", - "Hostnames"); - list = xcalloc(memInUse(MEM_NETDBENTRY), sizeof(netdbEntry *)); - i = 0; - hash_first(addr_table); - while ((n = (netdbEntry *) hash_next(addr_table))) - *(list + i++) = n; - if (i != memInUse(MEM_NETDBENTRY)) - debug(38, 0) ("WARNING: netdb_addrs count off, found %d, expected %d\n", - i, memInUse(MEM_NETDBENTRY)); - qsort((char *) list, - i, - sizeof(netdbEntry *), - sortByRtt); - for (k = 0; k < i; k++) { - n = *(list + k); - storeAppendPrintf(sentry, "%-16.16s %4d/%4d %7.1f %5.1f", - n->network, - n->pings_recv, - n->pings_sent, - n->rtt, - n->hops); - for (x = n->hosts; x; x = x->next) - storeAppendPrintf(sentry, " %s", hashKeyStr(&x->hash)); - storeAppendPrintf(sentry, "\n"); - p = n->peers; - for (j = 0; j < n->n_peers; j++, p++) { - storeAppendPrintf(sentry, " %-22.22s %7.1f %5.1f\n", - p->peername, - p->rtt, - p->hops); - } - } - xfree(list); -#else - storeAppendPrintf(sentry, - "NETDB support not compiled into this Squid cache.\n"); -#endif -} - -int -netdbHostHops(const char *host) -{ -#if USE_ICMP - netdbEntry *n = netdbLookupHost(host); - if (n) { - n->last_use_time = squid_curtime; - return (int) (n->hops + 0.5); - } -#endif - return 0; -} - -int -netdbHostRtt(const char *host) -{ -#if USE_ICMP - netdbEntry *n = netdbLookupHost(host); - if (n) { - n->last_use_time = squid_curtime; - return (int) (n->rtt + 0.5); - } -#endif - return 0; -} - -void -netdbHostData(const char *host, int *samp, int *rtt, int *hops) -{ -#if USE_ICMP - netdbEntry *n = netdbLookupHost(host); - if (n == NULL) - return; - *samp = n->pings_recv; - *rtt = (int) (n->rtt + 0.5); - *hops = (int) (n->hops + 0.5); -#endif -} - -int -netdbHostPeerRtt(const char *host, peer * p) -{ -#if USE_ICMP - const netdbEntry *n = netdbLookupHost(host); - if (n) { - const net_db_peer *np = netdbPeerByName(n, p->host); - if (np && np->expires >= squid_curtime) - return (int) (np->rtt + 0.5); - } -#endif - return 0; -} - -void -netdbUpdatePeer(request_t * r, peer * e, int irtt, int ihops) -{ -#if USE_ICMP - netdbEntry *n; - double rtt = (double) irtt; - double hops = (double) ihops; - net_db_peer *p; - debug(38, 3) ("netdbUpdatePeer: '%s', %d hops, %d rtt\n", r->host, ihops, irtt); - n = netdbLookupHost(r->host); - if (n == NULL) { - debug(38, 3) ("netdbUpdatePeer: host '%s' not found\n", r->host); - return; - } - if ((p = netdbPeerByName(n, e->host)) == NULL) - p = netdbPeerAdd(n, e); - p->rtt = rtt; - p->hops = hops; - p->expires = squid_curtime + 3600; - if (n->n_peers < 2) - return; - qsort((char *) n->peers, - n->n_peers, - sizeof(net_db_peer), - sortPeerByRtt); -#endif -} - -void -netdbExchangeUpdatePeer(struct in_addr addr, peer * e, double rtt, double hops) -{ -#if USE_ICMP - netdbEntry *n; - net_db_peer *p; - debug(38, 5) ("netdbExchangeUpdatePeer: '%s', %0.1f hops, %0.1f rtt\n", - inet_ntoa(addr), hops, rtt); - n = netdbLookupAddr(addr); - if (n == NULL) - n = netdbAdd(addr); - assert(NULL != n); - if ((p = netdbPeerByName(n, e->host)) == NULL) - p = netdbPeerAdd(n, e); - p->rtt = rtt; - p->hops = hops; - p->expires = squid_curtime + 3600; /* XXX ? */ - if (n->n_peers < 2) - return; - qsort((char *) n->peers, - n->n_peers, - sizeof(net_db_peer), - sortPeerByRtt); -#endif -} - -void -netdbDeleteAddrNetwork(struct in_addr addr) -{ -#if USE_ICMP - netdbEntry *n = netdbLookupAddr(addr); - if (n == NULL) - return; - debug(38, 3) ("netdbDeleteAddrNetwork: %s\n", n->network); - netdbRelease(n); -#endif -} - -void -netdbBinaryExchange(StoreEntry * s) -{ - http_reply *reply = s->mem_obj->reply; - http_version_t version; -#if USE_ICMP - netdbEntry *n; - int i; - int j; - int rec_sz; - char *buf; - struct in_addr addr; - storeBuffer(s); - httpReplyReset(reply); - httpBuildVersion(&version, 1, 0); - httpReplySetHeaders(reply, version, HTTP_OK, "OK", - NULL, -1, squid_curtime, -2); - httpReplySwapOut(reply, s); - rec_sz = 0; - rec_sz += 1 + sizeof(addr.s_addr); - rec_sz += 1 + sizeof(int); - rec_sz += 1 + sizeof(int); - buf = memAllocate(MEM_4K_BUF); - i = 0; - hash_first(addr_table); - while ((n = (netdbEntry *) hash_next(addr_table))) { - if (0.0 == n->rtt) - continue; - if (n->rtt > 60000) /* RTT > 1 MIN probably bogus */ - continue; - if (!safe_inet_addr(n->network, &addr)) - continue; - buf[i++] = (char) NETDB_EX_NETWORK; - xmemcpy(&buf[i], &addr.s_addr, sizeof(addr.s_addr)); - i += sizeof(addr.s_addr); - buf[i++] = (char) NETDB_EX_RTT; - j = htonl((int) (n->rtt * 1000)); - xmemcpy(&buf[i], &j, sizeof(int)); - i += sizeof(int); - buf[i++] = (char) NETDB_EX_HOPS; - j = htonl((int) (n->hops * 1000)); - xmemcpy(&buf[i], &j, sizeof(int)); - i += sizeof(int); - if (i + rec_sz > 4096) { - storeAppend(s, buf, i); - i = 0; - } - } - if (i > 0) { - storeAppend(s, buf, i); - i = 0; - } - assert(0 == i); - storeBufferFlush(s); - memFree(buf, MEM_4K_BUF); -#else - httpReplyReset(reply); - httpBuildVersion(&version, 1, 0); - httpReplySetHeaders(reply, version, HTTP_BAD_REQUEST, "Bad Request", - NULL, -1, squid_curtime, -2); - storeAppendPrintf(s, "NETDB support not compiled into this Squid cache.\n"); -#endif - storeComplete(s); -} - -#if USE_ICMP -CBDATA_TYPE(netdbExchangeState); -#endif - -void -netdbExchangeStart(void *data) -{ -#if USE_ICMP - peer *p = data; - char *uri; - netdbExchangeState *ex; - StoreIOBuffer tempBuffer = EMPTYIOBUFFER; - CBDATA_INIT_TYPE(netdbExchangeState); - ex = cbdataAlloc(netdbExchangeState); - ex->p = cbdataReference(p); - uri = internalRemoteUri(p->host, p->http_port, "/squid-internal-dynamic/", "netdb"); - debug(38, 3) ("netdbExchangeStart: Requesting '%s'\n", uri); - assert(NULL != uri); - ex->r = urlParse(METHOD_GET, uri); - if (NULL == ex->r) { - debug(38, 1) ("netdbExchangeStart: Bad URI %s\n", uri); - return; - } - requestLink(ex->r); - assert(NULL != ex->r); - httpBuildVersion(&ex->r->http_ver, 1, 0); - ex->connstate = STATE_HEADER; - ex->e = storeCreateEntry(uri, uri, null_request_flags, METHOD_GET); - ex->buf_sz = NETDB_REQBUF_SZ; - assert(NULL != ex->e); - ex->sc = storeClientListAdd(ex->e, ex); - tempBuffer.offset = 0; - tempBuffer.length = ex->buf_sz; - tempBuffer.data = ex->buf; - storeClientCopy(ex->sc, ex->e, tempBuffer, - netdbExchangeHandleReply, ex); - ex->r->flags.loopdetect = 1; /* cheat! -- force direct */ - if (p->login) - xstrncpy(ex->r->login, p->login, MAX_LOGIN_SZ); - fwdStart(-1, ex->e, ex->r); -#endif -} - -peer * -netdbClosestParent(request_t * request) -{ -#if USE_ICMP - peer *p = NULL; - netdbEntry *n; - const ipcache_addrs *ia; - net_db_peer *h; - int i; - n = netdbLookupHost(request->host); - if (NULL == n) { - /* try IP addr */ - ia = ipcache_gethostbyname(request->host, 0); - if (NULL != ia) - n = netdbLookupAddr(ia->in_addrs[ia->cur]); - } - if (NULL == n) - return NULL; - if (0 == n->n_peers) - return NULL; - /* - * Find the parent with the least RTT to the origin server. - * Make sure we don't return a parent who is farther away than - * we are. Note, the n->peers list is pre-sorted by RTT. - */ - for (i = 0; i < n->n_peers; i++) { - h = &n->peers[i]; - if (n->rtt > 0) - if (n->rtt < h->rtt) - break; - p = peerFindByName(h->peername); - if (NULL == p) /* not found */ - continue; - if (neighborType(p, request) != PEER_PARENT) - continue; - if (!peerHTTPOkay(p, request)) /* not allowed */ - continue; - return p; - } -#endif - return NULL; -} --- /dev/null Wed Feb 14 01:07:22 2007 +++ squid/src/net_db.cc Wed Feb 14 01:07:37 2007 @@ -0,0 +1,1150 @@ + +/* + * $Id: net_db.cc,v 1.1.2.1 2002/10/09 05:21:29 rbcollins Exp $ + * + * DEBUG: section 38 Network Measurement Database + * AUTHOR: Duane Wessels + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +/* + * XXX XXX XXX + * + * This code may be slightly broken now. If you're getting consistent + * (sometimes working) corrupt data exchanges, please contact adrian + * (adrian@squid-cache.org) to sort them out. + */ + +#include "squid.h" +#include "Store.h" + + +#if USE_ICMP +#include "StoreClient.h" + +#define NETDB_REQBUF_SZ 4096 + +typedef enum { + STATE_NONE, + STATE_HEADER, + STATE_BODY +} netdb_conn_state_t; + +typedef struct { + peer *p; + StoreEntry *e; + store_client *sc; + request_t *r; + off_t used; + size_t buf_sz; + char buf[NETDB_REQBUF_SZ]; + int buf_ofs; + netdb_conn_state_t connstate; +} netdbExchangeState; + +static hash_table *addr_table = NULL; +static hash_table *host_table = NULL; + +static struct in_addr networkFromInaddr(struct in_addr a); +static void netdbRelease(netdbEntry * n); +static void netdbHashInsert(netdbEntry * n, struct in_addr addr); +static void netdbHashDelete(const char *key); +static void netdbHostInsert(netdbEntry * n, const char *hostname); +static void netdbHostDelete(const net_db_name * x); +static void netdbPurgeLRU(void); +static netdbEntry *netdbLookupHost(const char *key); +static net_db_peer *netdbPeerByName(const netdbEntry * n, const char *); +static net_db_peer *netdbPeerAdd(netdbEntry * n, peer * e); +static const char *netdbPeerName(const char *name); +static IPH netdbSendPing; +static QS sortPeerByRtt; +static QS sortByRtt; +static QS netdbLRU; +static FREE netdbFreeNameEntry; +static FREE netdbFreeNetdbEntry; +static STCB netdbExchangeHandleReply; +static void netdbExchangeDone(void *); + +/* We have to keep a local list of peer names. The Peers structure + * gets freed during a reconfigure. We want this database to + * remain persisitent, so _net_db_peer->peername points into this + * linked list */ +static wordlist *peer_names = NULL; + +static void +netdbHashInsert(netdbEntry * n, struct in_addr addr) +{ + xstrncpy(n->network, inet_ntoa(networkFromInaddr(addr)), 16); + n->hash.key = n->network; + assert(hash_lookup(addr_table, n->network) == NULL); + hash_join(addr_table, &n->hash); +} + +static void +netdbHashDelete(const char *key) +{ + hash_link *hptr = hash_lookup(addr_table, key); + if (hptr == NULL) { + debug_trap("netdbHashDelete: key not found"); + return; + } + hash_remove_link(addr_table, hptr); +} + +static void +netdbHostInsert(netdbEntry * n, const char *hostname) +{ + net_db_name *x = memAllocate(MEM_NET_DB_NAME); + x->hash.key = xstrdup(hostname); + x->next = n->hosts; + n->hosts = x; + x->net_db_entry = n; + assert(hash_lookup(host_table, hostname) == NULL); + hash_join(host_table, &x->hash); + n->link_count++; +} + +static void +netdbHostDelete(const net_db_name * x) +{ + netdbEntry *n; + net_db_name **X; + assert(x != NULL); + assert(x->net_db_entry != NULL); + n = x->net_db_entry; + n->link_count--; + for (X = &n->hosts; *X; X = &(*X)->next) { + if (*X == x) { + *X = x->next; + break; + } + } + hash_remove_link(host_table, (hash_link *) x); + xfree(x->hash.key); + memFree((void *) x, MEM_NET_DB_NAME); +} + +static netdbEntry * +netdbLookupHost(const char *key) +{ + net_db_name *x = (net_db_name *) hash_lookup(host_table, key); + return x ? x->net_db_entry : NULL; +} + +static void +netdbRelease(netdbEntry * n) +{ + net_db_name *x; + net_db_name *next; + for (x = n->hosts; x; x = next) { + next = x->next; + netdbHostDelete(x); + } + n->hosts = NULL; + safe_free(n->peers); + n->peers = NULL; + n->n_peers = 0; + n->n_peers_alloc = 0; + if (n->link_count == 0) { + netdbHashDelete(n->network); + memFree(n, MEM_NETDBENTRY); + } +} + +static int +netdbLRU(const void *A, const void *B) +{ + const netdbEntry *const *n1 = A; + const netdbEntry *const *n2 = B; + if ((*n1)->last_use_time > (*n2)->last_use_time) + return (1); + if ((*n1)->last_use_time < (*n2)->last_use_time) + return (-1); + return (0); +} + +static void +netdbPurgeLRU(void) +{ + netdbEntry *n; + netdbEntry **list; + int k = 0; + int list_count = 0; + int removed = 0; + list = xcalloc(memInUse(MEM_NETDBENTRY), sizeof(netdbEntry *)); + hash_first(addr_table); + while ((n = (netdbEntry *) hash_next(addr_table))) { + assert(list_count < memInUse(MEM_NETDBENTRY)); + *(list + list_count) = n; + list_count++; + } + qsort((char *) list, + list_count, + sizeof(netdbEntry *), + netdbLRU); + for (k = 0; k < list_count; k++) { + if (memInUse(MEM_NETDBENTRY) < Config.Netdb.low) + break; + netdbRelease(*(list + k)); + removed++; + } + xfree(list); +} + +static netdbEntry * +netdbLookupAddr(struct in_addr addr) +{ + netdbEntry *n; + char *key = inet_ntoa(networkFromInaddr(addr)); + n = (netdbEntry *) hash_lookup(addr_table, key); + return n; +} + +static netdbEntry * +netdbAdd(struct in_addr addr) +{ + netdbEntry *n; + if (memInUse(MEM_NETDBENTRY) > Config.Netdb.high) + netdbPurgeLRU(); + if ((n = netdbLookupAddr(addr)) == NULL) { + n = memAllocate(MEM_NETDBENTRY); + netdbHashInsert(n, addr); + } + return n; +} + +static void +netdbSendPing(const ipcache_addrs * ia, void *data) +{ + struct in_addr addr; + char *hostname = ((generic_cbdata *) data)->data; + netdbEntry *n; + netdbEntry *na; + net_db_name *x; + net_db_name **X; + cbdataFree(data); + if (ia == NULL) { + xfree(hostname); + return; + } + addr = ia->in_addrs[ia->cur]; + if ((n = netdbLookupHost(hostname)) == NULL) { + n = netdbAdd(addr); + netdbHostInsert(n, hostname); + } else if ((na = netdbLookupAddr(addr)) != n) { + /* + *hostname moved from 'network n' to 'network na'! + */ + if (na == NULL) + na = netdbAdd(addr); + debug(38, 3) ("netdbSendPing: %s moved from %s to %s\n", + hostname, n->network, na->network); + x = (net_db_name *) hash_lookup(host_table, hostname); + if (x == NULL) { + debug(38, 1) ("netdbSendPing: net_db_name list bug: %s not found", hostname); + xfree(hostname); + return; + } + /* remove net_db_name from 'network n' linked list */ + for (X = &n->hosts; *X; X = &(*X)->next) { + if (*X == x) { + *X = x->next; + break; + } + } + n->link_count--; + /* point to 'network na' from host entry */ + x->net_db_entry = na; + /* link net_db_name to 'network na' */ + x->next = na->hosts; + na->hosts = x; + na->link_count++; + n = na; + } + if (n->next_ping_time <= squid_curtime) { + debug(38, 3) ("netdbSendPing: pinging %s\n", hostname); + icmpDomainPing(addr, hostname); + n->pings_sent++; + n->next_ping_time = squid_curtime + Config.Netdb.period; + n->last_use_time = squid_curtime; + } + xfree(hostname); +} + +static struct in_addr +networkFromInaddr(struct in_addr a) +{ + struct in_addr b; + b.s_addr = ntohl(a.s_addr); +#if USE_CLASSFUL + if (IN_CLASSC(b.s_addr)) + b.s_addr &= IN_CLASSC_NET; + else if (IN_CLASSB(b.s_addr)) + b.s_addr &= IN_CLASSB_NET; + else if (IN_CLASSA(b.s_addr)) + b.s_addr &= IN_CLASSA_NET; +#else + /* use /24 for everything */ + b.s_addr &= IN_CLASSC_NET; +#endif + b.s_addr = htonl(b.s_addr); + return b; +} + +static int +sortByRtt(const void *A, const void *B) +{ + const netdbEntry *const *n1 = A; + const netdbEntry *const *n2 = B; + if ((*n1)->rtt > (*n2)->rtt) + return 1; + else if ((*n1)->rtt < (*n2)->rtt) + return -1; + else + return 0; +} + +static net_db_peer * +netdbPeerByName(const netdbEntry * n, const char *peername) +{ + int i; + net_db_peer *p = n->peers; + for (i = 0; i < n->n_peers; i++, p++) { + if (!strcmp(p->peername, peername)) + return p; + } + return NULL; +} + +static net_db_peer * +netdbPeerAdd(netdbEntry * n, peer * e) +{ + net_db_peer *p; + net_db_peer *o; + int osize; + int i; + if (n->n_peers == n->n_peers_alloc) { + o = n->peers; + osize = n->n_peers_alloc; + if (n->n_peers_alloc == 0) + n->n_peers_alloc = 2; + else + n->n_peers_alloc <<= 1; + debug(38, 3) ("netdbPeerAdd: Growing peer list for '%s' to %d\n", + n->network, n->n_peers_alloc); + n->peers = xcalloc(n->n_peers_alloc, sizeof(net_db_peer)); + for (i = 0; i < osize; i++) + *(n->peers + i) = *(o + i); + if (osize) { + safe_free(o); + } + } + p = n->peers + n->n_peers; + p->peername = netdbPeerName(e->host); + n->n_peers++; + return p; +} + +static int +sortPeerByRtt(const void *A, const void *B) +{ + const net_db_peer *p1 = A; + const net_db_peer *p2 = B; + if (p1->rtt > p2->rtt) + return 1; + else if (p1->rtt < p2->rtt) + return -1; + else + return 0; +} + +static void +netdbSaveState(void *foo) +{ + LOCAL_ARRAY(char, path, SQUID_MAXPATHLEN); + Logfile *lf; + netdbEntry *n; + net_db_name *x; + struct timeval start = current_time; + int count = 0; + snprintf(path, SQUID_MAXPATHLEN, "%s/netdb_state", storeSwapDir(0)); + /* + * This was nicer when we were using stdio, but thanks to + * Solaris bugs, its a bad idea. fopen can fail if more than + * 256 FDs are open. + */ + /* + * unlink() is here because there is currently no way to make + * logfileOpen() use O_TRUNC. + */ + unlink(path); + lf = logfileOpen(path, 4096, 0); + if (NULL == lf) { + debug(50, 1) ("netdbSaveState: %s: %s\n", path, xstrerror()); + return; + } + hash_first(addr_table); + while ((n = (netdbEntry *) hash_next(addr_table))) { + if (n->pings_recv == 0) + continue; + logfilePrintf(lf, "%s %d %d %10.5f %10.5f %d %d", + n->network, + n->pings_sent, + n->pings_recv, + n->hops, + n->rtt, + (int) n->next_ping_time, + (int) n->last_use_time); + for (x = n->hosts; x; x = x->next) + logfilePrintf(lf, " %s", hashKeyStr(&x->hash)); + logfilePrintf(lf, "\n"); + count++; +#undef RBUF_SZ + } + logfileClose(lf); + getCurrentTime(); + debug(38, 1) ("NETDB state saved; %d entries, %d msec\n", + count, tvSubMsec(start, current_time)); + eventAddIsh("netdbSaveState", netdbSaveState, NULL, 3600.0, 1); +} + +static void +netdbReloadState(void) +{ + LOCAL_ARRAY(char, path, SQUID_MAXPATHLEN); + char *buf; + char *t; + char *s; + int fd; + int l; + struct stat sb; + netdbEntry *n; + netdbEntry N; + struct in_addr addr; + int count = 0; + struct timeval start = current_time; + snprintf(path, SQUID_MAXPATHLEN, "%s/netdb_state", storeSwapDir(0)); + /* + * This was nicer when we were using stdio, but thanks to + * Solaris bugs, its a bad idea. fopen can fail if more than + * 256 FDs are open. + */ + fd = file_open(path, O_RDONLY | O_TEXT); + if (fd < 0) + return; + if (fstat(fd, &sb) < 0) { + file_close(fd); + return; + } + t = buf = xcalloc(1, sb.st_size + 1); + l = FD_READ_METHOD(fd, buf, sb.st_size); + file_close(fd); + if (l <= 0) + return; + while ((s = strchr(t, '\n'))) { + char *q; + assert(s - buf < l); + *s = '\0'; + memset(&N, '\0', sizeof(netdbEntry)); + q = strtok(t, w_space); + t = s + 1; + if (NULL == q) + continue; + if (!safe_inet_addr(q, &addr)) + continue; + if (netdbLookupAddr(addr) != NULL) /* no dups! */ + continue; + if ((q = strtok(NULL, w_space)) == NULL) + continue; + N.pings_sent = atoi(q); + if ((q = strtok(NULL, w_space)) == NULL) + continue; + N.pings_recv = atoi(q); + if (N.pings_recv == 0) + continue; + /* give this measurement low weight */ + N.pings_sent = 1; + N.pings_recv = 1; + if ((q = strtok(NULL, w_space)) == NULL) + continue; + N.hops = atof(q); + if ((q = strtok(NULL, w_space)) == NULL) + continue; + N.rtt = atof(q); + if ((q = strtok(NULL, w_space)) == NULL) + continue; + N.next_ping_time = (time_t) atoi(q); + if ((q = strtok(NULL, w_space)) == NULL) + continue; + N.last_use_time = (time_t) atoi(q); + n = memAllocate(MEM_NETDBENTRY); + xmemcpy(n, &N, sizeof(netdbEntry)); + netdbHashInsert(n, addr); + while ((q = strtok(NULL, w_space)) != NULL) { + if (netdbLookupHost(q) != NULL) /* no dups! */ + continue; + netdbHostInsert(n, q); + } + count++; + } + xfree(buf); + getCurrentTime(); + debug(38, 1) ("NETDB state reloaded; %d entries, %d msec\n", + count, tvSubMsec(start, current_time)); +} + +static const char * +netdbPeerName(const char *name) +{ + const wordlist *w; + for (w = peer_names; w; w = w->next) { + if (!strcmp(w->key, name)) + return w->key; + } + return wordlistAdd(&peer_names, name); +} + +static void +netdbFreeNetdbEntry(void *data) +{ + netdbEntry *n = data; + safe_free(n->peers); + memFree(n, MEM_NETDBENTRY); +} + +static void +netdbFreeNameEntry(void *data) +{ + net_db_name *x = data; + xfree(x->hash.key); + memFree(x, MEM_NET_DB_NAME); +} + + +static void +netdbExchangeHandleReply(void *data, StoreIOBuffer recievedData) +{ + netdbExchangeState *ex = data; + int rec_sz = 0; + off_t o; + struct in_addr addr; + double rtt; + double hops; + char *p; + int j; + HttpReply *rep; + size_t hdr_sz; + int nused = 0; + int size; + int oldbufofs = ex->buf_ofs; + + rec_sz = 0; + rec_sz += 1 + sizeof(addr.s_addr); + rec_sz += 1 + sizeof(int); + rec_sz += 1 + sizeof(int); + debug(38, 3) ("netdbExchangeHandleReply: %d read bytes\n", (int) recievedData.length); + if (!cbdataReferenceValid(ex->p)) { + debug(38, 3) ("netdbExchangeHandleReply: Peer became invalid\n"); + netdbExchangeDone(ex); + return; + } + debug(38, 3) ("netdbExchangeHandleReply: for '%s:%d'\n", ex->p->host, ex->p->http_port); + p = ex->buf; + + /* Get the size of the buffer now */ + size = ex->buf_ofs + recievedData.length; + debug(38, 3) ("netdbExchangeHandleReply: %d bytes buf\n", (int) size); + + /* Check if we're still doing headers */ + if (ex->connstate == STATE_HEADER) { + + ex->buf_ofs += recievedData.length; + + /* skip reply headers */ + if ((hdr_sz = headersEnd(p, ex->buf_ofs))) { + debug(38, 5) ("netdbExchangeHandleReply: hdr_sz = %d\n", hdr_sz); + rep = ex->e->mem_obj->reply; + if (0 == rep->sline.status) + httpReplyParse(rep, ex->buf, hdr_sz); + debug(38, 3) ("netdbExchangeHandleReply: reply status %d\n", + rep->sline.status); + if (HTTP_OK != rep->sline.status) { + netdbExchangeDone(ex); + return; + } + assert(ex->buf_ofs >= hdr_sz); + + /* + * Now, point p to the part of the buffer where the data + * starts, and update the size accordingly + */ + assert(ex->used == 0); + ex->used = hdr_sz; + size = ex->buf_ofs - hdr_sz; + p += hdr_sz; + + /* Finally, set the conn state mode to STATE_BODY */ + ex->connstate = STATE_BODY; + } else { + StoreIOBuffer tempBuffer = EMPTYIOBUFFER; + tempBuffer.offset = ex->buf_ofs; + tempBuffer.length = ex->buf_sz - ex->buf_ofs; + tempBuffer.data = ex->buf + ex->buf_ofs; + /* Have more headers .. */ + storeClientCopy(ex->sc, ex->e, tempBuffer, + netdbExchangeHandleReply, ex); + return; + } + } + assert(ex->connstate == STATE_BODY); + + /* If we get here, we have some body to parse .. */ + debug(38, 5) ("netdbExchangeHandleReply: start parsing loop, size = %d\n", + size); + while (size >= rec_sz) { + debug(38, 5) ("netdbExchangeHandleReply: in parsing loop, size = %d\n", + size); + addr.s_addr = any_addr.s_addr; + hops = rtt = 0.0; + for (o = 0; o < rec_sz;) { + switch ((int) *(p + o)) { + case NETDB_EX_NETWORK: + o++; + xmemcpy(&addr.s_addr, p + o, sizeof(addr.s_addr)); + o += sizeof(addr.s_addr); + break; + case NETDB_EX_RTT: + o++; + xmemcpy(&j, p + o, sizeof(int)); + o += sizeof(int); + rtt = (double) ntohl(j) / 1000.0; + break; + case NETDB_EX_HOPS: + o++; + xmemcpy(&j, p + o, sizeof(int)); + o += sizeof(int); + hops = (double) ntohl(j) / 1000.0; + break; + default: + debug(38, 1) ("netdbExchangeHandleReply: corrupt data, aborting\n"); + netdbExchangeDone(ex); + return; + } + } + if (addr.s_addr != any_addr.s_addr && rtt > 0) + netdbExchangeUpdatePeer(addr, ex->p, rtt, hops); + assert(o == rec_sz); + ex->used += rec_sz; + size -= rec_sz; + p += rec_sz; + nused++; + } + + /* + * Copy anything that is left over to the beginning of the buffer, + * and adjust buf_ofs accordingly + */ + + /* + * Evilly, size refers to the buf size left now, + * ex->buf_ofs is the original buffer size, so just copy that + * much data over + */ + memmove(ex->buf, ex->buf + (ex->buf_ofs - size), size); + ex->buf_ofs = size; + + /* + * And don't re-copy the remaining data .. + */ + ex->used += size; + + /* + * Now the tricky bit - size _included_ the leftover bit from the _last_ + * storeClientCopy. We don't want to include that, or our offset will be wrong. + * So, don't count the size of the leftover buffer we began with. + * This can _disappear_ when we're not tracking offsets .. + */ + ex->used -= oldbufofs; + + debug(38, 3) ("netdbExchangeHandleReply: size left over in this buffer: %d bytes\n", size); + + debug(38, 3) ("netdbExchangeHandleReply: used %d entries, (x %d bytes) == %d bytes total\n", + nused, rec_sz, nused * rec_sz); + debug(38, 3) ("netdbExchangeHandleReply: used %ld\n", (long int) ex->used); + if (EBIT_TEST(ex->e->flags, ENTRY_ABORTED)) { + debug(38, 3) ("netdbExchangeHandleReply: ENTRY_ABORTED\n"); + netdbExchangeDone(ex); + } else if (ex->e->store_status == STORE_PENDING) { + StoreIOBuffer tempBuffer = EMPTYIOBUFFER; + tempBuffer.offset = ex->used; + tempBuffer.length = ex->buf_sz - ex->buf_ofs; + tempBuffer.data = ex->buf + ex->buf_ofs; + debug(38, 3) ("netdbExchangeHandleReply: STORE_PENDING\n"); + storeClientCopy(ex->sc, ex->e, tempBuffer, + netdbExchangeHandleReply, ex); + } else if (ex->used < ex->e->mem_obj->inmem_hi) { + StoreIOBuffer tempBuffer = EMPTYIOBUFFER; + tempBuffer.offset = ex->used; + tempBuffer.length = ex->buf_sz - ex->buf_ofs; + tempBuffer.data = ex->buf + ex->buf_ofs; + debug(38, 3) ("netdbExchangeHandleReply: ex->e->mem_obj->inmem_hi\n"); + storeClientCopy(ex->sc, ex->e, tempBuffer, + netdbExchangeHandleReply, ex); + } else { + debug(38, 3) ("netdbExchangeHandleReply: Done\n"); + netdbExchangeDone(ex); + } +} + +static void +netdbExchangeDone(void *data) +{ + netdbExchangeState *ex = data; + debug(38, 3) ("netdbExchangeDone: %s\n", storeUrl(ex->e)); + requestUnlink(ex->r); + storeUnregister(ex->sc, ex->e, ex); + storeUnlockObject(ex->e); + cbdataReferenceDone(ex->p); + cbdataFree(ex); +} + +#endif /* USE_ICMP */ + +/* PUBLIC FUNCTIONS */ + +void +netdbInit(void) +{ +#if USE_ICMP + int n; + if (addr_table) + return; + n = hashPrime(Config.Netdb.high / 4); + addr_table = hash_create((HASHCMP *) strcmp, n, hash_string); + n = hashPrime(3 * Config.Netdb.high / 4); + host_table = hash_create((HASHCMP *) strcmp, n, hash_string); + eventAddIsh("netdbSaveState", netdbSaveState, NULL, 3600.0, 1); + netdbReloadState(); + cachemgrRegister("netdb", + "Network Measurement Database", + netdbDump, 0, 1); +#endif +} + +void +netdbPingSite(const char *hostname) +{ +#if USE_ICMP + netdbEntry *n; + generic_cbdata *h; + if ((n = netdbLookupHost(hostname)) != NULL) + if (n->next_ping_time > squid_curtime) + return; + h = cbdataAlloc(generic_cbdata); + h->data = xstrdup(hostname); + ipcache_nbgethostbyname(hostname, netdbSendPing, h); +#endif +} + +void +netdbHandlePingReply(const struct sockaddr_in *from, int hops, int rtt) +{ +#if USE_ICMP + netdbEntry *n; + int N; + debug(38, 3) ("netdbHandlePingReply: from %s\n", inet_ntoa(from->sin_addr)); + if ((n = netdbLookupAddr(from->sin_addr)) == NULL) + return; + N = ++n->pings_recv; + if (N > 5) + N = 5; + if (rtt < 1.0) + rtt = 1.0; + n->hops = ((n->hops * (N - 1)) + hops) / N; + n->rtt = ((n->rtt * (N - 1)) + rtt) / N; + debug(38, 3) ("netdbHandlePingReply: %s; rtt=%5.1f hops=%4.1f\n", + n->network, + n->rtt, + n->hops); +#endif +} + +void +netdbFreeMemory(void) +{ +#if USE_ICMP + hashFreeItems(addr_table, netdbFreeNetdbEntry); + hashFreeMemory(addr_table); + addr_table = NULL; + hashFreeItems(host_table, netdbFreeNameEntry); + hashFreeMemory(host_table); + host_table = NULL; + wordlistDestroy(&peer_names); + peer_names = NULL; +#endif +} + +int +netdbHops(struct in_addr addr) +{ +#if USE_ICMP + netdbEntry *n = netdbLookupAddr(addr); + if (n && n->pings_recv) { + n->last_use_time = squid_curtime; + return (int) (n->hops + 0.5); + } +#endif + return 256; +} + +void +netdbDump(StoreEntry * sentry) +{ +#if USE_ICMP + netdbEntry *n; + netdbEntry **list; + net_db_name *x; + int k; + int i; + int j; + net_db_peer *p; + storeAppendPrintf(sentry, "Network DB Statistics:\n"); + storeAppendPrintf(sentry, "%-16.16s %9s %7s %5s %s\n", + "Network", + "recv/sent", + "RTT", + "Hops", + "Hostnames"); + list = xcalloc(memInUse(MEM_NETDBENTRY), sizeof(netdbEntry *)); + i = 0; + hash_first(addr_table); + while ((n = (netdbEntry *) hash_next(addr_table))) + *(list + i++) = n; + if (i != memInUse(MEM_NETDBENTRY)) + debug(38, 0) ("WARNING: netdb_addrs count off, found %d, expected %d\n", + i, memInUse(MEM_NETDBENTRY)); + qsort((char *) list, + i, + sizeof(netdbEntry *), + sortByRtt); + for (k = 0; k < i; k++) { + n = *(list + k); + storeAppendPrintf(sentry, "%-16.16s %4d/%4d %7.1f %5.1f", + n->network, + n->pings_recv, + n->pings_sent, + n->rtt, + n->hops); + for (x = n->hosts; x; x = x->next) + storeAppendPrintf(sentry, " %s", hashKeyStr(&x->hash)); + storeAppendPrintf(sentry, "\n"); + p = n->peers; + for (j = 0; j < n->n_peers; j++, p++) { + storeAppendPrintf(sentry, " %-22.22s %7.1f %5.1f\n", + p->peername, + p->rtt, + p->hops); + } + } + xfree(list); +#else + storeAppendPrintf(sentry, + "NETDB support not compiled into this Squid cache.\n"); +#endif +} + +int +netdbHostHops(const char *host) +{ +#if USE_ICMP + netdbEntry *n = netdbLookupHost(host); + if (n) { + n->last_use_time = squid_curtime; + return (int) (n->hops + 0.5); + } +#endif + return 0; +} + +int +netdbHostRtt(const char *host) +{ +#if USE_ICMP + netdbEntry *n = netdbLookupHost(host); + if (n) { + n->last_use_time = squid_curtime; + return (int) (n->rtt + 0.5); + } +#endif + return 0; +} + +void +netdbHostData(const char *host, int *samp, int *rtt, int *hops) +{ +#if USE_ICMP + netdbEntry *n = netdbLookupHost(host); + if (n == NULL) + return; + *samp = n->pings_recv; + *rtt = (int) (n->rtt + 0.5); + *hops = (int) (n->hops + 0.5); +#endif +} + +int +netdbHostPeerRtt(const char *host, peer * p) +{ +#if USE_ICMP + const netdbEntry *n = netdbLookupHost(host); + if (n) { + const net_db_peer *np = netdbPeerByName(n, p->host); + if (np && np->expires >= squid_curtime) + return (int) (np->rtt + 0.5); + } +#endif + return 0; +} + +void +netdbUpdatePeer(request_t * r, peer * e, int irtt, int ihops) +{ +#if USE_ICMP + netdbEntry *n; + double rtt = (double) irtt; + double hops = (double) ihops; + net_db_peer *p; + debug(38, 3) ("netdbUpdatePeer: '%s', %d hops, %d rtt\n", r->host, ihops, irtt); + n = netdbLookupHost(r->host); + if (n == NULL) { + debug(38, 3) ("netdbUpdatePeer: host '%s' not found\n", r->host); + return; + } + if ((p = netdbPeerByName(n, e->host)) == NULL) + p = netdbPeerAdd(n, e); + p->rtt = rtt; + p->hops = hops; + p->expires = squid_curtime + 3600; + if (n->n_peers < 2) + return; + qsort((char *) n->peers, + n->n_peers, + sizeof(net_db_peer), + sortPeerByRtt); +#endif +} + +void +netdbExchangeUpdatePeer(struct in_addr addr, peer * e, double rtt, double hops) +{ +#if USE_ICMP + netdbEntry *n; + net_db_peer *p; + debug(38, 5) ("netdbExchangeUpdatePeer: '%s', %0.1f hops, %0.1f rtt\n", + inet_ntoa(addr), hops, rtt); + n = netdbLookupAddr(addr); + if (n == NULL) + n = netdbAdd(addr); + assert(NULL != n); + if ((p = netdbPeerByName(n, e->host)) == NULL) + p = netdbPeerAdd(n, e); + p->rtt = rtt; + p->hops = hops; + p->expires = squid_curtime + 3600; /* XXX ? */ + if (n->n_peers < 2) + return; + qsort((char *) n->peers, + n->n_peers, + sizeof(net_db_peer), + sortPeerByRtt); +#endif +} + +void +netdbDeleteAddrNetwork(struct in_addr addr) +{ +#if USE_ICMP + netdbEntry *n = netdbLookupAddr(addr); + if (n == NULL) + return; + debug(38, 3) ("netdbDeleteAddrNetwork: %s\n", n->network); + netdbRelease(n); +#endif +} + +void +netdbBinaryExchange(StoreEntry * s) +{ + http_reply *reply = s->mem_obj->reply; + http_version_t version; +#if USE_ICMP + netdbEntry *n; + int i; + int j; + int rec_sz; + char *buf; + struct in_addr addr; + storeBuffer(s); + httpReplyReset(reply); + httpBuildVersion(&version, 1, 0); + httpReplySetHeaders(reply, version, HTTP_OK, "OK", + NULL, -1, squid_curtime, -2); + httpReplySwapOut(reply, s); + rec_sz = 0; + rec_sz += 1 + sizeof(addr.s_addr); + rec_sz += 1 + sizeof(int); + rec_sz += 1 + sizeof(int); + buf = memAllocate(MEM_4K_BUF); + i = 0; + hash_first(addr_table); + while ((n = (netdbEntry *) hash_next(addr_table))) { + if (0.0 == n->rtt) + continue; + if (n->rtt > 60000) /* RTT > 1 MIN probably bogus */ + continue; + if (!safe_inet_addr(n->network, &addr)) + continue; + buf[i++] = (char) NETDB_EX_NETWORK; + xmemcpy(&buf[i], &addr.s_addr, sizeof(addr.s_addr)); + i += sizeof(addr.s_addr); + buf[i++] = (char) NETDB_EX_RTT; + j = htonl((int) (n->rtt * 1000)); + xmemcpy(&buf[i], &j, sizeof(int)); + i += sizeof(int); + buf[i++] = (char) NETDB_EX_HOPS; + j = htonl((int) (n->hops * 1000)); + xmemcpy(&buf[i], &j, sizeof(int)); + i += sizeof(int); + if (i + rec_sz > 4096) { + storeAppend(s, buf, i); + i = 0; + } + } + if (i > 0) { + storeAppend(s, buf, i); + i = 0; + } + assert(0 == i); + storeBufferFlush(s); + memFree(buf, MEM_4K_BUF); +#else + httpReplyReset(reply); + httpBuildVersion(&version, 1, 0); + httpReplySetHeaders(reply, version, HTTP_BAD_REQUEST, "Bad Request", + NULL, -1, squid_curtime, -2); + storeAppendPrintf(s, "NETDB support not compiled into this Squid cache.\n"); +#endif + storeComplete(s); +} + +#if USE_ICMP +CBDATA_TYPE(netdbExchangeState); +#endif + +void +netdbExchangeStart(void *data) +{ +#if USE_ICMP + peer *p = data; + char *uri; + netdbExchangeState *ex; + StoreIOBuffer tempBuffer = EMPTYIOBUFFER; + CBDATA_INIT_TYPE(netdbExchangeState); + ex = cbdataAlloc(netdbExchangeState); + ex->p = cbdataReference(p); + uri = internalRemoteUri(p->host, p->http_port, "/squid-internal-dynamic/", "netdb"); + debug(38, 3) ("netdbExchangeStart: Requesting '%s'\n", uri); + assert(NULL != uri); + ex->r = urlParse(METHOD_GET, uri); + if (NULL == ex->r) { + debug(38, 1) ("netdbExchangeStart: Bad URI %s\n", uri); + return; + } + requestLink(ex->r); + assert(NULL != ex->r); + httpBuildVersion(&ex->r->http_ver, 1, 0); + ex->connstate = STATE_HEADER; + ex->e = storeCreateEntry(uri, uri, null_request_flags, METHOD_GET); + ex->buf_sz = NETDB_REQBUF_SZ; + assert(NULL != ex->e); + ex->sc = storeClientListAdd(ex->e, ex); + tempBuffer.offset = 0; + tempBuffer.length = ex->buf_sz; + tempBuffer.data = ex->buf; + storeClientCopy(ex->sc, ex->e, tempBuffer, + netdbExchangeHandleReply, ex); + ex->r->flags.loopdetect = 1; /* cheat! -- force direct */ + if (p->login) + xstrncpy(ex->r->login, p->login, MAX_LOGIN_SZ); + fwdStart(-1, ex->e, ex->r); +#endif +} + +peer * +netdbClosestParent(request_t * request) +{ +#if USE_ICMP + peer *p = NULL; + netdbEntry *n; + const ipcache_addrs *ia; + net_db_peer *h; + int i; + n = netdbLookupHost(request->host); + if (NULL == n) { + /* try IP addr */ + ia = ipcache_gethostbyname(request->host, 0); + if (NULL != ia) + n = netdbLookupAddr(ia->in_addrs[ia->cur]); + } + if (NULL == n) + return NULL; + if (0 == n->n_peers) + return NULL; + /* + * Find the parent with the least RTT to the origin server. + * Make sure we don't return a parent who is farther away than + * we are. Note, the n->peers list is pre-sorted by RTT. + */ + for (i = 0; i < n->n_peers; i++) { + h = &n->peers[i]; + if (n->rtt > 0) + if (n->rtt < h->rtt) + break; + p = peerFindByName(h->peername); + if (NULL == p) /* not found */ + continue; + if (neighborType(p, request) != PEER_PARENT) + continue; + if (!peerHTTPOkay(p, request)) /* not allowed */ + continue; + return p; + } +#endif + return NULL; +} --- squid/src/store_dir.c Wed Feb 14 01:07:37 2007 +++ /dev/null Wed Feb 14 01:07:22 2007 @@ -1,546 +0,0 @@ - -/* - * $Id: store_dir.c,v 1.20.22.3 2002/10/04 21:57:52 rbcollins Exp $ - * - * DEBUG: section 47 Store Directory Routines - * AUTHOR: Duane Wessels - * - * SQUID Web Proxy Cache http://www.squid-cache.org/ - * ---------------------------------------------------------- - * - * Squid is the result of efforts by numerous individuals from - * the Internet community; see the CONTRIBUTORS file for full - * details. Many organizations have provided support for Squid's - * development; see the SPONSORS file for full details. Squid is - * Copyrighted (C) 2001 by the Regents of the University of - * California; see the COPYRIGHT file for full details. Squid - * incorporates software developed and/or copyrighted by other - * sources; see the CREDITS file for full details. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. - * - */ - -#include "squid.h" -#include "Store.h" - -#if HAVE_STATVFS -#if HAVE_SYS_STATVFS_H -#include -#endif -#endif -/* Windows uses sys/vfs.h */ -#if HAVE_SYS_VFS_H -#include -#endif - -static int storeDirValidSwapDirSize(int, ssize_t); -static STDIRSELECT storeDirSelectSwapDirRoundRobin; -static STDIRSELECT storeDirSelectSwapDirLeastLoad; - -/* - * This function pointer is set according to 'store_dir_select_algorithm' - * in squid.conf. - */ -STDIRSELECT *storeDirSelectSwapDir = storeDirSelectSwapDirLeastLoad; - -void -storeDirInit(void) -{ - int i; - SwapDir *sd; - for (i = 0; i < Config.cacheSwap.n_configured; i++) { - sd = &Config.cacheSwap.swapDirs[i]; - sd->init(sd); - } - if (0 == strcasecmp(Config.store_dir_select_algorithm, "round-robin")) { - storeDirSelectSwapDir = storeDirSelectSwapDirRoundRobin; - debug(47, 1) ("Using Round Robin store dir selection\n"); - } else { - storeDirSelectSwapDir = storeDirSelectSwapDirLeastLoad; - debug(47, 1) ("Using Least Load store dir selection\n"); - } -} - -void -storeCreateSwapDirectories(void) -{ - int i; - SwapDir *sd; - pid_t pid; - int status; - for (i = 0; i < Config.cacheSwap.n_configured; i++) { - if (fork()) - continue; - sd = &Config.cacheSwap.swapDirs[i]; - if (NULL != sd->newfs) - sd->newfs(sd); - exit(0); - } - do { -#ifdef _SQUID_NEXT_ - pid = wait3(&status, WNOHANG, NULL); -#else - pid = waitpid(-1, &status, 0); -#endif - } while (pid > 0 || (pid < 0 && errno == EINTR)); -} - -/* - * Determine whether the given directory can handle this object - * size - * - * Note: if the object size is -1, then the only swapdirs that - * will return true here are ones that have max_obj_size = -1, - * ie any-sized-object swapdirs. This is a good thing. - */ -static int -storeDirValidSwapDirSize(int swapdir, ssize_t objsize) -{ - /* - * If the swapdir's max_obj_size is -1, then it definitely can - */ - if (Config.cacheSwap.swapDirs[swapdir].max_objsize == -1) - return 1; - - /* - * If the object size is -1, then if the storedir isn't -1 we - * can't store it - */ - if ((objsize == -1) && - (Config.cacheSwap.swapDirs[swapdir].max_objsize != -1)) - return 0; - - /* - * Else, make sure that the max object size is larger than objsize - */ - if (Config.cacheSwap.swapDirs[swapdir].max_objsize > objsize) - return 1; - else - return 0; -} - - -/* - * This new selection scheme simply does round-robin on all SwapDirs. - * A SwapDir is skipped if it is over the max_size (100%) limit, or - * overloaded. - */ -static int -storeDirSelectSwapDirRoundRobin(const StoreEntry * e) -{ - static int dirn = 0; - int i; - int load; - SwapDir *sd; - ssize_t objsize = (ssize_t) objectLen(e); - for (i = 0; i <= Config.cacheSwap.n_configured; i++) { - if (++dirn >= Config.cacheSwap.n_configured) - dirn = 0; - sd = &Config.cacheSwap.swapDirs[dirn]; - if (sd->flags.read_only) - continue; - if (sd->cur_size > sd->max_size) - continue; - if (!storeDirValidSwapDirSize(i, objsize)) - continue; - /* check for error or overload condition */ - load = sd->checkobj(sd, e); - if (load < 0 || load > 1000) { - continue; - } - return dirn; - } - return -1; -} - -/* - * Spread load across all of the store directories - * - * Note: We should modify this later on to prefer sticking objects - * in the *tightest fit* swapdir to conserve space, along with the - * actual swapdir usage. But for now, this hack will do while - * testing, so you should order your swapdirs in the config file - * from smallest maxobjsize to unlimited (-1) maxobjsize. - * - * We also have to choose nleast == nconf since we need to consider - * ALL swapdirs, regardless of state. Again, this is a hack while - * we sort out the real usefulness of this algorithm. - */ -static int -storeDirSelectSwapDirLeastLoad(const StoreEntry * e) -{ - ssize_t objsize; - ssize_t most_free = 0, cur_free; - ssize_t least_objsize = -1; - int least_load = INT_MAX; - int load; - int dirn = -1; - int i; - SwapDir *SD; - - /* Calculate the object size */ - objsize = (ssize_t) objectLen(e); - if (objsize != -1) - objsize += e->mem_obj->swap_hdr_sz; - for (i = 0; i < Config.cacheSwap.n_configured; i++) { - SD = &Config.cacheSwap.swapDirs[i]; - SD->flags.selected = 0; - load = SD->checkobj(SD, e); - if (load < 0 || load > 1000) { - continue; - } - if (!storeDirValidSwapDirSize(i, objsize)) - continue; - if (SD->flags.read_only) - continue; - if (SD->cur_size > SD->max_size) - continue; - if (load > least_load) - continue; - cur_free = SD->max_size - SD->cur_size; - /* If the load is equal, then look in more details */ - if (load == least_load) { - /* closest max_objsize fit */ - if (least_objsize != -1) - if (SD->max_objsize > least_objsize || SD->max_objsize == -1) - continue; - /* most free */ - if (cur_free < most_free) - continue; - } - least_load = load; - least_objsize = SD->max_objsize; - most_free = cur_free; - dirn = i; - } - if (dirn >= 0) - Config.cacheSwap.swapDirs[dirn].flags.selected = 1; - return dirn; -} - - - -char * -storeSwapDir(int dirn) -{ - assert(0 <= dirn && dirn < Config.cacheSwap.n_configured); - return Config.cacheSwap.swapDirs[dirn].path; -} - -/* - * An entry written to the swap log MUST have the following - * properties. - * 1. It MUST be a public key. It does no good to log - * a public ADD, change the key, then log a private - * DEL. So we need to log a DEL before we change a - * key from public to private. - * 2. It MUST have a valid (> -1) swap_filen. - */ -void -storeDirSwapLog(const StoreEntry * e, int op) -{ - SwapDir *sd; - assert(!EBIT_TEST(e->flags, KEY_PRIVATE)); - assert(e->swap_filen >= 0); - /* - * icons and such; don't write them to the swap log - */ - if (EBIT_TEST(e->flags, ENTRY_SPECIAL)) - return; - assert(op > SWAP_LOG_NOP && op < SWAP_LOG_MAX); - debug(20, 3) ("storeDirSwapLog: %s %s %d %08X\n", - swap_log_op_str[op], - storeKeyText(e->hash.key), - e->swap_dirn, - e->swap_filen); - sd = &Config.cacheSwap.swapDirs[e->swap_dirn]; - sd->log.write(sd, e, op); -} - -void -storeDirUpdateSwapSize(SwapDir * SD, size_t size, int sign) -{ - int blks = (size + SD->fs.blksize - 1) / SD->fs.blksize; - int k = (blks * SD->fs.blksize >> 10) * sign; - SD->cur_size += k; - store_swap_size += k; - if (sign > 0) - n_disk_objects++; - else if (sign < 0) - n_disk_objects--; -} - -void -storeDirStats(StoreEntry * sentry) -{ - int i; - SwapDir *SD; - - storeAppendPrintf(sentry, "Store Directory Statistics:\n"); - storeAppendPrintf(sentry, "Store Entries : %d\n", - storeEntryInUse()); - storeAppendPrintf(sentry, "Maximum Swap Size : %8ld KB\n", - (long int) Config.Swap.maxSize); - storeAppendPrintf(sentry, "Current Store Swap Size: %8lu KB\n", - store_swap_size); - storeAppendPrintf(sentry, "Current Capacity : %d%% used, %d%% free\n", - percent((int) store_swap_size, (int) Config.Swap.maxSize), - percent((int) (Config.Swap.maxSize - store_swap_size), (int) Config.Swap.maxSize)); - /* FIXME Here we should output memory statistics */ - - /* Now go through each swapdir, calling its statfs routine */ - for (i = 0; i < Config.cacheSwap.n_configured; i++) { - storeAppendPrintf(sentry, "\n"); - SD = &(Config.cacheSwap.swapDirs[i]); - storeAppendPrintf(sentry, "Store Directory #%d (%s): %s\n", i, SD->type, - storeSwapDir(i)); - storeAppendPrintf(sentry, "FS Block Size %d Bytes\n", - SD->fs.blksize); - SD->statfs(SD, sentry); - if (SD->repl) { - storeAppendPrintf(sentry, "Removal policy: %s\n", SD->repl->_type); - if (SD->repl->Stats) - SD->repl->Stats(SD->repl, sentry); - } - } -} - -void -storeDirConfigure(void) -{ - SwapDir *SD; - int i; - Config.Swap.maxSize = 0; - for (i = 0; i < Config.cacheSwap.n_configured; i++) { - SD = &Config.cacheSwap.swapDirs[i]; - Config.Swap.maxSize += SD->max_size; - SD->low_size = (int) (((float) SD->max_size * - (float) Config.Swap.lowWaterMark) / 100.0); - } -} - -void -storeDirDiskFull(sdirno dirn) -{ - SwapDir *SD = &Config.cacheSwap.swapDirs[dirn]; - assert(0 <= dirn && dirn < Config.cacheSwap.n_configured); - if (SD->cur_size >= SD->max_size) - return; - SD->max_size = SD->cur_size; - debug(20, 1) ("WARNING: Shrinking cache_dir #%d to %d KB\n", - dirn, SD->cur_size); -} - -void -storeDirOpenSwapLogs(void) -{ - int dirn; - SwapDir *sd; - for (dirn = 0; dirn < Config.cacheSwap.n_configured; dirn++) { - sd = &Config.cacheSwap.swapDirs[dirn]; - if (sd->log.open) - sd->log.open(sd); - } -} - -void -storeDirCloseSwapLogs(void) -{ - int dirn; - SwapDir *sd; - for (dirn = 0; dirn < Config.cacheSwap.n_configured; dirn++) { - sd = &Config.cacheSwap.swapDirs[dirn]; - if (sd->log.close) - sd->log.close(sd); - } -} - -/* - * storeDirWriteCleanLogs - * - * Writes a "clean" swap log file from in-memory metadata. - * This is a rewrite of the original function to troll each - * StoreDir and write the logs, and flush at the end of - * the run. Thanks goes to Eric Stern, since this solution - * came out of his COSS code. - */ -#define CLEAN_BUF_SZ 16384 -int -storeDirWriteCleanLogs(int reopen) -{ - const StoreEntry *e = NULL; - int n = 0; - struct timeval start; - double dt; - SwapDir *sd; - int dirn; - int notdone = 1; - if (store_dirs_rebuilding) { - debug(20, 1) ("Not currently OK to rewrite swap log.\n"); - debug(20, 1) ("storeDirWriteCleanLogs: Operation aborted.\n"); - return 0; - } - debug(20, 1) ("storeDirWriteCleanLogs: Starting...\n"); - getCurrentTime(); - start = current_time; - for (dirn = 0; dirn < Config.cacheSwap.n_configured; dirn++) { - sd = &Config.cacheSwap.swapDirs[dirn]; - if (sd->log.clean.start(sd) < 0) { - debug(20, 1) ("log.clean.start() failed for dir #%d\n", sd->index); - continue; - } - } - while (notdone) { - notdone = 0; - for (dirn = 0; dirn < Config.cacheSwap.n_configured; dirn++) { - sd = &Config.cacheSwap.swapDirs[dirn]; - if (NULL == sd->log.clean.write) - continue; - e = sd->log.clean.nextentry(sd); - if (!e) - continue; - notdone = 1; - if (e->swap_filen < 0) - continue; - if (e->swap_status != SWAPOUT_DONE) - continue; - if (e->swap_file_sz <= 0) - continue; - if (EBIT_TEST(e->flags, RELEASE_REQUEST)) - continue; - if (EBIT_TEST(e->flags, KEY_PRIVATE)) - continue; - if (EBIT_TEST(e->flags, ENTRY_SPECIAL)) - continue; - sd->log.clean.write(sd, e); - if ((++n & 0xFFFF) == 0) { - getCurrentTime(); - debug(20, 1) (" %7d entries written so far.\n", n); - } - } - } - /* Flush */ - for (dirn = 0; dirn < Config.cacheSwap.n_configured; dirn++) { - sd = &Config.cacheSwap.swapDirs[dirn]; - sd->log.clean.done(sd); - } - if (reopen) - storeDirOpenSwapLogs(); - getCurrentTime(); - dt = tvSubDsec(start, current_time); - debug(20, 1) (" Finished. Wrote %d entries.\n", n); - debug(20, 1) (" Took %3.1f seconds (%6.1f entries/sec).\n", - dt, (double) n / (dt > 0.0 ? dt : 1.0)); - return n; -} -#undef CLEAN_BUF_SZ - -/* - * sync all avaliable fs'es .. - */ -void -storeDirSync(void) -{ - int i; - SwapDir *SD; - - for (i = 0; i < Config.cacheSwap.n_configured; i++) { - SD = &Config.cacheSwap.swapDirs[i]; - if (SD->sync != NULL) - SD->sync(SD); - } -} - -/* - * handle callbacks all avaliable fs'es .. - */ -void -storeDirCallback(void) -{ - int i, j; - SwapDir *SD; - static int ndir = 0; - do { - j = 0; - for (i = 0; i < Config.cacheSwap.n_configured; i++) { - if (ndir >= Config.cacheSwap.n_configured) - ndir = ndir % Config.cacheSwap.n_configured; - SD = &Config.cacheSwap.swapDirs[ndir++]; - if (NULL == SD->callback) - continue; - j += SD->callback(SD); - } - } while (j > 0); - ndir++; -} - -int -storeDirGetBlkSize(const char *path, int *blksize) -{ -#if HAVE_STATVFS - struct statvfs sfs; - if (statvfs(path, &sfs)) { - debug(50, 1) ("%s: %s\n", path, xstrerror()); - *blksize = 2048; - return 1; - } - *blksize = (int) sfs.f_frsize; -#else - struct statfs sfs; - if (statfs(path, &sfs)) { - debug(50, 1) ("%s: %s\n", path, xstrerror()); - *blksize = 2048; - return 1; - } - *blksize = (int) sfs.f_bsize; -#endif - /* - * Sanity check; make sure we have a meaningful value. - */ - if (*blksize < 512) - *blksize = 2048; - return 0; -} - -#define fsbtoblk(num, fsbs, bs) \ - (((fsbs) != 0 && (fsbs) < (bs)) ? \ - (num) / ((bs) / (fsbs)) : (num) * ((fsbs) / (bs))) -int -storeDirGetUFSStats(const char *path, int *totl_kb, int *free_kb, int *totl_in, int *free_in) -{ -#if HAVE_STATVFS - struct statvfs sfs; - if (statvfs(path, &sfs)) { - debug(50, 1) ("%s: %s\n", path, xstrerror()); - return 1; - } - *totl_kb = (int) fsbtoblk(sfs.f_blocks, sfs.f_frsize, 1024); - *free_kb = (int) fsbtoblk(sfs.f_bfree, sfs.f_frsize, 1024); - *totl_in = (int) sfs.f_files; - *free_in = (int) sfs.f_ffree; -#else - struct statfs sfs; - if (statfs(path, &sfs)) { - debug(50, 1) ("%s: %s\n", path, xstrerror()); - return 1; - } - *totl_kb = (int) fsbtoblk(sfs.f_blocks, sfs.f_bsize, 1024); - *free_kb = (int) fsbtoblk(sfs.f_bfree, sfs.f_bsize, 1024); - *totl_in = (int) sfs.f_files; - *free_in = (int) sfs.f_ffree; -#endif - return 0; -} --- /dev/null Wed Feb 14 01:07:22 2007 +++ squid/src/store_dir.cc Wed Feb 14 01:07:38 2007 @@ -0,0 +1,546 @@ + +/* + * $Id: store_dir.cc,v 1.1.2.1 2002/10/09 05:21:29 rbcollins Exp $ + * + * DEBUG: section 47 Store Directory Routines + * AUTHOR: Duane Wessels + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#include "squid.h" +#include "Store.h" + +#if HAVE_STATVFS +#if HAVE_SYS_STATVFS_H +#include +#endif +#endif +/* Windows uses sys/vfs.h */ +#if HAVE_SYS_VFS_H +#include +#endif + +static int storeDirValidSwapDirSize(int, ssize_t); +static STDIRSELECT storeDirSelectSwapDirRoundRobin; +static STDIRSELECT storeDirSelectSwapDirLeastLoad; + +/* + * This function pointer is set according to 'store_dir_select_algorithm' + * in squid.conf. + */ +STDIRSELECT *storeDirSelectSwapDir = storeDirSelectSwapDirLeastLoad; + +void +storeDirInit(void) +{ + int i; + SwapDir *sd; + for (i = 0; i < Config.cacheSwap.n_configured; i++) { + sd = &Config.cacheSwap.swapDirs[i]; + sd->init(sd); + } + if (0 == strcasecmp(Config.store_dir_select_algorithm, "round-robin")) { + storeDirSelectSwapDir = storeDirSelectSwapDirRoundRobin; + debug(47, 1) ("Using Round Robin store dir selection\n"); + } else { + storeDirSelectSwapDir = storeDirSelectSwapDirLeastLoad; + debug(47, 1) ("Using Least Load store dir selection\n"); + } +} + +void +storeCreateSwapDirectories(void) +{ + int i; + SwapDir *sd; + pid_t pid; + int status; + for (i = 0; i < Config.cacheSwap.n_configured; i++) { + if (fork()) + continue; + sd = &Config.cacheSwap.swapDirs[i]; + if (NULL != sd->newfs) + sd->newfs(sd); + exit(0); + } + do { +#ifdef _SQUID_NEXT_ + pid = wait3(&status, WNOHANG, NULL); +#else + pid = waitpid(-1, &status, 0); +#endif + } while (pid > 0 || (pid < 0 && errno == EINTR)); +} + +/* + * Determine whether the given directory can handle this object + * size + * + * Note: if the object size is -1, then the only swapdirs that + * will return true here are ones that have max_obj_size = -1, + * ie any-sized-object swapdirs. This is a good thing. + */ +static int +storeDirValidSwapDirSize(int swapdir, ssize_t objsize) +{ + /* + * If the swapdir's max_obj_size is -1, then it definitely can + */ + if (Config.cacheSwap.swapDirs[swapdir].max_objsize == -1) + return 1; + + /* + * If the object size is -1, then if the storedir isn't -1 we + * can't store it + */ + if ((objsize == -1) && + (Config.cacheSwap.swapDirs[swapdir].max_objsize != -1)) + return 0; + + /* + * Else, make sure that the max object size is larger than objsize + */ + if (Config.cacheSwap.swapDirs[swapdir].max_objsize > objsize) + return 1; + else + return 0; +} + + +/* + * This new selection scheme simply does round-robin on all SwapDirs. + * A SwapDir is skipped if it is over the max_size (100%) limit, or + * overloaded. + */ +static int +storeDirSelectSwapDirRoundRobin(const StoreEntry * e) +{ + static int dirn = 0; + int i; + int load; + SwapDir *sd; + ssize_t objsize = (ssize_t) objectLen(e); + for (i = 0; i <= Config.cacheSwap.n_configured; i++) { + if (++dirn >= Config.cacheSwap.n_configured) + dirn = 0; + sd = &Config.cacheSwap.swapDirs[dirn]; + if (sd->flags.read_only) + continue; + if (sd->cur_size > sd->max_size) + continue; + if (!storeDirValidSwapDirSize(i, objsize)) + continue; + /* check for error or overload condition */ + load = sd->checkobj(sd, e); + if (load < 0 || load > 1000) { + continue; + } + return dirn; + } + return -1; +} + +/* + * Spread load across all of the store directories + * + * Note: We should modify this later on to prefer sticking objects + * in the *tightest fit* swapdir to conserve space, along with the + * actual swapdir usage. But for now, this hack will do while + * testing, so you should order your swapdirs in the config file + * from smallest maxobjsize to unlimited (-1) maxobjsize. + * + * We also have to choose nleast == nconf since we need to consider + * ALL swapdirs, regardless of state. Again, this is a hack while + * we sort out the real usefulness of this algorithm. + */ +static int +storeDirSelectSwapDirLeastLoad(const StoreEntry * e) +{ + ssize_t objsize; + ssize_t most_free = 0, cur_free; + ssize_t least_objsize = -1; + int least_load = INT_MAX; + int load; + int dirn = -1; + int i; + SwapDir *SD; + + /* Calculate the object size */ + objsize = (ssize_t) objectLen(e); + if (objsize != -1) + objsize += e->mem_obj->swap_hdr_sz; + for (i = 0; i < Config.cacheSwap.n_configured; i++) { + SD = &Config.cacheSwap.swapDirs[i]; + SD->flags.selected = 0; + load = SD->checkobj(SD, e); + if (load < 0 || load > 1000) { + continue; + } + if (!storeDirValidSwapDirSize(i, objsize)) + continue; + if (SD->flags.read_only) + continue; + if (SD->cur_size > SD->max_size) + continue; + if (load > least_load) + continue; + cur_free = SD->max_size - SD->cur_size; + /* If the load is equal, then look in more details */ + if (load == least_load) { + /* closest max_objsize fit */ + if (least_objsize != -1) + if (SD->max_objsize > least_objsize || SD->max_objsize == -1) + continue; + /* most free */ + if (cur_free < most_free) + continue; + } + least_load = load; + least_objsize = SD->max_objsize; + most_free = cur_free; + dirn = i; + } + if (dirn >= 0) + Config.cacheSwap.swapDirs[dirn].flags.selected = 1; + return dirn; +} + + + +char * +storeSwapDir(int dirn) +{ + assert(0 <= dirn && dirn < Config.cacheSwap.n_configured); + return Config.cacheSwap.swapDirs[dirn].path; +} + +/* + * An entry written to the swap log MUST have the following + * properties. + * 1. It MUST be a public key. It does no good to log + * a public ADD, change the key, then log a private + * DEL. So we need to log a DEL before we change a + * key from public to private. + * 2. It MUST have a valid (> -1) swap_filen. + */ +void +storeDirSwapLog(const StoreEntry * e, int op) +{ + SwapDir *sd; + assert(!EBIT_TEST(e->flags, KEY_PRIVATE)); + assert(e->swap_filen >= 0); + /* + * icons and such; don't write them to the swap log + */ + if (EBIT_TEST(e->flags, ENTRY_SPECIAL)) + return; + assert(op > SWAP_LOG_NOP && op < SWAP_LOG_MAX); + debug(20, 3) ("storeDirSwapLog: %s %s %d %08X\n", + swap_log_op_str[op], + storeKeyText((const cache_key *)e->hash.key), + e->swap_dirn, + e->swap_filen); + sd = &Config.cacheSwap.swapDirs[e->swap_dirn]; + sd->log.write(sd, e, op); +} + +void +storeDirUpdateSwapSize(SwapDir * SD, size_t size, int sign) +{ + int blks = (size + SD->fs.blksize - 1) / SD->fs.blksize; + int k = (blks * SD->fs.blksize >> 10) * sign; + SD->cur_size += k; + store_swap_size += k; + if (sign > 0) + n_disk_objects++; + else if (sign < 0) + n_disk_objects--; +} + +void +storeDirStats(StoreEntry * sentry) +{ + int i; + SwapDir *SD; + + storeAppendPrintf(sentry, "Store Directory Statistics:\n"); + storeAppendPrintf(sentry, "Store Entries : %d\n", + storeEntryInUse()); + storeAppendPrintf(sentry, "Maximum Swap Size : %8ld KB\n", + (long int) Config.Swap.maxSize); + storeAppendPrintf(sentry, "Current Store Swap Size: %8lu KB\n", + store_swap_size); + storeAppendPrintf(sentry, "Current Capacity : %d%% used, %d%% free\n", + percent((int) store_swap_size, (int) Config.Swap.maxSize), + percent((int) (Config.Swap.maxSize - store_swap_size), (int) Config.Swap.maxSize)); + /* FIXME Here we should output memory statistics */ + + /* Now go through each swapdir, calling its statfs routine */ + for (i = 0; i < Config.cacheSwap.n_configured; i++) { + storeAppendPrintf(sentry, "\n"); + SD = &(Config.cacheSwap.swapDirs[i]); + storeAppendPrintf(sentry, "Store Directory #%d (%s): %s\n", i, SD->type, + storeSwapDir(i)); + storeAppendPrintf(sentry, "FS Block Size %d Bytes\n", + SD->fs.blksize); + SD->statfs(SD, sentry); + if (SD->repl) { + storeAppendPrintf(sentry, "Removal policy: %s\n", SD->repl->_type); + if (SD->repl->Stats) + SD->repl->Stats(SD->repl, sentry); + } + } +} + +void +storeDirConfigure(void) +{ + SwapDir *SD; + int i; + Config.Swap.maxSize = 0; + for (i = 0; i < Config.cacheSwap.n_configured; i++) { + SD = &Config.cacheSwap.swapDirs[i]; + Config.Swap.maxSize += SD->max_size; + SD->low_size = (int) (((float) SD->max_size * + (float) Config.Swap.lowWaterMark) / 100.0); + } +} + +void +storeDirDiskFull(sdirno dirn) +{ + SwapDir *SD = &Config.cacheSwap.swapDirs[dirn]; + assert(0 <= dirn && dirn < Config.cacheSwap.n_configured); + if (SD->cur_size >= SD->max_size) + return; + SD->max_size = SD->cur_size; + debug(20, 1) ("WARNING: Shrinking cache_dir #%d to %d KB\n", + dirn, SD->cur_size); +} + +void +storeDirOpenSwapLogs(void) +{ + int dirn; + SwapDir *sd; + for (dirn = 0; dirn < Config.cacheSwap.n_configured; dirn++) { + sd = &Config.cacheSwap.swapDirs[dirn]; + if (sd->log.open) + sd->log.open(sd); + } +} + +void +storeDirCloseSwapLogs(void) +{ + int dirn; + SwapDir *sd; + for (dirn = 0; dirn < Config.cacheSwap.n_configured; dirn++) { + sd = &Config.cacheSwap.swapDirs[dirn]; + if (sd->log.close) + sd->log.close(sd); + } +} + +/* + * storeDirWriteCleanLogs + * + * Writes a "clean" swap log file from in-memory metadata. + * This is a rewrite of the original function to troll each + * StoreDir and write the logs, and flush at the end of + * the run. Thanks goes to Eric Stern, since this solution + * came out of his COSS code. + */ +#define CLEAN_BUF_SZ 16384 +int +storeDirWriteCleanLogs(int reopen) +{ + const StoreEntry *e = NULL; + int n = 0; + struct timeval start; + double dt; + SwapDir *sd; + int dirn; + int notdone = 1; + if (store_dirs_rebuilding) { + debug(20, 1) ("Not currently OK to rewrite swap log.\n"); + debug(20, 1) ("storeDirWriteCleanLogs: Operation aborted.\n"); + return 0; + } + debug(20, 1) ("storeDirWriteCleanLogs: Starting...\n"); + getCurrentTime(); + start = current_time; + for (dirn = 0; dirn < Config.cacheSwap.n_configured; dirn++) { + sd = &Config.cacheSwap.swapDirs[dirn]; + if (sd->log.clean.start(sd) < 0) { + debug(20, 1) ("log.clean.start() failed for dir #%d\n", sd->index); + continue; + } + } + while (notdone) { + notdone = 0; + for (dirn = 0; dirn < Config.cacheSwap.n_configured; dirn++) { + sd = &Config.cacheSwap.swapDirs[dirn]; + if (NULL == sd->log.clean.write) + continue; + e = sd->log.clean.nextentry(sd); + if (!e) + continue; + notdone = 1; + if (e->swap_filen < 0) + continue; + if (e->swap_status != SWAPOUT_DONE) + continue; + if (e->swap_file_sz <= 0) + continue; + if (EBIT_TEST(e->flags, RELEASE_REQUEST)) + continue; + if (EBIT_TEST(e->flags, KEY_PRIVATE)) + continue; + if (EBIT_TEST(e->flags, ENTRY_SPECIAL)) + continue; + sd->log.clean.write(sd, e); + if ((++n & 0xFFFF) == 0) { + getCurrentTime(); + debug(20, 1) (" %7d entries written so far.\n", n); + } + } + } + /* Flush */ + for (dirn = 0; dirn < Config.cacheSwap.n_configured; dirn++) { + sd = &Config.cacheSwap.swapDirs[dirn]; + sd->log.clean.done(sd); + } + if (reopen) + storeDirOpenSwapLogs(); + getCurrentTime(); + dt = tvSubDsec(start, current_time); + debug(20, 1) (" Finished. Wrote %d entries.\n", n); + debug(20, 1) (" Took %3.1f seconds (%6.1f entries/sec).\n", + dt, (double) n / (dt > 0.0 ? dt : 1.0)); + return n; +} +#undef CLEAN_BUF_SZ + +/* + * sync all avaliable fs'es .. + */ +void +storeDirSync(void) +{ + int i; + SwapDir *SD; + + for (i = 0; i < Config.cacheSwap.n_configured; i++) { + SD = &Config.cacheSwap.swapDirs[i]; + if (SD->sync != NULL) + SD->sync(SD); + } +} + +/* + * handle callbacks all avaliable fs'es .. + */ +void +storeDirCallback(void) +{ + int i, j; + SwapDir *SD; + static int ndir = 0; + do { + j = 0; + for (i = 0; i < Config.cacheSwap.n_configured; i++) { + if (ndir >= Config.cacheSwap.n_configured) + ndir = ndir % Config.cacheSwap.n_configured; + SD = &Config.cacheSwap.swapDirs[ndir++]; + if (NULL == SD->callback) + continue; + j += SD->callback(SD); + } + } while (j > 0); + ndir++; +} + +int +storeDirGetBlkSize(const char *path, int *blksize) +{ +#if HAVE_STATVFS + struct statvfs sfs; + if (statvfs(path, &sfs)) { + debug(50, 1) ("%s: %s\n", path, xstrerror()); + *blksize = 2048; + return 1; + } + *blksize = (int) sfs.f_frsize; +#else + struct statfs sfs; + if (statfs(path, &sfs)) { + debug(50, 1) ("%s: %s\n", path, xstrerror()); + *blksize = 2048; + return 1; + } + *blksize = (int) sfs.f_bsize; +#endif + /* + * Sanity check; make sure we have a meaningful value. + */ + if (*blksize < 512) + *blksize = 2048; + return 0; +} + +#define fsbtoblk(num, fsbs, bs) \ + (((fsbs) != 0 && (fsbs) < (bs)) ? \ + (num) / ((bs) / (fsbs)) : (num) * ((fsbs) / (bs))) +int +storeDirGetUFSStats(const char *path, int *totl_kb, int *free_kb, int *totl_in, int *free_in) +{ +#if HAVE_STATVFS + struct statvfs sfs; + if (statvfs(path, &sfs)) { + debug(50, 1) ("%s: %s\n", path, xstrerror()); + return 1; + } + *totl_kb = (int) fsbtoblk(sfs.f_blocks, sfs.f_frsize, 1024); + *free_kb = (int) fsbtoblk(sfs.f_bfree, sfs.f_frsize, 1024); + *totl_in = (int) sfs.f_files; + *free_in = (int) sfs.f_ffree; +#else + struct statfs sfs; + if (statfs(path, &sfs)) { + debug(50, 1) ("%s: %s\n", path, xstrerror()); + return 1; + } + *totl_kb = (int) fsbtoblk(sfs.f_blocks, sfs.f_bsize, 1024); + *free_kb = (int) fsbtoblk(sfs.f_bfree, sfs.f_bsize, 1024); + *totl_in = (int) sfs.f_files; + *free_in = (int) sfs.f_ffree; +#endif + return 0; +} --- squid/src/whois.c Wed Feb 14 01:07:38 2007 +++ /dev/null Wed Feb 14 01:07:22 2007 @@ -1,141 +0,0 @@ - -/* - * $Id: whois.c,v 1.9.10.1 2002/10/04 07:07:29 rbcollins Exp $ - * - * DEBUG: section 75 WHOIS protocol - * AUTHOR: Duane Wessels, Kostas Anagnostakis - * - * SQUID Web Proxy Cache http://www.squid-cache.org/ - * ---------------------------------------------------------- - * - * Squid is the result of efforts by numerous individuals from - * the Internet community; see the CONTRIBUTORS file for full - * details. Many organizations have provided support for Squid's - * development; see the SPONSORS file for full details. Squid is - * Copyrighted (C) 2001 by the Regents of the University of - * California; see the COPYRIGHT file for full details. Squid - * incorporates software developed and/or copyrighted by other - * sources; see the CREDITS file for full details. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. - * - */ - -#include "squid.h" -#include "Store.h" - -#define WHOIS_PORT 43 - -typedef struct { - StoreEntry *entry; - request_t *request; - FwdState *fwd; -} WhoisState; - -static PF whoisClose; -static PF whoisTimeout; -static PF whoisReadReply; - -/* PUBLIC */ - -CBDATA_TYPE(WhoisState); - -void -whoisStart(FwdState * fwd) -{ - WhoisState *p; - int fd = fwd->server_fd; - char *buf; - size_t l; - CBDATA_INIT_TYPE(WhoisState); - p = cbdataAlloc(WhoisState); - p->request = fwd->request; - p->entry = fwd->entry; - p->fwd = fwd; - storeLockObject(p->entry); - comm_add_close_handler(fd, whoisClose, p); - l = strLen(p->request->urlpath) + 3; - buf = xmalloc(l); - snprintf(buf, l, "%s\r\n", strBuf(p->request->urlpath) + 1); - comm_write(fd, buf, strlen(buf), NULL, p, xfree); - commSetSelect(fd, COMM_SELECT_READ, whoisReadReply, p, 0); - commSetTimeout(fd, Config.Timeout.read, whoisTimeout, p); -} - -/* PRIVATE */ - -static void -whoisTimeout(int fd, void *data) -{ - WhoisState *p = data; - debug(75, 1) ("whoisTimeout: %s\n", storeUrl(p->entry)); - whoisClose(fd, p); -} - -static void -whoisReadReply(int fd, void *data) -{ - WhoisState *p = data; - StoreEntry *entry = p->entry; - char *buf = memAllocate(MEM_4K_BUF); - MemObject *mem = entry->mem_obj; - int len; - statCounter.syscalls.sock.reads++; - len = FD_READ_METHOD(fd, buf, 4095); - buf[len] = '\0'; - debug(75, 3) ("whoisReadReply: FD %d read %d bytes\n", fd, len); - debug(75, 5) ("{%s}\n", buf); - if (len > 0) { - if (0 == mem->inmem_hi) - mem->reply->sline.status = HTTP_OK; - fd_bytes(fd, len, FD_READ); - kb_incr(&statCounter.server.all.kbytes_in, len); - kb_incr(&statCounter.server.http.kbytes_in, len); - storeAppend(entry, buf, len); - commSetSelect(fd, COMM_SELECT_READ, whoisReadReply, p, Config.Timeout.read); - } else if (len < 0) { - debug(50, 2) ("whoisReadReply: FD %d: read failure: %s.\n", - fd, xstrerror()); - if (ignoreErrno(errno)) { - commSetSelect(fd, COMM_SELECT_READ, whoisReadReply, p, Config.Timeout.read); - } else if (mem->inmem_hi == 0) { - ErrorState *err; - err = errorCon(ERR_READ_ERROR, HTTP_INTERNAL_SERVER_ERROR); - err->xerrno = errno; - fwdFail(p->fwd, err); - comm_close(fd); - } else { - comm_close(fd); - } - } else { - storeTimestampsSet(entry); - storeBufferFlush(entry); - if (!EBIT_TEST(entry->flags, RELEASE_REQUEST)) - storeSetPublicKey(entry); - fwdComplete(p->fwd); - debug(75, 3) ("whoisReadReply: Done: %s\n", storeUrl(entry)); - comm_close(fd); - } - memFree(buf, MEM_4K_BUF); -} - -static void -whoisClose(int fd, void *data) -{ - WhoisState *p = data; - debug(75, 3) ("whoisClose: FD %d\n", fd); - storeUnlockObject(p->entry); - cbdataFree(p); -} --- /dev/null Wed Feb 14 01:07:22 2007 +++ squid/src/whois.cc Wed Feb 14 01:07:38 2007 @@ -0,0 +1,141 @@ + +/* + * $Id: whois.cc,v 1.1.2.1 2002/10/09 05:21:29 rbcollins Exp $ + * + * DEBUG: section 75 WHOIS protocol + * AUTHOR: Duane Wessels, Kostas Anagnostakis + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#include "squid.h" +#include "Store.h" + +#define WHOIS_PORT 43 + +typedef struct { + StoreEntry *entry; + request_t *request; + FwdState *fwd; +} WhoisState; + +static PF whoisClose; +static PF whoisTimeout; +static PF whoisReadReply; + +/* PUBLIC */ + +CBDATA_TYPE(WhoisState); + +void +whoisStart(FwdState * fwd) +{ + WhoisState *p; + int fd = fwd->server_fd; + char *buf; + size_t l; + CBDATA_INIT_TYPE(WhoisState); + p = cbdataAlloc(WhoisState); + p->request = fwd->request; + p->entry = fwd->entry; + p->fwd = fwd; + storeLockObject(p->entry); + comm_add_close_handler(fd, whoisClose, p); + l = strLen(p->request->urlpath) + 3; + buf = (char *)xmalloc(l); + snprintf(buf, l, "%s\r\n", strBuf(p->request->urlpath) + 1); + comm_write(fd, buf, strlen(buf), NULL, p, xfree); + commSetSelect(fd, COMM_SELECT_READ, whoisReadReply, p, 0); + commSetTimeout(fd, Config.Timeout.read, whoisTimeout, p); +} + +/* PRIVATE */ + +static void +whoisTimeout(int fd, void *data) +{ + WhoisState *p = (WhoisState *)data; + debug(75, 1) ("whoisTimeout: %s\n", storeUrl(p->entry)); + whoisClose(fd, p); +} + +static void +whoisReadReply(int fd, void *data) +{ + WhoisState *p = (WhoisState *)data; + StoreEntry *entry = p->entry; + char *buf = (char *)memAllocate(MEM_4K_BUF); + MemObject *mem = entry->mem_obj; + int len; + statCounter.syscalls.sock.reads++; + len = FD_READ_METHOD(fd, buf, 4095); + buf[len] = '\0'; + debug(75, 3) ("whoisReadReply: FD %d read %d bytes\n", fd, len); + debug(75, 5) ("{%s}\n", buf); + if (len > 0) { + if (0 == mem->inmem_hi) + mem->reply->sline.status = HTTP_OK; + fd_bytes(fd, len, FD_READ); + kb_incr(&statCounter.server.all.kbytes_in, len); + kb_incr(&statCounter.server.http.kbytes_in, len); + storeAppend(entry, buf, len); + commSetSelect(fd, COMM_SELECT_READ, whoisReadReply, p, Config.Timeout.read); + } else if (len < 0) { + debug(50, 2) ("whoisReadReply: FD %d: read failure: %s.\n", + fd, xstrerror()); + if (ignoreErrno(errno)) { + commSetSelect(fd, COMM_SELECT_READ, whoisReadReply, p, Config.Timeout.read); + } else if (mem->inmem_hi == 0) { + ErrorState *err; + err = errorCon(ERR_READ_ERROR, HTTP_INTERNAL_SERVER_ERROR); + err->xerrno = errno; + fwdFail(p->fwd, err); + comm_close(fd); + } else { + comm_close(fd); + } + } else { + storeTimestampsSet(entry); + storeBufferFlush(entry); + if (!EBIT_TEST(entry->flags, RELEASE_REQUEST)) + storeSetPublicKey(entry); + fwdComplete(p->fwd); + debug(75, 3) ("whoisReadReply: Done: %s\n", storeUrl(entry)); + comm_close(fd); + } + memFree(buf, MEM_4K_BUF); +} + +static void +whoisClose(int fd, void *data) +{ + WhoisState *p = (WhoisState *)data; + debug(75, 3) ("whoisClose: FD %d\n", fd); + storeUnlockObject(p->entry); + cbdataFree(p); +}