/*
irssi.c : irssi
- Copyright (C) 1999-2000 Timo Sirainen
+ Copyright (C) 1999-2000, 2007 Timo Sirainen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
static GMainLoop *main_loop;
int quitting;
+int quit_signalled;
+int protocols_deinit;
-static const char *firsttimer_text =
- "Looks like this is the first time you've run irssi.\n"
- "This is just a reminder that you really should go read\n"
- "startup-HOWTO if you haven't already. You can find it\n"
- "and more irssi beginner info at http://irssi.org/help/\n"
- "\n"
- "For the truly impatient people who don't like any automatic\n"
- "window creation or closing, just type: /MANUAL-WINDOWS";
static int display_firsttimer = FALSE;
+/* Protocol exit signal to tell protocol has gone away. Safe to quit. */
+
+static void sig_protocol_exit(void)
+{
+ protocols_deinit = TRUE;
+ if (!quitting && quit_signalled)
+ quitting = TRUE;
+}
static void sig_exit(void)
{
- quitting = TRUE;
+ quit_signalled = TRUE;
+
+ /* If protocol hasn't finished yet, wait untill it sends "chat protocol
+ deinit" signal. */
+ if (!protocols_deinit)
+ return;
+ quitting = TRUE;
}
/* redraw irssi's screen.. */
theme_register(gui_text_formats);
signal_add_last("gui exit", (SIGNAL_FUNC) sig_exit);
+ signal_add_last("chat protocol deinit",
+ (SIGNAL_FUNC) sig_protocol_exit);
}
static void textui_finish_init(void)
{
quitting = FALSE;
+ quit_signalled = FALSE;
+ protocols_deinit = FALSE;
if (dummy)
term_dummy_init();
fe_common_core_finish_init();
signal_emit("irssi init finished", 0);
-
-#if 0
- if (display_firsttimer) {
- printtext_window(active_win, MSGLEVEL_CLIENTNOTICE,
- "%s", firsttimer_text);
- }
-#endif
}
static void textui_deinit(void)
dirty_check(); /* one last time to print any quit messages */
signal_remove("gui exit", (SIGNAL_FUNC) sig_exit);
+ signal_remove("chat protocol deinit", (SIGNAL_FUNC) sig_protocol_exit);
if (dummy)
term_dummy_deinit();
dummy = FALSE;
quitting = FALSE;
+ quit_signalled = FALSE;
+ protocols_deinit = FALSE;
core_init_paths(argc, argv);
check_files();
if (!pw) {
if (completion)
completion(FALSE, context);
+ silc_free(pk);
return;
}
format, 0, verify);
g_free(format);
silc_free(fingerprint);
+ silc_free(babbleprint);
+ silc_free(pk);
return;
} else {
/* The key already exists, verify it. */
format, 0, verify);
g_free(format);
silc_free(fingerprint);
+ silc_free(babbleprint);
+ silc_free(pk);
return;
}
format, 0, verify);
g_free(format);
silc_free(fingerprint);
+ silc_free(babbleprint);
+ silc_free(pk);
return;
}
+ silc_pkcs_public_key_free(local_pubkey);
/* Compare the keys */
if (memcmp(encpk, pk, encpk_len)) {
format, 0, verify);
g_free(format);
silc_free(fingerprint);
+ silc_free(babbleprint);
silc_free(encpk);
+ silc_free(pk);
return;
}
completion(TRUE, context);
silc_free(encpk);
silc_free(fingerprint);
+ silc_free(babbleprint);
silc_free(verify->filename);
silc_free(verify->entity);
silc_free(verify->entity_name);
silc_free(verify);
+ silc_free(pk);
}
}
}
if (strcmp(opt->longName, "hostname") == 0) {
- g_free(opt_hostname);
- opt_hostname = g_strdup(arg);
+ silc_free(opt_hostname);
+ opt_hostname = strdup(arg);
}
if (strcmp(opt->longName, "list-ciphers") == 0) {
SILC_LOG_DEBUG(("Client library has stopped"));
if (idletag != -1)
g_source_remove(idletag);
+ signal_emit("chat protocol deinit", 1,
+ chat_protocol_find("SILC"));
}
static void sig_gui_quit(SILC_SERVER_REC *server, const char *msg)
}
/* Initialize the SILC client */
+ opt_hostname = (opt_hostname ? opt_hostname : silc_net_localhost());
if (!silc_client_init(silc_client, settings_get_str("user_name"),
- opt_hostname ? opt_hostname : silc_net_localhost(),
- settings_get_str("real_name"), silc_running, NULL)) {
+ opt_hostname, settings_get_str("real_name"),
+ silc_running, NULL)) {
sleep(1);
exit(1);
return;
if (idletag != -1)
g_source_remove(idletag);
- signal_emit("chat protocol deinit", 1,
- chat_protocol_find("SILC"));
+ if (opt_hostname)
+ silc_free(opt_hostname);
+ if (opt_nickname)
+ g_free(opt_nickname);
+
signal_remove("setup changed", (SIGNAL_FUNC) sig_setup_changed);
signal_remove("irssi init finished", (SIGNAL_FUNC) sig_init_finished);
signal_remove("gui exit", (SIGNAL_FUNC) sig_gui_quit);
+ silc_hash_free(sha1hash);
+
silc_queue_deinit();
silc_server_deinit();
silc_channels_deinit();
chat_protocol_unregister("SILC");
- silc_pkcs_private_key_free(irssi_privkey);
silc_pkcs_public_key_free(irssi_pubkey);
+ silc_pkcs_private_key_free(irssi_privkey);
silc_client_free(silc_client);
}
if (params.detach_data)
printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
SILCTXT_REATTACH, server->tag);
+ silc_free(file);
/* Start key exchange */
server->op = silc_client_key_exchange(silc_client, ¶ms,
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2000 - 2006 Pekka Riikonen
+ Copyright (C) 2000 - 2007 Pekka Riikonen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
* Add new entry to the cache. Returns the allocated cache entry if the
* entry was added successfully, or NULL if error occurred. The `name' is
* the name associated with the ID, the `id' the actual ID and the
- * `context' a caller specific context.
- *
- * The `name', `id' and `context' pointers will be stored in the cache,
- * and if the caller frees these pointers the caller is also responsible
- * of deleting the cache entry.
+ * `context' a caller specific context. The caller is responsible of
+ * freeing the `name' and `id' when the entry is deleted.
*
***/
SilcIDCacheEntry
silc_hash_free(conn->internal->sha1hash);
silc_atomic_uninit16(&conn->internal->cmd_ident);
+ if (conn->internal->rekey)
+ silc_ske_free_rekey_material(conn->internal->rekey);
+
+ if (conn->internal->cop)
+ silc_async_free(conn->internal->cop);
+
silc_free(conn->internal);
memset(conn, 'F', sizeof(*conn));
silc_free(conn);
silc_hmac_unregister_all();
}
+ silc_packet_engine_stop(client->internal->packet_engine);
+ silc_dlist_uninit(client->internal->ftp_sessions);
silc_atomic_uninit16(&client->internal->conns);
+ silc_mutex_free(client->internal->lock);
silc_free(client->username);
silc_free(client->hostname);
silc_free(client->realname);
conn->callback(client, conn, SILC_CLIENT_CONN_SUCCESS, 0, NULL,
conn->callback_context);
+ silc_async_free(conn->internal->cop);
+ conn->internal->cop = NULL;
+
return SILC_FSM_FINISH;
}
SilcBool silc_client_del_channel(SilcClient client, SilcClientConnection conn,
SilcChannelEntry channel)
{
+ SilcIDCacheEntry id_cache;
SilcBool ret;
SilcCipher key;
SilcHmac hmac;
SILC_LOG_DEBUG(("Deleting channel %p", channel));
silc_mutex_lock(conn->internal->lock);
+ if (silc_idcache_find_by_context(conn->internal->channel_cache, channel,
+ &id_cache))
+ silc_free(id_cache->name);
ret = silc_idcache_del_by_context(conn->internal->channel_cache,
channel, NULL);
silc_mutex_unlock(conn->internal->lock);
SilcBool silc_client_del_server(SilcClient client, SilcClientConnection conn,
SilcServerEntry server)
{
+ SilcIDCacheEntry id_cache;
SilcBool ret;
if (!server)
SILC_LOG_DEBUG(("Deleting server %p", server));
silc_mutex_lock(conn->internal->lock);
+ if (silc_idcache_find_by_context(conn->internal->server_cache, server,
+ &id_cache))
+ silc_free(id_cache->name);
ret = silc_idcache_del_by_context(conn->internal->server_cache,
server, NULL);
silc_mutex_unlock(conn->internal->lock);
conn->internal->registering = FALSE;
silc_schedule_task_del_by_all(conn->internal->schedule, 0,
silc_client_connect_timeout, conn);
+ silc_async_free(conn->internal->cop);
+ conn->internal->cop = NULL;
return SILC_FSM_FINISH;
}
silc_client_connect_timeout, conn);
silc_free(resume->nickname);
silc_free(resume);
+ silc_async_free(conn->internal->cop);
+ conn->internal->cop = NULL;
return SILC_FSM_FINISH;
}
void silc_packet_engine_stop(SilcPacketEngine engine)
{
+ SilcPacket packet;
SILC_LOG_DEBUG(("Stopping packet engine"));
if (!engine)
return;
- /* XXX */
+ /* Free packet free list */
+ silc_list_start(engine->packet_pool);
+ while ((packet = silc_list_get(engine->packet_pool))) {
+ silc_buffer_purge(&packet->buffer);
+ silc_free(packet);
+ }
+ silc_hash_table_free(engine->contexts);
+ silc_mutex_free(engine->lock);
silc_free(engine);
}
silc_dlist_uninit(stream->process);
}
- /* XXX */
+ /* Destroy ciphers and HMACs */
+ if (stream->send_key[0])
+ silc_cipher_free(stream->send_key[0]);
+ if (stream->receive_key[0])
+ silc_cipher_free(stream->receive_key[0]);
+ if (stream->send_hmac[0])
+ silc_hmac_free(stream->send_hmac[0]);
+ if (stream->receive_hmac[0])
+ silc_hmac_free(stream->receive_hmac[0]);
+ if (stream->send_key[1])
+ silc_cipher_free(stream->send_key[1]);
+ if (stream->receive_key[1])
+ silc_cipher_free(stream->receive_key[1]);
+ if (stream->send_hmac[1])
+ silc_hmac_free(stream->send_hmac[1]);
+ if (stream->receive_hmac[1])
+ silc_hmac_free(stream->receive_hmac[1]);
+
+ /* Free IDs */
+ silc_free(stream->src_id);
+ silc_free(stream->dst_id);
silc_atomic_uninit8(&stream->refcnt);
silc_mutex_free(stream->lock);
} else {
if (stream->send_key[0] && send_key)
silc_cipher_free(stream->send_key[0]);
- if (stream->send_key[1] && receive_key)
+ if (stream->receive_key[0] && receive_key)
silc_cipher_free(stream->receive_key[0]);
if (stream->send_hmac[0] && send_hmac)
silc_hmac_free(stream->send_hmac[0]);
if (read_more && !pws->blocking) {
/* More data will be available (in blocking mode not supported). */
silc_buffer_pull(&packet->buffer, len);
- silc_list_insert(pws->in_queue, NULL, packet);
+ silc_list_insert(pws->in_queue, NULL, packet);
silc_schedule_task_add_timeout(pws->stream->sc->schedule,
silc_packet_wrap_read_more, pws, 0, 0);
pws->read_more = TRUE;
if (hash == SILC_ALL_HASH_FUNCTIONS || entry == hash) {
silc_dlist_del(silc_hash_list, entry);
silc_free(entry->name);
+ silc_free(entry->oid);
silc_free(entry);
if (silc_dlist_count(silc_hash_list) == 0) {
void silc_pkcs_public_key_free(SilcPublicKey public_key)
{
public_key->pkcs->public_key_free(public_key->public_key);
+ silc_free(public_key);
}
/* Exports public key */
void silc_pkcs_private_key_free(SilcPrivateKey private_key)
{
private_key->pkcs->private_key_free(private_key->private_key);
+ silc_free(private_key);
}
/* Encrypts */
struct SilcConnAuthStruct {
SilcSKE ske;
SilcFSM fsm;
+ SilcAsyncOperationStruct op;
SilcConnectionType conn_type;
SilcAuthMethod auth_method;
void *auth_data;
SilcConnAuthCompletion completion,
void *context)
{
- SilcAsyncOperation op;
-
SILC_LOG_DEBUG(("Connection authentication as initiator"));
if (auth_method == SILC_AUTH_PASSWORD && !auth_data) {
SILC_PACKET_FAILURE, -1);
/* Start the protocol */
- op = silc_async_alloc(silc_connauth_abort, NULL, connauth);
+ silc_async_init(&connauth->op, silc_connauth_abort, NULL, connauth);
silc_fsm_start(connauth->fsm, silc_connauth_st_initiator_start);
- return op;
+ return &connauth->op;
}
SilcConnAuthCompletion completion,
void *context)
{
- SilcAsyncOperation op;
-
SILC_LOG_DEBUG(("Connection authentication as responder"));
connauth->get_auth_data = get_auth_data;
SILC_PACKET_FAILURE, -1);
/* Start the protocol */
- op = silc_async_alloc(silc_connauth_abort, NULL, connauth);
+ silc_async_init(&connauth->op, silc_connauth_abort, NULL, connauth);
silc_fsm_start(connauth->fsm, silc_connauth_st_responder_start);
- return op;
+ return &connauth->op;
}
}
/* Handle rekey and SUCCESS packets synchronously. After SUCCESS packets
- they keys are taken into use immediately, hence the synchronous
+ they keys are taken into use immediately, hence the synchronous
processing to get the keys in use as soon as possible. */
if (ske->rekeying || packet->type == SILC_PACKET_SUCCESS)
silc_fsm_continue_sync(&ske->fsm);
silc_hash_free(ske->prop->hash);
if (ske->prop->hmac)
silc_hmac_free(ske->prop->hmac);
+ if (ske->prop->public_key)
+ silc_pkcs_public_key_free(ske->prop->public_key);
silc_free(ske->prop);
}
if (ske->keymat)
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2005 Pekka Riikonen
+ Copyright (C) 2005 - 2007 Pekka Riikonen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
* SYNOPSIS
*
* typedef SilcBool (*SilcAsyncOperationPause)(SilcAsyncOperation op,
- * SilcBool pause_operation,
- * void *context);
+ * SilcBool pause_operation,
+ * void *context);
*
* DESCRIPTION
*
* SYNOPSIS
*
* SilcBool silc_async_init(SilcAsyncOperation op,
- * SilcAsyncOperationAbort abort_cb,
- * SilcAsyncOperationPause pause_cb,
- * void *context);
+ * SilcAsyncOperationAbort abort_cb,
+ * SilcAsyncOperationPause pause_cb,
+ * void *context);
*
* DESCRIPTION
*
* layer to abort the asynchronous operation, by calling the
* silc_async_abort. Since this use pre-allocated context, the function
* silc_async_free need not be called. This function is equivalent
- * to silc_async_alloc except this does not allocate any memory.
+ * to silc_async_alloc except this does not allocate any memory. The `op'
+ * needs not be uninitialized.
*
* If the `pause_cb' is provided then the upper layer may also halt and
* then later resume the execution of the operation, by calling the
/*
- stacktrace.c
+ stacktrace.c
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2002 Pekka Riikonen
+ Copyright (C) 2002, 2007 Pekka Riikonen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
static SilcBool dump = FALSE;
static SilcBool malloc_check = FALSE;
-#define SILC_ST_DEPTH 10
+#ifdef SILC_DEBUG
+#define SILC_ST_DEPTH 15
+#else
+#define SILC_ST_DEPTH 8
+#endif /* SILC_DEBUG */
/* Memory block with stack trace */
typedef struct SilcStBlockStruct {
for (s = stack; s; s = s->next) {
if (s->file == stack->file && s->line == stack->line &&
s->depth == stack->depth &&
- !memcmp(s->stack, stack->stack,
+ !memcmp(s->stack, stack->stack,
(s->depth * sizeof(stack->stack[0])))) {
blocks++;
bytes += s->size;
if (!leaks) {
fprintf(stderr, "\nNo memory leaks\n");
} else {
- fprintf(stderr,
+ fprintf(stderr,
"-----------------------------------------\n"
"-----------------------------------------\n"
" Memory leaks dumped to 'stacktrace.log'\n"