struct listen *l; /* Back to the listener (and ops) */
struct writebuf wb; /* Write buffer for our reply */
struct proxy *px; /* Proxy if conn goes via NAT */
+ struct client *next; /* Next in a chain of clients */
};
/* A proxy connection. */
selbuf b; /* Accumulate the response line */
struct writebuf wb; /* Write buffer for query */
char nat[ADDRLEN]; /* Server address, as text */
+ struct proxy *next; /* Next in a chain of proxies */
};
/*----- Static variables --------------------------------------------------*/
static unsigned char tokenbuf[4096]; /* Random-ish data for tokens */
static size_t tokenptr = sizeof(tokenbuf); /* Current read position */
-static int randfd; /* File descriptor for random data */
+
+static struct client *dead_clients = 0; /* List of defunct clients */
+static struct proxy *dead_proxies = 0; /* List of defunct proxies */
static unsigned flags = 0; /* Various interesting flags */
#define F_SYSLOG 1u /* Use syslog for logging */
/*----- General utilities -------------------------------------------------*/
-/* Format and log MSG somewhere sensible, at the syslog(3) priority PRIO.
- * Prefix it with a description of the query Q, if non-null.
- */
-void logmsg(const struct query *q, int prio, const char *msg, ...)
+static void vlogmsg(const struct query *q, int prio,
+ const char *msg, va_list *ap)
{
- va_list ap;
dstr d = DSTR_INIT;
time_t t;
struct tm *tm;
char buf[64];
- va_start(ap, msg);
if (q) {
dputsock(&d, q->ao, &q->s[L]);
dstr_puts(&d, " <-> ");
dputsock(&d, q->ao, &q->s[R]);
dstr_puts(&d, ": ");
}
- dstr_vputf(&d, msg, &ap);
- va_end(ap);
+ dstr_vputf(&d, msg, ap);
if (!(flags & F_RUNNING))
moan("%s", d.buf);
dstr_destroy(&d);
}
+/* Format and log MSG somewhere sensible, at the syslog(3) priority PRIO.
+ * Prefix it with a description of the query Q, if non-null.
+ */
+void logmsg(const struct query *q, int prio, const char *msg, ...)
+{
+ va_list ap;
+
+ va_start(ap, msg);
+ vlogmsg(q, prio, msg, &ap);
+ va_end(ap);
+}
+
+/* Format and report MSG as a fatal error, and exit. */
+void fatal(const char *msg, ...)
+{
+ va_list ap;
+
+ va_start(ap, msg);
+ vlogmsg(0, LOG_CRIT, msg, &ap);
+ va_end(ap);
+ exit(1);
+}
+
/* Fix up a socket FD so that it won't bite us. Returns zero on success, or
* nonzero on error.
*/
conn_kill(&px->cn);
else {
close(px->fd);
- selbuf_destroy(&px->b);
- free_writebuf(&px->wb);
+ selbuf_disable(&px->b);
}
- selbuf_enable(&px->c->b);
px->c->px = 0;
- xfree(px);
+ selbuf_enable(&px->c->b);
+ px->next = dead_proxies;
+ dead_proxies = px;
+}
+
+/* Delayed destruction of unsafe parts of proxies. */
+static void reap_dead_proxies(void)
+{
+ struct proxy *px, *pp;
+
+ for (px = dead_proxies; px; px = pp) {
+ pp = px->next;
+ if (px->fd != -1) {
+ selbuf_destroy(&px->b);
+ free_writebuf(&px->wb);
+ }
+ xfree(px);
+ }
+ dead_proxies = 0;
}
/* Notification that a line (presumably a reply) has been received from the
/* Disconnect a client, freeing up any associated resources. */
static void disconnect_client(struct client *c)
{
+ selbuf_disable(&c->b);
close(c->fd);
- selbuf_destroy(&c->b);
sel_rmtimer(&c->t);
free_writebuf(&c->wb);
if (c->px) cancel_proxy(c->px);
- xfree(c);
+ c->next = dead_clients;
+ dead_clients = c;
+}
+
+/* Throw away dead clients now that we've reached a safe point in the
+ * program.
+ */
+static void reap_dead_clients(void)
+{
+ struct client *c, *cc;
+ for (c = dead_clients; c; c = cc) {
+ cc = c->next;
+ selbuf_destroy(&c->b);
+ xfree(c);
+ }
+ dead_clients = 0;
}
/* Time out a client because it's been idle for too long. */
* from the kernel.
*/
if (tokenptr + TOKENRANDSZ >= sizeof(tokenbuf)) {
- if (read(randfd, tokenbuf, sizeof(tokenbuf)) < sizeof(tokenbuf))
- die(1, "unexpected short read or error from `/dev/urandom'");
+ fill_random(tokenbuf, sizeof(tokenbuf));
tokenptr = 0;
}
struct listen *l = p;
struct client *c;
struct sockaddr_storage ssr, ssl;
- size_t ssz = sizeof(ssr);
+ socklen_t ssz = sizeof(ssr);
int sk;
/* Accept the new connection. */
if (load_policy_file(policyfile, &policy))
exit(1);
- /* Open the random data source. */
- if ((randfd = open("/dev/urandom", O_RDONLY)) < 0) {
- die(1, "failed to open `/dev/urandom' for reading: %s",
- strerror(errno));
- }
-
/* Set up the I/O event system. */
sel_init(&sel);
for (;;) {
if (sel_select(&sel) && errno != EINTR)
die(1, "select failed: %s", strerror(errno));
+ reap_dead_proxies();
+ reap_dead_clients();
}
/* This just keeps the compiler happy. */