mirror of
https://github.com/irssi/irssi.git
synced 2024-12-04 14:46:39 -05:00
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
This commit is contained in:
parent
ebd09ede51
commit
6774b4b30f
@ -313,6 +313,7 @@ void command_runsub(const char *cmd, const char *data,
|
|||||||
subcmd = g_strconcat("command ", newcmd, NULL);
|
subcmd = g_strconcat("command ", newcmd, NULL);
|
||||||
|
|
||||||
g_strdown(subcmd);
|
g_strdown(subcmd);
|
||||||
|
if (server != NULL) server_ref(server);
|
||||||
if (!signal_emit(subcmd, 3, args, server, item)) {
|
if (!signal_emit(subcmd, 3, args, server, item)) {
|
||||||
defcmd = g_strdup_printf("default command %s", cmd);
|
defcmd = g_strdup_printf("default command %s", cmd);
|
||||||
if (!signal_emit(defcmd, 3, data, server, item)) {
|
if (!signal_emit(defcmd, 3, data, server, item)) {
|
||||||
@ -321,6 +322,7 @@ void command_runsub(const char *cmd, const char *data,
|
|||||||
}
|
}
|
||||||
g_free(defcmd);
|
g_free(defcmd);
|
||||||
}
|
}
|
||||||
|
if (server != NULL) server_unref(server);
|
||||||
|
|
||||||
g_free(subcmd);
|
g_free(subcmd);
|
||||||
g_free(orig);
|
g_free(orig);
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
int type; /* module_get_uniq_id("SERVER", 0) */
|
int type; /* module_get_uniq_id("SERVER", 0) */
|
||||||
int chat_type; /* chat_protocol_lookup(xx) */
|
int chat_type; /* chat_protocol_lookup(xx) */
|
||||||
|
|
||||||
|
int refcount;
|
||||||
|
|
||||||
STRUCT_SERVER_CONNECT_REC *connrec;
|
STRUCT_SERVER_CONNECT_REC *connrec;
|
||||||
time_t connect_time; /* connection time */
|
time_t connect_time; /* connection time */
|
||||||
time_t real_connect_time; /* time when server replied that we really are connected */
|
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 *tag; /* tag name for addressing server */
|
||||||
char *nick; /* current nick */
|
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 connection_lost:1; /* Connection lost unintentionally */
|
||||||
unsigned int session_reconnect:1; /* Connected to this server with /UPGRADE */
|
unsigned int session_reconnect:1; /* Connected to this server with /UPGRADE */
|
||||||
unsigned int no_reconnect:1; /* Don't reconnect to server */
|
unsigned int no_reconnect:1; /* Don't reconnect to server */
|
||||||
|
@ -45,23 +45,26 @@ void server_connect_failed(SERVER_REC *server, const char *msg)
|
|||||||
lookup_servers = g_slist_remove(lookup_servers, server);
|
lookup_servers = g_slist_remove(lookup_servers, server);
|
||||||
|
|
||||||
signal_emit("server connect failed", 2, server, msg);
|
signal_emit("server connect failed", 2, server, msg);
|
||||||
if (server->connect_tag != -1)
|
|
||||||
|
if (server->connect_tag != -1) {
|
||||||
g_source_remove(server->connect_tag);
|
g_source_remove(server->connect_tag);
|
||||||
if (server->handle != NULL)
|
server->connect_tag = -1;
|
||||||
|
}
|
||||||
|
if (server->handle != NULL) {
|
||||||
net_sendbuffer_destroy(server->handle, TRUE);
|
net_sendbuffer_destroy(server->handle, TRUE);
|
||||||
|
server->handle = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (server->connect_pipe[0] != NULL) {
|
if (server->connect_pipe[0] != NULL) {
|
||||||
g_io_channel_close(server->connect_pipe[0]);
|
g_io_channel_close(server->connect_pipe[0]);
|
||||||
g_io_channel_unref(server->connect_pipe[0]);
|
g_io_channel_unref(server->connect_pipe[0]);
|
||||||
g_io_channel_close(server->connect_pipe[1]);
|
g_io_channel_close(server->connect_pipe[1]);
|
||||||
g_io_channel_unref(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_unref(server);
|
||||||
server_connect_unref(server->connrec);
|
|
||||||
g_free_not_null(server->nick);
|
|
||||||
g_free(server->tag);
|
|
||||||
g_free(server);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* generate tag from server's address */
|
/* generate tag from server's address */
|
||||||
@ -242,6 +245,7 @@ void server_connect_init(SERVER_REC *server)
|
|||||||
|
|
||||||
MODULE_DATA_INIT(server);
|
MODULE_DATA_INIT(server);
|
||||||
server->type = module_get_uniq_id("SERVER", 0);
|
server->type = module_get_uniq_id("SERVER", 0);
|
||||||
|
server_ref(server);
|
||||||
|
|
||||||
server->nick = g_strdup(server->connrec->nick);
|
server->nick = g_strdup(server->connrec->nick);
|
||||||
if (server->connrec->username == NULL || *server->connrec->username == '\0') {
|
if (server->connrec->username == NULL || *server->connrec->username == '\0') {
|
||||||
@ -358,15 +362,41 @@ void server_disconnect(SERVER_REC *server)
|
|||||||
server->handle = NULL;
|
server->handle = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (server->readtag > 0)
|
if (server->readtag > 0) {
|
||||||
g_source_remove(server->readtag);
|
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);
|
MODULE_DATA_DEINIT(server);
|
||||||
server_connect_unref(server->connrec);
|
server_connect_unref(server->connrec);
|
||||||
rawlog_destroy(server->rawlog);
|
if (server->rawlog != NULL) rawlog_destroy(server->rawlog);
|
||||||
line_split_free(server->buffer);
|
if (server->buffer != NULL) line_split_free(server->buffer);
|
||||||
g_free_not_null(server->version);
|
g_free(server->version);
|
||||||
g_free_not_null(server->away_reason);
|
g_free(server->away_reason);
|
||||||
g_free(server->nick);
|
g_free(server->nick);
|
||||||
g_free(server->tag);
|
g_free(server->tag);
|
||||||
g_free(server);
|
g_free(server);
|
||||||
|
@ -39,6 +39,9 @@ void servers_deinit(void);
|
|||||||
/* Disconnect from server */
|
/* Disconnect from server */
|
||||||
void server_disconnect(SERVER_REC *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_tag(const char *tag);
|
||||||
SERVER_REC *server_find_chatnet(const char *chatnet);
|
SERVER_REC *server_find_chatnet(const char *chatnet);
|
||||||
|
|
||||||
|
@ -375,14 +375,15 @@ static void irc_parse_incoming(SERVER_REC *server)
|
|||||||
too slowly, so read only a few times from the socket before
|
too slowly, so read only a few times from the socket before
|
||||||
letting other tasks to run. */
|
letting other tasks to run. */
|
||||||
count = 0;
|
count = 0;
|
||||||
while (irc_receive_line(server, &str, count < MAX_SOCKET_READS) > 0) {
|
server_ref(server);
|
||||||
|
while (!server->disconnected &&
|
||||||
|
irc_receive_line(server, &str, count < MAX_SOCKET_READS) > 0) {
|
||||||
rawlog_input(server->rawlog, str);
|
rawlog_input(server->rawlog, str);
|
||||||
signal_emit_id(signal_server_incoming, 2, server, str);
|
signal_emit_id(signal_server_incoming, 2, server, str);
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
if (g_slist_find(servers, server) == NULL)
|
|
||||||
break; /* disconnected */
|
|
||||||
}
|
}
|
||||||
|
server_unref(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void irc_init_server(IRC_SERVER_REC *server)
|
static void irc_init_server(IRC_SERVER_REC *server)
|
||||||
|
@ -59,6 +59,14 @@ void
|
|||||||
server_disconnect(server)
|
server_disconnect(server)
|
||||||
Irssi::Server server
|
Irssi::Server server
|
||||||
|
|
||||||
|
void
|
||||||
|
server_ref(server)
|
||||||
|
Irssi::Server server
|
||||||
|
|
||||||
|
void
|
||||||
|
server_unref(server)
|
||||||
|
Irssi::Server server
|
||||||
|
|
||||||
int
|
int
|
||||||
isnickflag(server, flag)
|
isnickflag(server, flag)
|
||||||
Irssi::Server server
|
Irssi::Server server
|
||||||
|
@ -22,4 +22,4 @@ extern PerlInterpreter *my_perl; /* must be called my_perl or some perl implemen
|
|||||||
|
|
||||||
/* Change this every time when some API changes between irssi's perl module
|
/* Change this every time when some API changes between irssi's perl module
|
||||||
(or irssi itself) and irssi's perl libraries. */
|
(or irssi itself) and irssi's perl libraries. */
|
||||||
#define IRSSI_PERL_API_VERSION 20011204
|
#define IRSSI_PERL_API_VERSION 20011214
|
||||||
|
Loading…
Reference in New Issue
Block a user