diff --git a/src/core/chat-commands.c b/src/core/chat-commands.c index 6ddd2f1a..bdd64e4f 100644 --- a/src/core/chat-commands.c +++ b/src/core/chat-commands.c @@ -73,7 +73,7 @@ static SERVER_CONNECT_REC *get_server_connect(const char *data, int *plus_addr) if (proto->not_initialized) { /* trying to use protocol that isn't yet initialized */ signal_emit("chat protocol unknown", 1, proto->name); - server_connect_free(conn); + server_connect_unref(conn); cmd_params_free(free_arg); return NULL; } @@ -102,8 +102,10 @@ static void cmd_connect(const char *data) SERVER_CONNECT_REC *conn; conn = get_server_connect(data, NULL); - if (conn != NULL) + if (conn != NULL) { CHAT_PROTOCOL(conn)->server_connect(conn); + server_connect_unref(conn); + } } static RECONNECT_REC *find_reconnect_server(int chat_type, @@ -147,6 +149,7 @@ static void update_reconnection(SERVER_CONNECT_REC *conn, SERVER_REC *server) if (server != NULL) { oldconn = server->connrec; + server_connect_ref(oldconn); reconnect_save_status(conn, server); } else { /* maybe we can reconnect some server from @@ -156,7 +159,8 @@ static void update_reconnection(SERVER_CONNECT_REC *conn, SERVER_REC *server) if (recon == NULL) return; oldconn = recon->conn; - server_reconnect_destroy(recon, FALSE); + server_connect_ref(oldconn); + server_reconnect_destroy(recon); conn->away_reason = g_strdup(oldconn->away_reason); conn->channels = g_strdup(oldconn->channels); @@ -167,11 +171,10 @@ static void update_reconnection(SERVER_CONNECT_REC *conn, SERVER_REC *server) if (conn->chatnet == NULL && oldconn->chatnet != NULL) conn->chatnet = g_strdup(oldconn->chatnet); + server_connect_unref(oldconn); if (server != NULL) { signal_emit("command disconnect", 2, "* Changing server", server); - } else { - server_connect_free(oldconn); } } @@ -201,6 +204,7 @@ static void cmd_server_connect(const char *data, SERVER_REC *server) if (!plus_addr) update_reconnection(conn, server); CHAT_PROTOCOL(conn)->server_connect(conn); + server_connect_unref(conn); } } diff --git a/src/core/chat-protocols.h b/src/core/chat-protocols.h index 74e34151..eeb0075f 100644 --- a/src/core/chat-protocols.h +++ b/src/core/chat-protocols.h @@ -15,6 +15,7 @@ typedef struct { SERVER_SETUP_REC *(*create_server_setup) (void); CHANNEL_SETUP_REC *(*create_channel_setup) (void); SERVER_CONNECT_REC *(*create_server_connect) (void); + void (*destroy_server_connect) (SERVER_CONNECT_REC *); SERVER_REC *(*server_connect) (SERVER_CONNECT_REC *); CHANNEL_REC *(*channel_create) (SERVER_REC *, const char *, int); diff --git a/src/core/server-connect-rec.h b/src/core/server-connect-rec.h index bf54f267..4dcc5142 100644 --- a/src/core/server-connect-rec.h +++ b/src/core/server-connect-rec.h @@ -3,6 +3,8 @@ int type; /* module_get_uniq_id("SERVER CONNECT", 0) */ int chat_type; /* chat_protocol_lookup(xx) */ +int refcount; + /* if we're connecting via proxy, or just NULLs */ char *proxy; int proxy_port; diff --git a/src/core/servers-reconnect.c b/src/core/servers-reconnect.c index e2815bc4..50572058 100644 --- a/src/core/servers-reconnect.c +++ b/src/core/servers-reconnect.c @@ -56,20 +56,22 @@ static void server_reconnect_add(SERVER_CONNECT_REC *conn, rec = g_new(RECONNECT_REC, 1); rec->tag = ++last_reconnect_tag; - rec->conn = conn; rec->next_connect = next_connect; + rec->conn = conn; + server_connect_ref(conn); + reconnects = g_slist_append(reconnects, rec); } -void server_reconnect_destroy(RECONNECT_REC *rec, int free_conn) +void server_reconnect_destroy(RECONNECT_REC *rec) { g_return_if_fail(rec != NULL); reconnects = g_slist_remove(reconnects, rec); signal_emit("server reconnect remove", 1, rec); - if (free_conn) server_connect_free(rec->conn); + server_connect_unref(rec->conn); g_free(rec); if (reconnects == NULL) @@ -95,8 +97,10 @@ static int server_reconnect_timeout(void) if (rec->next_connect <= now) { conn = rec->conn; - server_reconnect_destroy(rec, FALSE); + server_connect_ref(conn); + server_reconnect_destroy(rec); CHAT_PROTOCOL(conn)->server_connect(conn); + server_connect_unref(conn); } } @@ -118,6 +122,7 @@ static void sserver_connect(SERVER_SETUP_REC *rec, SERVER_CONNECT_REC *conn) /* connect to server.. */ CHAT_PROTOCOL(conn)->server_connect(conn); } + server_connect_unref(conn); } static SERVER_CONNECT_REC * @@ -129,6 +134,7 @@ server_connect_copy_skeleton(SERVER_CONNECT_REC *src, int connect_info) signal_emit("server connect copy", 2, &dest, src); g_return_val_if_fail(dest != NULL, NULL); + server_connect_ref(dest); dest->type = module_get_uniq_id("SERVER CONNECT", 0); dest->reconnection = src->reconnection; dest->proxy = g_strdup(src->proxy); @@ -226,6 +232,7 @@ static void sig_reconnect(SERVER_REC *server) server_reconnect_add(conn, (server->connect_time == 0 ? time(NULL) : server->connect_time) + reconnect_time); } + server_connect_unref(conn); return; } @@ -270,7 +277,7 @@ static void sig_reconnect(SERVER_REC *server) if (through) { /* shouldn't happen unless there's no servers in this chatnet in setup.. */ - server_connect_free(conn); + server_connect_unref(conn); break; } @@ -294,7 +301,7 @@ static void sig_connected(SERVER_REC *server) static void cmd_rmreconns(void) { while (reconnects != NULL) - server_reconnect_destroy(reconnects->data, TRUE); + server_reconnect_destroy(reconnects->data); } static RECONNECT_REC *reconnect_find_tag(int tag) @@ -325,7 +332,8 @@ static void reconnect_all(void) rec = reconnects->data; list = g_slist_append(list, rec->conn); - server_reconnect_destroy(rec, FALSE); + server_connect_unref(rec->conn); + server_reconnect_destroy(rec); } @@ -333,6 +341,7 @@ static void reconnect_all(void) conn = list->data; CHAT_PROTOCOL(conn)->server_connect(conn); + server_connect_unref(conn); list = g_slist_remove(list, conn); } } @@ -356,6 +365,7 @@ static void cmd_reconnect(const char *data, SERVER_REC *server) conn->reconnection = TRUE; CHAT_PROTOCOL(conn)->server_connect(conn); + server_connect_unref(conn); return; } @@ -384,8 +394,10 @@ static void cmd_reconnect(const char *data, SERVER_REC *server) } conn = rec->conn; - server_reconnect_destroy(rec, FALSE); + server_connect_ref(conn); + server_reconnect_destroy(rec); CHAT_PROTOCOL(conn)->server_connect(conn); + server_connect_unref(conn); } static void cmd_disconnect(const char *data, SERVER_REC *server) @@ -400,7 +412,7 @@ static void cmd_disconnect(const char *data, SERVER_REC *server) if (rec == NULL) signal_emit("server reconnect not found", 1, data); else - server_reconnect_destroy(rec, TRUE); + server_reconnect_destroy(rec); signal_stop(); } @@ -413,7 +425,7 @@ static void sig_chat_protocol_deinit(CHAT_PROTOCOL_REC *proto) next = tmp->next; if (rec->conn->chat_type == proto->id) - server_reconnect_destroy(rec, TRUE); + server_reconnect_destroy(rec); } } diff --git a/src/core/servers-reconnect.h b/src/core/servers-reconnect.h index bf3e640d..835d58d5 100644 --- a/src/core/servers-reconnect.h +++ b/src/core/servers-reconnect.h @@ -15,7 +15,7 @@ typedef struct { extern GSList *reconnects; void reconnect_save_status(SERVER_CONNECT_REC *conn, SERVER_REC *server); -void server_reconnect_destroy(RECONNECT_REC *rec, int free_conn); +void server_reconnect_destroy(RECONNECT_REC *rec); void servers_reconnect_init(void); void servers_reconnect_deinit(void); diff --git a/src/core/servers-setup.c b/src/core/servers-setup.c index 38d34ecd..3aaa7633 100644 --- a/src/core/servers-setup.c +++ b/src/core/servers-setup.c @@ -168,15 +168,15 @@ static void server_setup_fill_chatnet(SERVER_CONNECT_REC *conn, g_return_if_fail(IS_SERVER_CONNECT(conn)); g_return_if_fail(IS_CHATNET(chatnet)); - if (chatnet->nick) { + if (chatnet->nick != NULL) { g_free(conn->nick); conn->nick = g_strdup(chatnet->nick);; } - if (chatnet->username) { + if (chatnet->username != NULL) { g_free(conn->username); conn->username = g_strdup(chatnet->username);; } - if (chatnet->realname) { + if (chatnet->realname != NULL) { g_free(conn->realname); conn->realname = g_strdup(chatnet->realname);; } @@ -212,6 +212,8 @@ create_addr_conn(int chat_type, const char *address, int port, chat_protocol_get_default(); conn = proto->create_server_connect(); + server_connect_ref(conn); + conn->chat_type = proto->id; if (chatnet != NULL && *chatnet != '\0') conn->chatnet = g_strdup(chatnet); diff --git a/src/core/servers.c b/src/core/servers.c index 6b6c8087..0c1bcc6f 100644 --- a/src/core/servers.c +++ b/src/core/servers.c @@ -59,7 +59,7 @@ void server_connect_failed(SERVER_REC *server, const char *msg) } MODULE_DATA_DEINIT(server); - server_connect_free(server->connrec); + server_connect_unref(server->connrec); g_free_not_null(server->nick); g_free(server->tag); g_free(server); @@ -361,7 +361,7 @@ void server_disconnect(SERVER_REC *server) g_source_remove(server->readtag); MODULE_DATA_DEINIT(server); - server_connect_free(server->connrec); + server_connect_unref(server->connrec); rawlog_destroy(server->rawlog); line_split_free(server->buffer); g_free_not_null(server->version); @@ -413,12 +413,25 @@ SERVER_REC *server_find_chatnet(const char *chatnet) return NULL; } -void server_connect_free(SERVER_CONNECT_REC *conn) +void server_connect_ref(SERVER_CONNECT_REC *conn) +{ + conn->refcount++; +} + +void server_connect_unref(SERVER_CONNECT_REC *conn) { g_return_if_fail(IS_SERVER_CONNECT(conn)); - signal_emit("server connect free", 1, conn); - g_free_not_null(conn->proxy); + if (--conn->refcount > 0) + return; + if (conn->refcount < 0) { + g_warning("Connection '%s' refcount = %d", + conn->tag, conn->refcount); + } + + CHAT_PROTOCOL(conn)->destroy_server_connect(conn); + + g_free_not_null(conn->proxy); g_free_not_null(conn->proxy_string); g_free_not_null(conn->proxy_password); diff --git a/src/core/servers.h b/src/core/servers.h index 75e4cbf0..c59c7b8c 100644 --- a/src/core/servers.h +++ b/src/core/servers.h @@ -41,7 +41,8 @@ SERVER_REC *server_find_chatnet(const char *chatnet); /* starts connecting to server */ int server_start_connect(SERVER_REC *server); -void server_connect_free(SERVER_CONNECT_REC *conn); +void server_connect_ref(SERVER_CONNECT_REC *conn); +void server_connect_unref(SERVER_CONNECT_REC *conn); /* initializes server record but doesn't start connecting */ void server_connect_init(SERVER_REC *server); diff --git a/src/irc/core/irc-core.c b/src/irc/core/irc-core.c index 4de12831..607f36d7 100644 --- a/src/irc/core/irc-core.c +++ b/src/irc/core/irc-core.c @@ -65,6 +65,18 @@ static SERVER_CONNECT_REC *create_server_connect(void) return g_malloc0(sizeof(IRC_SERVER_CONNECT_REC)); } +static void destroy_server_connect(SERVER_CONNECT_REC *conn) +{ + IRC_SERVER_CONNECT_REC *ircconn; + + ircconn = IRC_SERVER_CONNECT(conn); + if (ircconn == NULL) + return; + + g_free_not_null(ircconn->usermode); + g_free_not_null(ircconn->alternate_nick); +} + void irc_core_init(void) { CHAT_PROTOCOL_REC *rec; @@ -80,6 +92,7 @@ void irc_core_init(void) rec->create_server_setup = create_server_setup; rec->create_channel_setup = create_channel_setup; rec->create_server_connect = create_server_connect; + rec->destroy_server_connect = destroy_server_connect; rec->server_connect = (SERVER_REC *(*) (SERVER_CONNECT_REC *)) irc_server_connect; diff --git a/src/irc/core/irc-servers.c b/src/irc/core/irc-servers.c index 6933361a..e34519fc 100644 --- a/src/irc/core/irc-servers.c +++ b/src/irc/core/irc-servers.c @@ -55,15 +55,6 @@ void irc_servers_reconnect_deinit(void); static int cmd_tag; -static void sig_server_connect_free(IRC_SERVER_CONNECT_REC *conn) -{ - if (!IS_IRC_SERVER_CONNECT(conn)) - return; - - g_free_not_null(conn->usermode); - g_free_not_null(conn->alternate_nick); -} - static int isnickflag_func(char flag) { return isnickflag(flag); @@ -171,8 +162,12 @@ IRC_SERVER_REC *irc_server_connect(IRC_SERVER_CONNECT_REC *conn) server = g_new0(IRC_SERVER_REC, 1); server->chat_type = IRC_PROTOCOL; + server->connrec = conn; - if (server->connrec->port <= 0) server->connrec->port = 6667; + server_connect_ref(SERVER_CONNECT(conn)); + + if (server->connrec->port <= 0) + server->connrec->port = 6667; server->cmd_queue_speed = conn->cmd_queue_speed > 0 ? conn->cmd_queue_speed : settings_get_int("cmd_queue_speed"); @@ -191,7 +186,7 @@ IRC_SERVER_REC *irc_server_connect(IRC_SERVER_CONNECT_REC *conn) conn->max_msgs : DEFAULT_MAX_MSGS; if (!server_start_connect((SERVER_REC *) server)) { - server_connect_free(SERVER_CONNECT(conn)); + server_connect_unref(SERVER_CONNECT(conn)); g_free(server); return NULL; } @@ -498,7 +493,6 @@ void irc_servers_init(void) cmd_tag = g_timeout_add(500, (GSourceFunc) servers_cmd_timeout, NULL); - signal_add("server connect free", (SIGNAL_FUNC) sig_server_connect_free); signal_add_first("server looking", (SIGNAL_FUNC) sig_server_looking); signal_add_first("server connected", (SIGNAL_FUNC) sig_connected); signal_add_last("server disconnected", (SIGNAL_FUNC) sig_disconnected); @@ -520,7 +514,6 @@ void irc_servers_deinit(void) { g_source_remove(cmd_tag); - signal_remove("server connect free", (SIGNAL_FUNC) sig_server_connect_free); signal_remove("server looking", (SIGNAL_FUNC) sig_server_looking); signal_remove("server connected", (SIGNAL_FUNC) sig_connected); signal_remove("server disconnected", (SIGNAL_FUNC) sig_disconnected);