#
# Makefile for the Squid Object Cache server
#
-# $Id: Makefile.in,v 1.67 1997/04/02 04:39:55 wessels Exp $
+# $Id: Makefile.in,v 1.68 1997/04/28 04:22:55 wessels Exp $
#
# Uncomment and customize the following to suit your needs:
#
DEFAULT_PID_FILE = $(localstatedir)/logs/squid.pid
DEFAULT_SWAP_DIR = $(localstatedir)/cache
DEFAULT_PINGER = $(libexecdir)/pinger
+DEFAULT_UNLINKD = $(libexecdir)/unlinkd
CC = @CC@
MAKEDEPEND = @MAKEDEPEND@
INSTALL = @INSTALL@
INSTALL_BIN = @INSTALL_PROGRAM@
INSTALL_FILE = @INSTALL_DATA@
+INSTALL_SUID = @INSTALL_PROGRAM@ -o root -m 4755
RANLIB = @RANLIB@
LN_S = @LN_S@
PERL = @PERL@
PINGER_LIBS = -L../lib -lmiscutil $(XTRA_LIBS)
PROGS = squid client
-UTILS = dnsserver ftpget pinger
+UTILS = dnsserver ftpget unlinkd
+SUID_UTILS = pinger
CGIPROGS = cachemgr.cgi
OBJS = \
acl.o \
store_dir.o \
storetoString.o \
tools.o \
+ unlinkd.o \
url.o \
useragent.o \
wais.o \
-DDEFAULT_STORE_LOG=\"$(DEFAULT_STORE_LOG)\" \
-DDEFAULT_PID_FILE=\"$(DEFAULT_PID_FILE)\" \
-DDEFAULT_SWAP_DIR=\"$(DEFAULT_SWAP_DIR)\" \
- -DDEFAULT_PINGER=\"$(DEFAULT_PINGER)\"
+ -DDEFAULT_PINGER=\"$(DEFAULT_PINGER)\" \
+ -DDEFAULT_UNLINKD=\"$(DEFAULT_UNLINKD)\"
-all: squid.conf $(PROGS) $(UTILS) $(CGIPROGS)
+all: squid.conf $(PROGS) $(UTILS) $(SUID_UTILS) $(CGIPROGS)
$(OBJS): ../include/version.h
pinger: pinger.o
$(CC) -o $@ $(LDFLAGS) pinger.o debug.o $(PINGER_LIBS)
+unlinkd: unlinkd.c
+ $(CC) $(CFLAGS) -DUNLINK_DAEMON $(srcdir)/unlinkd.c -o $@ $(LDFLAGS)
+
squid.conf: squid.conf.pre Makefile
sed "\
s%@DEFAULT_CONFIG_FILE@%$(DEFAULT_CONFIG_FILE)%g;\
s%@DEFAULT_FTPGET@%$(DEFAULT_FTPGET)%g;\
s%@DEFAULT_DNSSERVER@%$(DEFAULT_DNSSERVER)%g;\
+ s%@DEFAULT_UNLINKD@%$(DEFAULT_UNLINKD)%g;\
+ s%@DEFAULT_PINGER@%$(DEFAULT_PINGER)%g;\
s%@DEFAULT_CACHE_LOG@%$(DEFAULT_CACHE_LOG)%g;\
s%@DEFAULT_ACCESS_LOG@%$(DEFAULT_ACCESS_LOG)%g;\
s%@DEFAULT_STORE_LOG@%$(DEFAULT_STORE_LOG)%g;\
$(INSTALL_FILE) squid.conf $(sysconfdir); \
fi
+install-pinger:
+ @f=pinger; \
+ if test -f $(libexecdir)/$$f; then \
+ echo $(MV) $(libexecdir)/$$f $(libexecdir)/-$$f; \
+ $(MV) $(libexecdir)/$$f $(libexecdir)/-$$f; \
+ fi; \
+ echo $(INSTALL_SUID) $$f $(libexecdir); \
+ $(INSTALL_SUID) $$f $(libexecdir) || exit 1; \
+ if test -f $(libexecdir)/-$$f; then \
+ echo $(RM) -f $(libexecdir)/-$$f; \
+ $(RM) -f $(libexecdir)/-$$f; \
+ fi
+
clean:
- -rm -rf *.o *pure_* core $(PROGS) $(UTILS) $(CGIPROGS)
+ -rm -rf *.o *pure_* core $(PROGS) $(UTILS) $(CGIPROGS) $(SUID_UTILS)
realclean: clean
-rm -f Makefile squid.conf squid.conf.pre
/*
- * $Id: acl.cc,v 1.90 1997/03/04 05:16:24 wessels Exp $
+ * $Id: acl.cc,v 1.91 1997/04/28 04:22:56 wessels Exp $
*
* DEBUG: section 28 Access Control
* AUTHOR: Duane Wessels
static int
decode_addr(const char *asc, struct in_addr *addr, struct in_addr *mask)
{
- u_num32 a = 0;
+ u_num32 a;
int a1 = 0, a2 = 0, a3 = 0, a4 = 0;
struct hostent *hp = NULL;
switch (sscanf(asc, "%d.%d.%d.%d", &a1, &a2, &a3, &a4)) {
case 4: /* a dotted quad */
- if ((a = (u_num32) inet_addr(asc)) != inaddr_none ||
- !strcmp(asc, "255.255.255.255")) {
- addr->s_addr = a;
- /* inet_addr() outputs in network byte order */
+ if (!safe_inet_addr(asc, addr)) {
+ debug(28, 0, "decode_addr: unsafe IP address: '%s'\n", asc);
+ fatal("decode_addr: unsafe IP address");
}
break;
case 1: /* a significant bits value for a mask */
static int
aclIpNetworkCompare(const void *a, splayNode * n)
{
- struct in_addr *A = (struct in_addr *) a;
+ struct in_addr A = *(struct in_addr *) a;
struct _acl_ip_data *q = n->data;
struct in_addr B = q->addr1;
struct in_addr C = q->addr2;
int rc = 0;
- A->s_addr &= q->mask.s_addr; /* apply netmask */
+ A.s_addr &= q->mask.s_addr; /* apply netmask */
if (C.s_addr == 0) { /* single address check */
- if (ntohl(A->s_addr) > ntohl(B.s_addr))
+ if (ntohl(A.s_addr) > ntohl(B.s_addr))
rc = 1;
- else if (ntohl(A->s_addr) < ntohl(B.s_addr))
+ else if (ntohl(A.s_addr) < ntohl(B.s_addr))
rc = -1;
else
rc = 0;
} else { /* range address check */
- if (ntohl(A->s_addr) > ntohl(C.s_addr))
+ if (ntohl(A.s_addr) > ntohl(C.s_addr))
rc = 1;
- else if (ntohl(A->s_addr) < ntohl(B.s_addr))
+ else if (ntohl(A.s_addr) < ntohl(B.s_addr))
rc = -1;
else
rc = 0;
/*
- * $Id: cache_cf.cc,v 1.180 1997/04/25 22:01:16 wessels Exp $
+ * $Id: cache_cf.cc,v 1.181 1997/04/28 04:22:57 wessels Exp $
*
* DEBUG: section 3 Configuration File Parsing
* AUTHOR: Harvest Derived
#define DefaultSwapLowWaterMark 90 /* 90% */
#define DefaultNetdbHigh 1000 /* counts, not percents */
#define DefaultNetdbLow 900
+#define DefaultNetdbPeriod 300 /* 5 minutes */
#define DefaultWaisRelayHost (char *)NULL
#define DefaultWaisRelayPort 0
-#define DefaultReferenceAge 0 /* disabled */
+#define DefaultReferenceAge (86400*365) /* 1 year */
#define DefaultNegativeTtl (5 * 60) /* 5 min */
#define DefaultNegativeDnsTtl (2 * 60) /* 2 min */
#define DefaultPositiveDnsTtl (360 * 60) /* 6 hours */
#define DefaultFtpgetOptions ""
#define DefaultDnsserverProgram DEFAULT_DNSSERVER
#define DefaultPingerProgram DEFAULT_PINGER
+#define DefaultUnlinkdProgram DEFAULT_UNLINKD
#define DefaultRedirectProgram (char *)NULL /* default NONE */
#define DefaultEffectiveUser (char *)NULL /* default NONE */
#define DefaultEffectiveGroup (char *)NULL /* default NONE */
#define DefaultTcpRcvBufsz 0 /* use system default */
#define DefaultUdpMaxHitObjsz SQUID_UDP_SO_SNDBUF /* from configure */
#define DefaultTcpIncomingAddr INADDR_ANY
-#define DefaultTcpOutgoingAddr inaddr_none
+#define DefaultTcpOutgoingAddr no_addr.s_addr
#define DefaultUdpIncomingAddr INADDR_ANY
-#define DefaultUdpOutgoingAddr inaddr_none
+#define DefaultUdpOutgoingAddr no_addr.s_addr
#define DefaultClientNetmask 0xFFFFFFFFul
#define DefaultPassProxy NULL
#define DefaultSslProxy NULL
#define DefaultOptionsLogUdp 1 /* on */
#define DefaultOptionsEnablePurge 0 /* default off */
+#define DefaultOptionsClientDb 1 /* default on */
+#define DefaultOptionsQueryIcmp 0 /* default off */
+
int httpd_accel_mode = 0; /* for fast access */
const char *DefaultSwapDir = DEFAULT_SWAP_DIR;
static void parseEffectiveUserLine _PARAMS((void));
static void parseErrHtmlLine _PARAMS((void));
static void parseFtpOptionsLine _PARAMS((void));
-static void parseFtpProgramLine _PARAMS((void));
static void parseFtpUserLine _PARAMS((void));
static void parseWordlist _PARAMS((wordlist **));
static void parseHostAclLine _PARAMS((void));
static void parseWAISRelayLine _PARAMS((void));
static void parseMinutesLine _PARAMS((int *));
static void parseCachemgrPasswd _PARAMS((void));
-static void parsePathname _PARAMS((char **));
+static void parsePathname _PARAMS((char **, int fatal));
static void parseProxyLine _PARAMS((peer **));
static void parseHttpAnonymizer _PARAMS((int *));
+static int parseTimeUnits _PARAMS((const char *unit));
+static void parseTimeLine _PARAMS((int *iptr, const char *units));
static void
self_destruct(void)
weight = atoi(token + 7);
} else if (!strncasecmp(token, "ttl=", 4)) {
mcast_ttl = atoi(token + 4);
+ if (mcast_ttl < 0)
+ mcast_ttl = 0;
+ if (mcast_ttl > 128)
+ mcast_ttl = 128;
} else if (!strncasecmp(token, "default", 7)) {
options |= NEIGHBOR_DEFAULT_PARENT;
} else if (!strncasecmp(token, "round-robin", 11)) {
}
static void
-parsePathname(char **path)
+parsePathname(char **path, int fatal)
{
char *token;
+ struct stat sb;
token = strtok(NULL, w_space);
if (token == NULL)
self_destruct();
safe_free(*path);
*path = xstrdup(token);
-}
-
-static void
-parseFtpProgramLine(void)
-{
- char *token;
- token = strtok(NULL, w_space);
- if (token == NULL)
+ if (fatal && stat(token, &sb) < 0) {
+ debug(50, 1, "parsePathname: %s: %s\n", token, xstrerror());
self_destruct();
- safe_free(Config.Program.ftpget);
- Config.Program.ftpget = xstrdup(token);
+ }
}
static void
token = strtok(NULL, w_space);
if (token == NULL)
self_destruct();
- if (inet_addr(token) != inaddr_none)
- (*addr).s_addr = inet_addr(token);
+ if (safe_inet_addr(token, addr) == 1)
+ (void) 0;
else if ((hp = gethostbyname(token))) /* dont use ipcache */
*addr = inaddrFromHostent(hp);
else
token = strtok(NULL, w_space);
if (token == NULL)
self_destruct();
- if (inet_addr(token) != inaddr_none)
- Config.vizHack.addr.s_addr = inet_addr(token);
+ if (safe_inet_addr(token, &Config.vizHack.addr) == 1)
+ (void) 0;
else if ((hp = gethostbyname(token))) /* dont use ipcache */
Config.vizHack.addr = inaddrFromHostent(hp);
else
parseCacheDir();
else if (!strcmp(token, "cache_log"))
- parsePathname(&Config.Log.log);
+ parsePathname(&Config.Log.log, 0);
else if (!strcmp(token, "cache_access_log"))
- parsePathname(&Config.Log.access);
+ parsePathname(&Config.Log.access, 0);
else if (!strcmp(token, "cache_store_log"))
- parsePathname(&Config.Log.store);
+ parsePathname(&Config.Log.store, 0);
else if (!strcmp(token, "cache_swap_log"))
- parsePathname(&Config.Log.swap);
+ parsePathname(&Config.Log.swap, 0);
#if USE_USERAGENT_LOG
else if (!strcmp(token, "useragent_log"))
- parsePathname(&Config.Log.useragent);
+ parsePathname(&Config.Log.useragent, 0);
#endif
else if (!strcmp(token, "logfile_rotate"))
else if (!strcmp(token, "client_lifetime"))
parseMinutesLine(&Config.lifetimeDefault);
else if (!strcmp(token, "reference_age"))
- parseMinutesLine(&Config.referenceAge);
+ parseTimeLine(&Config.referenceAge, "minutes");
else if (!strcmp(token, "shutdown_lifetime"))
parseIntegerValue(&Config.lifetimeShutdown);
parseIntegerValue(&Config.connectTimeout);
else if (!strcmp(token, "cache_ftp_program"))
- parseFtpProgramLine();
+ parsePathname(&Config.Program.ftpget, 1);
else if (!strcmp(token, "ftpget_program"))
- parseFtpProgramLine();
+ parsePathname(&Config.Program.ftpget, 1);
else if (!strcmp(token, "cache_ftp_options"))
parseFtpOptionsLine();
parseFtpOptionsLine();
else if (!strcmp(token, "cache_dns_program"))
- parsePathname(&Config.Program.dnsserver);
+ parsePathname(&Config.Program.dnsserver, 1);
else if (!strcmp(token, "dns_children"))
parseIntegerValue(&Config.dnsChildren);
parseOnOff(&Config.Options.res_defnames);
else if (!strcmp(token, "redirect_program"))
- parsePathname(&Config.Program.redirect);
+ parsePathname(&Config.Program.redirect, 1);
else if (!strcmp(token, "redirect_children"))
parseIntegerValue(&Config.redirectChildren);
+ else if (!strcmp(token, "pinger_program"))
+ parsePathname(&Config.Program.pinger, 1);
+
+ else if (!strcmp(token, "unlinkd_program"))
+ parsePathname(&Config.Program.unlinkd, 1);
+
#if USE_PROXY_AUTH
else if (!strcmp(token, "proxy_auth"))
parseProxyAuthLine();
parseDebugOptionsLine();
else if (!strcmp(token, "pid_filename"))
- parsePathname(&Config.pidFilename);
+ parsePathname(&Config.pidFilename, 0);
else if (!strcmp(token, "visible_hostname"))
parseVisibleHostnameLine();
parseOnOff(&Config.Options.log_udp);
else if (!strcmp(token, "http_anonymizer"))
parseHttpAnonymizer(&Config.Options.anonymizer);
+ else if (!strcmp(token, "client_db"))
+ parseOnOff(&Config.Options.client_db);
+ else if (!strcmp(token, "query_icmp"))
+ parseOnOff(&Config.Options.query_icmp);
else if (!strcmp(token, "minimum_direct_hops"))
parseIntegerValue(&Config.minDirectHops);
parseIntegerValue(&Config.Netdb.high);
else if (!strcmp(token, "netdb_low"))
parseIntegerValue(&Config.Netdb.low);
- else if (!strcmp(token, "netdb_ttl"))
- parseIntegerValue(&Config.Netdb.ttl);
+ else if (!strcmp(token, "netdb_ping_period"))
+ parseTimeLine(&Config.Netdb.period, "seconds");
/* If unknown, treat as a comment line */
else {
safe_free(Config.Program.ftpget_opts);
safe_free(Config.Program.dnsserver);
safe_free(Config.Program.redirect);
+ safe_free(Config.Program.unlinkd);
safe_free(Config.Program.pinger);
safe_free(Config.Accel.host);
safe_free(Config.Accel.prefix);
Config.Swap.lowWaterMark = DefaultSwapLowWaterMark;
Config.Netdb.high = DefaultNetdbHigh;
Config.Netdb.low = DefaultNetdbLow;
+ Config.Netdb.period = DefaultNetdbPeriod;
Config.Wais.relayHost = safe_xstrdup(DefaultWaisRelayHost);
Config.Wais.relayPort = DefaultWaisRelayPort;
Config.Program.dnsserver = safe_xstrdup(DefaultDnsserverProgram);
Config.Program.redirect = safe_xstrdup(DefaultRedirectProgram);
Config.Program.pinger = safe_xstrdup(DefaultPingerProgram);
+ Config.Program.unlinkd = safe_xstrdup(DefaultUnlinkdProgram);
Config.Accel.host = safe_xstrdup(DefaultAccelHost);
Config.Accel.prefix = safe_xstrdup(DefaultAccelPrefix);
Config.Accel.port = DefaultAccelPort;
Config.Options.res_defnames = DefaultOptionsResDefnames;
Config.Options.anonymizer = DefaultOptionsAnonymizer;
Config.Options.enable_purge = DefaultOptionsEnablePurge;
+ Config.Options.client_db = DefaultOptionsClientDb;
+ Config.Options.query_icmp = DefaultOptionsQueryIcmp;
}
static void
else
Config.appendDomainLen = 0;
}
+
+/* Parse a time specification from the config file. Store the
+ * result in 'iptr', after converting it to 'units' */
+static void
+parseTimeLine(int *iptr, const char *units)
+{
+ char *token;
+ double d;
+ int m;
+ int u;
+ if ((u = parseTimeUnits(units)) == 0)
+ self_destruct();
+ if ((token = strtok(NULL, w_space)) == NULL)
+ self_destruct();
+ d = atof(token);
+ m = u; /* default to 'units' if none specified */
+ if ((token = strtok(NULL, w_space)) != NULL) {
+ if ((m = parseTimeUnits(token)) == 0)
+ self_destruct();
+ }
+ *iptr = m * d / u;
+}
+
+static int
+parseTimeUnits(const char *unit)
+{
+ if (!strncasecmp(unit, "second", 6))
+ return 1;
+ if (!strncasecmp(unit, "minute", 6))
+ return 60;
+ if (!strncasecmp(unit, "hour", 4))
+ return 3600;
+ if (!strncasecmp(unit, "day", 3))
+ return 86400;
+ if (!strncasecmp(unit, "week", 4))
+ return 86400 * 7;
+ if (!strncasecmp(unit, "fortnight", 9))
+ return 86400 * 14;
+ if (!strncasecmp(unit, "month", 5))
+ return 86400 * 30;
+ if (!strncasecmp(unit, "year", 4))
+ return 86400 * 365.2522;
+ if (!strncasecmp(unit, "decade", 6))
+ return 86400 * 365.2522 * 10;
+ debug(3, 1, "parseTimeUnits: unknown time unit '%s'\n", unit);
+ return 0;
+}
/*
- * $Id: cachemgr.cc,v 1.53 1997/01/13 22:47:03 wessels Exp $
+ * $Id: cachemgr.cc,v 1.54 1997/04/28 04:22:59 wessels Exp $
*
* DEBUG: section 0 CGI Cache Manager
* AUTHOR: Harvest Derived
static const char *const w_space = " \t\n\r";
static const char *progname = NULL;
static time_t now;
-static unsigned int inaddr_none;
+static struct in_addr no_addr;
static char x2c _PARAMS((char *));
static int client_comm_connect _PARAMS((int sock, char *dest_host, u_short dest_port));
int single = TRUE;
float f1;
- inaddr_none = inet_addr("255.255.255.255");
+ safe_inet_addr("255.255.255.255", &no_addr);
now = time(NULL);
if ((s = strrchr(argv[0], '/')))
progname = xstrdup(s + 1);
perror("client: socket");
exit(1);
}
- if ((conn = client_comm_connect(conn, hostname, portnum)) < 0) {
+ if (client_comm_connect(conn, hostname, portnum) < 0) {
printf("Error: connecting to cache mgr: %s:%d\n", hostname, portnum);
printf("%s</PRE></BODY></HTML>\n", xstrerror());
exit(1);
{
const struct hostent *hp;
static struct sockaddr_in to_addr;
- unsigned long haddr;
/* Set up the destination socket address for message to send to. */
memset(&to_addr, '\0', sizeof(struct sockaddr_in));
to_addr.sin_family = AF_INET;
if ((hp = gethostbyname(dest_host)) != NULL)
- xmemcpy(&to_addr.sin_addr, hp->h_addr, hp->h_length);
- else if ((haddr = inet_addr(dest_host)) != inaddr_none)
- xmemcpy(&to_addr.sin_addr, &haddr, sizeof(haddr));
+ xmemcpy(&to_addr.sin_addr.s_addr, hp->h_addr, hp->h_length);
+ else if (safe_inet_addr(dest_host, &to_addr.sin_addr))
+ (void) 0;
else
return (-1);
/*
- * $Id: client_db.cc,v 1.9 1996/12/20 23:21:26 wessels Exp $
+ * $Id: client_db.cc,v 1.10 1997/04/28 04:22:59 wessels Exp $
*
* DEBUG: section 0 Client Database
* AUTHOR: Duane Wessels
void
clientdbUpdate(struct in_addr addr, log_type log_type, u_short port)
{
- char *key = inet_ntoa(addr);
- ClientInfo *c = (ClientInfo *) hash_lookup(client_table, key);
+ char *key;
+ ClientInfo *c;
+ if (!Config.Options.client_db)
+ return;
+ key = inet_ntoa(addr);
+ c = (ClientInfo *) hash_lookup(client_table, key);
if (c == NULL)
c = clientdbAdd(addr);
if (c == NULL)
int
clientdbDeniedPercent(struct in_addr addr)
{
- char *key = inet_ntoa(addr);
+ char *key;
int n = 100;
- ClientInfo *c = (ClientInfo *) hash_lookup(client_table, key);
+ ClientInfo *c;
+ if (!Config.Options.client_db)
+ return 0;
+ key = inet_ntoa(addr);
+ c = (ClientInfo *) hash_lookup(client_table, key);
if (c == NULL)
return 0;
if (c->Icp.n_requests > 100)
/*
- * $Id: client_side.cc,v 1.95 1997/03/29 04:45:14 wessels Exp $
+ * $Id: client_side.cc,v 1.96 1997/04/28 04:23:00 wessels Exp $
*
* DEBUG: section 33 Client-side Routines
* AUTHOR: Duane Wessels
debug(33, 5, "clientAccessCheckDone: '%s' answer=%d\n", icpState->url, answer);
if (answer) {
urlCanonical(icpState->request, icpState->url);
+ if (icpState->redirect_state != REDIRECT_NONE)
+ fatal_dump("clientAccessCheckDone: wrong redirect_state");
+ icpState->redirect_state = REDIRECT_PENDING;
redirectStart(fd, icpState, clientRedirectDone, icpState);
} else {
debug(33, 5, "Access Denied: %s\n", icpState->url);
request_t *old_request = icpState->request;
debug(33, 5, "clientRedirectDone: '%s' result=%s\n", icpState->url,
result ? result : "NULL");
+ if (icpState->redirect_state != REDIRECT_PENDING)
+ fatal_dump("clientRedirectDone: wrong redirect_state");
+ icpState->redirect_state = REDIRECT_DONE;
if (result)
new_request = urlParse(old_request->method, result);
if (new_request) {
/*
- * $Id: comm.cc,v 1.140 1997/03/04 05:16:27 wessels Exp $
+ * $Id: comm.cc,v 1.141 1997/04/28 04:23:01 wessels Exp $
*
* DEBUG: section 5 Socket Functions
* AUTHOR: Harvest Derived
static void commSetTcpRcvbuf _PARAMS((int, int));
static void commConnectFree _PARAMS((int fd, void *data));
static void commConnectHandle _PARAMS((int fd, void *data));
+static void commHandleWrite _PARAMS((int fd, RWStateData * state));
-static int *fd_lifetime = NULL;
static struct timeval zero_tv;
void
if (note)
fd_note(new_socket, note);
conn->openned = 1;
+ conn->lifetime = -1;
if (!BIT_TEST(flags, COMM_NOCLOEXEC))
commSetCloseOnExec(new_socket);
if (port > (u_short) 0) {
if (do_reuse)
commSetReuseAddr(new_socket);
}
- if (addr.s_addr != inaddr_none)
+ if (addr.s_addr != no_addr.s_addr)
if (commBind(new_socket, addr, port) != COMM_OK)
return COMM_ERROR;
conn->local_port = port;
int
comm_set_fd_lifetime(int fd, int lifetime)
{
+ FD_ENTRY *f;
debug(5, 3, "comm_set_fd_lifetime: FD %d lft %d\n", fd, lifetime);
if (fd < 0 || fd > Squid_MaxFD)
return 0;
+ f = &fd_table[fd];
if (lifetime < 0)
- return fd_lifetime[fd] = -1;
+ return f->lifetime = -1;
if (shutdown_pending || reread_pending) {
/* don't increase the lifetime if something pending */
- if (fd_lifetime[fd] > -1 && (fd_lifetime[fd] - squid_curtime) < lifetime)
- return fd_lifetime[fd];
+ if (f->lifetime > -1 && (f->lifetime - squid_curtime) < lifetime)
+ return f->lifetime;
}
- return fd_lifetime[fd] = (int) squid_curtime + lifetime;
-}
-
-int
-comm_get_fd_lifetime(int fd)
-{
- if (fd < 0)
- return 0;
- return fd_lifetime[fd];
-}
-
-int
-comm_get_fd_timeout(int fd)
-{
- if (fd < 0)
- return 0;
- return fd_table[fd].timeout_time;
+ return f->lifetime = (int) squid_curtime + lifetime;
}
int
}
conn->openned = 0;
RWStateCallbackAndFree(fd, COMM_ERROR);
- comm_set_fd_lifetime(fd, -1); /* invalidate the lifetime */
fdstat_close(fd); /* update fdstat */
commCallCloseHandlers(fd);
memset(conn, '\0', sizeof(FD_ENTRY));
#if USE_ASYNC_IO
aioClose(fd);
#else
+ conn->lifetime = -1;
close(fd);
#endif
}
static void
comm_select_incoming(void)
{
- int fd = 0;
+ int fd;
int fds[4];
struct pollfd pfds[4];
unsigned long N = 0;
- unsigned long i = 0;
+ unsigned long i, nfds;
int dopoll = 0;
PF hdl = NULL;
if (theInIcpConnection >= 0)
fds[N++] = theOutIcpConnection;
if (theHttpConnection >= 0 && fdstat_are_n_free_fd(RESERVED_FD))
fds[N++] = theHttpConnection;
- fds[N++] = 0;
- for (i = 0; i < N; i++) {
+ for (i = nfds = 0; i < N; i++) {
+ int events;
fd = fds[i];
- pfds[i].events = 0;
- pfds[i].revents = 0;
- pfds[i].fd = fd;
- if (fd_table[fd].read_handler) {
- pfds[i].events |= POLLRDNORM;
- dopoll++;
- }
- if (fd_table[fd].write_handler) {
- pfds[i].events |= POLLWRNORM;
- dopoll++;
+ events = 0;
+ if (fd_table[fd].read_handler)
+ events |= POLLRDNORM;
+ if (fd_table[fd].write_handler)
+ events |= POLLWRNORM;
+ if (events) {
+ pfds[nfds].fd = fd;
+ pfds[nfds].events = events;
+ pfds[nfds].revents = 0;
+ nfds++;
}
- if (pfds[i].events == 0)
- pfds[i].fd = -1;
}
- if (!dopoll)
+ if (!nfds)
+ return;
+ if (poll(pfds, nfds, 0) < 1)
return;
- poll(pfds, N, 0);
+#ifndef LESS_TIMING
getCurrentTime();
- for (i = 0; i < N; i++) {
- if (pfds[i].fd == -1)
+#endif
+ for (i = 0; i < nfds; i++) {
+ int revents;
+ if (((revents = pfds[i].revents) == 0) || ((fd = pfds[i].fd) == -1))
continue;
- fd = fds[i];
- if (fd_table[fd].read_handler) {
- if (pfds[i].revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR)) {
- hdl = fd_table[fd].read_handler;
- fd_table[fd].read_handler = 0;
- hdl(fd, fd_table[fd].read_data);
- }
+ if (revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR)) {
+ hdl = fd_table[fd].read_handler;
+ fd_table[fd].read_handler = 0;
+ hdl(fd, fd_table[fd].read_data);
}
- if (fd_table[fd].write_handler) {
- if (pfds[i].revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR)) {
- hdl = fd_table[fd].write_handler;
- fd_table[fd].write_handler = 0;
- hdl(fd, fd_table[fd].write_data);
- }
+ if (revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR)) {
+ hdl = fd_table[fd].write_handler;
+ fd_table[fd].write_handler = 0;
+ hdl(fd, fd_table[fd].write_data);
}
}
/* TO FIX: repoll ICP connection here */
return;
if (select(maxfd, &read_mask, &write_mask, NULL, &zero_tv) < 1)
return;
+#ifndef LESS_TIMING
getCurrentTime();
+#endif
for (i = 0; i < N; i++) {
fd = fds[i];
if (FD_ISSET(fd, &read_mask)) {
}
#endif
-
#ifdef USE_POLL
/* poll all sockets; call handlers for those that are ready. */
int
int i;
int maxfd;
unsigned long nfds;
- int incnfd;
int num;
static time_t last_timeout = 0;
static time_t pending_time;
- int poll_time = 0;
+ int poll_time;
time_t timeout;
- struct close_handler *ch = NULL;
- struct close_handler *next = NULL;
- FD_ENTRY *f = NULL;
/* assume all process are very fast (less than 1 second). Call
* time() only once */
getCurrentTime();
ftpServerClose();
dnsShutdownServers();
redirectShutdownServers();
- if (shutdown_pending > 0)
+ /* shutdown_pending will be set to
+ * +1 for SIGTERM
+ * -1 for SIGINT */
+ /* reread_pending always == 1 when SIGHUP received */
+ if (shutdown_pending > 0 || reread_pending > 0)
setSocketShutdownLifetimes(Config.lifetimeShutdown);
else
setSocketShutdownLifetimes(0);
}
- maxfd = fdstat_biggest_fd() + 1;
- for (nfds = 0, i = 0; i < maxfd; i++) {
- pfds[i].fd = i;
- pfds[i].events = 0;
- if (i == theHttpConnection && !fdstat_are_n_free_fd(RESERVED_FD))
- continue;
+ nfds = 0;
+ maxfd = Biggest_FD + 1;
+ httpindex = -1;
+ for (i = 0; i < maxfd; i++) {
+ int events;
+ events = 0;
/* Check each open socket for a handler. */
- incnfd = 0;
- if (fd_table[i].read_handler
- && fd_table[i].stall_until <= squid_curtime) {
- pfds[i].events |= POLLRDNORM;
- incnfd = 1;
+ if (fd_table[i].read_handler && fd_table[i].stall_until <= squid_curtime)
+ events |= POLLRDNORM;
+ if (fd_table[i].write_handler)
+ events |= POLLWRNORM;
+ if (events) {
+ if (i == theHttpConnection)
+ httpindex = nfds;
+ pfds[nfds].fd = i;
+ pfds[nfds].events = events;
+ pfds[nfds].revents = 0;
+ nfds++;
+ if (pfds[i].events == 0)
+ pfds[i].fd = -1;
}
- if (fd_table[i].write_handler) {
- pfds[i].events |= POLLWRNORM;
- incnfd = 1;
+ /* If we're out of free fd's, don't poll the http incoming fd */
+ if (!fdstat_are_n_free_fd(RESERVED_FD) && httpindex >= 0) {
+ pfds[httpindex].fd = -1;
+ pfds[httpindex].events = 0;
}
- if (incnfd)
- nfds++;
- if (pfds[i].events == 0)
- pfds[i].fd = -1;
- }
- if (shutdown_pending || reread_pending) {
- debug(5, 2, "comm_select: Still waiting on %d FDs\n", nfds);
+ if (shutdown_pending || reread_pending)
+ debug(5, 2, "comm_select: Still waiting on %d FDs\n", nfds);
if (pending_time == 0)
pending_time = squid_curtime;
if ((squid_curtime - pending_time) > (Config.lifetimeShutdown + 5)) {
pfds[fd].fd = -1;
}
}
- } else
- pending_time = 0;
+ }
+ pending_time = 0;
if (nfds == 0)
return COMM_SHUTDOWN;
poll_time = sec > 0 ? 100 : 0;
aioCheckCallbacks();
#endif
for (;;) {
- num = poll(pfds, maxfd, poll_time);
+ poll_time = sec > 0 ? 1000 : 0;
+ num = poll(pfds, nfds, poll_time);
+ select_loops++;
+ getCurrentTime();
if (num >= 0)
break;
if (errno == EINTR)
/* scan each socket but the accept socket. Poll this
* more frequently to minimize losses due to the 5 connect
* limit in SunOS */
- for (i = 0; i < maxfd; i++) {
- if ((fd = pfds[i].fd) == -1)
+ for (i = 0; i < nfds; i++) {
+ int revents;
+ if (((revents = pfds[i].revents) == 0) || ((fd = pfds[i].fd) == -1))
continue;
/*
* Admit more connections quickly until we hit the hard limit.
comm_select_incoming();
if ((fd == theInIcpConnection) || (fd == theHttpConnection) || (fd == theOutIcpConnection) || (fd == 0))
continue;
- if (fd_table[fd].read_handler && (pfds[i].revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR))) {
+ if (revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR)) {
debug(5, 6, "comm_select: FD %d ready for reading\n", fd);
hdl = fd_table[fd].read_handler;
fd_table[fd].read_handler = 0;
hdl(fd, fd_table[fd].read_data);
}
- if (fd_table[fd].write_handler && (pfds[i].revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR))) {
+ if (revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR)) {
debug(5, 5, "comm_select: FD %d ready for writing\n", fd);
hdl = fd_table[fd].write_handler;
fd_table[fd].write_handler = 0;
hdl(fd, fd_table[fd].write_data);
}
- if (pfds[i].revents & POLLNVAL) {
- f = &fd_table[fd];
+ if (revents & POLLNVAL) {
+ struct close_handler *ch;
+ struct close_handler *next;
+ FD_ENTRY *f = &fd_table[fd];
debug(5, 0, "WARNING: FD %d has handlers, but it's invalid.\n", fd);
debug(5, 0, "FD %d is a %s\n", fd, fdstatTypeStr[fdstatGetType(fd)]);
debug(5, 0, "--> %s\n", fd_note(fd, NULL));
ftpServerClose();
dnsShutdownServers();
redirectShutdownServers();
- if (shutdown_pending > 0)
+ /* shutdown_pending will be set to
+ * +1 for SIGTERM
+ * -1 for SIGINT */
+ /* reread_pending always == 1 when SIGHUP received */
+ if (shutdown_pending > 0 || reread_pending > 0)
setSocketShutdownLifetimes(Config.lifetimeShutdown);
else
setSocketShutdownLifetimes(0);
}
nfds = 0;
- maxfd = fdstat_biggest_fd() + 1;
+ maxfd = Biggest_FD + 1;
for (i = 0; i < maxfd; i++) {
/* Check each open socket for a handler. */
if (fd_table[i].stall_until > squid_curtime)
FD_SET(i, &writefds);
}
}
- if (!fdstat_are_n_free_fd(RESERVED_FD)) {
+ if (!fdstat_are_n_free_fd(RESERVED_FD) && theHttpConnection >= 0) {
FD_CLR(theHttpConnection, &readfds);
}
if (shutdown_pending || reread_pending)
poll_time.tv_sec = sec > 0 ? 1 : 0;
poll_time.tv_usec = 0;
num = select(maxfd, &readfds, &writefds, NULL, &poll_time);
+ select_loops++;
getCurrentTime();
if (num >= 0)
break;
* Since Squid_MaxFD can be as high as several thousand, don't waste them */
RESERVED_FD = min(100, Squid_MaxFD / 4);
/* hardwired lifetimes */
- fd_lifetime = xmalloc(sizeof(int) * Squid_MaxFD);
for (i = 0; i < Squid_MaxFD; i++)
comm_set_fd_lifetime(i, -1); /* denotes invalid */
meta_data.misc += Squid_MaxFD * sizeof(int);
FD_ENTRY *f = NULL;
void *data;
/* scan for timeout */
- for (fd = 0; fd < Squid_MaxFD; ++fd) {
+ for (fd = 0; fd <= Biggest_FD; fd++) {
f = &fd_table[fd];
+ if (!f->openned)
+ continue;
if ((hdl = f->timeout_handler) == NULL)
continue;
if (f->timeout_time > squid_curtime)
checkLifetimes(void)
{
int fd;
- time_t lft;
FD_ENTRY *fde = NULL;
PF hdl = NULL;
- for (fd = 0; fd < Squid_MaxFD; fd++) {
- if ((lft = comm_get_fd_lifetime(fd)) == -1)
+ for (fd = 0; fd <= Biggest_FD; fd++) {
+ fde = &fd_table[fd];
+ if (!fde->openned)
+ continue;
+ if (fde->lifetime < 0)
continue;
- if (lft > squid_curtime)
+ if (fde->lifetime > squid_curtime)
continue;
debug(5, 5, "checkLifetimes: FD %d Expired\n", fd);
- fde = &fd_table[fd];
if ((hdl = fde->lifetime_handler) != NULL) {
debug(5, 5, "checkLifetimes: FD %d: Calling lifetime handler\n", fd);
hdl(fd, fde->lifetime_data);
commFreeMemory(void)
{
safe_free(fd_table);
- safe_free(fd_lifetime);
}
/*
- * $Id: disk.cc,v 1.57 1997/02/26 19:46:11 wessels Exp $
+ * $Id: disk.cc,v 1.58 1997/04/28 04:23:03 wessels Exp $
*
* DEBUG: section 6 Disk I/O Routines
* AUTHOR: Harvest Derived
xfree(ctrlp);
}
-
/* must close a disk file */
int
return DISK_OK;
}
+void
+file_open_fd(int fd, const char *name, File_Desc_Type type)
+{
+ FileEntry *f = &file_table[fd];
+ fdstat_open(fd, type);
+ commSetCloseOnExec(fd);
+ xstrncpy(f->filename, name, SQUID_MAXPATHLEN);
+ f->at_eof = NO;
+ f->open_stat = FILE_OPEN;
+ f->close_request = NOT_REQUEST;
+ f->write_pending = NO_WRT_PENDING;
+ f->write_daemon = NOT_PRESENT;
+ f->write_q = NULL;
+ memset(&fd_table[fd], '\0', sizeof(FD_ENTRY));
+}
+
/* close a disk file. */
int
{
dwrite_q *wq = NULL;
- if (file_table[fd].open_stat == FILE_NOT_OPEN)
+ if (file_table[fd].open_stat == FILE_NOT_OPEN) {
+ debug_trap("file_write: FILE_NOT_OPEN");
return DISK_ERROR;
+ }
/* if we got here. Caller is eligible to write. */
wq = xcalloc(1, sizeof(dwrite_q));
wq->buf = ptr_to_buf;
file_table[fd].write_q_tail = wq;
}
- if (file_table[fd].write_daemon == PRESENT)
- return DISK_OK;
+ if (file_table[fd].write_daemon != PRESENT) {
#if USE_ASYNC_IO
- diskHandleWrite(fd, &file_table[fd]);
+ diskHandleWrite(fd, &file_table[fd]);
#else
- commSetSelect(fd,
- COMM_SELECT_WRITE,
- (PF) diskHandleWrite,
- (void *) &file_table[fd],
- 0);
+ commSetSelect(fd,
+ COMM_SELECT_WRITE,
+ (PF) diskHandleWrite,
+ (void *) &file_table[fd],
+ 0);
#endif
+ file_table[fd].write_daemon = PRESENT;
+ }
return DISK_OK;
}
/*
- * $Id: dns.cc,v 1.30 1997/02/07 04:57:13 wessels Exp $
+ * $Id: dns.cc,v 1.31 1997/04/28 04:23:04 wessels Exp $
*
* DEBUG: section 34 Dnsserver interface
* AUTHOR: Harvest Derived
dns_child_table[k]->id = k + 1;
dns_child_table[k]->inpipe = dnssocket;
dns_child_table[k]->outpipe = dnssocket;
- dns_child_table[k]->lastcall = squid_curtime;
+ dns_child_table[k]->answer = squid_curtime;
+ dns_child_table[k]->dispatch_time = current_time;
dns_child_table[k]->size = DNS_INBUF_SZ - 1;
dns_child_table[k]->offset = 0;
dns_child_table[k]->ip_inbuf = xcalloc(DNS_INBUF_SZ, 1);
NDnsServersAlloc++;
}
}
- if (NDnsServersAlloc == 0)
+ if (NDnsServersAlloc == 0 && Config.dnsChildren > 0)
fatal("Failed to start any dnsservers");
debug(34, 1, "Started %d 'dnsserver' processes\n", NDnsServersAlloc);
}
dnsStats(StoreEntry * sentry)
{
int k;
-
+ dnsserver_t *dns = NULL;
storeAppendPrintf(sentry, "{DNSServer Statistics:\n");
storeAppendPrintf(sentry, "{dnsserver requests: %d}\n",
DnsStats.requests);
k + 1,
DnsStats.hist[k]);
}
- storeAppendPrintf(sentry, "}\n\n");
+ storeAppendPrintf(sentry, "{}\n");
+ storeAppendPrintf(sentry, "{dnsservers status:}\n");
+ for (k = 0; k < NDnsServersAlloc; k++) {
+ dns = *(dns_child_table + k);
+ storeAppendPrintf(sentry, "{dnsserver #%d:}\n", k + 1);
+ storeAppendPrintf(sentry, "{ Flags: %c%c%c}\n",
+ dns->flags & DNS_FLAG_ALIVE ? 'A' : ' ',
+ dns->flags & DNS_FLAG_BUSY ? 'B' : ' ',
+ dns->flags & DNS_FLAG_CLOSING ? 'C' : ' ');
+ storeAppendPrintf(sentry, "{ FDs (in/out): %d/%d}\n",
+ dns->inpipe, dns->outpipe);
+ storeAppendPrintf(sentry, "{ Alive since: %s}\n",
+ mkrfc1123(dns->answer));
+ storeAppendPrintf(sentry, "{ Last Dispatched: %0.3f seconds ago}\n",
+ 0.001 * tvSubMsec(dns->dispatch_time, current_time));
+ storeAppendPrintf(sentry, "{ Read Buffer Size: %d bytes}\n",
+ dns->size);
+ storeAppendPrintf(sentry, "{ Read Offset: %d bytes}\n",
+ dns->offset);
+ }
+ storeAppendPrintf(sentry, "\n{Flags key:}\n\n");
+ storeAppendPrintf(sentry, "{ A = ALIVE}\n");
+ storeAppendPrintf(sentry, "{ B = BUSY}\n");
+ storeAppendPrintf(sentry, "{ C = CLOSING}\n");
+
storeAppendPrintf(sentry, close_bracket);
}
/*
- * $Id: dnsserver.cc,v 1.32 1997/02/06 18:02:10 wessels Exp $
+ * $Id: dnsserver.cc,v 1.33 1997/04/28 04:23:05 wessels Exp $
*
* DEBUG: section 0 DNS Resolver
* AUTHOR: Harvest Derived
#endif /* _SQUID_NEXT_ */
static int do_debug = 0;
-static unsigned int inaddr_none;
+static struct in_addr no_addr;
/* error messages from gethostbyname() */
static char *
int i;
int c;
- inaddr_none = inet_addr("255.255.255.255");
+ safe_inet_addr("255.255.255.255", &no_addr);
#if HAVE_RES_INIT
res_init();
for (;;) {
int retry_count = 0;
- int addrbuf;
+ struct in_addr ip;
memset(request, '\0', 256);
/* read from ipcache */
result = NULL;
start = time(NULL);
/* check if it's already an IP address in text form. */
- if (inet_addr(request) != inaddr_none) {
+ if (safe_inet_addr(request, &ip)) {
#if NO_REVERSE_LOOKUP
printf("$name %s\n", request);
printf("$h_name %s\n", request);
fflush(stdout);
continue;
#endif
- addrbuf = inet_addr(request);
for (;;) {
- result = gethostbyaddr((char *) &addrbuf, 4, AF_INET);
+ result = gethostbyaddr((char *) &ip.s_addr, 4, AF_INET);
if (result || h_errno != TRY_AGAIN)
break;
if (++retry_count == 2)
/*
- * $Id: fqdncache.cc,v 1.47 1997/03/04 05:16:28 wessels Exp $
+ * $Id: fqdncache.cc,v 1.48 1997/04/28 04:23:07 wessels Exp $
*
* DEBUG: section 35 FQDN Cache
* AUTHOR: Harvest Derived
static void fqdncache_release _PARAMS((fqdncache_entry *));
static fqdncache_entry *fqdncache_GetFirst _PARAMS((void));
static fqdncache_entry *fqdncache_GetNext _PARAMS((void));
-static fqdncache_entry *fqdncache_create _PARAMS((void));
+static fqdncache_entry *fqdncache_create _PARAMS((const char *name));
static void fqdncache_add_to_hash _PARAMS((fqdncache_entry *));
static void fqdncache_call_pending _PARAMS((fqdncache_entry *));
-static void fqdncache_call_pending_badname _PARAMS((int fd, FQDNH handler, void *));
-static void fqdncache_add _PARAMS((const char *, fqdncache_entry *, const struct hostent *, int));
+static void fqdncacheAddHostent _PARAMS((fqdncache_entry *, const struct hostent *));
static int fqdncacheHasPending _PARAMS((const fqdncache_entry *));
static fqdncache_entry *fqdncache_get _PARAMS((const char *));
static void dummy_handler _PARAMS((int, const char *, void *));
static void fqdncacheEnqueue _PARAMS((fqdncache_entry *));
static void *fqdncacheDequeue _PARAMS((void));
static void fqdncache_dnsDispatch _PARAMS((dnsserver_t *, fqdncache_entry *));
+static void fqdncacheChangeKey _PARAMS((fqdncache_entry * i));
+static void fqdncacheLockEntry _PARAMS((fqdncache_entry * f));
+static void fqdncacheUnlockEntry _PARAMS((fqdncache_entry * f));
static HashID fqdn_table = 0;
static struct fqdncacheQueueData *fqdncacheQueueHead = NULL;
fqdncacheQueueTailP = &fqdncacheQueueHead;
safe_free(old);
}
+ if (f && f->status != FQDN_PENDING)
+ debug_trap("fqdncacheDequeue: status != FQDN_PENDING");
return f;
}
static void
fqdncache_release(fqdncache_entry * f)
{
- fqdncache_entry *result = NULL;
hash_link *table_entry = NULL;
int k;
debug(35, 0, "fqdncache_release: Could not find key '%s'\n", f->name);
return;
}
- result = (fqdncache_entry *) table_entry;
- if (f != result)
- fatal_dump("fqdncache_release: expected f == result!");
+ if (f != (fqdncache_entry *) table_entry)
+ fatal_dump("fqdncache_release: f != table_entry!");
if (f->status == FQDN_PENDING) {
debug(35, 1, "fqdncache_release: Someone called on a PENDING entry\n");
return;
}
if (hash_remove_link(fqdn_table, table_entry)) {
debug(35, 0, "fqdncache_release: hash_remove_link() failed for '%s'\n",
- result->name);
+ f->name);
return;
}
- if (result->status == FQDN_CACHED) {
+ if (f->status == FQDN_CACHED) {
for (k = 0; k < (int) f->name_count; k++)
safe_free(f->names[k]);
debug(35, 5, "fqdncache_release: Released FQDN record for '%s'.\n",
- result->name);
+ f->name);
}
- safe_free(result->name);
- safe_free(result->error_message);
- memset(result, '\0', sizeof(fqdncache_entry));
- safe_free(result);
+ safe_free(f->name);
+ safe_free(f->error_message);
+ safe_free(f);
--meta_data.fqdncache_count;
return;
}
return 0;
if (f->status == FQDN_DISPATCHED)
return 0;
+ if (f->locks != 0)
+ return 0;
if (f->expires > squid_curtime)
return 0;
return 1;
/* sort LRU candidate list */
qsort((char *) LRU_list,
LRU_list_count,
- sizeof(f),
- (int (*)(const void *, const void *)) fqdncache_compareLastRef);
- for (k = 0; LRU_list[k] && (meta_data.fqdncache_count > fqdncache_low)
- && k < LRU_list_count;
- ++k) {
+ sizeof(fqdncache_entry *),
+ (QS) fqdncache_compareLastRef);
+ for (k = 0; k < LRU_list_count; k++) {
+ if (meta_data.fqdncache_count < fqdncache_low)
+ break;
+ if (LRU_list[k] == NULL)
+ break;
fqdncache_release(LRU_list[k]);
removed++;
}
/* create blank fqdncache_entry */
static fqdncache_entry *
-fqdncache_create(void)
+fqdncache_create(const char *name)
{
static fqdncache_entry *new;
}
meta_data.fqdncache_count++;
new = xcalloc(1, sizeof(fqdncache_entry));
+ new->name = xstrdup(name);
+ new->expires = squid_curtime + Config.negativeDnsTtl;
+ fqdncache_add_to_hash(new);
return new;
}
debug(35, 5, "fqdncache_add_to_hash: name <%s>\n", f->name);
}
-
static void
-fqdncache_add(const char *name, fqdncache_entry * f, const struct hostent *hp, int cached)
+fqdncacheAddHostent(fqdncache_entry * f, const struct hostent *hp)
{
int k;
+ f->name_count = 0;
+ f->names[f->name_count++] = xstrdup((char *) hp->h_name);
+ for (k = 0; hp->h_aliases[k]; k++) {
+ f->names[f->name_count++] = xstrdup(hp->h_aliases[k]);
+ if (f->name_count == FQDN_MAX_NAMES)
+ break;
+ }
+}
+static fqdncache_entry *
+fqdncacheAddNew(const char *name, const struct hostent *hp, fqdncache_status_t status)
+{
+ fqdncache_entry *f;
if (fqdncache_get(name))
- fatal_dump("fqdncache_add: somebody adding a duplicate!");
- debug(35, 10, "fqdncache_add: Adding name '%s' (%s).\n", name,
- cached ? "cached" : "not cached");
- f->name = xstrdup(name);
- if (cached) {
- f->name_count = 0;
- f->names[f->name_count++] = xstrdup((char *) hp->h_name);
- for (k = 0; hp->h_aliases[k]; k++) {
- f->names[f->name_count++] = xstrdup(hp->h_aliases[k]);
- if (f->name_count == FQDN_MAX_NAMES)
- break;
- }
- f->lastref = squid_curtime;
- f->status = FQDN_CACHED;
- f->expires = squid_curtime + Config.positiveDnsTtl;
- } else {
- f->lastref = squid_curtime;
- f->status = FQDN_NEGATIVE_CACHED;
- f->expires = squid_curtime + Config.negativeDnsTtl;
- }
- fqdncache_add_to_hash(f);
+ fatal_dump("fqdncacheAddNew: somebody adding a duplicate!");
+ debug(14, 10, "fqdncacheAddNew: Adding '%s', status=%c\n",
+ name,
+ fqdncache_status_char[status]);
+ f = fqdncache_create(name);
+ if (hp)
+ fqdncacheAddHostent(f, hp);
+ f->status = status;
+ f->lastref = squid_curtime;
+ return f;
}
/* walks down the pending list, calling handlers */
f->lastref = squid_curtime;
+ fqdncacheLockEntry(f);
while (f->pending_head != NULL) {
p = f->pending_head;
f->pending_head = p->next;
(f->status == FQDN_CACHED) ? f->names[0] : NULL,
p->handlerData);
}
- memset(p, '\0', sizeof(struct _fqdn_pending));
safe_free(p);
}
f->pending_head = NULL; /* nuke list */
debug(35, 10, "fqdncache_call_pending: Called %d handlers.\n", nhandler);
-}
-
-static void
-fqdncache_call_pending_badname(int fd, FQDNH handler, void *data)
-{
- debug(35, 0, "fqdncache_call_pending_badname: Bad Name: Calling handler with NULL result.\n");
- handler(fd, NULL, data);
+ fqdncacheUnlockEntry(f);
}
static fqdncache_entry *
return &f;
}
+static void
+fqdncacheNudgeQueue(void)
+{
+ dnsserver_t *dnsData;
+ fqdncache_entry *f = NULL;
+ while ((dnsData = dnsGetFirstAvailable()) && (f = fqdncacheDequeue()))
+ fqdncache_dnsDispatch(dnsData, f);
+}
+
static void
fqdncache_dnsHandleRead(int fd, void *data)
{
DnsStats.replies++;
dnsData->offset += len;
dnsData->ip_inbuf[dnsData->offset] = '\0';
-
+ f = dnsData->data;
+ if (f->status != FQDN_DISPATCHED)
+ fatal_dump("fqdncache_dnsHandleRead: bad status");
if (strstr(dnsData->ip_inbuf, "$end\n")) {
/* end of record found */
svc_time = tvSubMsec(dnsData->dispatch_time, current_time);
} else {
dnsData->offset = 0;
dnsData->ip_inbuf[0] = '\0';
- f = dnsData->data;
f->name_count = x->name_count;
for (n = 0; n < (int) f->name_count; n++)
f->names[n] = x->names[n];
f->expires = x->expires;
fqdncache_call_pending(f);
}
+ fqdncacheUnlockEntry(f); /* unlock from FQDN_DISPATCHED */
}
if (dnsData->offset == 0) {
dnsData->data = NULL;
COMM_SELECT_READ,
fqdncache_dnsHandleRead,
dnsData, 0);
- while ((dnsData = dnsGetFirstAvailable()) && (f = fqdncacheDequeue()))
- fqdncache_dnsDispatch(dnsData, f);
+ fqdncacheNudgeQueue();
}
static void
{
struct _fqdn_pending *pending = xcalloc(1, sizeof(struct _fqdn_pending));
struct _fqdn_pending **I = NULL;
-
+ f->lastref = squid_curtime;
pending->fd = fd;
pending->handler = handler;
pending->handlerData = handlerData;
-
for (I = &(f->pending_head); *I; I = &((*I)->next));
*I = pending;
+ if (f->status == IP_PENDING)
+ fqdncacheNudgeQueue();
}
-int
+void
fqdncache_nbgethostbyaddr(struct in_addr addr, int fd, FQDNH handler, void *handlerData)
{
fqdncache_entry *f = NULL;
if (name == NULL || name[0] == '\0') {
debug(35, 4, "fqdncache_nbgethostbyaddr: Invalid name!\n");
- fqdncache_call_pending_badname(fd, handler, handlerData);
- return 0;
+ handler(fd, NULL, handlerData);
+ return;
}
if ((f = fqdncache_get(name))) {
if (fqdncacheExpiredEntry(f)) {
/* MISS: No entry, create the new one */
debug(35, 5, "fqdncache_nbgethostbyaddr: MISS for '%s'\n", name);
FqdncacheStats.misses++;
- f = fqdncache_create();
- f->name = xstrdup(name);
- f->status = FQDN_PENDING;
+ f = fqdncacheAddNew(name, NULL, FQDN_PENDING);
fqdncacheAddPending(f, fd, handler, handlerData);
- fqdncache_add_to_hash(f);
} else if (f->status == FQDN_CACHED || f->status == FQDN_NEGATIVE_CACHED) {
/* HIT */
debug(35, 4, "fqdncache_nbgethostbyaddr: HIT for '%s'\n", name);
FqdncacheStats.hits++;
fqdncacheAddPending(f, fd, handler, handlerData);
fqdncache_call_pending(f);
- return 0;
+ return;
} else if (f->status == FQDN_PENDING || f->status == FQDN_DISPATCHED) {
debug(35, 4, "fqdncache_nbgethostbyaddr: PENDING for '%s'\n", name);
FqdncacheStats.pending_hits++;
fqdncacheAddPending(f, fd, handler, handlerData);
- return 0;
+ if (squid_curtime - f->expires > 600) {
+ debug(14, 0, "fqdncache_nbgethostbyname: '%s' PENDING for %d seconds, aborting\n", name, squid_curtime + Config.negativeDnsTtl - f->expires);
+ fqdncacheChangeKey(f);
+ fqdncache_call_pending(f);
+ }
+ return;
} else {
fatal_dump("fqdncache_nbgethostbyaddr: BAD fqdncache_entry status");
}
/* for HIT, PENDING, DISPATCHED we've returned. For MISS we continue */
- if ((dnsData = dnsGetFirstAvailable()))
+ if ((dnsData = dnsGetFirstAvailable())) {
fqdncache_dnsDispatch(dnsData, f);
- else
+ return;
+ }
+ if (NDnsServersAlloc > 0) {
fqdncacheEnqueue(f);
- return 0;
+ return;
+ }
+ fqdncache_gethostbyaddr(addr, FQDN_BLOCKING_LOOKUP);
+ fqdncache_call_pending(f);
}
static void
fqdncache_release(f);
return;
}
- f->status = FQDN_DISPATCHED;
+ if (f->status != FQDN_PENDING)
+ debug_trap("fqdncache_dnsDispatch: status != FQDN_PENDING");
buf = xcalloc(1, 256);
sprintf(buf, "%1.254s\n", f->name);
dns->flags |= DNS_FLAG_BUSY;
dns->data = f;
+ f->status = FQDN_DISPATCHED;
comm_write(dns->outpipe,
buf,
strlen(buf),
dns->dispatch_time = current_time;
DnsStats.requests++;
DnsStats.hist[dns->id - 1]++;
+ fqdncacheLockEntry(f); /* lock while IP_DISPATCHED */
}
char *name = inet_ntoa(addr);
fqdncache_entry *f = NULL;
const struct hostent *hp = NULL;
- unsigned int ip;
+ struct in_addr ip;
static char *static_name = NULL;
if (!name)
fatal_dump("fqdncache_gethostbyaddr: NULL name");
FqdncacheStats.requests++;
if ((f = fqdncache_get(name))) {
+ if (fqdncacheExpiredEntry(f)) {
+ fqdncache_release(f);
+ f = NULL;
+ }
+ }
+ if (f) {
if (f->status == FQDN_PENDING || f->status == FQDN_DISPATCHED) {
- FqdncacheStats.pending_hits++;
- return NULL;
+ if (!BIT_TEST(flags, IP_BLOCKING_LOOKUP)) {
+ FqdncacheStats.pending_hits++;
+ return NULL;
+ }
} else if (f->status == FQDN_NEGATIVE_CACHED) {
FqdncacheStats.negative_hits++;
dns_error_message = f->error_message;
return f->names[0];
}
}
- FqdncacheStats.misses++;
/* check if it's already a FQDN address in text form. */
- if (inet_addr(name) == inaddr_none) {
+ if (!safe_inet_addr(name, &ip))
return name;
- }
- if (flags & FQDN_BLOCKING_LOOKUP) {
+ FqdncacheStats.misses++;
+ if (BIT_TEST(flags, FQDN_BLOCKING_LOOKUP)) {
+ if (NDnsServersAlloc)
+ debug(14, 0, "WARNING: blocking on gethostbyaddr() for '%s'\n", name);
FqdncacheStats.ghba_calls++;
- ip = inet_addr(name);
- hp = gethostbyaddr((char *) &ip, 4, AF_INET);
+ hp = gethostbyaddr((char *) &ip.s_addr, 4, AF_INET);
if (hp && hp->h_name && (hp->h_name[0] != '\0') && fqdn_table) {
- if (f->status == FQDN_PENDING || f->status == FQDN_DISPATCHED) {
+ if (f == NULL) {
+ f = fqdncacheAddNew(name, hp, FQDN_CACHED);
+ } else if (f->status == FQDN_DISPATCHED) {
+ /* only dnsHandleRead() can change from DISPATCHED to CACHED */
xfree(static_name);
static_name = xstrdup(hp->h_name);
return static_name;
+ } else {
+ fqdncacheAddHostent(f, hp);
+ f->status = FQDN_CACHED;
}
- /* good address, cached */
- fqdncache_add(name, fqdncache_create(), hp, 1);
- f = fqdncache_get(name);
+ f->expires = squid_curtime + Config.positiveDnsTtl;
return f->names[0];
}
/* bad address, negative cached */
- if (fqdn_table)
- fqdncache_add(name, fqdncache_create(), hp, 0);
- return NULL;
+ if (fqdn_table && f == NULL) {
+ f = fqdncacheAddNew(name, hp, FQDN_NEGATIVE_CACHED);
+ f->expires = squid_curtime + Config.negativeDnsTtl;
+ return NULL;
+ }
}
if (flags & FQDN_LOOKUP_IF_MISS)
fqdncache_nbgethostbyaddr(addr, -1, dummy_handler, NULL);
return 1;
}
+static void
+fqdncacheLockEntry(fqdncache_entry * f)
+{
+ f->locks++;
+}
+
+static void
+fqdncacheUnlockEntry(fqdncache_entry * f)
+{
+ if (f->locks == 0) {
+ debug_trap("fqdncacheUnlockEntry: Entry has no locks");
+ return;
+ }
+ f->locks--;
+ if (fqdncacheExpiredEntry(f))
+ fqdncache_release(f);
+}
+
void
fqdncacheFreeMemory(void)
{
xfree(list);
hashFreeMemory(fqdn_table);
}
+
+static void
+fqdncacheChangeKey(fqdncache_entry * f)
+{
+ static int index = 0;
+ LOCAL_ARRAY(char, new_key, 256);
+ hash_link *table_entry = hash_lookup(fqdn_table, f->name);
+ if (table_entry == NULL) {
+ debug(14, 0, "fqdncacheChangeKey: Could not find key '%s'\n", f->name);
+ return;
+ }
+ if (f != (fqdncache_entry *) table_entry) {
+ debug_trap("fqdncacheChangeKey: f != table_entry!");
+ return;
+ }
+ if (hash_remove_link(fqdn_table, table_entry)) {
+ debug_trap("fqdncacheChangeKey: hash_remove_link() failed\n");
+ return;
+ }
+ sprintf(new_key, "%d/", ++index);
+ strncat(new_key, f->name, 128);
+ debug(14, 1, "fqdncacheChangeKey: from '%s' to '%s'\n", f->name, new_key);
+ safe_free(f->name);
+ f->name = xstrdup(new_key);
+ fqdncache_add_to_hash(f);
+}
+
+/* call during reconfigure phase to clear out all the
+ * pending and dispatched reqeusts that got lost */
+void
+fqdncache_restart(void)
+{
+ fqdncache_entry *this;
+ fqdncache_entry *next;
+ if (fqdn_table == 0)
+ fatal_dump("fqdncache_restart: fqdn_table == 0\n");
+ while (fqdncacheDequeue());
+ next = (fqdncache_entry *) hash_first(fqdn_table);
+ while ((this = next)) {
+ next = (fqdncache_entry *) hash_next(fqdn_table);
+ if (this->status == FQDN_CACHED)
+ continue;
+ if (this->status == FQDN_NEGATIVE_CACHED)
+ continue;
+ /* else its PENDING or DISPATCHED; there are no dnsservers
+ * running, so abort it */
+ this->status = FQDN_NEGATIVE_CACHED;
+ fqdncache_release(this);
+ }
+}
/*
- * $Id: ftp.cc,v 1.98 1997/03/29 04:45:16 wessels Exp $
+ * $Id: ftp.cc,v 1.99 1997/04/28 04:23:08 wessels Exp $
*
* DEBUG: section 9 File Transfer Protocol (FTP)
* AUTHOR: Harvest Derived
static void
ftp_login_parser(const char *login, FtpStateData * data)
{
- char *user = data->user;
- char *password = data->password;
char *s = NULL;
-
- strcpy(user, login);
- s = strchr(user, ':');
- if (s) {
+ xstrncpy(data->user, login, MAX_URL);
+ if ((s = strchr(data->user, ':'))) {
*s = 0;
- strcpy(password, s + 1);
+ xstrncpy(data->password, s + 1, MAX_URL);
} else {
- strcpy(password, null_string);
- }
-
- if (!*user && !*password) {
- strcpy(user, "anonymous");
- strcpy(password, Config.ftpUser);
+ xstrncpy(data->password, null_string, MAX_URL);
}
+ if (data->user[0] || data->password[0])
+ return;
+ xstrncpy(data->user, "anonymous", MAX_URL);
+ xstrncpy(data->password, Config.ftpUser, MAX_URL);
}
/* This will be called when socket lifetime is expired. */
char *s = NULL;
int got_timeout = 0;
int got_negttl = 0;
- int buflen;
debug(9, 5, "ftpSendRequest: FD %d\n", fd);
- buflen = strlen(data->request->urlpath) + 256;
buf = get_free_8k_page();
path = data->request->urlpath;
if (data->authenticated) {
strcat(buf, "-a ");
}
- if (Config.Addrs.tcp_outgoing.s_addr != inaddr_none) {
+ if (Config.Addrs.tcp_outgoing.s_addr != no_addr.s_addr) {
sprintf(tbuf, "-o %s ", inet_ntoa(Config.Addrs.tcp_outgoing));
strcat(buf, tbuf);
}
return base64_decode(t);
}
+/*
+ * ftpCheckAuth
+ *
+ * Return 1 if we have everything needed to complete this request.
+ * Return 0 if something is missing.
+ */
+static int
+ftpCheckAuth(FtpStateData * ftpState, char *req_hdr)
+{
+ char *orig_user;
+ char *auth;
+ ftp_login_parser(ftpState->request->login, ftpState);
+ if (ftpState->user[0] && ftpState->password[0])
+ return 1; /* name and passwd both in URL */
+ if (!ftpState->user[0] && !ftpState->password[0])
+ return 1; /* no name or passwd */
+ if (ftpState->password[0])
+ return 1; /* passwd with no name? */
+ /* URL has name, but no passwd */
+ if ((auth = ftpGetBasicAuth(req_hdr)) == NULL)
+ return 0; /* need auth header */
+ orig_user = xstrdup(ftpState->user);
+ ftp_login_parser(auth, ftpState);
+ if (!strcmp(orig_user, ftpState->user)) {
+ xfree(orig_user);
+ return 1; /* same username */
+ }
+ strcpy(ftpState->user, orig_user);
+ xfree(orig_user);
+ return 0; /* different username */
+}
+
int
ftpStart(request_t * request, StoreEntry * entry)
FtpStateData *ftpData = xcalloc(1, sizeof(FtpStateData));
char *req_hdr;
char *response;
- char *auth;
ftpData->entry = entry;
xfree(ctrlp);
req_hdr = entry->mem_obj->mime_hdr;
ftpData->request = requestLink(request);
- /* Parse login info. */
- if ((auth = ftpGetBasicAuth(req_hdr))) {
- ftp_login_parser(auth, ftpData);
- ftpData->authenticated = 1;
- } else {
- ftp_login_parser(request->login, ftpData);
- if (*ftpData->user && !*ftpData->password) {
- /* This request is not fully authenticated */
- if (request->port == 21) {
- sprintf(realm, "ftp %s", ftpData->user);
- } else {
- sprintf(realm, "ftp %s port %d",
- ftpData->user, request->port);
- }
- response = authorization_needed_msg(request, realm);
- storeAppend(entry, response, strlen(response));
- httpParseReplyHeaders(response, entry->mem_obj->reply);
- storeComplete(entry);
- ftpStateFree(-1, ftpData);
- return;
+ if (!ftpCheckAuth(ftpData, req_hdr)) {
+ /* This request is not fully authenticated */
+ if (request->port == 21) {
+ sprintf(realm, "ftp %s", ftpData->user);
+ } else {
+ sprintf(realm, "ftp %s port %d",
+ ftpData->user, request->port);
}
+ response = authorization_needed_msg(request, realm);
+ storeAppend(entry, response, strlen(response));
+ httpParseReplyHeaders(response, entry->mem_obj->reply);
+ storeComplete(entry);
+ ftpStateFree(-1, ftpData);
+ return;
}
debug(9, 5, "FtpStart: host=%s, path=%s, user=%s, passwd=%s\n",
ftpData->request->host, ftpData->request->urlpath,
comm_close(fd);
return;
}
- fdstat_open(fd, FD_SOCKET);
commSetNonBlocking(fd);
(void) fd_note(fd, ftpData->entry->url);
/* Install connection complete handler. */
close(ftpget_to_squid[1]);
dup2(cfd, 3); /* pass listening socket to ftpget */
/* inherit stdin,stdout,stderr */
- for (cfd = 4; cfd <= fdstat_biggest_fd(); cfd++)
+ for (cfd = 4; cfd <= Biggest_FD; cfd++)
(void) close(cfd);
sprintf(pbuf, "%d", ftpget_port);
execlp(ftpget, ftpget, "-S", pbuf, NULL);
/*
- * $Id: http.cc,v 1.153 1997/03/04 05:16:31 wessels Exp $
+ * $Id: http.cc,v 1.154 1997/04/28 04:23:11 wessels Exp $
*
* DEBUG: section 11 Hypertext Transfer Protocol (HTTP)
* AUTHOR: Harvest Derived
put_free_8k_page(httpState->reply_hdr);
httpState->reply_hdr = NULL;
}
+ if (httpState->ip_lookup_pending)
+ ipcache_unregister(httpState->request->host, httpState->fd);
requestUnlink(httpState->request);
requestUnlink(httpState->orig_request);
xfree(httpState);
errno = 0;
len = read(fd, buf, SQUID_TCP_SO_RCVBUF);
debug(11, 5, "httpReadReply: FD %d: len %d.\n", fd, len);
- comm_set_fd_lifetime(fd, 86400); /* extend after good read */
if (len > 0) {
+ comm_set_fd_lifetime(fd, 86400); /* extend after good read */
IOStats.Http.reads++;
for (clen = len - 1, bin = 0; clen; bin++)
clen >>= 1;
size_t out_sz,
int cfd)
{
+ LOCAL_ARRAY(char, ybuf, MAX_URL + 32);
char *xbuf = get_free_4k_page();
- char *ybuf = get_free_8k_page();
char *viabuf = get_free_4k_page();
char *fwdbuf = get_free_4k_page();
char *t = NULL;
}
httpAppendRequestHeader(hdr_out, null_string, &len, out_sz);
put_free_4k_page(xbuf);
- put_free_8k_page(ybuf);
put_free_4k_page(viabuf);
put_free_4k_page(fwdbuf);
if (in_len)
httpState->request = requestLink(request);
httpState->neighbor = e;
httpState->orig_request = requestLink(orig_request);
+ httpState->fd = sock;
/* register the handler to free HTTP state data when the FD closes */
- comm_add_close_handler(sock,
+ comm_add_close_handler(httpState->fd,
httpStateFree,
(void *) httpState);
request->method = orig_request->method;
request->port = e->http_port;
xstrncpy(request->urlpath, url, MAX_URL);
BIT_SET(request->flags, REQ_PROXYING);
+ httpState->ip_lookup_pending = 1;
ipcache_nbgethostbyname(request->host,
- sock,
+ httpState->fd,
httpConnect,
httpState);
return;
HttpStateData *httpState = data;
request_t *request = httpState->request;
StoreEntry *entry = httpState->entry;
+ httpState->ip_lookup_pending = 0;
if (ia == NULL) {
debug(11, 4, "httpConnect: Unknown host: %s\n", request->host);
squid_error_entry(entry, ERR_DNS_FAIL, dns_error_message);
httpState->req_hdr = req_hdr;
httpState->req_hdr_sz = req_hdr_sz;
httpState->request = requestLink(request);
- comm_add_close_handler(sock,
+ httpState->fd = sock;
+ comm_add_close_handler(httpState->fd,
httpStateFree,
(void *) httpState);
+ httpState->ip_lookup_pending = 1;
ipcache_nbgethostbyname(request->host,
- sock,
+ httpState->fd,
httpConnect,
httpState);
}
/*
- * $Id: icmp.cc,v 1.32 1997/03/04 05:16:32 wessels Exp $
+ * $Id: icmp.cc,v 1.33 1997/04/28 04:23:12 wessels Exp $
*
* DEBUG: section 37 ICMP Routines
* AUTHOR: Duane Wessels
local_addr,
0,
COMM_NONBLOCKING,
- "ICMP Socket");
+ "Pinger Socket");
if (icmp_sock < 0) {
debug(50, 0, "icmpOpen: icmp_sock: %s\n", xstrerror());
return;
}
if (pid == 0) { /* child */
char *x = xcalloc(strlen(Config.debugOptions) + 32, 1);
- sprintf(x, "SQUID_DEBUG=%s\n", Config.debugOptions);
+ sprintf(x, "SQUID_DEBUG=%s", Config.debugOptions);
putenv(x);
comm_close(icmp_sock);
dup2(child_sock, 0);
/*
- * $Id: ipcache.cc,v 1.108 1997/03/04 05:16:35 wessels Exp $
+ * $Id: ipcache.cc,v 1.109 1997/04/28 04:23:15 wessels Exp $
*
* DEBUG: section 14 IP Cache
* AUTHOR: Harvest Derived
#include "squid.h"
-#define MAX_LINELEN (4096)
-
-#define IP_LOW_WATER 90
-#define IP_HIGH_WATER 95
-
struct _ip_pending {
int fd;
IPH handler;
int errors;
int avg_svc_time;
int ghbn_calls; /* # calls to blocking gethostbyname() */
+ int release_locked;
} IpcacheStats;
static int ipcache_testname _PARAMS((void));
static int ipcache_compareLastRef _PARAMS((ipcache_entry **, ipcache_entry **));
static int ipcache_reverseLastRef _PARAMS((ipcache_entry **, ipcache_entry **));
-static int ipcache_dnsHandleRead _PARAMS((int, dnsserver_t *));
+static void ipcache_dnsHandleRead _PARAMS((int, dnsserver_t *));
static ipcache_entry *ipcache_parsebuffer _PARAMS((const char *buf, dnsserver_t *));
static void ipcache_release _PARAMS((ipcache_entry *));
static ipcache_entry *ipcache_GetFirst _PARAMS((void));
ipcacheQueueTailP = &ipcacheQueueHead;
safe_free(old);
}
+ if (i && i->status != IP_PENDING)
+ debug_trap("ipcacheDequeue: status != IP_PENDING");
return i;
}
}
if (i != (ipcache_entry *) table_entry)
fatal_dump("ipcache_release: i != table_entry!");
- if (i->status == IP_PENDING) {
- debug(14, 1, "ipcache_release: Someone called on a PENDING entry\n");
- return;
- }
- if (i->status == IP_DISPATCHED) {
- debug(14, 1, "ipcache_release: Someone called on a DISPATCHED entry\n");
+ if (i->locks) {
+ i->expires = squid_curtime;
+ IpcacheStats.release_locked++;
return;
}
if (hash_remove_link(ip_table, table_entry)) {
xmemcpy(&i->addrs.in_addrs[k].s_addr,
*(hp->h_addr_list + k),
hp->h_length);
- i->status = IP_CACHED;
}
static ipcache_entry *
debug(14, 5, "ipcache_parsebuffer: parsing:\n%s", inbuf);
memset(&i, '\0', sizeof(ipcache_entry));
i.expires = squid_curtime + Config.positiveDnsTtl;
- i.status = IP_DISPATCHED;
for (token = strtok(buf, w_space); token; token = strtok(NULL, w_space)) {
if (!strcmp(token, "$end")) {
break;
for (k = 0; k < ipcount; k++) {
if ((token = strtok(NULL, w_space)) == NULL)
fatal_dump("Invalid IP address");
- i.addrs.in_addrs[k].s_addr = inet_addr(token);
+ if (!safe_inet_addr(token, &i.addrs.in_addrs[k]))
+ fatal_dump("Invalid IP address");
}
} else if (!strcmp(token, "$aliascount")) {
if ((token = strtok(NULL, w_space)) == NULL)
ipcache_dnsDispatch(dnsData, i);
}
-static int
+static void
ipcache_dnsHandleRead(int fd, dnsserver_t * dnsData)
{
int len;
COMM_SELECT_READ,
(PF) ipcache_dnsHandleRead,
dnsData, 0);
- return 0;
+ return;
}
debug(14, dnsData->flags & DNS_FLAG_CLOSING ? 5 : 1,
"FD %d: Connection from DNSSERVER #%d is closed, disabling\n",
NULL,
NULL, 0);
comm_close(fd);
- return 0;
+ return;
}
n = ++IpcacheStats.replies;
DnsStats.replies++;
} else {
dnsData->offset = 0;
dnsData->ip_inbuf[0] = '\0';
- i = dnsData->data;
i->addrs = x->addrs;
i->error_message = x->error_message;
i->status = x->status;
(PF) ipcache_dnsHandleRead,
dnsData, 0);
ipcacheNudgeQueue();
- return 0;
}
static void
{
ipcache_entry *i = NULL;
dnsserver_t *dnsData = NULL;
- ipcache_addrs *addrs = NULL;
+ const ipcache_addrs *addrs = NULL;
if (!handler)
fatal_dump("ipcache_nbgethostbyname: NULL handler");
ipcache_dnsDispatch(dnsData, i);
return;
}
- if (addrs != NULL) /* TEMPORARY */
- debug_trap("ipcache_nbgethostbyname: Stack Trashed");
if (NDnsServersAlloc > 0) {
ipcacheEnqueue(i);
return;
}
- if (addrs != NULL) /* TEMPORARY */
- debug_trap("ipcache_nbgethostbyname: Stack Trashed");
- if (NDnsServersAlloc)
- debug(14, 0, "WARNING: blocking on gethostbyname() for '%s'\n", name);
ipcache_gethostbyname(name, IP_BLOCKING_LOOKUP);
ipcache_call_pending(i);
}
if (!BIT_TEST(dns->flags, DNS_FLAG_ALIVE))
debug_trap("Dispatching a dead DNS server");
if (!ipcacheHasPending(i)) {
- debug(14, 0, "ipcache_dnsDispatch: skipping '%s' because no handler.\n",
+ debug(14, 0, "Skipping lookup of '%s' because client(s) disappeared.\n",
i->name);
i->status = IP_NEGATIVE_CACHED;
ipcache_release(i);
return;
}
+ if (i->status != IP_PENDING)
+ debug_trap("ipcache_dnsDispatch: status != IP_PENDING");
buf = xcalloc(1, 256);
sprintf(buf, "%1.254s\n", i->name);
dns->flags |= DNS_FLAG_BUSY;
dns->data = i;
- dns->lastcall = squid_curtime;
i->status = IP_DISPATCHED;
comm_write(dns->outpipe,
buf,
return addrs;
IpcacheStats.misses++;
if (BIT_TEST(flags, IP_BLOCKING_LOOKUP)) {
+ if (NDnsServersAlloc)
+ debug(14, 0, "WARNING: blocking on gethostbyname() for '%s'\n", name);
IpcacheStats.ghbn_calls++;
hp = gethostbyname(name);
if (hp && hp->h_name && (hp->h_name[0] != '\0') && ip_table) {
/* good address, cached */
if (i == NULL) {
i = ipcacheAddNew(name, hp, IP_CACHED);
- } else if (i->status == IP_PENDING || i->status == IP_DISPATCHED) {
+ } else if (i->status == IP_DISPATCHED) {
/* only dnsHandleRead() can change from DISPATCHED to CACHED */
static_addrs.count = 1;
static_addrs.cur = 0;
return &static_addrs;
} else {
ipcacheAddHostent(i, hp);
+ i->status = IP_CACHED;
}
i->expires = squid_curtime + Config.positiveDnsTtl;
#if LIBRESOLV_DNS_TTL_HACK
IpcacheStats.misses);
storeAppendPrintf(sentry, "{Blocking calls to gethostbyname(): %d}\n",
IpcacheStats.ghbn_calls);
+ storeAppendPrintf(sentry, "{Attempts to release locked entries: %d}\n",
+ IpcacheStats.release_locked);
storeAppendPrintf(sentry, "{dnsserver avg service time: %d msec}\n",
IpcacheStats.avg_svc_time);
storeAppendPrintf(sentry, "}\n\n");
ipcache_addrs *
ipcacheCheckNumeric(const char *name)
{
- unsigned int ip;
+ struct in_addr ip;
/* check if it's already a IP address in text form. */
- if ((ip = inet_addr(name)) == inaddr_none)
+ if (!safe_inet_addr(name, &ip))
return NULL;
static_addrs.count = 1;
static_addrs.cur = 0;
- static_addrs.in_addrs[0].s_addr = ip;
+ static_addrs.in_addrs[0].s_addr = ip.s_addr;
return &static_addrs;
}
debug_trap("ipcacheChangeKey: hash_remove_link() failed\n");
return;
}
- sprintf(new_key, "%d/%-128.128s", ++index, i->name);
+ sprintf(new_key, "%d/", ++index);
+ strncat(new_key, i->name, 128);
debug(14, 1, "ipcacheChangeKey: from '%s' to '%s'\n", i->name, new_key);
safe_free(i->name);
i->name = xstrdup(new_key);
ipcache_add_to_hash(i);
}
+
+/* call during reconfigure phase to clear out all the
+ * pending and dispatched reqeusts that got lost */
+void
+ipcache_restart(void)
+{
+ ipcache_entry *this;
+ ipcache_entry *next;
+ if (ip_table == 0)
+ fatal_dump("ipcache_restart: ip_table == 0\n");
+ while (ipcacheDequeue());
+ next = (ipcache_entry *) hash_first(ip_table);
+ while ((this = next)) {
+ next = (ipcache_entry *) hash_next(ip_table);
+ if (this->status == IP_CACHED)
+ continue;
+ if (this->status == IP_NEGATIVE_CACHED)
+ continue;
+ /* else its PENDING or DISPATCHED; there are no dnsservers
+ * running, so abort it */
+ this->status = IP_NEGATIVE_CACHED;
+ ipcache_release(this);
+ }
+ /* recalculate these while we're at it */
+ ipcache_high = (long) (((float) Config.ipcache.size *
+ (float) Config.ipcache.high) / (float) 100);
+ ipcache_low = (long) (((float) Config.ipcache.size *
+ (float) Config.ipcache.low) / (float) 100);
+}
/*
- * $Id: main.cc,v 1.140 1997/04/25 06:38:21 wessels Exp $
+ * $Id: main.cc,v 1.141 1997/04/28 04:23:16 wessels Exp $
*
* DEBUG: section 1 Startup and Main Loop
* AUTHOR: Harvest Derived
int opt_accel_uses_host = 0;
int vhost_mode = 0;
int Squid_MaxFD = SQUID_MAXFD;
+int Biggest_FD = -1;
+int select_loops = 0; /* how many times thru select loop */
volatile int unbuffered_logs = 1; /* debug and hierarchy unbuffered by default */
volatile int shutdown_pending = 0; /* set by SIGTERM handler (shut_down()) */
volatile int reread_pending = 0; /* set by SIGHUP handler */
const char *const dash_str = "-";
const char *const null_string = "";
char ThisCache[SQUIDHOSTNAMELEN << 1];
-unsigned int inaddr_none;
/* for error reporting from xmalloc and friends */
extern void (*failure_notify) _PARAMS((const char *));
fprintf(stderr,
"Usage: %s [-hsvzCDFRUVY] [-f config-file] [-[au] port] [-k signal]\n"
" -a port Specify ASCII port number (default: %d).\n"
+ " -b Buffer log output (default is unbuffered).\n"
" -f file Use given config-file instead of\n"
" %s\n"
" -h Print help message.\n"
" -R Do not set REUSEADDR on port.\n"
" -U Unlink expired objects on reload.\n"
" -V Virtual host httpd-accelerator.\n"
- " -Y Only return UDP_HIT or UDP_MISSNOFETCH during fast reload.\n",
+ " -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
appname, CACHE_HTTP_PORT, DefaultConfigFile, CACHE_ICP_PORT);
exit(1);
}
debug(1, 1, "Accepting ICP connections on FD %d.\n",
theInIcpConnection);
- if ((addr = Config.Addrs.udp_outgoing).s_addr != inaddr_none) {
+ if ((addr = Config.Addrs.udp_outgoing).s_addr != no_addr.s_addr) {
enter_suid();
theOutIcpConnection = comm_open(SOCK_DGRAM,
0,
neighborsDestroy();
parseConfigFile(ConfigFile);
_db_init(Config.Log.log, Config.debugOptions);
+ ipcache_restart(); /* clear stuck entries */
+ fqdncache_restart(); /* sigh, fqdncache too */
dnsOpenServers();
redirectOpenServers();
serverConnectionsOpen();
#endif
if (first_time) {
+ unlinkdInit();
/* module initialization */
urlInitialize();
stat_init(&HTTPCacheInfo, Config.Log.access);
if (Config.Announce.on)
eventAdd("start_announce", start_announce, NULL, 3600);
eventAdd("ipcache_purgelru", (EVH) ipcache_purgelru, NULL, 10);
- eventAdd("peerUpdateFudge", peerUpdateFudge, NULL, 10);
}
first_time = 0;
}
#endif /* HAVE_MALLOPT */
memset(&local_addr, '\0', sizeof(struct in_addr));
- local_addr.s_addr = inet_addr(localhost);
+ safe_inet_addr(localhost, &local_addr);
memset(&any_addr, '\0', sizeof(struct in_addr));
- any_addr.s_addr = inet_addr("0.0.0.0");
+ safe_inet_addr("0.0.0.0", &any_addr);
memset(&no_addr, '\0', sizeof(struct in_addr));
- no_addr.s_addr = inet_addr("255.255.255.255");
- inaddr_none = inet_addr("255.255.255.255");
+ safe_inet_addr("255.255.255.255", &no_addr);
#if HAVE_SRANDOM
srandom(time(NULL));
comm_init();
/* we have to init fdstat here. */
- fdstat_init(PREOPEN_FD);
+ fdstat_init();
fdstat_open(0, FD_LOG);
fdstat_open(1, FD_LOG);
fdstat_open(2, FD_LOG);
/*
- * $Id: neighbors.cc,v 1.130 1997/03/29 04:45:18 wessels Exp $
+ * $Id: neighbors.cc,v 1.131 1997/04/28 04:23:17 wessels Exp $
*
* DEBUG: section 15 Neighbor Routines
* AUTHOR: Harvest Derived
#include "squid.h"
+/* count mcast group peers every 15 minutes */
+#define MCAST_COUNT_RATE 900
+
static int peerAllowedToUse _PARAMS((const peer *, request_t *));
static int peerHTTPOkay _PARAMS((const peer *, request_t *));
static int peerWouldBePinged _PARAMS((const peer *, request_t *));
static void peerCheckConnect _PARAMS((void *));
static void peerCheckConnect2 _PARAMS((int, const ipcache_addrs *, void *));
static void peerCheckConnectDone _PARAMS((int, int, void *));
+static void peerCountMcastPeersDone _PARAMS((void *data));
+static void peerCountMcastPeersStart _PARAMS((void *data));
+static void peerCountMcastPeersSchedule _PARAMS((peer * p, time_t when));
+static void peerCountHandleIcpReply _PARAMS((peer * p, peer_t type, icp_opcode op, void *data));
static icp_common_t echo_hdr;
static u_short echo_port;
static int NLateReplies = 0;
-static int NObjectsQueried = 0;
-static int MulticastFudgeFactor = 1;
static struct {
int n;
peer *peers_head;
peer *peers_tail;
peer *first_ping;
+ peer *removed;
} Peers = {
0, NULL, NULL, NULL
};
-const char *hier_strings[] =
-{
- "NONE",
- "DIRECT",
- "SIBLING_HIT",
- "PARENT_HIT",
- "DEFAULT_PARENT",
- "SINGLE_PARENT",
- "FIRST_UP_PARENT",
- "NO_PARENT_DIRECT",
- "BEST_PARENT_MISS",
- "NO_DIRECT_FAIL",
- "SOURCE_FASTEST",
- "SIBLING_UDP_HIT_OBJ",
- "PARENT_UDP_HIT_OBJ",
- "PASSTHROUGH_PARENT",
- "SSL_PARENT_MISS",
- "ROUNDROBIN_PARENT",
- "INVALID CODE"
-};
-
char *
neighborTypeStr(const peer * e)
{
}
if (e) {
*E = e->next;
- peerDestroy(e);
+ e->next = Peers.removed;
+ Peers.removed = e;
+ e->stats.ack_deficit = HIER_MAX_DEFICIT;
Peers.n--;
}
Peers.first_ping = Peers.peers_head;
peerDestroy(e);
Peers.n--;
}
+ for (e = Peers.removed; e; e = next) {
+ next = e->next;
+ peerDestroy(e);
+ }
memset(&Peers, '\0', sizeof(Peers));
}
int reqnum = 0;
int flags;
icp_common_t *query;
- int ICP_queries_sent = 0;
- int ICP_mcasts_sent = 0;
+ int queries_sent = 0;
int peers_pinged = 0;
if (Peers.peers_head == NULL)
}
if (entry->swap_status != NO_SWAP)
fatal_dump("neighborsUdpPing: bad swap_status");
+ mem->w_rtt = 0;
+ mem->e_pings_closest_parent = NULL;
+ mem->p_rtt = 0;
mem->start_ping = current_time;
mem->icp_reply_callback = callback;
mem->ircb_data = callback_data;
debug(15, 4, "neighborsUdpPing: pinging peer %s for '%s'\n",
e->host, url);
if (e->type == PEER_MULTICAST)
- comm_set_mcast_ttl(theOutIcpConnection, e->mcast_ttl);
+ comm_set_mcast_ttl(theOutIcpConnection, e->mcast.ttl);
reqnum = storeReqnum(entry, request->method);
debug(15, 3, "neighborsUdpPing: key = '%s'\n", entry->key);
debug(15, 3, "neighborsUdpPing: reqnum = %d\n", reqnum);
query,
LOG_TAG_NONE,
PROTO_NONE);
- ICP_queries_sent++;
} else {
flags = 0;
/* check if we should set ICP_FLAG_HIT_OBJ */
if (!BIT_TEST(request->flags, REQ_NOCACHE))
if (e->icp_version == ICP_VERSION_2)
flags |= ICP_FLAG_HIT_OBJ;
+ if (Config.Options.query_icmp)
+ if (e->icp_version == ICP_VERSION_2)
+ flags |= ICP_FLAG_SRC_RTT;
query = icpCreateMessage(ICP_OP_QUERY, flags, url, reqnum, 0);
icpUdpSend(theOutIcpConnection,
&e->in_addr,
query,
LOG_TAG_NONE,
PROTO_NONE);
- ICP_queries_sent++;
}
+ queries_sent++;
e->stats.ack_deficit++;
e->stats.pings_sent++;
e->host, e->stats.ack_deficit);
if (e->type == PEER_MULTICAST) {
e->stats.ack_deficit = 0;
- ICP_mcasts_sent++;
+ (*exprep) += e->mcast.n_replies_expected;
} else if (neighborUp(e)) {
/* its alive, expect a reply from it */
(*exprep)++;
query,
LOG_TAG_NONE,
PROTO_NONE);
- ICP_queries_sent++;
}
} else {
debug(15, 6, "neighborsUdpPing: Source Ping: unknown host: %s\n",
host);
}
}
- if ((ICP_queries_sent))
- NObjectsQueried++;
- if ((ICP_mcasts_sent))
- *exprep += MulticastFudgeFactor;
+#if LOG_ICP_NUMBERS
+ request->hierarchy.n_sent = peers_pinged;
+ request->hierarchy.n_expect = *exprep;
+#endif
return peers_pinged;
}
NLateReplies++;
}
+/* ignoreMulticastReply
+ *
+ * We want to ignore replies from multicast peers if the
+ * cache_host_domain rules would normally prevent the peer
+ * from being used
+ */
+static int
+ignoreMulticastReply(peer * e, MemObject * mem)
+{
+ if (e == NULL)
+ return 0;
+ if (!BIT_TEST(e->options, NEIGHBOR_MCAST_RESPONDER))
+ return 0;
+ if (peerHTTPOkay(e, mem->request))
+ return 0;
+ return 1;
+}
+
+/* I should attach these records to the entry. We take the first
+ * hit we get our wait until everyone misses. The timeout handler
+ * call needs to nip this shopping list or call one of the misses.
+ *
+ * If a hit process is already started, then sobeit
+ */
void
neighborsUdpAck(int fd, const char *url, icp_common_t * header, const struct sockaddr_in *from, StoreEntry * entry, char *data, int data_sz)
{
opcode_d, url, e ? e->host : "source");
if (e)
ntype = neighborType(e, mem->request);
- if (opcode == ICP_OP_MISS) {
+ if (ignoreMulticastReply(e, mem)) {
+ neighborCountIgnored(e, opcode);
+ } else if (opcode == ICP_OP_SECHO) {
+ /* Received source-ping reply */
+ if (e) {
+ debug(15, 1, "Ignoring SECHO from neighbor %s\n", e->host);
+ neighborCountIgnored(e, opcode);
+ } else {
+ /* if we reach here, source-ping reply is the first 'parent',
+ * so fetch directly from the source */
+ debug(15, 6, "Source is the first to respond.\n");
+ hierarchyNote(entry->mem_obj->request,
+ SOURCE_FASTEST,
+ 0,
+ fqdnFromAddr(from->sin_addr));
+ entry->ping_status = PING_DONE;
+ protoStart(0, entry, NULL, entry->mem_obj->request);
+ return;
+ }
+ } else if (opcode == ICP_OP_MISS) {
if (e == NULL) {
debug(15, 1, "Ignoring MISS from non-peer %s\n",
inet_ntoa(from->sin_addr));
neighborCountIgnored(e, opcode);
}
}
- } else if (opcode == ICP_OP_MISSNOFETCH) {
+ } else if (opcode == ICP_OP_MISS_NOFETCH) {
mem->icp_reply_callback(e, ntype, opcode, mem->ircb_data);
} else {
debug(15, 0, "neighborsUdpAck: Unexpected ICP reply: %s\n", opcode_d);
e = xcalloc(1, sizeof(peer));
e->http_port = http_port;
e->icp_port = icp_port;
- e->mcast_ttl = mcast_ttl;
+ e->mcast.ttl = mcast_ttl;
e->options = options;
e->weight = weight;
e->host = xstrdup(host);
return;
if (!e->tcp_up)
eventDelete(peerCheckConnect, e);
+ if (e->type == PEER_MULTICAST) {
+ if (e->mcast.flags & PEER_COUNT_EVENT_PENDING)
+ eventDelete(peerCountMcastPeersStart, e);
+ if (e->mcast.flags & PEER_COUNTING)
+ eventDelete(peerCountMcastPeersDone, e);
+ }
for (l = e->pinglist; l; l = nl) {
nl = l->next;
safe_free(l->domain);
safe_free(l);
}
+ if (e->ip_lookup_pending)
+ ipcache_unregister(e->host, e->ipcache_fd);
safe_free(e->host);
safe_free(e);
}
-void
-peerUpdateFudge(void *unused)
-{
- if ((NObjectsQueried)) {
- MulticastFudgeFactor = NLateReplies / NObjectsQueried;
- if (NObjectsQueried > 20) {
- /* Re-scale this so it adjusts faster */
- NLateReplies = 20 * NLateReplies / NObjectsQueried;
- NObjectsQueried = 20;
- }
- }
- eventAdd("peerUpdateFudge", peerUpdateFudge, NULL, 10);
- debug(15, 3, "peerUpdateFudge: Factor = %d\n", MulticastFudgeFactor);
-}
-
static void
peerDNSConfigure(int fd, const ipcache_addrs * ia, void *data)
{
peer *e = data;
struct sockaddr_in *ap;
int j;
+ e->ip_lookup_pending = 0;
if (e->n_addresses == 0) {
debug(15, 1, "Configuring %s %s/%d/%d\n", neighborTypeStr(e),
e->host, e->http_port, e->icp_port);
if (e->type == PEER_MULTICAST)
- debug(15, 1, " Multicast TTL = %d\n", e->mcast_ttl);
+ debug(15, 1, " Multicast TTL = %d\n", e->mcast.ttl);
}
e->n_addresses = 0;
if (ia == NULL) {
debug(0, 0, "WARNING: DNS lookup for '%s' failed!\n", e->host);
-#ifdef DONT
- debug(0, 0, "THIS NEIGHBOR WILL BE IGNORED.\n");
- neighborRemove(e);
-#endif
return;
}
if ((int) ia->count < 1) {
debug(0, 0, "WARNING: No IP address found for '%s'!\n", e->host);
-#ifdef DONT
- debug(0, 0, "THIS NEIGHBOR WILL BE IGNORED.\n");
- neighborRemove(e);
-#endif
return;
}
for (j = 0; j < (int) ia->count && j < PEER_MAX_ADDRESSES; j++) {
ap->sin_family = AF_INET;
ap->sin_addr = e->addresses[0];
ap->sin_port = htons(e->icp_port);
+ if (e->type == PEER_MULTICAST)
+ peerCountMcastPeersSchedule(e, 10);
}
static void
peer *next = Peers.peers_head;
while ((e = next)) {
next = e->next;
- ipcache_nbgethostbyname(e->host, 0, peerDNSConfigure, (void *) e);
+ e->ip_lookup_pending = 1;
+ /* some random, bogus FD for ipcache */
+ e->ipcache_fd = Squid_MaxFD + current_time.tv_usec;
+ ipcache_nbgethostbyname(e->host, e->ipcache_fd, peerDNSConfigure, e);
}
/* Reconfigure the peers every hour */
eventAdd("peerRefreshDNS", peerRefreshDNS, NULL, 3600);
0, COMM_NONBLOCKING, p->host);
if (fd < 0)
return;
+ p->ip_lookup_pending = 1;
+ p->ipcache_fd = fd;
ipcache_nbgethostbyname(p->host, fd, peerCheckConnect2, p);
}
peerCheckConnect2(int fd, const ipcache_addrs * ia, void *data)
{
peer *p = data;
+ p->ip_lookup_pending = 0;
commConnectStart(fd,
p->host,
p->http_port,
p->last_fail_time = squid_curtime;
eventAdd("peerCheckConnect", peerCheckConnect, p, 80);
}
+
+static void
+peerCountMcastPeersSchedule(peer * p, time_t when)
+{
+ if (p->mcast.flags & PEER_COUNT_EVENT_PENDING)
+ return;
+ eventAdd("peerCountMcastPeersStart",
+ peerCountMcastPeersStart,
+ p,
+ when);
+ p->mcast.flags |= PEER_COUNT_EVENT_PENDING;
+}
+
+static void
+peerCountMcastPeersStart(void *data)
+{
+ peer *p = data;
+ ps_state *psstate = xcalloc(1, sizeof(ps_state));
+ StoreEntry *fake;
+ MemObject *mem;
+ icp_common_t *query;
+ LOCAL_ARRAY(char, url, MAX_URL);
+ if (p->type != PEER_MULTICAST)
+ fatal_dump("peerCountMcastPeersStart: non-multicast peer");
+ p->mcast.flags &= ~PEER_COUNT_EVENT_PENDING;
+ sprintf(url, "http://%s/", inet_ntoa(p->in_addr.sin_addr));
+ fake = storeCreateEntry(url, NULL, 0, 0, METHOD_GET);
+ psstate->request = requestLink(urlParse(METHOD_GET, url));
+ psstate->entry = fake;
+ psstate->callback = NULL;
+ psstate->fail_callback = NULL;
+ psstate->callback_data = p;
+ psstate->icp.start = current_time;
+ mem = fake->mem_obj;
+ mem->start_ping = current_time;
+ mem->icp_reply_callback = peerCountHandleIcpReply;
+ mem->ircb_data = psstate;
+ comm_set_mcast_ttl(theOutIcpConnection, p->mcast.ttl);
+ p->mcast.reqnum = storeReqnum(fake, METHOD_GET);
+ query = icpCreateMessage(ICP_OP_QUERY, 0, url, p->mcast.reqnum, 0);
+ icpUdpSend(theOutIcpConnection,
+ &p->in_addr,
+ query,
+ LOG_TAG_NONE,
+ PROTO_NONE);
+ fake->ping_status = PING_WAITING;
+ eventAdd("peerCountMcastPeersDone",
+ peerCountMcastPeersDone,
+ p,
+ Config.neighborTimeout);
+ p->mcast.flags |= PEER_COUNTING;
+ peerCountMcastPeersSchedule(p, MCAST_COUNT_RATE);
+}
+
+static void
+peerCountMcastPeersDone(void *data)
+{
+ ps_state *psstate = data;
+ peer *p = psstate->callback_data;
+ StoreEntry *fake = psstate->entry;
+ double old;
+ double new;
+ double D;
+ p->mcast.flags &= ~PEER_COUNTING;
+ D = (double) ++p->mcast.n_times_counted;
+ if (D > 10.0)
+ D = 10.0;
+ old = p->mcast.avg_n_members;
+ new = (double) psstate->icp.n_recv;
+ p->mcast.avg_n_members = (old * (D - 1.0) + new) / D;
+ debug(15, 1, "Group %s: %d replies, %4.1f average\n",
+ p->host,
+ psstate->icp.n_recv,
+ p->mcast.avg_n_members);
+ p->mcast.n_replies_expected = (int) p->mcast.avg_n_members;
+ fake->store_status = STORE_ABORTED;
+ storeReleaseRequest(fake);
+ storeUnlockObject(fake);
+}
+
+static void
+peerCountHandleIcpReply(peer * p, peer_t type, icp_opcode op, void *data)
+{
+ ps_state *psstate = data;
+ psstate->icp.n_recv++;
+ debug(0, 0, "peerCountHandleIcpReply: %d replies\n", psstate->icp.n_recv);
+}
/*
- * $Id: net_db.cc,v 1.31 1997/02/19 17:11:07 wessels Exp $
+ * $Id: net_db.cc,v 1.32 1997/04/28 04:23:19 wessels Exp $
*
* DEBUG: section 37 Network Measurement Database
* AUTHOR: Duane Wessels
static void netdbHashLink _PARAMS((netdbEntry * n, const char *hostname));
static void netdbHashUnlink _PARAMS((const char *key));
static void netdbPurgeLRU _PARAMS((void));
+static net_db_peer *netdbPeerByName _PARAMS((const netdbEntry * n, const char *));
+static net_db_peer *netdbPeerAdd _PARAMS((netdbEntry * n, peer * e));
+static char *netdbPeerName _PARAMS((const char *name));
+
+/* 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 wordlist **peer_names_tail = &peer_names;
+static const char *const w_space = " \t\n\r";
static void
netdbHashInsert(netdbEntry * n, struct in_addr addr)
static void
netdbHashLink(netdbEntry * n, const char *hostname)
{
- struct _net_db_name *x = xcalloc(1, sizeof(struct _net_db_name));
+ net_db_name *x = xcalloc(1, sizeof(net_db_name));
x->name = xstrdup(hostname);
x->next = n->hosts;
n->hosts = x;
static void
netdbRelease(netdbEntry * n)
{
- struct _net_db_name *x;
- struct _net_db_name *next;
+ net_db_name *x;
+ net_db_name *next;
for (x = n->hosts; x; x = next) {
next = x->next;
netdbHashUnlink(x->name);
safe_free(x);
}
n->hosts = NULL;
+ safe_free(n->peers);
+ meta_data.netdb_peers -= n->n_peers_alloc;
+ n->peers = NULL;
+ n->n_peers = 0;
+ n->n_peers_alloc = 0;
if (n->link_count == 0) {
netdbHashDelete(n->network);
xfree(n);
debug(37, 3, "netdbSendPing: pinging %s\n", hostname);
icmpDomainPing(addr, hostname);
n->pings_sent++;
- n->next_ping_time = squid_curtime + Config.Netdb.ttl;
+ n->next_ping_time = squid_curtime + Config.Netdb.period;
n->last_use_time = squid_curtime;
xfree(hostname);
}
{
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
-sortByHops(netdbEntry ** n1, netdbEntry ** n2)
+sortByRtt(netdbEntry ** n1, netdbEntry ** n2)
{
- if ((*n1)->hops > (*n2)->hops)
+ if ((*n1)->rtt > (*n2)->rtt)
return 1;
- else if ((*n1)->hops < (*n2)->hops)
+ 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(37, 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));
+ meta_data.netdb_peers += n->n_peers_alloc;
+ for (i = 0; i < osize; i++)
+ *(n->peers + i) = *(o + i);
+ if (osize) {
+ safe_free(o);
+ meta_data.netdb_peers -= osize;
+ }
+ }
+ p = n->peers + n->n_peers;
+ p->peername = netdbPeerName(e->host);
+ n->n_peers++;
+ return p;
+}
+
+static int
+sortPeerByRtt(net_db_peer * p1, net_db_peer * p2)
+{
+ 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);
+ FILE *fp;
+ netdbEntry *n;
+ netdbEntry *next;
+ net_db_name *x;
+ struct timeval start = current_time;
+ int count = 0;
+ sprintf(path, "%s/netdb_state", swappath(0));
+ fp = fopen(path, "w");
+ if (fp == NULL) {
+ debug(50, 1, "netdbSaveState: %s: %s\n", path, xstrerror());
+ return;
+ }
+ next = (netdbEntry *) hash_first(addr_table);
+ while ((n = next)) {
+ next = (netdbEntry *) hash_next(addr_table);
+ if (n->pings_recv == 0)
+ continue;
+ fprintf(fp, "%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)
+ fprintf(fp, " %s", x->name);
+ fprintf(fp, "\n");
+ count++;
+ }
+ fclose(fp);
+ getCurrentTime();
+ debug(37, 0, "NETDB state saved; %d entries, %d msec\n",
+ count, tvSubMsec(start, current_time));
+ eventAdd("netdbSaveState", netdbSaveState, NULL, 3617);
+}
+
+static void
+netdbReloadState(void)
+{
+ LOCAL_ARRAY(char, path, SQUID_MAXPATHLEN);
+ char *buf = get_free_4k_page();
+ char *t;
+ FILE *fp;
+ netdbEntry *n;
+ netdbEntry N;
+ struct in_addr addr;
+ int count = 0;
+ struct timeval start = current_time;
+ sprintf(path, "%s/netdb_state", swappath(0));
+ fp = fopen(path, "r");
+ if (fp == NULL)
+ return;
+ while (fgets(buf, 4095, fp)) {
+ memset(&N, '\0', sizeof(netdbEntry));
+ if ((t = strtok(buf, w_space)) == NULL)
+ continue;
+ if (!safe_inet_addr(t, &addr))
+ continue;
+ if ((t = strtok(NULL, w_space)) == NULL)
+ continue;
+ N.pings_sent = atoi(t);
+ if ((t = strtok(NULL, w_space)) == NULL)
+ continue;
+ N.pings_recv = atoi(t);
+ if (N.pings_recv == 0)
+ continue;
+ /* give this measurement low weight */
+ N.pings_sent = 1;
+ N.pings_recv = 1;
+ if ((t = strtok(NULL, w_space)) == NULL)
+ continue;
+ N.hops = atof(t);
+ if ((t = strtok(NULL, w_space)) == NULL)
+ continue;
+ N.rtt = atof(t);
+ if ((t = strtok(NULL, w_space)) == NULL)
+ continue;
+ N.next_ping_time = (time_t) atoi(t);
+ if ((t = strtok(NULL, w_space)) == NULL)
+ continue;
+ N.last_use_time = (time_t) atoi(t);
+ n = xcalloc(1, sizeof(netdbEntry));
+ memcpy(n, &N, sizeof(netdbEntry));
+ netdbHashInsert(n, addr);
+ while ((t = strtok(NULL, w_space)) != NULL)
+ netdbHashLink(n, t);
+ count++;
+ }
+ put_free_4k_page(buf);
+ fclose(fp);
+ getCurrentTime();
+ debug(37, 0, "NETDB state reloaded; %d entries, %d msec\n",
+ count, tvSubMsec(start, current_time));
+}
+
+static char *
+netdbPeerName(const char *name)
+{
+ wordlist *w;
+ for (w = peer_names; w; w = w->next) {
+ if (!strcmp(w->key, name))
+ return w->key;
+ }
+ w = xcalloc(1, sizeof(wordlist));
+ w->key = xstrdup(name);
+ *peer_names_tail = w;
+ peer_names_tail = &w->next;
+ return w->key;
+}
+
+
+
#endif /* USE_ICMP */
/* PUBLIC FUNCTIONS */
return;
addr_table = hash_create((int (*)_PARAMS((const char *, const char *))) strcmp, 229, hash_string);
host_table = hash_create((int (*)_PARAMS((const char *, const char *))) strcmp, 467, hash_string);
+ eventAdd("netdbSaveState", netdbSaveState, NULL, 3617);
+ netdbReloadState();
#endif
}
debug(37, 3, "netdbHandlePingReply: from %s\n", inet_ntoa(from->sin_addr));
if ((n = netdbLookupAddr(from->sin_addr)) == NULL)
return;
- N = ++n->n;
- if (N > 100)
- N = 100;
+ N = ++n->pings_recv;
+ if (N > 5)
+ N = 5;
n->hops = ((n->hops * (N - 1)) + hops) / N;
n->rtt = ((n->rtt * (N - 1)) + rtt) / N;
- n->pings_recv++;
debug(37, 3, "netdbHandlePingReply: %s; rtt=%5.1f hops=%4.1f\n",
n->network,
n->rtt,
netdbEntry **L1;
hash_link *h;
hash_link **L2;
- struct _net_db_name *x;
+ net_db_name *x;
int i = 0;
int j;
L1 = xcalloc(meta_data.netdb_addrs, sizeof(netdbEntry *));
n->hosts = x->next;
safe_free(x);
}
+ safe_free(n->peers);
xfree(n);
}
xfree(L1);
xfree(L2);
hashFreeMemory(addr_table);
hashFreeMemory(host_table);
+ wordlistDestroy(&peer_names);
+ peer_names = NULL;
+ peer_names_tail = &peer_names;
#endif
}
#if USE_ICMP
netdbEntry *n;
netdbEntry **list;
- struct _net_db_name *x;
+ 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",
qsort((char *) list,
i,
sizeof(netdbEntry *),
- (QS) sortByHops);
+ (QS) sortByRtt);
for (k = 0; k < i; k++) {
n = *(list + k);
storeAppendPrintf(sentry, "{%-16.16s %4d/%4d %7.1f %5.1f", /* } */
for (x = n->hosts; x; x = x->next)
storeAppendPrintf(sentry, " %s", x->name);
storeAppendPrintf(sentry, close_bracket);
+ 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);
+ }
}
storeAppendPrintf(sentry, close_bracket);
xfree(list);
{
#if USE_ICMP
netdbEntry *n = netdbLookupHost(host);
- if (n)
+ if (n) {
+ n->last_use_time = squid_curtime;
return (int) (n->hops + 0.5);
+ }
#endif
- return 0xFFFF;
+ return 0;
}
int
{
#if USE_ICMP
netdbEntry *n = netdbLookupHost(host);
- if (n)
+ if (n) {
+ n->last_use_time = squid_curtime;
return (int) (n->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(37, 3, "netdbUpdatePeer: '%s', %d hops, %d rtt\n", r->host, ihops, irtt);
+ n = netdbLookupHost(r->host);
+ if (n == NULL) {
+ debug(37, 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),
+ (QS) sortPeerByRtt);
#endif
- return 0xFFFF;
}
/*
- * $Id: peer_select.cc,v 1.8 1997/03/29 04:45:19 wessels Exp $
+ * $Id: peer_select.cc,v 1.9 1997/04/28 04:23:21 wessels Exp $
*
* DEBUG: section 44 Peer Selection Algorithm
* AUTHOR: Duane Wessels
#include "squid.h"
+const char *hier_strings[] =
+{
+ "NONE",
+ "DIRECT",
+ "SIBLING_HIT",
+ "PARENT_HIT",
+ "DEFAULT_PARENT",
+ "SINGLE_PARENT",
+ "FIRST_UP_PARENT",
+ "NO_PARENT_DIRECT",
+ "FIRST_PARENT_MISS",
+ "CLOSEST_PARENT_MISS",
+ "CLOSEST_DIRECT",
+ "NO_DIRECT_FAIL",
+ "SOURCE_FASTEST",
+ "SIBLING_UDP_HIT_OBJ",
+ "PARENT_UDP_HIT_OBJ",
+ "PASSTHROUGH_PARENT",
+ "SSL_PARENT_MISS",
+ "ROUNDROBIN_PARENT",
+ "INVALID CODE"
+};
+
static struct {
int timeouts;
} PeerStats;
peer *p;
if (request->method == METHOD_CONNECT)
if ((p = Config.sslProxy)) {
- *code = HIER_SSL_PARENT;
+ *code = SSL_PARENT;
return p;
}
if (request->method != METHOD_GET)
if ((p = Config.passProxy)) {
- *code = HIER_PASS_PARENT;
+ *code = PASS_PARENT;
return p;
}
if ((p = getDefaultParent(request))) {
- *code = HIER_DEFAULT_PARENT;
+ *code = DEFAULT_PARENT;
return p;
}
if ((p = getSingleParent(request))) {
- *code = HIER_SINGLE_PARENT;
+ *code = SINGLE_PARENT;
return p;
}
if ((p = getRoundRobinParent(request))) {
- *code = HIER_ROUNDROBIN_PARENT;
+ *code = ROUNDROBIN_PARENT;
return p;
}
if ((p = getFirstUpParent(request))) {
- *code = HIER_FIRSTUP_PARENT;
+ *code = FIRSTUP_PARENT;
return p;
}
return NULL;
}
debug(44, 3, "peerSelect: direct = %d\n", direct);
if (direct == DIRECT_YES) {
- debug(44, 3, "peerSelect: HIER_DIRECT\n");
- hierarchyNote(request, HIER_DIRECT, &psstate->icp, request->host);
+ debug(44, 3, "peerSelect: DIRECT\n");
+ hierarchyNote(request, DIRECT, &psstate->icp, request->host);
peerSelectCallback(psstate, NULL);
return;
}
}
debug_trap("peerSelect: neighborsUdpPing returned 0");
}
- if ((p = psstate->best_parent)) {
- code = HIER_BEST_PARENT_MISS;
+ if ((p = psstate->first_parent_miss)) {
+ code = FIRST_PARENT_MISS;
debug(44, 3, "peerSelect: %s/%s\n", hier_strings[code], p->host);
hierarchyNote(request, code, &psstate->icp, p->host);
peerSelectCallback(psstate, p);
} else if (direct != DIRECT_NO) {
- code = HIER_DIRECT;
+ code = DIRECT;
debug(44, 3, "peerSelect: %s/%s\n", hier_strings[code], request->host);
hierarchyNote(request, code, &psstate->icp, request->host);
peerSelectCallback(psstate, NULL);
hierarchyNote(request, code, &psstate->icp, p->host);
peerSelectCallback(psstate, p);
} else {
- code = HIER_NO_DIRECT_FAIL;
+ code = NO_DIRECT_FAIL;
hierarchyNote(request, code, &psstate->icp, NULL);
peerSelectCallbackFail(psstate);
}
if (type == PEER_PARENT) {
w_rtt = tvSubMsec(psstate->icp.start, current_time) / p->weight;
if (psstate->icp.w_rtt == 0 || w_rtt < psstate->icp.w_rtt) {
- psstate->best_parent = p;
+ psstate->first_parent_miss = p;
psstate->icp.w_rtt = w_rtt;
}
}
} else if (op == ICP_OP_HIT || op == ICP_OP_HIT_OBJ) {
hierarchyNote(request,
- type == PEER_PARENT ? HIER_PARENT_HIT : HIER_SIBLING_HIT,
+ type == PEER_PARENT ? PARENT_HIT : SIBLING_HIT,
&psstate->icp,
p->host);
peerSelectCallback(psstate, p);
return;
} else if (op == ICP_OP_SECHO) {
hierarchyNote(request,
- HIER_SOURCE_FASTEST,
+ SOURCE_FASTEST,
&psstate->icp,
request->host);
peerSelectCallback(psstate, p);
/*
- * $Id: pinger.cc,v 1.20 1997/03/04 05:16:39 wessels Exp $
+ * $Id: pinger.cc,v 1.21 1997/04/28 04:23:22 wessels Exp $
*
* DEBUG: section 42 ICMP Pinger program
* AUTHOR: Duane Wessels
#define ip_dst daddr
#endif
-#define MAX_PAYLOAD (8192 - sizeof(struct icmphdr) - sizeof (char) - sizeof(struct timeval) - 1)
+#define MAX_PKT_SZ 8192
+#define MAX_PAYLOAD (MAX_PKT_SZ - sizeof(struct icmphdr) - sizeof (char) - sizeof(struct timeval) - 1)
typedef struct {
struct timeval tv;
static void
pingerSendEcho(struct in_addr to, int opcode, char *payload, int len)
{
- LOCAL_ARRAY(char, pkt, 8192);
+ LOCAL_ARRAY(char, pkt, MAX_PKT_SZ);
struct icmphdr *icmp = NULL;
icmpEchoData *echo;
int icmp_pktsize = sizeof(struct icmphdr);
int x;
struct sockaddr_in S;
- memset(pkt, '\0', 8192);
+ memset(pkt, '\0', MAX_PKT_SZ);
icmp = (struct icmphdr *) (void *) pkt;
icmp->icmp_type = ICMP_ECHO;
icmp->icmp_code = 0;
int iphdrlen = 20;
struct iphdr *ip = NULL;
struct icmphdr *icmp = NULL;
- LOCAL_ARRAY(char, pkt, 8192);
+ LOCAL_ARRAY(char, pkt, MAX_PKT_SZ);
struct timeval now;
icmpEchoData *echo;
static pingerReplyData preply;
fromlen = sizeof(from);
n = recvfrom(icmp_sock,
pkt,
- 8192,
+ MAX_PKT_SZ,
0,
(struct sockaddr *) &from,
&fromlen);
preply.opcode = echo->opcode;
preply.hops = ipHops(ip->ip_ttl);
preply.rtt = tvSubMsec(echo->tv, now);
- preply.psize = n - iphdrlen - (sizeof(icmpEchoData) - 8192);
+ preply.psize = n - iphdrlen - (sizeof(icmpEchoData) - MAX_PKT_SZ);
pingerSendtoSquid(&preply);
pingerLog(icmp, from.sin_addr, preply.rtt, preply.hops);
}
int guess_size;
memset(&pecho, '\0', sizeof(pecho));
n = recv(0, (char *) &pecho, sizeof(pecho), 0);
- if (n < 0) {
- perror("recv");
+ if (n < 0)
return n;
- }
- guess_size = n - (sizeof(pingerEchoData) - 8192);
+ guess_size = n - (sizeof(pingerEchoData) - MAX_PKT_SZ);
if (guess_size != pecho.psize)
fprintf(stderr, "size mismatch, guess=%d psize=%d\n",
guess_size, pecho.psize);
static void
pingerSendtoSquid(pingerReplyData * preply)
{
- int len = sizeof(pingerReplyData) - 8192 + preply->psize;
+ int len = sizeof(pingerReplyData) - MAX_PKT_SZ + preply->psize;
if (send(1, (char *) preply, len, 0) < 0) {
debug(50, 0, "pinger: send: %s\n", xstrerror());
exit(1);
if (x < 0)
return 1;
if (FD_ISSET(0, &R))
- if (pingerReadRequest() < 0)
+ if (pingerReadRequest() < 0) {
+ debug(42, 0, "Pinger exiting.\n");
return 1;
+ }
if (FD_ISSET(icmp_sock, &R))
pingerRecv();
if (10 + last_check_time < squid_curtime) {
/*
- * $Id: redirect.cc,v 1.34 1997/01/31 23:38:38 wessels Exp $
+ * $Id: redirect.cc,v 1.35 1997/04/28 04:23:24 wessels Exp $
*
* DEBUG: section 29 Redirector
* AUTHOR: Duane Wessels
}
comm_set_fd_lifetime(sfd, -1);
debug(29, 4, "redirect_create_redirector: FD %d connected to %s #%d.\n",
- sfd, command, n_redirector++);
+ sfd, command, ++n_redirector);
slp.tv_sec = 0;
slp.tv_usec = 250000;
select(0, NULL, NULL, NULL, &slp);
} else {
debug(29, 5, "redirectHandleRead: reply: '%s'\n",
redirector->inbuf);
+ /* careful here. r->data might point to something which
+ * has recently been freed. If so, we require that r->handler
+ * be NULL */
if (r->handler) {
r->handler(r->data,
t == redirector->inbuf ? NULL : redirector->inbuf);
{
redirectStateData *r = NULL;
redirector_t *redirector = NULL;
+ debug(29, 5, "redirectStart: '%s'\n", icpState->url);
if (!handler)
fatal_dump("redirectStart: NULL handler");
if (!icpState)
/*
- * $Id: squid.h,v 1.103 1997/04/02 05:22:14 wessels Exp $
+ * $Id: squid.h,v 1.104 1997/04/28 04:23:27 wessels Exp $
*
* AUTHOR: Duane Wessels
*
#include "cache_cf.h"
#include "comm.h"
#include "debug.h"
-#include "disk.h"
#include "fdstat.h"
#include "hash.h"
#include "proto.h" /* must go before neighbors.h */
#include "client_db.h"
#include "objcache.h"
#include "refresh.h"
+#include "unlinkd.h"
+#include "disk.h"
#if !HAVE_TEMPNAM
#include "tempnam.h"
extern int opt_no_ipcache; /* main.c */
extern int vhost_mode; /* main.c */
extern int Squid_MaxFD; /* main.c */
+extern int Biggest_FD; /* main.c */
+extern int select_loops; /* main.c */
extern const char *const version_string; /* main.c */
extern const char *const appname; /* main.c */
extern struct in_addr local_addr; /* main.c */
extern struct in_addr theOutICPAddr; /* main.c */
extern const char *const localhost;
-extern unsigned int inaddr_none;
extern struct in_addr no_addr; /* comm.c */
extern int opt_udp_hit_obj; /* main.c */
extern int opt_mem_pools; /* main.c */
extern int opt_accel_uses_host; /* main.c */
extern char ThisCache[]; /* main.c */
-/* Prototypes and definitions which don't really deserve a seaprate
+/* Prototypes and definitions which don't really deserve a separate
* include file */
#define CONNECT_PORT 443
/*
- * $Id: ssl.cc,v 1.43 1997/03/29 04:45:20 wessels Exp $
+ * $Id: ssl.cc,v 1.44 1997/04/28 04:23:27 wessels Exp $
*
* DEBUG: section 26 Secure Sockets Layer Proxy
* AUTHOR: Duane Wessels
time_t timeout;
int *size_ptr; /* pointer to size in an icpStateData for logging */
int proxying;
+ int ip_lookup_pending;
} SslStateData;
static const char *const conn_established = "HTTP/1.0 200 Connection established\r\n\r\n";
safe_free(sslState->client.buf);
xfree(sslState->url);
requestUnlink(sslState->request);
+ if (sslState->ip_lookup_pending)
+ ipcache_unregister(sslState->host, sslState->server.fd);
safe_free(sslState);
}
SslStateData *sslState = data;
request_t *request = sslState->request;
char *buf = NULL;
+ sslState->ip_lookup_pending = 0;
if (ia == NULL) {
debug(26, 4, "sslConnect: Unknown host: %s\n", sslState->host);
buf = squid_error_url(sslState->url,
} else {
sslState->port = CACHE_HTTP_PORT;
}
+ sslState->ip_lookup_pending = 1;
ipcache_nbgethostbyname(sslState->host,
sslState->server.fd,
sslConnect,
/*
- * $Id: stat.cc,v 1.132 1997/04/25 21:43:58 wessels Exp $
+ * $Id: stat.cc,v 1.133 1997/04/28 04:23:28 wessels Exp $
*
* DEBUG: section 18 Cache Manager Statistics
* AUTHOR: Harvest Derived
const char *const open_bracket = "{\n";
const char *const close_bracket = "}\n";
-extern char *diskFileName _PARAMS((int));
+extern int unlinkd_count;
+extern int fileno_stack_count;
/* LOCALS */
static const char *describeStatuses _PARAMS((const StoreEntry *));
int flags = (int) entry->flag;
char *t;
buf[0] = '\0';
+#ifdef OLD_CODE
if (BIT_TEST(flags, IP_LOOKUP_PENDING))
strcat(buf, "IP,");
+#endif
if (BIT_TEST(flags, DELETE_BEHIND))
strcat(buf, "DB,");
if (BIT_TEST(flags, CLIENT_ABORT_REQUEST))
char *s = NULL;
int lft;
int to;
+ FD_ENTRY *f;
storeAppendPrintf(sentry, open_bracket);
storeAppendPrintf(sentry, "{Active file descriptors:}\n");
"Description");
storeAppendPrintf(sentry, "{---- ------ ---- ---- --------------------- ------------------------------}\n");
for (i = 0; i < Squid_MaxFD; i++) {
+ f = &fd_table[i];
if (!fdstat_isopen(i))
continue;
j = fdstatGetType(i);
fdstatTypeStr[j]);
switch (j) {
case FD_SOCKET:
- if ((lft = comm_get_fd_lifetime(i)) < 0)
+ if ((lft = f->lifetime) < 0)
lft = 0;
- to = comm_get_fd_timeout(i);
+ to = f->timeout_time;
if (lft > 0)
lft = (lft - squid_curtime) / 60;
if (to > 0)
meta_data.url_strings +
meta_data.netdb_addrs * sizeof(netdbEntry) +
meta_data.netdb_hosts * sizeof(struct _net_db_name) +
+ meta_data.netdb_peers * sizeof(struct _net_db_peer) +
meta_data.client_info * client_info_sz +
meta_data.misc;
}
storeAppendPrintf(sentry, "{\tNumber of UDP connections:\t%lu}\n",
nudpconn);
+
f = (float) (squid_curtime - squid_starttime);
storeAppendPrintf(sentry, "{\tConnections per hour:\t%.1f}\n",
f == 0.0 ? 0.0 : ((ntcpconn + nudpconn) / (f / 3600.0)));
+ storeAppendPrintf(sentry, "{\tSelect loop called: %d times, %0.3f ms avg}\n",
+ select_loops, 1000.0 * f / select_loops);
storeAppendPrintf(sentry, "{Cache information for %s:}\n",
appname);
store_mem_size >> 10);
storeAppendPrintf(sentry, "{\tStorage LRU Expiration Age:\t%6.2f days}\n",
(double) storeExpiredReferenceAge() / 86400.0);
+ storeAppendPrintf(sentry, "{\tRequests given to unlinkd:\t%d}\n",
+ unlinkd_count);
+ storeAppendPrintf(sentry, "{\tUnused fileno stack count:\t%d}\n",
+ fileno_stack_count);
#if HAVE_GETRUSAGE && defined(RUSAGE_SELF)
storeAppendPrintf(sentry, "{Resource usage for %s:}\n", appname);
storeAppendPrintf(sentry, "{\tMax number of file desc available: %4d}\n",
Squid_MaxFD);
storeAppendPrintf(sentry, "{\tLargest file desc currently in use: %4d}\n",
- fdstat_biggest_fd());
+ Biggest_FD);
storeAppendPrintf(sentry, "{\tAvailable number of file descriptors: %4d}\n",
fdstat_are_n_free_fd(0));
storeAppendPrintf(sentry, "{\tReserved number of file descriptors: %4d}\n",
(int) sizeof(struct _net_db_name),
(int) (meta_data.netdb_hosts * sizeof(struct _net_db_name) >> 10));
+ storeAppendPrintf(sentry, "{\t%-25.25s %7d x %4d bytes = %6d KB}\n",
+ "NetDB Peer Entries",
+ meta_data.netdb_peers,
+ (int) sizeof(struct _net_db_peer),
+ (int) (meta_data.netdb_peers * sizeof(struct _net_db_peer) >> 10));
+
storeAppendPrintf(sentry, "{\t%-25.25s %7d x %4d bytes = %6d KB}\n",
"ClientDB Entries",
meta_data.client_info,
const char *client = NULL;
hier_code hier_code = HIER_NONE;
const char *hier_host = dash_str;
+ int hier_timeout = 0;
+#ifdef LOG_ICP_NUMBERS
int ns = 0;
int ne = 0;
int nr = 0;
int tt = 0;
+#endif
if (obj->logfile_status != LOG_ENABLE)
return;
if (hierData) {
hier_code = hierData->code;
hier_host = hierData->host ? hierData->host : dash_str;
- if (hierData->icp.start.tv_sec && hierData->icp.stop.tv_sec)
- tt = tvSubMsec(hierData->icp.start, hierData->icp.stop);
- ns = hierData->icp.n_sent;
- ne = hierData->icp.n_replies_expected;
- nr = hierData->icp.n_recv;
+ hier_timeout = hierData->timeout;
+#ifdef LOG_ICP_NUMBERS
+ tt = hierData->delay;
+ ns = hierData->n_sent;
+ ne = hierData->n_expect;
+ nr = hierData->n_recv;
+#endif
}
if (Config.commonLogFormat)
sprintf(tmp, "%s %s - [%s] \"%s %s\" %s:%s %d\n",
hier_strings[hier_code],
size);
else
- sprintf(tmp, "%9d.%03d %6d %s %s/%03d %d %s %s %s %s/%s %d/%d/%d/%d %s\n",
+#ifdef LOG_ICP_NUMBERS
+ sprintf(tmp, "%9d.%03d %6d %s %s/%03d %d %s %s %s %s%s/%s/%d/%d/%d/%d %s\n",
+#else
+ sprintf(tmp, "%9d.%03d %6d %s %s/%03d %d %s %s %s %s%s/%s %s\n",
+#endif
(int) current_time.tv_sec,
(int) current_time.tv_usec / 1000,
msec,
method,
url,
ident,
+ hier_timeout ? "TIMEOUT_" : "",
hier_strings[hier_code],
hier_host,
+#ifdef LOG_ICP_NUMBERS
ns, ne, nr, tt,
+#endif
content_type);
#if LOG_FULL_HEADERS
if (Config.logMimeHdrs) {
/*
- * $Id: store.cc,v 1.221 1997/04/25 22:01:18 wessels Exp $
+ * $Id: store.cc,v 1.222 1997/04/28 04:23:30 wessels Exp $
*
* DEBUG: section 20 Storeage Manager
* AUTHOR: Harvest Derived
static HashID storeCreateHashTable _PARAMS((int (*)_PARAMS((const char *, const char *))));
static int compareLastRef _PARAMS((StoreEntry **, StoreEntry **));
static int compareSize _PARAMS((StoreEntry **, StoreEntry **));
-static int compareBucketOrder _PARAMS((struct _bucketOrder *,
- struct _bucketOrder *));
-static int storeCheckExpired _PARAMS((const StoreEntry *));
+static int compareBucketOrder _PARAMS((struct _bucketOrder *, struct _bucketOrder *));
+static int storeCheckExpired _PARAMS((const StoreEntry *, int flag));
static int storeCheckPurgeMem _PARAMS((const StoreEntry *));
static int storeClientListSearch _PARAMS((const MemObject *, int));
static int storeCopy _PARAMS((const StoreEntry *, int, int, char *, int *));
static void storeValidateComplete _PARAMS((void *data, int, int));
static void storeRebuiltFromDisk _PARAMS((struct storeRebuildState * data));
static unsigned int getKeyCounter _PARAMS((void));
+static void storePutUnusedFileno _PARAMS((int fileno));
+static int storeGetUnusedFileno _PARAMS((void));
/* Now, this table is inaccessible to outsider. They have to use a method
* to access a value in internal storage data structure. */
if (e->lock_count)
return (int) e->lock_count;
if (e->store_status == STORE_PENDING) {
+#ifdef COMPLAIN
debug_trap("storeUnlockObject: Someone unlocked STORE_PENDING object");
debug(20, 1, " --> Key '%s'\n", e->key);
+#endif
e->store_status = STORE_ABORTED;
}
+ if (storePendingNClients(e) > 0)
+ debug_trap("storeUnlockObject: unlocked entry with pending clients\n");
if (BIT_TEST(e->flag, RELEASE_REQUEST)) {
storeRelease(e);
} else if (BIT_TEST(e->flag, ABORT_MSG_PENDING)) {
file_close(fd);
if (e->swap_file_number != -1) {
storeDirMapBitReset(e->swap_file_number);
- safeunlink(storeSwapFullPath(e->swap_file_number, NULL), 0);
+ storePutUnusedFileno(e->swap_file_number);
e->swap_file_number = -1;
}
storeRelease(e);
{
swapout_ctrl_t *ctrlp;
LOCAL_ARRAY(char, swapfilename, SQUID_MAXPATHLEN);
- swapfileno = storeDirMapAllocate();
+ if ((swapfileno = storeGetUnusedFileno()) < 0)
+ swapfileno = storeDirMapAllocate();
storeSwapFullPath(swapfileno, swapfilename);
ctrlp = xmalloc(sizeof(swapout_ctrl_t));
ctrlp->swapfilename = xstrdup(swapfilename);
storeDoRebuildFromDisk(void *data)
{
struct storeRebuildState *RB = data;
+ LOCAL_ARRAY(char, swapfile, MAXPATHLEN);
LOCAL_ARRAY(char, url, MAX_URL);
StoreEntry *e = NULL;
time_t expires;
int x;
struct _rebuild_dir *d;
struct _rebuild_dir **D;
+ int used; /* is swapfile already in use? */
+ int newer; /* is the log entry newer than current entry? */
+
/* load a number of objects per invocation */
if ((d = RB->rebuild_dir) == NULL) {
storeRebuiltFromDisk(RB);
&scan3, /* last modified */
&scan4, /* size */
url); /* url */
- if (x != 6)
+ if (x < 1)
continue;
+ storeSwapFullPath(sfileno, swapfile);
+ if (x != 6) {
+ storePutUnusedFileno(sfileno);
+ continue;
+ }
if (sfileno < 0)
continue;
sfileno = storeDirProperFileno(d->dirn, sfileno);
RB->objcount--;
RB->dupcount++;
}
- /* Is the swap file number already taken? */
- if (storeDirMapBitTest(sfileno)) {
- /* Yes it is, we can't use this swapfile */
- debug(20, 2, "storeRebuildFromDisk: Line %d Active clash: file #%d\n",
- RB->linecount,
+ e = storeGet(url);
+ used = storeDirMapBitTest(sfileno);
+ /* If this URL already exists in the cache, does the swap log
+ * appear to have a newer entry? Compare 'timestamp' from the
+ * swap log to e->lastref. Note, we can't compare e->timestamp
+ * because it is the Date: header from the HTTP reply and
+ * doesn't really tell us when the object was added to the
+ * cache. */
+ newer = e ? (timestamp > e->lastref ? 1 : 0) : 0;
+ if (used && !newer) {
+ /* log entry is old, ignore it */
+ RB->clashcount++;
+ continue;
+ } else if (used && e && e->swap_file_number == sfileno) {
+ /* swapfile taken, same URL, newer, update meta */
+ e->lastref = timestamp;
+ e->timestamp = timestamp;
+ e->expires = expires;
+ e->lastmod = lastmod;
+ continue;
+ } else if (used) {
+ /* swapfile in use, not by this URL, log entry is newer */
+ /* This is sorta bad: the log entry should NOT be newer at this
+ * point. If the log is dirty, the filesize check should have
+ * caught this. If the log is clean, there should never be a
+ * newer entry. */
+ debug(20, 1, "WARNING: newer swaplog entry for fileno %08X\n",
sfileno);
- debug(20, 3, "storeRebuildFromDisk: --> '%s'\n", url);
- /* don't unlink the file! just skip this log entry */
+ /* I'm tempted to remove the swapfile here just to be safe,
+ * but there is a bad race condition in the NOVM version if
+ * the swapfile has recently been opened for writing, but
+ * not yet opened for reading. Because we can't map
+ * swapfiles back to StoreEntrys, we don't know the state
+ * of the entry using that file. */
RB->clashcount++;
continue;
+ } else if (e) {
+ /* URL already exists, this swapfile not being used */
+ /* junk old, load new */
+ storeRelease(e); /* release old entry */
+ RB->dupcount++;
+ } else {
+ /* URL doesnt exist, swapfile not in use */
+ /* load new */
+ (void) 0;
}
/* update store_swap_size */
storeDirUpdateSwapSize(sfileno, size, 1);
}
if ((n & 0xFFF) == 0)
debug(20, 2, "storeWalkThrough: %7d objects so far.\n", n);
- if (storeCheckExpired(e))
+ if (storeCheckExpired(e, 1))
count += storeRelease(e);
}
debug(20, 0, "storePurgeOld: Removed %d objects\n", count);
break;
if (storeEntryLocked(e))
continue;
- if (storeCheckExpired(e)) {
+ if (storeCheckExpired(e, 0)) {
debug(20, 2, "storeGetMemSpace: Expired: %s\n", e->url);
n_expired++;
storeRelease(e);
StoreEntry *e = NULL;
int scanned = 0;
int removed = 0;
- int expired = 0;
int locked = 0;
int locked_size = 0;
int list_count = 0;
LRU_list = xcalloc(max_list_count, sizeof(StoreEntry *));
/* remove expired objects until recover enough or no expired objects */
for (i = 0; i < store_buckets; i++) {
- int expired_in_one_bucket = 0;
link_ptr = hash_get_bucket(store_table, storeGetBucketNum());
if (link_ptr == NULL)
continue;
- /* this while loop handles one bucket of hash table */
- expired_in_one_bucket = 0;
+ /* this for loop handles one bucket of hash table */
for (; link_ptr; link_ptr = next) {
if (list_count == max_list_count)
break;
e = (StoreEntry *) link_ptr;
if (!BIT_TEST(e->flag, ENTRY_VALIDATED))
continue;
- if (storeCheckExpired(e)) {
+ if (storeCheckExpired(e, 0)) {
debug(20, 3, "storeGetSwapSpace: Expired '%s'\n", e->url);
- expired_in_one_bucket += storeRelease(e);
+ storeRelease(e);
} else if (!storeEntryLocked(e)) {
*(LRU_list + list_count) = e;
list_count++;
locked++;
locked_size += e->mem_obj->e_current_len;
}
- } /* while, end of one bucket of hash table */
- expired += expired_in_one_bucket;
- if (expired_in_one_bucket &&
- ((!fReduceSwap && (store_swap_size + kb_size <= store_swap_high)) ||
- (fReduceSwap && (store_swap_size + kb_size <= store_swap_low)))
- ) {
- fReduceSwap = 0;
- safe_free(LRU_list);
- debug(20, 2, "storeGetSwapSpace: Finished, %d objects expired.\n",
- expired);
- return 0;
- }
+ } /* for, end of one bucket of hash table */
qsort((char *) LRU_list,
list_count,
sizeof(StoreEntry *),
debug(20, 5, "storeRelease: Release anonymous object\n");
if (e->swap_status == SWAP_OK && (e->swap_file_number > -1)) {
- (void) safeunlink(storeSwapFullPath(e->swap_file_number, NULL), 1);
+ storePutUnusedFileno(e->swap_file_number);
storeDirUpdateSwapSize(e->swap_file_number, e->object_len, -1);
storeDirMapBitReset(e->swap_file_number);
e->swap_file_number = -1;
return 0;
}
-/* use this for internal call only */
static int
storeCopy(const StoreEntry * e, int stateoffset, int maxSize, char *buf, int *size)
{
- int available_to_write = 0;
-
- available_to_write = e->mem_obj->e_current_len - stateoffset;
-
- if (stateoffset < e->mem_obj->e_lowest_offset) {
- /* this should not happen. Logic race !!! */
- debug(20, 1, "storeCopy: Client Request a chunk of data in area lower than the lowest_offset\n");
- debug(20, 1, " Current Lowest offset : %d\n", e->mem_obj->e_lowest_offset);
- debug(20, 1, " Requested offset : %d\n", stateoffset);
- /* can't really do anything here. Client may hang until lifetime runout. */
- return 0;
+ int available;
+ MemObject *mem = e->mem_obj;
+ int s;
+ if (stateoffset < mem->e_lowest_offset) {
+ debug_trap("storeCopy: requested offset < e_lowest_offset");
+ return *size = 0;
}
- *size = (available_to_write >= maxSize) ?
- maxSize : available_to_write;
-
- debug(20, 6, "storeCopy: avail_to_write=%d, store_offset=%d\n",
- *size, stateoffset);
-
- if (*size > 0)
- if (e->mem_obj->data->mem_copy(e->mem_obj->data, stateoffset, buf, *size) < 0)
- return -1;
-
- return *size;
+ s = available = mem->e_current_len - stateoffset;
+ if (s < 0)
+ fatal_dump("storeCopy: offset > e_current_len");
+ if (s > maxSize)
+ s = maxSize;
+ debug(20, 6, "storeCopy: copying %d bytes at offset %d\n", s, stateoffset);
+ if (s > 0)
+ (void) mem->data->mem_copy(mem->data, stateoffset, buf, s);
+ return *size = s;
}
/* check if there is any client waiting for this object at all */
mem->clients[i].fd = -1;
}
for (i = 0; i < mem->nclients; i++) {
+ if (mem->clients[i].fd == fd)
+ return i; /* its already here */
if (mem->clients[i].fd == -1)
break;
}
scan_obj++;
next = link_ptr->next;
e = (StoreEntry *) link_ptr;
- if (!storeCheckExpired(e))
+ if (!storeCheckExpired(e, 1))
continue;
rm_obj += storeRelease(e);
}
}
static int
-storeCheckExpired(const StoreEntry * e)
+storeCheckExpired(const StoreEntry * e, int check_lru_age)
{
- time_t max_age = storeExpiredReferenceAge();
+ time_t max_age;
if (storeEntryLocked(e))
return 0;
if (BIT_TEST(e->flag, ENTRY_NEGCACHED) && squid_curtime >= e->expires)
return 1;
- if (max_age <= 0)
+ if (!check_lru_age)
+ return 0;
+ if ((max_age = storeExpiredReferenceAge()) <= 0)
return 0;
if (squid_curtime - e->lastref > max_age)
return 1;
/*
* storeExpiredReferenceAge
*
- * The LRU age is scaled exponentially between 1 minute and 1 year, when
- * store_swap_low < store_swap_size < store_swap_high. This keeps
- * store_swap_size within the low and high water marks. If the cache is
- * very busy then store_swap_size stays closer to the low water mark, if
- * it is not busy, then it will stay near the high water mark. The LRU
- * age value can be examined on the cachemgr 'info' page.
+ * The LRU age is scaled exponentially between 1 minute and
+ * Config.referenceAge , when store_swap_low < store_swap_size <
+ * store_swap_high. This keeps store_swap_size within the low and high
+ * water marks. If the cache is very busy then store_swap_size stays
+ * closer to the low water mark, if it is not busy, then it will stay
+ * near the high water mark. The LRU age value can be examined on the
+ * cachemgr 'info' page.
*/
time_t
storeExpiredReferenceAge(void)
double x;
double z;
time_t age;
- if (Config.referenceAge != 0)
- return Config.referenceAge;
- x = 2.0 * (store_swap_high - store_swap_size) / (store_swap_high - store_swap_low);
- x = x < 0.0 ? 0.0 : x > 2.0 ? 2.0 : x;
- z = pow(724.0, x); /* minutes [1:525600] */
+ if (Config.referenceAge == 0)
+ return 0;
+ x = (double) (store_swap_high - store_swap_size) / (store_swap_high - store_swap_low);
+ x = x < 0.0 ? 0.0 : x > 1.0 ? 1.0 : x;
+ z = pow((double) Config.referenceAge, x);
age = (time_t) (z * 60.0);
if (age < 60)
age = 60;
entry->lastmod = served_date;
entry->timestamp = served_date;
}
+
+#define FILENO_STACK_SIZE 128
+static int fileno_stack[FILENO_STACK_SIZE];
+int fileno_stack_count = 0;
+
+static int
+storeGetUnusedFileno(void)
+{
+ if (fileno_stack_count < 1)
+ return -1;
+ return fileno_stack[--fileno_stack_count];
+}
+
+static void
+storePutUnusedFileno(int fileno)
+{
+ if (fileno_stack_count < FILENO_STACK_SIZE)
+ fileno_stack[fileno_stack_count++] = fileno;
+ else
+ unlinkdUnlink(storeSwapFullPath(fileno, NULL));
+}
/*
- * $Id: tools.cc,v 1.98 1997/04/25 06:38:25 wessels Exp $
+ * $Id: tools.cc,v 1.99 1997/04/28 04:23:32 wessels Exp $
*
* DEBUG: section 21 Misc Functions
* AUTHOR: Harvest Derived
int gethostname _PARAMS((char *, int));
#endif
+static void
+releaseServerSockets(void)
+{
+ /* Release the main ports as early as possible */
+ if (theHttpConnection >= 0)
+ (void) close(theHttpConnection);
+ if (theInIcpConnection >= 0)
+ (void) close(theInIcpConnection);
+ if (theOutIcpConnection >= 0 && theOutIcpConnection != theInIcpConnection)
+ (void) close(theOutIcpConnection);
+}
+
static char *
dead_msg(void)
{
signal(SIGBUS, SIG_DFL);
signal(sig, SIG_DFL);
#endif
- /* Release the main ports as early as possible */
- if (theHttpConnection >= 0)
- (void) close(theHttpConnection);
- if (theInIcpConnection >= 0)
- (void) close(theInIcpConnection);
+ releaseServerSockets();
storeWriteCleanLogs();
PrintRusage(NULL, debug_log);
if (squid_curtime - SQUID_RELEASE_TIME < 864000) {
setSocketShutdownLifetimes(int lft)
{
FD_ENTRY *f = NULL;
- int cur;
int i;
- for (i = fdstat_biggest_fd(); i >= 0; i--) {
+ for (i = Biggest_FD; i >= 0; i--) {
f = &fd_table[i];
if (!f->read_handler && !f->write_handler)
continue;
if (fdstatGetType(i) != FD_SOCKET)
continue;
- cur = comm_get_fd_lifetime(i);
- if (cur > 0 && (cur - squid_curtime) <= lft)
+ if (f->lifetime > 0 && (f->lifetime - squid_curtime) <= lft)
continue;
comm_set_fd_lifetime(i, lft);
}
safeunlink(Config.pidFilename, 0);
leave_suid();
}
+ releaseServerSockets();
+ unlinkdClose();
storeWriteCleanLogs();
PrintRusage(NULL, debug_log);
storeCloseLog();
void
fatal(const char *message)
{
+ releaseServerSockets();
/* check for store_rebuilding flag because fatal() is often
* used in early initialization phases, long before we ever
* get to the store log. */
void
fatal_dump(const char *message)
{
+ releaseServerSockets();
if (message)
fatal_common(message);
if (opt_catch_signals)
if ((pwd = getpwnam(Config.effectiveUser)) == NULL)
return;
if (Config.effectiveGroup && (grp = getgrnam(Config.effectiveGroup))) {
- setgid(grp->gr_gid);
+ if (setgid(grp->gr_gid) < 0)
+ debug(50, 1, "leave_suid: setgid: %s\n", xstrerror());
} else {
- setgid(pwd->pw_gid);
+ if (setgid(pwd->pw_gid) < 0)
+ debug(50, 1, "leave_suid: setgid: %s\n", xstrerror());
}
debug(21, 3, "leave_suid: PID %d giving up root, becoming '%s'\n",
getpid(), pwd->pw_name);
#if HAVE_SETRESUID
- setresuid(pwd->pw_uid, pwd->pw_uid, 0);
+ if (setresuid(pwd->pw_uid, pwd->pw_uid, 0) < 0)
+ debug(50, 1, "leave_suid: setresuid: %s\n", xstrerror());
#elif HAVE_SETEUID
- seteuid(pwd->pw_uid);
+ if (seteuid(pwd->pw_uid) < 0)
+ debug(50, 1, "leave_suid: seteuid: %s\n", xstrerror());
#else
- setuid(pwd->pw_uid);
+ if (setuid(pwd->pw_uid) < 0)
+ debug(50, 1, "leave_suid: setuid: %s\n", xstrerror());
#endif
}
uid = geteuid();
debug(21, 3, "leave_suid: PID %d giving up root priveleges forever\n", getpid());
#if HAVE_SETRESUID
- setresuid(uid, uid, uid);
+ if (setresuid(uid, uid, uid) < 0)
+ debug(50, 1, "no_suid: setresuid: %s\n", xstrerror());
#else
setuid(0);
- setuid(uid);
+ if (setuid(uid) < 0)
+ debug(50, 1, "no_suid: setuid: %s\n", xstrerror());
#endif
}
/*
- * $Id: tunnel.cc,v 1.43 1997/03/29 04:45:20 wessels Exp $
+ * $Id: tunnel.cc,v 1.44 1997/04/28 04:23:27 wessels Exp $
*
* DEBUG: section 26 Secure Sockets Layer Proxy
* AUTHOR: Duane Wessels
time_t timeout;
int *size_ptr; /* pointer to size in an icpStateData for logging */
int proxying;
+ int ip_lookup_pending;
} SslStateData;
static const char *const conn_established = "HTTP/1.0 200 Connection established\r\n\r\n";
safe_free(sslState->client.buf);
xfree(sslState->url);
requestUnlink(sslState->request);
+ if (sslState->ip_lookup_pending)
+ ipcache_unregister(sslState->host, sslState->server.fd);
safe_free(sslState);
}
SslStateData *sslState = data;
request_t *request = sslState->request;
char *buf = NULL;
+ sslState->ip_lookup_pending = 0;
if (ia == NULL) {
debug(26, 4, "sslConnect: Unknown host: %s\n", sslState->host);
buf = squid_error_url(sslState->url,
} else {
sslState->port = CACHE_HTTP_PORT;
}
+ sslState->ip_lookup_pending = 1;
ipcache_nbgethostbyname(sslState->host,
sslState->server.fd,
sslConnect,
--- /dev/null
+/*
+ * $Id: unlinkd.cc,v 1.2 1997/04/28 04:23:32 wessels Exp $
+ *
+ * DEBUG: section 43 Unlink Daemon
+ * AUTHOR: Duane Wessels
+ *
+ * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ * Squid is the result of efforts by numerous individuals from the
+ * Internet community. Development is led by Duane Wessels of the
+ * National Laboratory for Applied Network Research and funded by
+ * the National Science Foundation.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+static char hello_string[] = "hi there\n";
+
+#ifdef UNLINK_DAEMON
+
+/* This is the external unlinkd process */
+
+#include "config.h"
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#if HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#define UNLINK_BUF_LEN 1024
+
+int
+main(int argc, char *argv[])
+{
+ char buf[UNLINK_BUF_LEN];
+ char *t;
+ setbuf(stdin, NULL);
+ write(1, hello_string, sizeof(hello_string));
+ while (fgets(buf, UNLINK_BUF_LEN, stdin)) {
+ if ((t = strchr(buf, '\n')))
+ *t = '\0';
+ unlink(buf);
+ }
+ exit(0);
+}
+
+#else /* UNLINK_DAEMON */
+
+/* This code gets linked to Squid */
+
+#include "squid.h"
+
+static int unlinkd_fd = -1;
+int unlinkd_count;
+
+static int unlinkdCreate _PARAMS((void));
+
+#define HELLO_BUFSIZ 128
+static int
+unlinkdCreate(void)
+{
+ pid_t pid;
+ int rfd1, rfd2, wfd1, wfd2;
+ int squid_to_unlinkd[2] =
+ {-1, -1};
+ int unlinkd_to_squid[2] =
+ {-1, -1};
+ int n;
+ char buf[HELLO_BUFSIZ];
+ struct timeval slp;
+ if (pipe(squid_to_unlinkd) < 0) {
+ debug(50, 0, "unlinkdCreate: pipe: %s\n", xstrerror());
+ return -1;
+ }
+ if (pipe(unlinkd_to_squid) < 0) {
+ debug(50, 0, "unlinkdCreate: pipe: %s\n", xstrerror());
+ return -1;
+ }
+ rfd1 = squid_to_unlinkd[0];
+ wfd1 = squid_to_unlinkd[1];
+ rfd2 = unlinkd_to_squid[0];
+ wfd2 = unlinkd_to_squid[1];
+ if ((pid = fork()) < 0) {
+ debug(50, 0, "unlinkdCreate: fork: %s\n", xstrerror());
+ close(rfd1);
+ close(wfd1);
+ close(rfd2);
+ close(wfd2);
+ return -1;
+ }
+ if (pid > 0) { /* parent process */
+ close(rfd1);
+ close(wfd2);
+ memset(buf, '\0', HELLO_BUFSIZ);
+ n = read(rfd2, buf, HELLO_BUFSIZ - 1);
+ close(rfd2);
+ if (n <= 0) {
+ debug(50, 0, "unlinkdCreate: handshake failed\n");
+ close(wfd1);
+ return -1;
+ } else if (strcmp(buf, hello_string)) {
+ debug(50, 0, "unlinkdCreate: handshake failed\n");
+ debug(50, 0, "--> got '%s'\n", rfc1738_escape(buf));
+ close(wfd1);
+ return -1;
+ }
+ comm_set_fd_lifetime(wfd1, -1);
+ slp.tv_sec = 0;
+ slp.tv_usec = 250000;
+ select(0, NULL, NULL, NULL, &slp);
+ file_open_fd(wfd1, "unlinkd socket", FD_PIPE);
+ commSetNonBlocking(wfd1);
+ return wfd1;
+ }
+ /* child */
+ no_suid(); /* give up extra priviliges */
+ close(wfd1);
+ close(rfd2);
+ dup2(rfd1, 0);
+ dup2(wfd2, 1);
+ close(rfd1); /* close FD since we dup'd it */
+ close(wfd2); /* close parent's FD */
+ commSetCloseOnExec(fileno(debug_log));
+ execlp(Config.Program.unlinkd, "(unlinkd)", NULL);
+ debug(50, 0, "unlinkdCreate: %s: %s\n",
+ Config.Program.unlinkd, xstrerror());
+ _exit(1);
+ return 0;
+}
+
+void
+unlinkdUnlink(const char *path)
+{
+ char *buf;
+ int l;
+ if (unlinkd_fd < 0) {
+ debug_trap("unlinkdUnlink: unlinkd_fd < 0");
+ safeunlink(path, 0);
+ return;
+ }
+ l = strlen(path) + 1;
+ buf = xcalloc(1, l + 1);
+ strcpy(buf, path);
+ strcat(buf, "\n");
+ file_write(unlinkd_fd,
+ buf,
+ l,
+ NULL, /* Handler */
+ NULL, /* Handler-data */
+ xfree);
+ unlinkd_count++;
+}
+
+void
+unlinkdClose(void)
+{
+ if (unlinkd_fd < 0) {
+ debug_trap("unlinkdClose: unlinkd_fd < 0");
+ return;
+ }
+ file_close(unlinkd_fd);
+ unlinkd_fd = -1;
+}
+
+void
+unlinkdInit(void)
+{
+ unlinkd_count = 0;
+ unlinkd_fd = unlinkdCreate();
+ if (unlinkd_fd < 0)
+ fatal("unlinkdInit: failed to start unlinkd\n");
+ fd_note(unlinkd_fd, Config.Program.unlinkd);
+ debug(43, 0, "Unlinkd pipe opened on FD %d\n", unlinkd_fd);
+}
+
+#endif /* ndef UNLINK_DAEMON */
/*
- * $Id: url.cc,v 1.54 1997/02/19 17:05:24 wessels Exp $
+ * $Id: url.cc,v 1.55 1997/04/28 04:23:34 wessels Exp $
*
* DEBUG: section 23 URL Parsing
* AUTHOR: Duane Wessels
return PROTO_WAIS;
if (strncasecmp(s, "cache_object", 12) == 0)
return PROTO_CACHEOBJ;
- if (strncasecmp(s, "file", 4) == 0)
- return PROTO_FTP;
return PROTO_NONE;
}
debug(23, 0, "urlParse: Invalid port == 0\n");
return NULL;
}
+#ifdef HARDCODE_DENY_PORTS
+ /* These ports are filtered in the default squid.conf, but
+ * maybe someone wants them hardcoded... */
+ if (port == 7 || port == 9 || port = 19) {
+ debug(23, 0, "urlParse: Deny access to port %d\n", port);
+ return NULL;
+ }
+#endif
#ifdef REMOVE_FTP_TRAILING_SLASHES
/* remove trailing slashes from FTP URLs */
if (protocol == PROTO_FTP) {
/*
- * $Id: wais.cc,v 1.62 1997/03/04 05:16:45 wessels Exp $
+ * $Id: wais.cc,v 1.63 1997/04/28 04:23:34 wessels Exp $
*
* DEBUG: section 24 WAIS Relay
* AUTHOR: Harvest Derived
int relayport;
char *mime_hdr;
char request[MAX_URL];
+ int ip_lookup_pending;
} WaisStateData;
static int waisStateFree _PARAMS((int, WaisStateData *));
if (waisState == NULL)
return 1;
storeUnlockObject(waisState->entry);
+ if (waisState->ip_lookup_pending)
+ ipcache_unregister(waisState->relayhost, waisState->fd);
xfree(waisState);
return 0;
}
comm_add_close_handler(waisState->fd,
(PF) waisStateFree,
(void *) waisState);
+ waisState->ip_lookup_pending = 1;
ipcache_nbgethostbyname(waisState->relayhost,
waisState->fd,
waisConnect,
waisConnect(int fd, const ipcache_addrs * ia, void *data)
{
WaisStateData *waisState = data;
+ waisState->ip_lookup_pending = 0;
if (!ipcache_gethostbyname(waisState->relayhost, 0)) {
debug(24, 4, "waisstart: Unknown host: %s\n", waisState->relayhost);
squid_error_entry(waisState->entry, ERR_DNS_FAIL, dns_error_message);