Merge branch 'master' of git://valera-ext.nynaeve.net/silc into silc.1.1.branch
authorPekka Riikonen <priikone@silcnet.org>
Sat, 22 Nov 2008 16:14:35 +0000 (18:14 +0200)
committerPekka Riikonen <priikone@silcnet.org>
Sat, 22 Nov 2008 16:14:35 +0000 (18:14 +0200)
Code cleanup during merge.

Reverted External IP commit

Reverted changes to silcsocketstream API.  The user context can be now
set to SilcClientConnectionParams.  Increased shared library revision to
avoid backwards incompatiblity.

Signed-off-by: Pekka Riikonen <priikone@silcnet.org>
18 files changed:
apps/irssi/src/silc/core/client_ops.c
apps/irssi/src/silc/core/clientutil.c
apps/irssi/src/silc/core/clientutil.h
apps/irssi/src/silc/core/silc-channels.c
apps/irssi/src/silc/core/silc-queries.c
apps/irssi/src/silc/core/silc-servers.c
apps/irssi/src/silc/core/silc-servers.h
apps/silcd/packet_receive.c
apps/silcd/server.c
apps/silcd/server_internal.h
apps/silcd/server_util.c
lib/configure.ad
lib/silcclient/client.c
lib/silcclient/client.h
lib/silcclient/client_entry.c
lib/silcclient/silcclient.h
lib/silcske/silcske.c
lib/silcske/silcske_i.h

index 38e90d0844553855d9cc38cc2497756754e37975..16feddc7583a8b2c18dd200f736473b2a8ba6d92 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2001 - 2007 Pekka Riikonen
+  Copyright (C) 2001 - 2008 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
@@ -30,6 +30,7 @@
 #include "silc-queries.h"
 #include "silc-nicklist.h"
 #include "silc-cmdqueue.h"
+#include "clientutil.h"
 
 #include "signals.h"
 #include "levels.h"
@@ -1438,6 +1439,21 @@ void silc_getkey_cb(bool success, void *context)
                       entity, name);
   }
 
+  /*
+   * Drop our references as need be.
+   */
+  switch (getkey->id_type) {
+  case SILC_ID_CLIENT:
+    silc_client_unref_client(getkey->client, getkey->conn,
+                            (SilcClientEntry)getkey->entry);
+    break;
+
+  case SILC_ID_SERVER:
+    silc_client_unref_server(getkey->client, getkey->conn,
+                            (SilcServerEntry)getkey->entry);
+    break;
+  }
+
   silc_free(getkey);
 }
 
@@ -1807,8 +1823,8 @@ void silc_command_reply(SilcClient client, SilcClientConnection conn,
       if (!ownnick)
        break;
       nicklist_set_own(CHANNEL(chanrec), ownnick);
-      signal_emit("channel joined", 1, chanrec);
       chanrec->entry = channel_entry;
+      signal_emit("channel joined", 1, chanrec);
 
       if (chanrec->topic)
        printformat_module("fe-common/silc", server,
@@ -2097,6 +2113,18 @@ void silc_command_reply(SilcClient client, SilcClientConnection conn,
                ((SilcClientEntry)entry)->nickname :
                ((SilcServerEntry)entry)->server_name);
 
+       switch (id_type) {
+       case SILC_ID_CLIENT:
+         name = ((SilcClientEntry)entry)->nickname;
+         silc_client_ref_client(client, conn, (SilcClientEntry)entry);
+         break;
+
+       case SILC_ID_SERVER:
+         name = ((SilcServerEntry)entry)->server_name;
+         silc_client_ref_server(client, conn, (SilcServerEntry)entry);
+         break;
+       }
+
        silc_verify_public_key_internal(client, conn, name,
                                        (id_type == SILC_ID_CLIENT ?
                                         SILC_CONN_CLIENT :
@@ -2366,11 +2394,13 @@ typedef struct {
   void *context;
 } *PublicKeyVerify;
 
-static void verify_public_key_completion(const char *line, void *context)
+static void verify_public_key_completion(const char *line, void *context,
+                                        SilcKeyboardPromptStatus reason)
 {
   PublicKeyVerify verify = (PublicKeyVerify)context;
+  SilcBool success = (reason == KeyboardCompletionSuccess);
 
-  if (line[0] == 'Y' || line[0] == 'y') {
+  if (success && (line[0] == 'Y' || line[0] == 'y')) {
     /* Call the completion */
     if (verify->completion)
       verify->completion(TRUE, verify->context);
@@ -2389,6 +2419,26 @@ static void verify_public_key_completion(const char *line, void *context)
                       verify->entity);
   }
 
+  /*
+   * If we were not called due to a failure to begin the callback, then we
+   * shall zero the async context block in the server record.  If we were
+   * called due to a failure to begin the callback, then it is possible that
+   * we failed due to an overlapping callback, in which case we shouldn't
+   * overwrite the async context block pointer.
+   */
+  if (reason != KeyboardCompletionFailed) {
+    /*
+     * Null out the completion context in the server record as this operation
+     * is done as far as we are concerned.  The underlying keyboard library
+     * routine will take care of freeing the async context memory when the
+     * actual callback is called by irssi in the abort case.  In the success
+     * case, it will free the async context memory after we return from this
+     * routine.
+     */
+    SILC_SERVER_REC *server = (SILC_SERVER_REC*)(verify->conn->context);
+    server->prompt_op = NULL;
+  }
+
   silc_free(verify->filename);
   silc_free(verify->entity);
   silc_free(verify->entity_name);
@@ -2413,6 +2463,7 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
   SilcPublicKey local_pubkey;
   SilcSILCPublicKey silc_pubkey;
   SilcUInt16 port;
+  SILC_SERVER_REC *server;
   const char *hostname, *ip;
   unsigned char *pk;
   SilcUInt32 pk_len;
@@ -2423,6 +2474,14 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
                  "server" : "client");
   int i;
 
+  server = (SILC_SERVER_REC*)conn->context;
+  SILC_VERIFY(server);
+  if (!server) {
+    if (completion)
+      completion(FALSE, context);
+    return;
+  }
+
   if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) {
     printformat_module("fe-common/silc", NULL, NULL,
                       MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
@@ -2531,8 +2590,8 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
                       SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
     format = format_get_text("fe-common/silc", NULL, NULL, NULL,
                             SILCTXT_PUBKEY_ACCEPT);
-    keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
-                           format, 0, verify);
+    silc_keyboard_entry_redirect(verify_public_key_completion,
+                           format, 0, verify, &server->prompt_op);
     g_free(format);
     silc_free(fingerprint);
     silc_free(babbleprint);
@@ -2564,8 +2623,8 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
                         SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
       format = format_get_text("fe-common/silc", NULL, NULL, NULL,
                               SILCTXT_PUBKEY_ACCEPT_ANYWAY);
-      keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
-                             format, 0, verify);
+      silc_keyboard_entry_redirect(verify_public_key_completion,
+                             format, 0, verify, &server->prompt_op);
       g_free(format);
       silc_free(fingerprint);
       silc_free(babbleprint);
@@ -2594,8 +2653,8 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
                         SILCTXT_PUBKEY_MALFORMED, entity);
       format = format_get_text("fe-common/silc", NULL, NULL, NULL,
                               SILCTXT_PUBKEY_ACCEPT_ANYWAY);
-      keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
-                             format, 0, verify);
+      silc_keyboard_entry_redirect(verify_public_key_completion,
+                             format, 0, verify, &server->prompt_op);
       g_free(format);
       silc_free(fingerprint);
       silc_free(babbleprint);
@@ -2630,8 +2689,8 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
       /* Ask user to verify the key and save it */
       format = format_get_text("fe-common/silc", NULL, NULL, NULL,
                               SILCTXT_PUBKEY_ACCEPT_ANYWAY);
-      keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
-                             format, 0, verify);
+      silc_keyboard_entry_redirect(verify_public_key_completion,
+                             format, 0, verify, &server->prompt_op);
       g_free(format);
       silc_free(fingerprint);
       silc_free(babbleprint);
@@ -2673,28 +2732,47 @@ silc_verify_public_key(SilcClient client, SilcClientConnection conn,
 
 typedef struct {
   SilcAskPassphrase completion;
+  SilcClientConnection conn;
   void *context;
 } *AskPassphrase;
 
-void ask_passphrase_completion(const char *passphrase, void *context)
+void ask_passphrase_completion(const char *passphrase, void *context,
+                              SilcKeyboardPromptStatus reason)
 {
   AskPassphrase p = (AskPassphrase)context;
   if (passphrase && passphrase[0] == '\0')
     passphrase = NULL;
   p->completion((unsigned char *)passphrase,
                passphrase ? strlen(passphrase) : 0, p->context);
+
+  if (reason != KeyboardCompletionFailed) {
+    SILC_SERVER_REC *server = (SILC_SERVER_REC *)(p->conn->context);
+    server->prompt_op = NULL;
+  }
+
   silc_free(p);
 }
 
 void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
                         SilcAskPassphrase completion, void *context)
 {
-  AskPassphrase p = silc_calloc(1, sizeof(*p));
+  SILC_SERVER_REC *server = (SILC_SERVER_REC*)(conn->context);
+  AskPassphrase p;
+
+  p = silc_calloc(1, sizeof(*p));
+  if (!p) {
+    if (completion)
+      completion(NULL, 0, context);
+    return;
+  }
+
   p->completion = completion;
-  p->context = context;
+  p->conn       = conn;
+  p->context    = context;
 
-  keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
-                         "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
+  silc_keyboard_entry_redirect(ask_passphrase_completion,
+                              "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN,
+                              p, &server->prompt_op);
 }
 
 typedef struct {
index 836347338a3457deaa8af281f5d37ef4d6775dc1..66c8eb9a987e9c617ac9eef0d0836f1ff9dee1c2 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2006 Pekka Riikonen
+  Copyright (C) 1997 - 2006, 2008 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
@@ -341,7 +341,7 @@ int silc_client_load_keys(SilcClient client)
 {
   char pub[256], prv[256];
   struct passwd *pw;
-  bool ret;
+  SilcBool ret;
 
   SILC_LOG_DEBUG(("Loading public and private keys"));
 
@@ -370,6 +370,181 @@ int silc_client_load_keys(SilcClient client)
   return ret;
 }
 
+static SilcBool silc_keyboard_prompt_pending;
+
+typedef struct {
+  SilcAsyncOperation async_context;
+  SILC_KEYBOARD_PROMPT_PROC user_prompt_proc;
+  void *user_context;
+  SilcBool aborted;
+  SilcBool *immediate_completion;
+} *SilcKeyboardEntryRedirectContext;
+
+static void silc_keyboard_entry_redirect_abort(SilcAsyncOperation op,
+                                              void *context)
+{
+  SilcKeyboardEntryRedirectContext ctx = context;
+
+  /*
+   * Flag ourselves as aborted so the irssi callback doesn't do any real
+   * work here.
+   */
+  ctx->aborted = TRUE;
+
+  /*
+   * Call the user routine to notify it that we are aborting, so that it may
+   * clean up anything that needs cleaning up, e.g. references.  The user
+   * may not reference the SilcAsyncOperation beyond this abort call.  The
+   * recommended procedure is for the user prompt routine to null out its
+   * reference to the SilcAsyncOperation context.  The underlying context
+   * structure will be released when the actual wrappered callback fires,
+   * though the wrappered callback will not call into user code now that
+   * the operation has been aborted.
+   */
+  ctx->user_prompt_proc(NULL, ctx->user_context, KeyboardCompletionAborted);
+}
+
+static void silc_keyboard_entry_redirect_completion(const char *line,
+                                                   void *context)
+{
+  SilcKeyboardEntryRedirectContext ctx = context;
+
+  /*
+   * If we are aborted, then don't call the user routine.  Note that we
+   * already notified the user that they were aborted when the abort
+   * call was made in the first place, so the user should not have any
+   * dangling references at this point.
+   *
+   * Otherwise, call the user routine.
+   */
+  if (!ctx->aborted) {
+    ctx->user_prompt_proc(line, ctx->user_context,
+                         KeyboardCompletionSuccess);
+  }
+
+  /*
+   * If there's a flag to set on completion, such that we can detect when the
+   * operation finished immediately instead of being processed as a callback,
+   * then set that now.
+   */
+  if (ctx->immediate_completion)
+    *ctx->immediate_completion = TRUE;
+
+  /*
+   * Clean up our internal context structures.  Note that we are considered
+   * responsible for handling the SilcAsyncOperation release in this model,
+   * unless we were aborted, in which case the abort request has released it.
+   */
+  if (!ctx->aborted)
+    silc_async_free(ctx->async_context);
+
+  silc_free(ctx);
+
+  /*
+   * Mark us as not having a keyboard prompt pending.
+   */
+  silc_keyboard_prompt_pending = FALSE;
+}
+
+/* Prompt for user input. */
+SilcBool silc_keyboard_entry_redirect(SILC_KEYBOARD_PROMPT_PROC prompt_func,
+                                     const char *entry,
+                                     int flags,
+                                     void *data,
+                                     SilcAsyncOperation *async)
+{
+  SilcKeyboardEntryRedirectContext ctx;
+  SilcBool completed_now;
+
+  /*
+   * Check if we already have a keyboard prompt pending.  This sucks, but
+   * irssi stores the keyboard prompt data in a global, and if we request
+   * a prompt while there is already a prompt in progress, the old prompt
+   * data is leaked.  If irssi gets its act together, this can (and should)
+   * go away.
+   */
+  if (silc_keyboard_prompt_pending) {
+    prompt_func(NULL, data, KeyboardCompletionFailed);
+    return FALSE;
+  }
+
+  /*
+   * Allocate our context blocks.
+   */
+  ctx = (SilcKeyboardEntryRedirectContext)silc_calloc(1, sizeof(*ctx));
+  if (!ctx) {
+    prompt_func(NULL, data, KeyboardCompletionFailed);
+    return FALSE;
+  }
+
+  ctx->async_context = silc_async_alloc(silc_keyboard_entry_redirect_abort,
+                                       NULL, ctx);
+  if (!ctx->async_context) {
+    silc_free(ctx);
+    prompt_func(NULL, data, KeyboardCompletionFailed);
+    return FALSE;
+  }
+
+  /*
+   * Initially, we don't consider ourselves as having finished.
+   */
+  completed_now = FALSE;
+
+  /*
+   * Since irssi can't handle overlapping keyboard prompt requests, block
+   * future requests until we are finished.  N.B. This should really be
+   * handled inside of irssi, but this requires a breaking change to how
+   * keyboard callbacks are processed from an API perspective.  A problem
+   * exists where another user could call a keyboard redirect request
+   * external to silc while we have one pending, and cause ours to get
+   * lost, in which case we will get stuck denying future prompt requests.
+   *
+   * Fortunately, nobody else seems to use keyboard prompt requests, at least
+   * not that I can tell.
+   */
+  silc_keyboard_prompt_pending = TRUE;
+
+  /*
+   * Set up the call to the irssi keyboard entry redirection facility.
+   */
+
+  ctx->user_prompt_proc     = prompt_func;
+  ctx->user_context         = data;
+  ctx->aborted              = FALSE;
+  ctx->immediate_completion = &completed_now;
+
+  keyboard_entry_redirect((SIGNAL_FUNC)silc_keyboard_entry_redirect_completion,
+                         entry, 0, ctx);
+
+  ctx->immediate_completion = NULL;
+
+  /*
+   * If we completed immediately, then there is nothing to return as the async
+   * context has already been released.  In this case we have completed with a
+   * success status, but there is no SilcAsyncOperation context to return.
+   */
+  if (completed_now) {
+    *async = NULL;
+    return TRUE;
+  }
+
+  /*
+   * Otherwise, we must return an async operation context to the caller, and
+   * we must unset the immediate_completion flag as we don't want to be
+   * notified anymore since we're returning out.  Note that this is not safe
+   * if keyboard_entry_redirect can call from a different thread, but we are
+   * assuming that it doesn't as there's already many other things that seem
+   * to make this assumption.
+   */
+  *async = ctx->async_context;
+
+  /*
+   * All done.  Irssi will invoke the callback on this thread at a later point
+   * in time.
+   */
+  return TRUE;
+}
+
 #ifdef SILC_PLUGIN
 void create_key_passphrase(const char *answer, CREATE_KEY_REC *rec)
 {
index 240100a600ed6d9b3c4dfedc82d66d82e7ba4af6..4b925f2f6ea2af84d29c0adfa417686dbe1f16a3 100644 (file)
@@ -4,13 +4,13 @@
 
   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
 
-  Copyright (C) 1997 - 2000 Pekka Riikonen
+  Copyright (C) 1997 - 2000, 2008 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
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
-  
+
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
@@ -31,6 +31,61 @@ void silc_client_list_pkcs();
 int silc_client_check_silc_dir();
 int silc_client_load_keys(SilcClient client);
 
+typedef enum {
+  KeyboardCompletionSuccess, /* Success; keyboard data returned to callback. */
+  KeyboardCompletionAborted, /* Operation was aborted after starting successfully. */
+  KeyboardCompletionFailed /* Operation was not started successfully. */
+} SilcKeyboardPromptStatus;
+
+typedef void (*SILC_KEYBOARD_PROMPT_PROC)(const char *line,
+                                         void *context,
+                                         SilcKeyboardPromptStatus reason);
+
+/*
+ * Prompt for keyboard input.
+ *
+ * If the function returns FALSE, then the prompt operation could not be
+ * initiated and the user supplied callback is called to indicate that the
+ * operation was not started (reason KeyboardCompletionFailed).  This can be
+ * used to centralize all cleanup work in the callback function.
+ *
+ * If the function returns TRUE, then the operation was initiated successfully
+ * and the prompt callback is guaranteed to be called sometime in the future.
+ * Note that it is posssible for the completion callback to have been already
+ * called by the time the function returns TRUE.  In this instance, the
+ * callback will eventually be called with KeyboardCompletionSuccess, unless
+ * the operation is aborted before then.
+ *
+ * If the function returns TRUE, then a SilcAsyncOperation context may be
+ * returned.  If an async operation context is returned, then the operation has
+ * not been completed immediately, and may be canceled with a call to
+ * silc_async_abort(*async).
+ *
+ * Note that the SilcAsyncOperation object's lifetime is managed internally.  A
+ * user may call silc_async_abort exactly once, after which it can never touch
+ * the async context again.  Additionally, the async context may not be
+ * referenced after the user callback returns.  The recommended way to handle
+ * the async operation context is to remove the reference to it when the user
+ * callback is called, either for an abort or regular completion.  If the
+ * callback is called with a KeyboardCompletionFailed reason, then no async
+ * context object was allocated.
+ *
+ * If an abort is requested, then the user callback is called with reason code
+ * KeyboardCompletionAborted.  In this case, the user should clean up all
+ * associated callback data and perform the handling expected in the abort case,
+ * such as the associated server connection going away while the operation was
+ * in progress.
+ *
+ * There can only be one keyboard redirect operation in progress.  If a
+ * keyboard redirect operation is aborted while we are still waiting for data,
+ * then we abort all callbacks until that callback returns.
+ */
+SilcBool silc_keyboard_entry_redirect(SILC_KEYBOARD_PROMPT_PROC prompt_func,
+                                     const char *entry,
+                                     int flags,
+                                     void *data,
+                                     SilcAsyncOperation *async);
+
 #ifdef SILC_PLUGIN
 typedef struct {
   char *old, *passphrase, *file, *pkcs;
index 1c6bb8d979a47376e49d0825e37da818a0292e45..055c6d7247a4df4d17af5379c96848a295408356 100644 (file)
@@ -31,6 +31,7 @@
 #include "rawlog.h"
 #include "misc.h"
 #include "settings.h"
+#include "special-vars.h"
 
 #include "channels-setup.h"
 
@@ -161,6 +162,25 @@ static void sig_server_quit(SILC_SERVER_REC *server, const char *msg)
     silc_command_exec(server, "QUIT", msg);
 }
 
+static void sig_silc_channel_joined(SILC_CHANNEL_REC *channel)
+{
+  CHANNEL_SETUP_REC *rec;
+
+  if (!IS_SILC_CHANNEL(channel))
+    return;
+  if (channel->server && channel->server->disconnected)
+    return;
+  if (channel->session_rejoin)
+    return;
+  
+  rec = channel_setup_find(channel->name, channel->server->connrec->chatnet); 
+
+  if (rec == NULL || rec->autosendcmd == NULL || !*rec->autosendcmd)
+    return;
+
+  eval_special_string(rec->autosendcmd, "", (SERVER_REC*)channel->server, (CHANNEL_REC*)channel);
+}
+
 /* Find Irssi channel entry by SILC channel entry */
 
 SILC_CHANNEL_REC *silc_channel_find_entry(SILC_SERVER_REC *server,
@@ -698,7 +718,7 @@ static void command_key(const char *data, SILC_SERVER_REC *server,
                                            argv[4], argv_lens[4]);
       } else if (type == 2) {
        /* Set private channel key */
-       if (!(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
+       if (!(channel_entry) || !(channel_entry->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
          printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
                             SILCTXT_CH_PRIVATE_KEY_NOMODE,
                             channel_entry->channel_name);
@@ -1261,6 +1281,7 @@ void silc_channels_init(void)
   signal_add("server connected", (SIGNAL_FUNC) sig_connected);
   signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
   signal_add("mime", (SIGNAL_FUNC) sig_mime);
+  signal_add("channel joined", (SIGNAL_FUNC) sig_silc_channel_joined);
 
   command_bind_silc("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
   command_bind_silc("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
@@ -1283,6 +1304,7 @@ void silc_channels_deinit(void)
   signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
   signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
   signal_remove("mime", (SIGNAL_FUNC) sig_mime);
+  signal_remove("channel joined", (SIGNAL_FUNC) sig_silc_channel_joined);
 
   command_unbind("part", (SIGNAL_FUNC) command_part);
   command_unbind("me", (SIGNAL_FUNC) command_me);
index 1e7f75132230b18e746d7825f4ed9b32c89f8883..ec29a2f32df8ffb85509834b69c010520d23139e 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2002 - 2007 Pekka Riikonen
+  Copyright (C) 2002 - 2008 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
 #include "modules.h"
 #include "commands.h"
 #include "misc.h"
+#include "clientutil.h"
 
 #include "fe-common/core/printtext.h"
 #include "fe-common/core/fe-channels.h"
 #include "fe-common/core/keyboard.h"
 #include "fe-common/silc/module-formats.h"
 
-static void silc_query_attributes_print_final(bool success, void *context);
-static void silc_query_attributes_accept(const char *line, void *context);
+static void silc_query_attributes_print_final(SilcBool success, void *context);
+static void silc_query_attributes_accept(const char *line, void *context,
+               SilcKeyboardPromptStatus reason);
 
 QUERY_REC *silc_query_create(const char *server_tag,
                             const char *nick, int automatic)
@@ -68,7 +70,7 @@ void command_attr(const char *data, SILC_SERVER_REC *server,
   SilcUInt32 argc;
   SilcUInt32 *argv_lens, *argv_types;
   const char *sv;
-  bool allowed;
+  SilcBool allowed;
 
   /* Now parse all arguments */
   tmp = g_strconcat("ATTR", " ", data, NULL);
@@ -252,7 +254,7 @@ void silc_query_attributes_default(SilcClient client,
   SilcAttributeObjDevice dev;
   SilcAttributeObjPk pk;
   SilcVCardStruct vcard;
-  bool allowed;
+  SilcBool allowed;
 
   memset(&service, 0, sizeof(service));
   memset(&geo, 0, sizeof(geo));
@@ -557,7 +559,8 @@ typedef struct {
   SilcVCardStruct vcard;
   SilcMime message;
   SilcMime extension;
-  bool nopk;
+  SilcBool nopk;
+  SilcBool autoaccept;
 } *AttrVerify;
 
 void silc_query_attributes_print(SILC_SERVER_REC *server,
@@ -917,7 +920,7 @@ void silc_query_attributes_print(SILC_SERVER_REC *server,
   }
 }
 
-static void silc_query_attributes_print_final(bool success, void *context)
+static void silc_query_attributes_print_final(SilcBool success, void *context)
 {
   AttrVerify verify = context;
   SILC_SERVER_REC *server = verify->server;
@@ -925,6 +928,7 @@ static void silc_query_attributes_print_final(bool success, void *context)
   unsigned char filename[256], *fingerprint = NULL, *tmp;
   struct stat st;
   int i;
+  size_t len;
 
   if (!verify->nopk) {
     if (success) {
@@ -945,7 +949,10 @@ static void silc_query_attributes_print_final(bool success, void *context)
   fingerprint = silc_hash_fingerprint(sha1hash,
                                      verify->userpk.data,
                                      verify->userpk.data_len);
-  for (i = 0; i < strlen(fingerprint); i++)
+
+  len = strlen(fingerprint);
+
+  for (i = 0; i < len; i++)
     if (fingerprint[i] == ' ')
       fingerprint[i] = '_';
 
@@ -959,17 +966,19 @@ static void silc_query_attributes_print_final(bool success, void *context)
     /* Ask to accept save requested attributes */
     format = format_get_text("fe-common/silc", NULL, NULL, NULL,
                             SILCTXT_ATTR_SAVE);
-    keyboard_entry_redirect((SIGNAL_FUNC)silc_query_attributes_accept,
-                           format, 0, verify);
+    silc_keyboard_entry_redirect(silc_query_attributes_accept,
+                           format, 0, verify, &server->prompt_op);
   } else {
     /* Save new data to existing directory */
-    silc_query_attributes_accept("Y", verify);
+    verify->autoaccept = TRUE; /* Ensure we don't twiddle the async context */
+    silc_query_attributes_accept("Y", verify, KeyboardCompletionSuccess);
   }
 
   g_free(format);
 }
 
-static void silc_query_attributes_accept(const char *line, void *context)
+static void silc_query_attributes_accept(const char *line, void *context,
+               SilcKeyboardPromptStatus reason)
 {
   AttrVerify verify = context;
   SILC_SERVER_REC *server = verify->server;
@@ -978,8 +987,9 @@ static void silc_query_attributes_accept(const char *line, void *context)
   unsigned char filename[256], filename2[256], *fingerprint = NULL, *tmp;
   SilcUInt32 len;
   int i;
+  SilcBool success = (reason == KeyboardCompletionSuccess);
 
-  if (line[0] == 'Y' || line[0] == 'y') {
+  if (success && (line[0] == 'Y' || line[0] == 'y')) {
     /* Save the attributes */
     memset(filename, 0, sizeof(filename));
     memset(filename2, 0, sizeof(filename2));
@@ -1066,6 +1076,8 @@ static void silc_query_attributes_accept(const char *line, void *context)
   }
 
  out:
+  if((!verify->autoaccept) && (reason != KeyboardCompletionFailed))
+    verify->server->prompt_op = NULL;
   silc_free(fingerprint);
   silc_free(verify->name);
   silc_vcard_free(&verify->vcard);
index e16fb02cdc056fef1116a982f49259c3bf0d7483..9dd1c8e25030a81b18c99fcef6c70540e3c327fd 100644 (file)
@@ -1,7 +1,7 @@
 /*
   silc-server.c : irssi
 
-  Copyright (C) 2000 - 2007 Timo Sirainen
+  Copyright (C) 2000 - 2008 Timo Sirainen
                             Pekka Riikonen <priikone@silcnet.org>
 
   This program is free software; you can redistribute it and/or modify
@@ -415,6 +415,7 @@ static void sig_connected_stream_created(SilcSocketStreamStatus status,
   params.timeout_secs = settings_get_int("key_exchange_timeout_secs");
   params.rekey_secs = settings_get_int("key_exchange_rekey_secs");
   params.pfs = settings_get_bool("key_exchange_rekey_pfs");
+  params.context = server;
 
   /* Try to read detached session data and use it if found. */
   file = silc_get_session_filename(server);
@@ -466,6 +467,12 @@ static void sig_disconnected(SILC_SERVER_REC *server)
   if (!IS_SILC_SERVER(server))
     return;
 
+  /* If we have a prompt in progress, then abort it. */
+  if (server->prompt_op) {
+    silc_async_abort(server->prompt_op, NULL, NULL);
+    server->prompt_op = NULL;
+  }
+
   if (server->conn) {
     /* Close connection */
     silc_client_close_connection(silc_client, server->conn);
index efde07e6efeb7735a117f2864b39b54114a11cfa..a638b1627ee721f394ac96755a5c4e40d1bb98b0 100644 (file)
@@ -46,6 +46,7 @@ typedef struct {
   SilcClientConnection conn;
   SilcAsyncOperation op;       /* Key exchange operation handle */
   SilcAsyncOperation tcp_op;   /* TCP stream creation operation handle */
+  SilcAsyncOperation prompt_op; /* Key verification operation handle */
   SilcUInt32 umode;
 } SILC_SERVER_REC;
 
index 73424a68988fe7b2016030d9c8de39bb8f33b7a9..ab174e4f5d000140e18aac2b179e83316b0c2675 100644 (file)
@@ -326,6 +326,7 @@ static void silc_server_notify_process(SilcServer server,
       tmp_len = 128;
 
     /* Update statistics */
+    SILC_VERIFY(server->stat.clients > 0);
     server->stat.clients--;
     if (server->stat.cell_clients)
       server->stat.cell_clients--;
@@ -1245,6 +1246,7 @@ static void silc_server_notify_process(SilcServer server,
            }
 
            /* Update statistics */
+           SILC_VERIFY(server->stat.clients > 0);
            server->stat.clients--;
            if (server->stat.cell_clients)
              server->stat.cell_clients--;
@@ -1490,6 +1492,7 @@ static void silc_server_notify_process(SilcServer server,
       }
 
       /* Update statistics */
+      SILC_VERIFY(server->stat.clients > 0);
       server->stat.clients--;
       if (server->stat.cell_clients)
        server->stat.cell_clients--;
@@ -3733,6 +3736,7 @@ void silc_server_resume_client(SilcServer server,
 
     /* Delete this current client entry since we're resuming to old one. */
     server->stat.my_clients--;
+    SILC_VERIFY(server->stat.clients > 0);
     server->stat.clients--;
     if (server->stat.cell_clients)
       server->stat.cell_clients--;
index 0e1cffb084ddac0918c65e38d35bcd17a0e4c0ef..c9825e008959d76a531aa30356dc2e8ddd830551 100644 (file)
@@ -1798,6 +1798,8 @@ void silc_server_start_key_exchange(SilcServerConnection sconn)
   }
   entry->server = server;
   entry->data.sconn = sconn;
+  entry->data.conn_type = SILC_CONN_UNKNOWN;
+  entry->data.status |= SILC_IDLIST_STATUS_LOCAL;
   silc_packet_set_context(sconn->sock, entry);
 
   SILC_LOG_DEBUG(("Created unknown connection %p", entry));
@@ -3129,6 +3131,7 @@ void silc_server_free_client_data(SilcServer server,
 
   /* Update statistics */
   server->stat.my_clients--;
+  SILC_VERIFY(server->stat.clients > 0);
   server->stat.clients--;
   if (server->stat.cell_clients)
     server->stat.cell_clients--;
index e6b916ec7a1431dafc0ba2d1547488f9502cea92..fd948ffe02c0158fb8f840fb5339d3a5657f5c8e 100644 (file)
@@ -236,6 +236,7 @@ do {                                                \
 SILC_TASK_CALLBACK(silc_server_rekey_final);
 SILC_TASK_CALLBACK(silc_server_rekey_callback);
 SILC_TASK_CALLBACK(silc_server_connect_to_router);
+SILC_TASK_CALLBACK(silc_server_connect_to_router_retry);
 void silc_server_watcher_list_destroy(void *key, void *context,
                                      void *user_context);
 
index 74ce18ba2902866107148517f3f961fe645dd714..9bcc47b20377b5c8c5acd8a0152dce1ca08d1656 100644 (file)
@@ -119,7 +119,7 @@ silc_server_remove_clients_channels(SilcServer server,
       silc_hash_table_add(channels, channel, channel);
   }
   silc_hash_table_list_reset(&htl);
-  assert(!silc_hash_table_count(client->channels));
+  SILC_VERIFY(!silc_hash_table_count(client->channels));
 }
 
 /* This function removes all client entries that are originated from
@@ -205,6 +205,7 @@ SilcBool silc_server_remove_clients_by_server(SilcServer server,
       }
 
       /* Update statistics */
+      SILC_VERIFY(server->stat.clients > 0);
       server->stat.clients--;
       if (server->stat.cell_clients)
        server->stat.cell_clients--;
@@ -268,6 +269,7 @@ SilcBool silc_server_remove_clients_by_server(SilcServer server,
       }
 
       /* Update statistics */
+      SILC_VERIFY(server->stat.clients > 0);
       server->stat.clients--;
       if (server->stat.cell_clients)
        server->stat.cell_clients--;
@@ -1560,6 +1562,7 @@ void silc_server_kill_client(SilcServer server,
     }
   } else {
     /* Update statistics */
+    SILC_VERIFY(server->stat.clients > 0);
     server->stat.clients--;
     if (server->stat.cell_clients)
       server->stat.cell_clients--;
@@ -2018,6 +2021,8 @@ void silc_server_inviteban_destruct(void *key, void *context,
 
 void silc_server_create_connections(SilcServer server)
 {
+  silc_schedule_task_del_by_callback(server->schedule,
+                                    silc_server_connect_to_router_retry);
   silc_schedule_task_del_by_callback(server->schedule,
                                     silc_server_connect_to_router);
   silc_schedule_task_add_timeout(server->schedule,
index 6f381c7b2729719b478a88f2848b0f474669f281..7badb52e48c1ec07d9452435b5f7a075d3a02e81 100644 (file)
@@ -88,8 +88,8 @@ LIBSILC_REVISION=0            # prev = 1
 LIBSILC_AGE=1                  # prev = 1
 
 # libsilcclient versions
-LIBSILCCLIENT_CURRENT=2                # prev = 1
-LIBSILCCLIENT_REVISION=1       # prev = 1
+LIBSILCCLIENT_CURRENT=3                # prev = 2
+LIBSILCCLIENT_REVISION=0       # prev = 1
 LIBSILCCLIENT_AGE=0            # prev = 0
 
 # libsilcserver versions
index 3ab7ba17b4aa96fc872496dce38c17ae078227d7..2c731ebd78bdccb4add462821898156b7d798e6b 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2007 Pekka Riikonen
+  Copyright (C) 1997 - 2008 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
@@ -621,8 +621,10 @@ silc_client_add_connection(SilcClient client,
   }
 
   /* Set parameters */
-  if (params)
+  if (params) {
     conn->internal->params = *params;
+    conn->context = params->context;
+  }
   if (!conn->internal->params.rekey_secs)
     conn->internal->params.rekey_secs = 3600;
 #ifndef SILC_DIST_INPLACE
index d66808dcef168e06473e7168104b18f97430ce43..8c9895531c107ba906a4af6c2cd4e20adba61550 100644 (file)
@@ -101,6 +101,9 @@ typedef struct SilcServerEntryInternalStruct {
   SilcRwLock lock;                          /* Read/write lock */
   SilcUInt16 resolve_cmd_ident;                     /* Resolving identifier */
   SilcAtomic32 refcnt;                      /* Reference counter */
+  SilcAtomic32 deleted;                             /* Flag indicating whether the
+                                               server object is already
+                                               scheduled for deletion. */
 } SilcServerEntryInternal;
 
 #endif /* CLIENT_H */
index 4664dbaa75f770446b457b8b7d830b67cab2d524..a7ec24ee2701801ad02b235fe6c773a54bc37149 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2001 - 2007 Pekka Riikonen
+  Copyright (C) 2001 - 2008 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
@@ -815,6 +815,9 @@ SilcClientEntry silc_client_add_client(SilcClient client,
                                                 NULL, NULL, NULL, TRUE);
   if (!client_entry->channels) {
     silc_free(client_entry->realname);
+    silc_atomic_uninit32(&client_entry->internal.deleted);
+    silc_atomic_uninit32(&client_entry->internal.refcnt);
+    silc_rwlock_free(client_entry->internal.lock);
     silc_free(client_entry);
     return NULL;
   }
@@ -824,8 +827,11 @@ SilcClientEntry silc_client_add_client(SilcClient client,
     nick = silc_identifier_check(parsed, strlen(parsed),
                                 SILC_STRING_UTF8, 128, NULL);
     if (!nick) {
-      silc_free(client_entry->realname);
       silc_hash_table_free(client_entry->channels);
+      silc_free(client_entry->realname);
+      silc_atomic_uninit32(&client_entry->internal.deleted);
+      silc_atomic_uninit32(&client_entry->internal.refcnt);
+      silc_rwlock_free(client_entry->internal.lock);
       silc_free(client_entry);
       return NULL;
     }
@@ -837,8 +843,11 @@ SilcClientEntry silc_client_add_client(SilcClient client,
   if (!silc_idcache_add(conn->internal->client_cache, nick,
                        &client_entry->id, client_entry)) {
     silc_free(nick);
-    silc_free(client_entry->realname);
     silc_hash_table_free(client_entry->channels);
+    silc_free(client_entry->realname);
+    silc_atomic_uninit32(&client_entry->internal.deleted);
+    silc_atomic_uninit32(&client_entry->internal.refcnt);
+    silc_rwlock_free(client_entry->internal.lock);
     silc_free(client_entry);
     silc_mutex_unlock(conn->internal->lock);
     return NULL;
@@ -1652,6 +1661,7 @@ SilcChannelEntry silc_client_add_channel(SilcClient client,
   if (!channel->channel_name) {
     silc_rwlock_free(channel->internal.lock);
     silc_atomic_uninit32(&channel->internal.refcnt);
+    silc_atomic_uninit32(&channel->internal.deleted);
     silc_free(channel);
     return NULL;
   }
@@ -1661,6 +1671,7 @@ SilcChannelEntry silc_client_add_channel(SilcClient client,
   if (!channel->user_list) {
     silc_rwlock_free(channel->internal.lock);
     silc_atomic_uninit32(&channel->internal.refcnt);
+    silc_atomic_uninit32(&channel->internal.deleted);
     silc_free(channel->channel_name);
     silc_free(channel);
     return NULL;
@@ -1672,6 +1683,7 @@ SilcChannelEntry silc_client_add_channel(SilcClient client,
   if (!channel_namec) {
     silc_rwlock_free(channel->internal.lock);
     silc_atomic_uninit32(&channel->internal.refcnt);
+    silc_atomic_uninit32(&channel->internal.deleted);
     silc_free(channel->channel_name);
     silc_hash_table_free(channel->user_list);
     silc_free(channel);
@@ -1685,6 +1697,7 @@ SilcChannelEntry silc_client_add_channel(SilcClient client,
                        &channel->id, channel)) {
     silc_rwlock_free(channel->internal.lock);
     silc_atomic_uninit32(&channel->internal.refcnt);
+    silc_atomic_uninit32(&channel->internal.deleted);
     silc_free(channel_namec);
     silc_free(channel->channel_name);
     silc_hash_table_free(channel->user_list);
@@ -2081,6 +2094,7 @@ SilcServerEntry silc_client_add_server(SilcClient client,
 
   silc_rwlock_alloc(&server_entry->internal.lock);
   silc_atomic_init32(&server_entry->internal.refcnt, 0);
+  silc_atomic_init32(&server_entry->internal.deleted, 1);
   server_entry->id = *server_id;
   if (server_name)
     server_entry->server_name = strdup(server_name);
@@ -2094,6 +2108,9 @@ SilcServerEntry silc_client_add_server(SilcClient client,
     if (!server_namec) {
       silc_free(server_entry->server_name);
       silc_free(server_entry->server_info);
+      silc_atomic_uninit32(&server_entry->internal.deleted);
+      silc_atomic_uninit32(&server_entry->internal.refcnt);
+      silc_rwlock_free(server_entry->internal.lock);
       silc_free(server_entry);
       return NULL;
     }
@@ -2107,6 +2124,9 @@ SilcServerEntry silc_client_add_server(SilcClient client,
     silc_free(server_namec);
     silc_free(server_entry->server_name);
     silc_free(server_entry->server_info);
+    silc_atomic_uninit32(&server_entry->internal.deleted);
+    silc_atomic_uninit32(&server_entry->internal.refcnt);
+    silc_rwlock_free(server_entry->internal.lock);
     silc_free(server_entry);
     silc_mutex_unlock(conn->internal->lock);
     return NULL;
@@ -2125,37 +2145,14 @@ SilcServerEntry silc_client_add_server(SilcClient client,
 SilcBool silc_client_del_server(SilcClient client, SilcClientConnection conn,
                                SilcServerEntry server)
 {
-  SilcIDCacheEntry id_cache;
-  SilcBool ret = TRUE;
-  char *namec;
-
   if (!server)
     return FALSE;
 
-  if (silc_atomic_sub_int32(&server->internal.refcnt, 1) > 0)
+  if (silc_atomic_sub_int32(&server->internal.deleted, 1) != 0)
     return FALSE;
 
-  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)) {
-    namec = id_cache->name;
-    ret = silc_idcache_del_by_context(conn->internal->server_cache,
-                                     server, NULL);
-    silc_free(namec);
-  }
-  silc_mutex_unlock(conn->internal->lock);
-
-  silc_free(server->server_name);
-  silc_free(server->server_info);
-  if (server->public_key)
-    silc_pkcs_public_key_free(server->public_key);
-  silc_atomic_uninit32(&server->internal.refcnt);
-  silc_rwlock_free(server->internal.lock);
-  silc_free(server);
-
-  return ret;
+  silc_client_unref_server(client, conn, server);
+  return TRUE;
 }
 
 /* Updates the `server_entry' with the new information sent as argument. */
@@ -2231,13 +2228,36 @@ SilcServerEntry silc_client_ref_server(SilcClient client,
 void silc_client_unref_server(SilcClient client, SilcClientConnection conn,
                              SilcServerEntry server_entry)
 {
-  if (server_entry) {
-    SILC_LOG_DEBUG(("Server %p refcnt %d->%d", server_entry,
-                   silc_atomic_get_int32(&server_entry->internal.refcnt),
-                   silc_atomic_get_int32(&server_entry->internal.refcnt)
-                   - 1));
-    silc_client_del_server(client, conn, server_entry);
+  SilcBool ret;
+  SilcIDCacheEntry id_cache;
+  char *namec;
+
+  if (!server_entry)
+    return;
+
+  if (silc_atomic_sub_int32(&server_entry->internal.refcnt, 1) > 0)
+    return;
+
+  SILC_LOG_DEBUG(("Deleting server %p", server_entry));
+
+  silc_mutex_lock(conn->internal->lock);
+  if (silc_idcache_find_by_context(conn->internal->server_cache, server_entry,
+                                  &id_cache)) {
+    namec = id_cache->name;
+    ret = silc_idcache_del_by_context(conn->internal->server_cache,
+                                     server_entry, NULL);
+    silc_free(namec);
   }
+  silc_mutex_unlock(conn->internal->lock);
+
+  silc_free(server_entry->server_name);
+  silc_free(server_entry->server_info);
+  if (server_entry->public_key)
+    silc_pkcs_public_key_free(server_entry->public_key);
+  silc_atomic_uninit32(&server_entry->internal.deleted);
+  silc_atomic_uninit32(&server_entry->internal.refcnt);
+  silc_rwlock_free(server_entry->internal.lock);
+  silc_free(server_entry);
 }
 
 /* Free server entry list */
index 898204a18f46663a571c0c38202d924fb9d3f089..00d0b5e58fbca0458059a82ae3f8db50a2271615 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2000 - 2007 Pekka Riikonen
+  Copyright (C) 2000 - 2008 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
@@ -943,6 +943,10 @@ typedef struct SilcClientConnectionParamsStruct {
      silc_client_attribute_add for more information on attributes. */
   SilcBool ignore_requested_attributes;
 
+  /* User context for SilcClientConnection.  If non-NULL this context is
+     set to the 'context' field in SilcClientConnection when the connection
+     context is created. */
+  void *context;
 } SilcClientConnectionParams;
 /***/
 
index bac8a5c4fac9b8feb642da88c272092fa4a1ccb3..a4822e95a505a8cb709d6d63bfb0f4eabf9e8f0f 100644 (file)
@@ -73,6 +73,41 @@ static SilcBool silc_ske_packet_send(SilcSKE ske,
                                     const unsigned char *data,
                                     SilcUInt32 data_len);
 
+/*
+ * Notify the owner of the ske that we failed.  Ensures that we don't make the
+ * same callout twice, as the notification callback routines are not designed
+ * to handle that case.
+ */
+static void silc_ske_notify_failure(SilcSKE ske)
+{
+  SILC_LOG_DEBUG(("Notifying SKE %p owner of failure (failure_notified = %lu)",
+                 ske, ske->failure_notified));
+
+  /*
+   * First, check if we have already made a failure callout.  If so, then we
+   * will stop here.
+   */
+  if (ske->failure_notified)
+    return;
+
+  /*
+   * Mark ourselves as having already sent the failure notification here and
+   * now.
+   */
+  ske->failure_notified = TRUE;
+
+  SILC_LOG_DEBUG(("Deliver failure notification for SKE %p (%s)",
+                 ske, ske->responder ? "responder" : "initiator"));
+
+  /*
+   * Finally, make the call to the owner's registered failure callback.
+   */
+  if (ske->responder)
+    silc_fsm_next(&ske->fsm, silc_ske_st_responder_failure);
+  else
+    silc_fsm_next(&ske->fsm, silc_ske_st_initiator_failure);
+}
+
 /* Packet callback */
 
 static SilcBool silc_ske_packet_receive(SilcPacketEngine engine,
@@ -107,12 +142,8 @@ static SilcBool silc_ske_packet_receive(SilcPacketEngine engine,
   }
 
   /* See if received failure from remote */
-  if (packet->type == SILC_PACKET_FAILURE) {
-    if (ske->responder)
-      silc_fsm_next(&ske->fsm, silc_ske_st_responder_failure);
-    else
-      silc_fsm_next(&ske->fsm, silc_ske_st_initiator_failure);
-  }
+  if (packet->type == SILC_PACKET_FAILURE)
+    silc_ske_notify_failure(ske);
 
   /* Handle rekey and SUCCESS packets synchronously.  After SUCCESS packets
      they keys are taken into use immediately, hence the synchronous
@@ -895,10 +926,7 @@ SILC_TASK_CALLBACK(silc_ske_packet_send_retry)
     silc_free(ske->retrans.data);
     ske->retrans.data = NULL;
     ske->status = SILC_SKE_STATUS_TIMEOUT;
-    if (ske->responder)
-      silc_fsm_next(&ske->fsm, silc_ske_st_responder_failure);
-    else
-      silc_fsm_next(&ske->fsm, silc_ske_st_initiator_failure);
+        silc_ske_notify_failure(ske);
     silc_fsm_continue_sync(&ske->fsm);
     return;
   }
@@ -957,7 +985,7 @@ static SilcBool silc_ske_packet_send(SilcSKE ske,
 static void silc_ske_completion(SilcSKE ske)
 {
   /* Call the completion callback */
-  if (!ske->freed && !ske->aborted && ske->callbacks->completed) {
+  if (!ske->aborted && ske->callbacks->completed) {
     if (ske->status != SILC_SKE_STATUS_OK)
       ske->callbacks->completed(ske, ske->status, NULL, NULL, NULL,
                                ske->callbacks->context);
@@ -973,9 +1001,7 @@ static void silc_ske_finished(SilcFSM fsm, void *fsm_context,
                              void *destructor_context)
 {
   SilcSKE ske = fsm_context;
-  ske->running = FALSE;
-  if (ske->freed)
-    silc_ske_free(ske);
+  silc_ske_free(ske);
 }
 
 /* Key exchange timeout task callback */
@@ -988,10 +1014,7 @@ SILC_TASK_CALLBACK(silc_ske_timeout)
 
   ske->packet = NULL;
   ske->status = SILC_SKE_STATUS_TIMEOUT;
-  if (ske->responder)
-    silc_fsm_next(&ske->fsm, silc_ske_st_responder_failure);
-  else
-    silc_fsm_next(&ske->fsm, silc_ske_st_initiator_failure);
+  silc_ske_notify_failure(ske);
 
   silc_fsm_continue_sync(&ske->fsm);
 }
@@ -1036,25 +1059,30 @@ SilcSKE silc_ske_alloc(SilcRng rng, SilcSchedule schedule,
 
 void silc_ske_free(SilcSKE ske)
 {
-  SILC_LOG_DEBUG(("Freeing Key Exchange object"));
-
   if (!ske)
     return;
 
-  if (ske->running) {
-    ske->freed = TRUE;
+  SILC_LOG_DEBUG(("Freeing Key Exchange object %p: aborted=%u refcount=%hu",
+                 ske, ske->aborted, ske->refcnt));
 
-    if (ske->aborted) {
-      /* If already aborted, destroy the session immediately */
-      ske->packet = NULL;
-      ske->status = SILC_SKE_STATUS_ERROR;
-      if (ske->responder)
-       silc_fsm_next(&ske->fsm, silc_ske_st_responder_failure);
-      else
-       silc_fsm_next(&ske->fsm, silc_ske_st_initiator_failure);
+  if (ske->aborted) {
+    /*
+     * If already aborted, destroy the session immediately.  Only do the
+     * notification work if we have not already though, as doing so twice
+     * results in memory corruption.  We may have silc_ske_free called
+     * twice, once when the abort is requested, and then again when the
+     * FSM finish routine is called.  We have to be prepared to handle
+     * that case.
+     */
+    ske->packet         = NULL;
+    ske->status         = SILC_SKE_STATUS_ERROR;
+
+    silc_ske_notify_failure(ske);
+
+    if (silc_fsm_is_started(&ske->fsm))
       silc_fsm_continue_sync(&ske->fsm);
-    }
-    return;
+    else
+      SILC_LOG_DEBUG(("Not continuing FSM as it's finished for SKE %p", ske));
   }
 
   ske->refcnt--;
@@ -1102,7 +1130,7 @@ void silc_ske_free(SilcSKE ske)
   silc_free(ske->hash);
   silc_free(ske->callbacks);
 
-  memset(ske, 'F', sizeof(*ske));
+  memset(ske, 0xdd, sizeof(*ske));
   silc_free(ske);
 }
 
@@ -1805,7 +1833,8 @@ SilcAsyncOperation silc_ske_initiator(SilcSKE ske,
                                      SilcSKEParams params,
                                      SilcSKEStartPayload start_payload)
 {
-  SILC_LOG_DEBUG(("Start SKE as initiator"));
+  SILC_LOG_DEBUG(("Start SKE %p as initiator; stream=%p; params=%p; "
+                 "start_payload=%p", ske, stream, params, start_payload));
 
   if (!ske || !stream || !params || !params->version)
     return NULL;
@@ -1831,7 +1860,7 @@ SilcAsyncOperation silc_ske_initiator(SilcSKE ske,
   ske->timeout = params->timeout_secs ? params->timeout_secs : 30;
   ske->start_payload = start_payload;
   ske->version = params->version;
-  ske->running = TRUE;
+  ++ ske->refcnt;
 
   /* Link to packet stream to get key exchange packets */
   ske->stream = stream;
@@ -2418,7 +2447,7 @@ SilcAsyncOperation silc_ske_responder(SilcSKE ske,
   ske->version = params->version;
   if (!ske->version)
     return NULL;
-  ske->running = TRUE;
+  ++ ske->refcnt;
 
   /* Link to packet stream to get key exchange packets */
   ske->stream = stream;
@@ -2676,8 +2705,8 @@ silc_ske_rekey_initiator(SilcSKE ske,
 
   ske->rekey = rekey;
   ske->responder = FALSE;
-  ske->running = TRUE;
   ske->rekeying = TRUE;
+  ++ ske->refcnt;
 
   /* Link to packet stream to get key exchange packets */
   ske->stream = stream;
@@ -2953,9 +2982,9 @@ silc_ske_rekey_responder(SilcSKE ske,
 
   ske->rekey = rekey;
   ske->responder = TRUE;
-  ske->running = TRUE;
   ske->rekeying = TRUE;
   ske->packet = packet;
+  ++ ske->refcnt;
 
   /* Link to packet stream to get key exchange packets */
   ske->stream = stream;
index 051324550b66727f0f413281fae1b8466df22b40..b7b6e2e76157315174ed1e609b838f1728efbd17 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2005 - 2007 Pekka Riikonen
+  Copyright (C) 2005 - 2008 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
@@ -90,11 +90,11 @@ struct SilcSKEStruct {
   SilcUInt16 timeout;                /* SKE timeout */
   SilcUInt16 refcnt;                 /* Reference counter */
 
-  unsigned int aborted    : 1;        /* Set when SKE aborted */
-  unsigned int freed      : 1;       /* Set when freed during session */
-  unsigned int responder  : 1;       /* Set when we are responder side */
-  unsigned int running    : 1;       /* Set when SKE is running */
-  unsigned int rekeying   : 1;       /* Set when rekeying */
+  unsigned int aborted          : 1;  /* Set when SKE aborted */
+  unsigned int responder        : 1;  /* Set when we are responder side */
+  unsigned int rekeying         : 1;  /* Set when rekeying */
+  unsigned int failure_notified : 1;  /* Set to indicate that we already called
+                                        the failure notify routine */
 };
 
 #endif /* SILCSKE_I_H */