From: Jelmer Vernooij Date: Wed, 21 Nov 2007 21:16:05 +0000 (+0100) Subject: Don't crash when network of listener goes away (#168). X-Git-Url: http://git.samba.org/samba.git/?p=jelmer%2Fctrlproxy.git;a=commitdiff_plain;h=ec04a99e21921b2150582691ec611749888b475e Don't crash when network of listener goes away (#168). --- diff --git a/NEWS b/NEWS index 1b5fcd7..20ba08c 100644 --- a/NEWS +++ b/NEWS @@ -16,6 +16,8 @@ Ctrlproxy 3.0.4 UNRELEASED BUG FIXES + * Don't crash when network of listener goes away. (#168) + * Don't abort when sending colon to listener. (#167) * Handle 263 response correctly. diff --git a/lib/client.c b/lib/client.c index 78722a6..faca248 100644 --- a/lib/client.c +++ b/lib/client.c @@ -263,6 +263,8 @@ void disconnect_client(struct client *c, const char *reason) if (c->network != NULL) c->network->clients = g_list_remove(c->network->clients, c); + network_unref(c->network); + pending_clients = g_list_remove(pending_clients, c); lose_client_hook_execute(c); @@ -658,7 +660,7 @@ struct client *client_init(struct network *n, GIOChannel *c, const char *desc) client->ping_id = g_timeout_add(1000 * 300, (GSourceFunc)client_ping, client); client->incoming = c; - client->network = n; + client->network = network_ref(n); client->description = g_strdup(desc); client->connected = TRUE; client->exit_on_close = FALSE; diff --git a/lib/network.c b/lib/network.c index b17940e..6242dca 100644 --- a/lib/network.c +++ b/lib/network.c @@ -1121,6 +1121,7 @@ struct network *load_network(struct global *global, struct network_config *sc) } s = g_new0(struct network, 1); + s->references = 1; s->config = sc; network_info_init(&s->info); s->info.name = g_strdup(s->config->name); @@ -1172,6 +1173,23 @@ static void free_pending_line(void *_line, void *userdata) free_line((struct line *)_line); } +static void free_network(struct network *s) +{ + g_queue_foreach(s->connection.pending_lines, free_pending_line, NULL); + g_queue_free(s->connection.pending_lines); + + free_network_info(&s->info); + +#ifdef HAVE_GNUTLS + ssl_free_client_credentials(s->ssl_credentials); +#endif + + g_iconv_close(s->connection.incoming_iconv); + g_iconv_close(s->connection.outgoing_iconv); + + g_free(s); +} + /** * Unload a network from a global context. * @@ -1182,10 +1200,6 @@ void unload_network(struct network *s) GList *l; g_assert(s); - if (s->connection.state == NETWORK_CONNECTION_STATE_MOTD_RECVD) { - log_network(LOG_INFO, s, "Closing connection"); - } - l = s->clients; while(l) { @@ -1198,19 +1212,7 @@ void unload_network(struct network *s) s->global->networks = g_list_remove(s->global->networks, s); } - g_queue_foreach(s->connection.pending_lines, free_pending_line, NULL); - g_queue_free(s->connection.pending_lines); - - free_network_info(&s->info); - -#ifdef HAVE_GNUTLS - ssl_free_client_credentials(s->ssl_credentials); -#endif - - g_iconv_close(s->connection.incoming_iconv); - g_iconv_close(s->connection.outgoing_iconv); - - g_free(s); + network_unref(s); } /** @@ -1447,4 +1449,22 @@ char *network_generate_feature_string(struct network *n) return network_info_string(&n->info); } +/** + * Increase the reference count for a network + */ +struct network *network_ref(struct network *n) +{ + if (n != NULL) + n->references++; + return n; +} + +void network_unref(struct network *n) +{ + if (n == NULL) + return; + n->references--; + if (n->references == 0) + free_network(n); +} diff --git a/lib/network.h b/lib/network.h index c7072e8..bf32f6b 100644 --- a/lib/network.h +++ b/lib/network.h @@ -93,6 +93,8 @@ struct network { struct global *global; struct network_config *config; + int references; + GList *clients; guint reconnect_id; @@ -127,5 +129,7 @@ typedef void (*new_network_notify_fn) (struct network *, void *); G_MODULE_EXPORT void register_new_network_notify(struct global *, new_network_notify_fn, void *userdata); G_MODULE_EXPORT G_GNUC_MALLOC struct linestack_context *new_linestack(struct network *network); G_MODULE_EXPORT G_GNUC_MALLOC char *network_generate_feature_string(struct network *n); +G_MODULE_EXPORT struct network *network_ref(struct network *); +G_MODULE_EXPORT void network_unref(struct network *); #endif /* __CTRLPROXY_NETWORK_H__ */ diff --git a/src/ctrlproxy.h b/src/ctrlproxy.h index 07bdf02..ed501ff 100644 --- a/src/ctrlproxy.h +++ b/src/ctrlproxy.h @@ -27,7 +27,7 @@ #include #include -#define CTRLPROXY_PLUGIN_VERSION 1 +#define CTRLPROXY_PLUGIN_VERSION 2 /** * @file diff --git a/src/listener.c b/src/listener.c index 1463807..239289a 100644 --- a/src/listener.c +++ b/src/listener.c @@ -436,6 +436,9 @@ void free_listeners(struct global *global) void free_listener(struct listener *l) { l->global->listeners = g_list_remove(l->global->listeners, l); + + network_unref(l->network); + g_free(l); } @@ -447,7 +450,7 @@ struct listener *listener_init(struct global *global, struct listener_config *cf l->global = global; if (l->config->network != NULL) { - l->network = find_network(global, l->config->network); + l->network = network_ref(find_network(global, l->config->network)); if (l->network == NULL) { free_listener(l); return NULL; @@ -465,7 +468,6 @@ static void auto_add_listener(struct network *n, void *private_data) struct listener *l; struct listener_config *cfg; - /* See if there is already a listener for n */ for (gl = n->global->listeners; gl; gl = gl->next) { l = gl->data; @@ -506,6 +508,7 @@ void fini_listeners(struct global *global) if (l->active) stop_listener(l); + } }