summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
authorTimo Sirainen <cras@irssi.org>2001-12-14 01:54:12 +0000
committercras <cras@dbcabf3a-b0e7-0310-adc4-f8d773084564>2001-12-14 01:54:12 +0000
commit6774b4b30f0b43fc7c9942bf4f4f39c953b5ef6e (patch)
treec6e4846117c6eb1fe83bcd3cdeeac4160eca037d /src/core
parentebd09ede510701de8782319ff47511abf55eddff (diff)
downloadirssi-6774b4b30f0b43fc7c9942bf4f4f39c953b5ef6e.zip
Added reference counting to server record. At least now we don't accidentally
use a destroyed server record when some /command disconnects the server (shouldn't happen really) or when irc_send_cmd() fails sending data to server and disconnects the server (I don't know if this ever happens, but if it does, it very well could have caused crashes) git-svn-id: http://svn.irssi.org/repos/irssi/trunk@2243 dbcabf3a-b0e7-0310-adc4-f8d773084564
Diffstat (limited to 'src/core')
-rw-r--r--src/core/commands.c2
-rw-r--r--src/core/server-rec.h5
-rw-r--r--src/core/servers.c54
-rw-r--r--src/core/servers.h3
4 files changed, 51 insertions, 13 deletions
diff --git a/src/core/commands.c b/src/core/commands.c
index d126c358..7893b1c1 100644
--- a/src/core/commands.c
+++ b/src/core/commands.c
@@ -313,6 +313,7 @@ void command_runsub(const char *cmd, const char *data,
subcmd = g_strconcat("command ", newcmd, NULL);
g_strdown(subcmd);
+ if (server != NULL) server_ref(server);
if (!signal_emit(subcmd, 3, args, server, item)) {
defcmd = g_strdup_printf("default command %s", cmd);
if (!signal_emit(defcmd, 3, data, server, item)) {
@@ -321,6 +322,7 @@ void command_runsub(const char *cmd, const char *data,
}
g_free(defcmd);
}
+ if (server != NULL) server_unref(server);
g_free(subcmd);
g_free(orig);
diff --git a/src/core/server-rec.h b/src/core/server-rec.h
index b88d2a41..9f5070f7 100644
--- a/src/core/server-rec.h
+++ b/src/core/server-rec.h
@@ -3,6 +3,8 @@
int type; /* module_get_uniq_id("SERVER", 0) */
int chat_type; /* chat_protocol_lookup(xx) */
+int refcount;
+
STRUCT_SERVER_CONNECT_REC *connrec;
time_t connect_time; /* connection time */
time_t real_connect_time; /* time when server replied that we really are connected */
@@ -10,7 +12,8 @@ time_t real_connect_time; /* time when server replied that we really are connect
char *tag; /* tag name for addressing server */
char *nick; /* current nick */
-unsigned int connected:1; /* connected to server */
+unsigned int connected:1; /* Connected to server */
+unsigned int disconnected:1; /* Disconnected, waiting for refcount to drop zero */
unsigned int connection_lost:1; /* Connection lost unintentionally */
unsigned int session_reconnect:1; /* Connected to this server with /UPGRADE */
unsigned int no_reconnect:1; /* Don't reconnect to server */
diff --git a/src/core/servers.c b/src/core/servers.c
index 199171fb..725010a8 100644
--- a/src/core/servers.c
+++ b/src/core/servers.c
@@ -45,23 +45,26 @@ void server_connect_failed(SERVER_REC *server, const char *msg)
lookup_servers = g_slist_remove(lookup_servers, server);
signal_emit("server connect failed", 2, server, msg);
- if (server->connect_tag != -1)
+
+ if (server->connect_tag != -1) {
g_source_remove(server->connect_tag);
- if (server->handle != NULL)
+ server->connect_tag = -1;
+ }
+ if (server->handle != NULL) {
net_sendbuffer_destroy(server->handle, TRUE);
+ server->handle = NULL;
+ }
if (server->connect_pipe[0] != NULL) {
g_io_channel_close(server->connect_pipe[0]);
g_io_channel_unref(server->connect_pipe[0]);
g_io_channel_close(server->connect_pipe[1]);
g_io_channel_unref(server->connect_pipe[1]);
+ server->connect_pipe[0] = NULL;
+ server->connect_pipe[1] = NULL;
}
- MODULE_DATA_DEINIT(server);
- server_connect_unref(server->connrec);
- g_free_not_null(server->nick);
- g_free(server->tag);
- g_free(server);
+ server_unref(server);
}
/* generate tag from server's address */
@@ -242,6 +245,7 @@ void server_connect_init(SERVER_REC *server)
MODULE_DATA_INIT(server);
server->type = module_get_uniq_id("SERVER", 0);
+ server_ref(server);
server->nick = g_strdup(server->connrec->nick);
if (server->connrec->username == NULL || *server->connrec->username == '\0') {
@@ -358,15 +362,41 @@ void server_disconnect(SERVER_REC *server)
server->handle = NULL;
}
- if (server->readtag > 0)
+ if (server->readtag > 0) {
g_source_remove(server->readtag);
+ server->readtag = -1;
+ }
+
+ server->disconnected = TRUE;
+ server_unref(server);
+}
+
+void server_ref(SERVER_REC *server)
+{
+ g_return_if_fail(IS_SERVER(server));
+
+ server->refcount++;
+}
+
+void server_unref(SERVER_REC *server)
+{
+ g_return_if_fail(IS_SERVER(server));
+
+ if (--server->refcount > 0)
+ return;
+
+ if (g_slist_find(servers, server) != NULL) {
+ g_warning("Non-referenced server wasn't disconnected");
+ server_disconnect(server);
+ return;
+ }
MODULE_DATA_DEINIT(server);
server_connect_unref(server->connrec);
- rawlog_destroy(server->rawlog);
- line_split_free(server->buffer);
- g_free_not_null(server->version);
- g_free_not_null(server->away_reason);
+ if (server->rawlog != NULL) rawlog_destroy(server->rawlog);
+ if (server->buffer != NULL) line_split_free(server->buffer);
+ g_free(server->version);
+ g_free(server->away_reason);
g_free(server->nick);
g_free(server->tag);
g_free(server);
diff --git a/src/core/servers.h b/src/core/servers.h
index 667a034e..ddeb2494 100644
--- a/src/core/servers.h
+++ b/src/core/servers.h
@@ -39,6 +39,9 @@ void servers_deinit(void);
/* Disconnect from server */
void server_disconnect(SERVER_REC *server);
+void server_ref(SERVER_REC *server);
+void server_unref(SERVER_REC *server);
+
SERVER_REC *server_find_tag(const char *tag);
SERVER_REC *server_find_chatnet(const char *chatnet);