Don't crash when network of listener goes away (#168).
authorJelmer Vernooij <jelmer@samba.org>
Wed, 21 Nov 2007 21:16:05 +0000 (22:16 +0100)
committerJelmer Vernooij <jelmer@samba.org>
Wed, 21 Nov 2007 21:16:05 +0000 (22:16 +0100)
NEWS
lib/client.c
lib/network.c
lib/network.h
src/ctrlproxy.h
src/listener.c

diff --git a/NEWS b/NEWS
index 1b5fcd755edace1df5992f344011d48f4c02a0cc..20ba08c3f115cfeeeaa3b97a128af5a142729717 100644 (file)
--- 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.
index 78722a68c6fac22445d7c35fa109fc33cee1b055..faca248597a5bfc2d79f2dad99339065b2ac607c 100644 (file)
@@ -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;
index b17940e179bd8b05954a67fb268b03f8f6143fa8..6242dca95b6e51dd628919ab5babaadbbbbf5c70 100644 (file)
@@ -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);
+}
 
index c7072e8bc1632aa62bbdfb0825d6c615a64a5b78..bf32f6b462dbbdb2cefe8e6a0a09992eb3b16b6c 100644 (file)
@@ -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__ */
index 07bdf02ba8162e247c415e42d2c09da2533ae949..ed501ff09558cb1f655ec3b6ec57f73ed1bcc08a 100644 (file)
@@ -27,7 +27,7 @@
 #include <glib.h>
 #include <gmodule.h>
 
-#define CTRLPROXY_PLUGIN_VERSION 1
+#define CTRLPROXY_PLUGIN_VERSION 2
 
 /**
  * @file
index 14638075ed37a5f4d81c55516f2278d3c3c37cf9..239289aab572c8b75d97a2e0af042056428bcd08 100644 (file)
@@ -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);
+
        }
 }