From: Mark Wooding Date: Mon, 22 Dec 2014 20:32:58 +0000 (+0000) Subject: yaid.c: Delay destruction of selbuf objects. X-Git-Tag: 1.0.3~3 X-Git-Url: https://git.distorted.org.uk/~mdw/yaid/commitdiff_plain/cbdfc91ee3dba8f1512ea4387643f51b5f63e404 yaid.c: Delay destruction of selbuf objects. It's not safe to destroy them from inside the per-line callback function, so make chains of defunct objects and arrange to destroy them properly in the main loop. --- diff --git a/yaid.c b/yaid.c index cc3bb47..da015e1 100644 --- a/yaid.c +++ b/yaid.c @@ -61,6 +61,7 @@ struct client { 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. */ @@ -71,6 +72,7 @@ struct proxy { 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 --------------------------------------------------*/ @@ -88,6 +90,9 @@ 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 */ #define F_RUNNING 2u /* Running properly now */ @@ -362,12 +367,28 @@ static void cancel_proxy(struct proxy *px) conn_kill(&px->cn); else { close(px->fd); - selbuf_destroy(&px->b); - free_writebuf(&px->wb); + selbuf_disable(&px->b); } px->c->px = 0; selbuf_enable(&px->c->b); - xfree(px); + 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 @@ -543,12 +564,27 @@ err_0: /* 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. */ @@ -1108,6 +1144,8 @@ int main(int argc, char *argv[]) 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. */