More client library rewrites (added rekey)
authorPekka Riikonen <priikone@silcnet.org>
Mon, 11 Dec 2006 15:42:26 +0000 (15:42 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Mon, 11 Dec 2006 15:42:26 +0000 (15:42 +0000)
14 files changed:
lib/silcclient/Makefile.ad
lib/silcclient/client.c
lib/silcclient/client_channel.c
lib/silcclient/client_connect.c
lib/silcclient/client_connect.h
lib/silcclient/client_entry.c
lib/silcclient/client_internal.h
lib/silcclient/client_notify.c
lib/silcclient/client_prvmsg.c
lib/silcclient/client_register.c
lib/silcclient/client_register.h
lib/silcclient/command.c
lib/silcclient/command_reply.c
lib/silcclient/silcclient.h

index 58912a132221333f26b591b03a76d8514692fc87..da702bbabb49c1a95895bae188d97dc59f49f505 100644 (file)
@@ -39,6 +39,6 @@ include_HEADERS=      \
 SILC_EXTRA_DIST = client_ops_example.c
 #endif SILC_DIST_TOOLKIT
 
-EXTRA_DIST = *.h $(SILC_EXTRA_DIST)
+EXTRA_DIST = *.h tests $(SILC_EXTRA_DIST)
 
 include $(top_srcdir)/Makefile.defines.in
index 9354d28d6c6e3b641a94dc0fe396cb2dd2477e4c..dd9797449ed5677a05f925d392b624fa2ef524c9 100644 (file)
@@ -78,7 +78,6 @@ static SilcBool silc_client_packet_receive(SilcPacketEngine engine,
   case SILC_PACKET_KEY_EXCHANGE:
   case SILC_PACKET_KEY_EXCHANGE_1:
   case SILC_PACKET_KEY_EXCHANGE_2:
-  case SILC_PACKET_REKEY:
   case SILC_PACKET_REKEY_DONE:
   case SILC_PACKET_CONNECTION_AUTH:
   case SILC_PACKET_CONNECTION_AUTH_REQUEST:
@@ -113,7 +112,20 @@ static void silc_client_packet_eos(SilcPacketEngine engine,
                                   void *callback_context,
                                   void *stream_context)
 {
-  SILC_LOG_DEBUG(("End of stream received"));
+  SilcClientConnection conn = stream_context;
+  SilcClient client = conn->client;
+
+  SILC_LOG_DEBUG(("Remote disconnected connection"));
+
+  /* Call connection callback */
+  conn->callback(client, conn, SILC_CLIENT_CONN_DISCONNECTED, 0, NULL,
+                conn->callback_context);
+
+  /* Signal to close connection */
+  if (!conn->internal->disconnected) {
+    conn->internal->disconnected = TRUE;
+    SILC_FSM_SEMA_POST(&conn->internal->wait_event);
+  }
 }
 
 /* Packet engine callback to indicate error */
@@ -124,7 +136,7 @@ static void silc_client_packet_error(SilcPacketEngine engine,
                                     void *callback_context,
                                     void *stream_context)
 {
-
+  /* Nothing */
 }
 
 /* Packet stream callbacks */
@@ -211,6 +223,17 @@ SILC_FSM_STATE(silc_client_connection_st_run)
     return SILC_FSM_CONTINUE;
   }
 
+  if (conn->internal->rekeying) {
+    SILC_LOG_DEBUG(("Event: rekey"));
+    conn->internal->rekeying = FALSE;
+
+    /*** Event: rekey */
+    silc_fsm_thread_init(thread, &conn->internal->fsm, conn,
+                        NULL, NULL, FALSE);
+    silc_fsm_start_sync(thread, silc_client_st_rekey);
+    return SILC_FSM_CONTINUE;
+  }
+
   if (conn->internal->disconnected) {
     /** Event: disconnected */
     SILC_LOG_DEBUG(("Event: disconnected"));
@@ -229,6 +252,7 @@ SILC_FSM_STATE(silc_client_connection_st_run)
 
 SILC_FSM_STATE(silc_client_connection_st_packet)
 {
+  SilcClientConnection conn = fsm_context;
   SilcPacket packet = state_context;
 
   SILC_LOG_DEBUG(("Parsing %s packet", silc_get_packet_name(packet->type)));
@@ -301,6 +325,16 @@ SILC_FSM_STATE(silc_client_connection_st_packet)
     //    silc_client_connection_auth_request(client, conn, packet);
     break;
 
+  case SILC_PACKET_REKEY:
+    /* Signal to start rekey */
+    conn->internal->rekey_responder = TRUE;
+    conn->internal->rekeying = TRUE;
+    SILC_FSM_SEMA_POST(&conn->internal->wait_event);
+
+    silc_packet_free(packet);
+    return SILC_FSM_FINISH;
+    break;
+
   default:
     silc_packet_free(packet);
     return SILC_FSM_FINISH;
@@ -471,8 +505,17 @@ silc_client_add_connection(SilcClient client,
     silc_free(conn->internal);
     return NULL;
   }
+
+  /* Set parameters */
   if (params)
     conn->internal->params = *params;
+  if (!conn->internal->params.rekey_secs)
+    conn->internal->params.rekey_secs = 3600;
+#ifndef SILC_DIST_INPLACE
+  if (conn->internal->params.rekey_secs < 300)
+    conn->internal->params.rekey_secs = 300;
+#endif /* SILC_DIST_INPLACE */
+
   conn->internal->verbose = TRUE;
   silc_list_init(conn->internal->pending_commands,
                 struct SilcClientCommandContextStruct, next);
@@ -503,6 +546,8 @@ silc_client_add_connection(SilcClient client,
   }
   silc_fsm_start(thread, silc_client_connection_st_start);
 
+  SILC_LOG_DEBUG(("New connection %p", conn));
+
   return conn;
 }
 
@@ -518,21 +563,25 @@ void silc_client_del_connection(SilcClient client, SilcClientConnection conn)
 
   SILC_LOG_DEBUG(("Freeing connection %p", conn));
 
+  silc_schedule_task_del_by_context(conn->internal->schedule, conn);
+
   /* Free all cache entries */
-  if (silc_idcache_get_all(conn->internal->client_cache, &list)) {
+  if (silc_idcache_get_all(conn->internal->server_cache, &list)) {
     silc_list_start(list);
     while ((entry = silc_list_get(list)))
-      silc_client_del_client(client, conn, entry->context);
+      silc_client_del_server(client, conn, entry->context);
   }
   if (silc_idcache_get_all(conn->internal->channel_cache, &list)) {
     silc_list_start(list);
-    while ((entry = silc_list_get(list)))
+    while ((entry = silc_list_get(list))) {
+      silc_client_empty_channel(client, conn, entry->context);
       silc_client_del_channel(client, conn, entry->context);
+    }
   }
-  if (silc_idcache_get_all(conn->internal->server_cache, &list)) {
+  if (silc_idcache_get_all(conn->internal->client_cache, &list)) {
     silc_list_start(list);
     while ((entry = silc_list_get(list)))
-      silc_client_del_server(client, conn, entry->context);
+      silc_client_del_client(client, conn, entry->context);
   }
 
   /* Free ID caches */
@@ -801,8 +850,6 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
 
   silc_protocol_free(protocol);
   silc_free(ctx->auth_data);
-  if (ctx->ske)
-    silc_ske_free(ctx->ske);
   silc_socket_free(ctx->sock);
   silc_free(ctx);
   conn->sock->protocol = NULL;
@@ -812,8 +859,6 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
   silc_protocol_free(protocol);
   silc_free(ctx->auth_data);
   silc_free(ctx->dest_id);
-  if (ctx->ske)
-    silc_ske_free(ctx->ske);
   conn->sock->protocol = NULL;
   silc_socket_free(ctx->sock);
 
@@ -993,9 +1038,6 @@ SilcClient silc_client_alloc(SilcClientOperations *ops,
   if (params)
     memcpy(new_client->internal->params, params, sizeof(*params));
 
-  if (!new_client->internal->params->rekey_secs)
-    new_client->internal->params->rekey_secs = 3600;
-
   if (!new_client->internal->params->connauth_request_secs)
     new_client->internal->params->connauth_request_secs = 2;
 
index 28cc6147099f53b100bb654e1ef5af0a11bfb30a..c7a414463b3a809940a60ba9c1062a8e1b4c4737 100644 (file)
@@ -763,6 +763,4 @@ void silc_client_empty_channel(SilcClient client,
     silc_free(chu);
   }
   silc_hash_table_list_reset(&htl);
-
-  silc_hash_table_free(channel->user_list);
 }
index 7c50d2b9e199b549364c65f9b6ef336e1fa16b2d..98b4372f3a698bb71f0a1e0ea255fa37b1a8d036 100644 (file)
@@ -21,8 +21,6 @@
 #include "silcclient.h"
 #include "client_internal.h"
 
-/************************** Types and definitions ***************************/
-
 /************************ Static utility functions **************************/
 
 /* Callback called after connected to remote host */
@@ -178,6 +176,8 @@ static void silc_client_ke_completion(SilcSKE ske,
                                 conn->remote_host,
                                 silc_ske_map_status(status));
 
+    silc_ske_free_rekey_material(rekey);
+
     silc_fsm_next(fsm, silc_client_st_connect_error);
     SILC_FSM_CALL_CONTINUE(fsm);
     return;
@@ -185,7 +185,7 @@ static void silc_client_ke_completion(SilcSKE ske,
 
   SILC_LOG_DEBUG(("Setting keys into use"));
 
-  /* Set the keys into use.  Data will be encrypted after this. */
+  /* Allocate the cipher and HMAC contexts */
   if (!silc_ske_set_keys(ske, keymat, prop, &send_key, &receive_key,
                         &hmac_send, &hmac_receive, &conn->internal->hash)) {
     /* Error setting keys */
@@ -200,20 +200,82 @@ static void silc_client_ke_completion(SilcSKE ske,
     conn->callback(client, conn, SILC_CLIENT_CONN_ERROR_KE, 0, NULL,
                   conn->callback_context);
 
+    silc_ske_free_rekey_material(rekey);
+
     silc_fsm_next(fsm, silc_client_st_connect_error);
     SILC_FSM_CALL_CONTINUE(fsm);
     return;
   }
 
-  silc_packet_set_ciphers(conn->stream, send_key, receive_key);
-  silc_packet_set_hmacs(conn->stream, hmac_send, hmac_receive);
+  /* Set the keys into the packet stream.  After this call packets will be
+     encrypted with these keys. */
+  if (!silc_packet_set_keys(conn->stream, send_key, receive_key, hmac_send,
+                           hmac_receive, FALSE)) {
+    /* Error setting keys */
+    SILC_LOG_DEBUG(("Could not set keys into use"));
+
+    if (conn->internal->verbose)
+      client->internal->ops->say(
+                      client, conn, SILC_CLIENT_MESSAGE_ERROR,
+                      "Error during key exchange with %s: cannot use keys",
+                      conn->remote_host);
+
+    conn->callback(client, conn, SILC_CLIENT_CONN_ERROR_KE, 0, NULL,
+                  conn->callback_context);
+
+    silc_ske_free_rekey_material(rekey);
+
+    silc_fsm_next(fsm, silc_client_st_connect_error);
+    SILC_FSM_CALL_CONTINUE(fsm);
+    return;
+  }
 
   conn->internal->rekey = rekey;
 
+  SILC_LOG_DEBUG(("Key Exchange completed"));
+
   /* Key exchange done */
   SILC_FSM_CALL_CONTINUE(fsm);
 }
 
+/* Rekey protocol completion callback */
+
+static void silc_client_rekey_completion(SilcSKE ske,
+                                        SilcSKEStatus status,
+                                        SilcSKESecurityProperties prop,
+                                        SilcSKEKeyMaterial keymat,
+                                        SilcSKERekeyMaterial rekey,
+                                        void *context)
+{
+  SilcFSMThread fsm = context;
+  SilcClientConnection conn = silc_fsm_get_context(fsm);
+  SilcClient client = conn->client;
+
+  conn->internal->op = NULL;
+  if (status != SILC_SKE_STATUS_OK) {
+    /* Rekey failed */
+    SILC_LOG_DEBUG(("Error during rekey with %s: %s (%d)",
+                   conn->remote_host, silc_ske_map_status(status), status));
+
+    if (conn->internal->verbose)
+      client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
+                                "Error during rekey with %s: %s",
+                                conn->remote_host,
+                                silc_ske_map_status(status));
+
+    silc_fsm_finish(fsm);
+    return;
+  }
+
+  silc_ske_free_rekey_material(conn->internal->rekey);
+  conn->internal->rekey = rekey;
+
+  SILC_LOG_DEBUG(("Rekey completed"));
+
+  /* Rekey done */
+  silc_fsm_finish(fsm);
+}
+
 /* Callback called by application to return authentication data */
 
 static void silc_client_connect_auth_method(SilcBool success,
@@ -261,6 +323,8 @@ static void silc_client_connect_auth_completion(SilcConnAuth connauth,
   SILC_FSM_CALL_CONTINUE(fsm);
 }
 
+/*************************** Connect remote host ****************************/
+
 /* Connection timeout callback */
 
 SILC_TASK_CALLBACK(silc_client_connect_timeout)
@@ -277,8 +341,6 @@ SILC_TASK_CALLBACK(silc_client_connect_timeout)
   silc_fsm_continue_sync(&conn->internal->event_thread);
 }
 
-/*************************** Connect remote host ****************************/
-
 /* Creates a connection to remote host */
 
 SILC_FSM_STATE(silc_client_st_connect)
@@ -490,7 +552,7 @@ SILC_FSM_STATE(silc_client_st_connect_auth_start)
   /* Allocate connection authentication protocol */
   connauth = silc_connauth_alloc(conn->internal->schedule,
                                 conn->internal->ske,
-                                client->internal->params->rekey_secs);
+                                conn->internal->params.rekey_secs);
   if (!connauth) {
     /** Out of memory */
     conn->callback(client, conn, SILC_CLIENT_CONN_ERROR_AUTH, 0, NULL,
@@ -519,6 +581,14 @@ SILC_FSM_STATE(silc_client_st_connected)
 
   SILC_LOG_DEBUG(("Connection established"));
 
+  silc_ske_free(conn->internal->ske);
+  conn->internal->ske = NULL;
+
+  /* Install rekey timer */
+  silc_schedule_task_add_timeout(conn->internal->schedule,
+                                silc_client_rekey_timer, conn,
+                                conn->internal->params.rekey_secs, 0);
+
   /* If we connected to server, now register to network. */
   if (conn->type == SILC_CONN_SERVER &&
       !conn->internal->params.no_authentication) {
@@ -536,7 +606,8 @@ SILC_FSM_STATE(silc_client_st_connected)
     return SILC_FSM_CONTINUE;
   }
 
-  silc_schedule_task_del_by_context(conn->internal->schedule, conn);
+  silc_schedule_task_del_by_all(conn->internal->schedule, 0,
+                               silc_client_connect_timeout, conn);
 
   /* Call connection callback */
   conn->callback(client, conn, SILC_CLIENT_CONN_SUCCESS, 0, NULL,
@@ -551,13 +622,71 @@ SILC_FSM_STATE(silc_client_st_connect_error)
 {
   SilcClientConnection conn = fsm_context;
 
+  if (conn->internal->ske) {
+    silc_ske_free(conn->internal->ske);
+    conn->internal->ske = NULL;
+  }
+
   /* Signal to close connection */
   if (!conn->internal->disconnected) {
     conn->internal->disconnected = TRUE;
     SILC_FSM_SEMA_POST(&conn->internal->wait_event);
   }
 
-  silc_schedule_task_del_by_context(conn->internal->schedule, conn);
+  silc_schedule_task_del_by_all(conn->internal->schedule, 0,
+                               silc_client_connect_timeout, conn);
 
   return SILC_FSM_FINISH;
 }
+
+/****************************** Connect rekey *******************************/
+
+/* Connection rekey timer callback */
+
+SILC_TASK_CALLBACK(silc_client_rekey_timer)
+{
+  SilcClientConnection conn = context;
+
+  /* Signal to start rekey */
+  conn->internal->rekeying = TRUE;
+  SILC_FSM_SEMA_POST(&conn->internal->wait_event);
+
+  /* Reinstall rekey timer */
+  silc_schedule_task_add_timeout(conn->internal->schedule,
+                                silc_client_rekey_timer, conn,
+                                conn->internal->params.rekey_secs, 0);
+}
+
+/* Performs rekey */
+
+SILC_FSM_STATE(silc_client_st_rekey)
+{
+  SilcClientConnection conn = fsm_context;
+  SilcClient client = conn->client;
+
+  SILC_LOG_DEBUG(("Rekey"));
+
+  /* Allocate SKE */
+  conn->internal->ske =
+    silc_ske_alloc(client->rng, conn->internal->schedule,
+                  conn->internal->params.repository,
+                  conn->public_key, conn->private_key, fsm);
+  if (!conn->internal->ske)
+    return SILC_FSM_FINISH;
+
+  /* Set SKE callbacks */
+  silc_ske_set_callbacks(conn->internal->ske, NULL,
+                        silc_client_rekey_completion, fsm);
+
+  /** Perform rekey */
+  if (!conn->internal->rekey_responder)
+    SILC_FSM_CALL(conn->internal->op = silc_ske_rekey_initiator(
+                                                   conn->internal->ske,
+                                                   conn->stream,
+                                                   conn->internal->rekey));
+  else
+    SILC_FSM_CALL(conn->internal->op = silc_ske_rekey_responder(
+                                                   conn->internal->ske,
+                                                   conn->stream,
+                                                   conn->internal->rekey));
+}
index 00d60f2087423da2fcde9be677fef096d4f3ae95..0ee3c9cab313958527e8c0204bd6b4f05473b86e 100644 (file)
@@ -29,5 +29,9 @@ SILC_FSM_STATE(silc_client_st_connect_auth);
 SILC_FSM_STATE(silc_client_st_connect_auth_start);
 SILC_FSM_STATE(silc_client_st_connected);
 SILC_FSM_STATE(silc_client_st_connect_error);
+SILC_FSM_STATE(silc_client_st_rekey);
+
+SILC_TASK_CALLBACK(silc_client_connect_timeout);
+SILC_TASK_CALLBACK(silc_client_rekey_timer);
 
 #endif /* CLIENT_CONNECT_H */
index c68dc4754508a7301bc6d200d90bd7ff28bbf175..980daea66746322437b3119d7f1fcd7026a99e7a 100644 (file)
@@ -841,13 +841,10 @@ SilcBool silc_client_del_client(SilcClient client, SilcClientConnection conn,
   if (!client_entry)
     return FALSE;
 
-  SILC_LOG_DEBUG(("Client %p refcnt %d->%d", client_entry,
-                 silc_atomic_get_int8(&client_entry->internal.refcnt),
-                 silc_atomic_get_int8(&client_entry->internal.refcnt) - 1));
   if (silc_atomic_sub_int8(&client_entry->internal.refcnt, 1) > 0)
     return FALSE;
 
-  SILC_LOG_DEBUG(("Deleting client %p"));
+  SILC_LOG_DEBUG(("Deleting client %p", client_entry));
 
   silc_mutex_lock(conn->internal->lock);
   ret = silc_idcache_del_by_context(conn->internal->client_cache,
@@ -881,13 +878,12 @@ void silc_client_ref_client(SilcClient client, SilcClientConnection conn,
 void silc_client_unref_client(SilcClient client, SilcClientConnection conn,
                              SilcClientEntry client_entry)
 {
-  if (client_entry)
+  if (client_entry) {
     SILC_LOG_DEBUG(("Client %p refcnt %d->%d", client_entry,
                    silc_atomic_get_int8(&client_entry->internal.refcnt),
                    silc_atomic_get_int8(&client_entry->internal.refcnt) - 1));
-  if (client_entry &&
-      silc_atomic_sub_int8(&client_entry->internal.refcnt, 1) == 0)
     silc_client_del_client(client, conn, client_entry);
+  }
 }
 
 /* Free client entry list */
@@ -1359,6 +1355,7 @@ SilcBool silc_client_del_channel(SilcClient client, SilcClientConnection conn,
     return FALSE;
 
   silc_client_empty_channel(client, conn, channel);
+  silc_hash_table_free(channel->user_list);
   silc_free(channel->channel_name);
   silc_free(channel->topic);
   if (channel->founder_key)
@@ -1420,6 +1417,9 @@ void silc_client_ref_channel(SilcClient client, SilcClientConnection conn,
                             SilcChannelEntry channel_entry)
 {
   silc_atomic_add_int8(&channel_entry->internal.refcnt, 1);
+  SILC_LOG_DEBUG(("Channel %p refcnt %d->%d", channel_entry,
+                 silc_atomic_get_int8(&channel_entry->internal.refcnt) - 1,
+                 silc_atomic_get_int8(&channel_entry->internal.refcnt)));
 }
 
 /* Release reference of channel entry */
@@ -1427,9 +1427,13 @@ void silc_client_ref_channel(SilcClient client, SilcClientConnection conn,
 void silc_client_unref_channel(SilcClient client, SilcClientConnection conn,
                               SilcChannelEntry channel_entry)
 {
-  if (channel_entry &&
-      silc_atomic_sub_int8(&channel_entry->internal.refcnt, 1) == 0)
+  if (channel_entry) {
+    SILC_LOG_DEBUG(("Channel %p refcnt %d->%d", channel_entry,
+                   silc_atomic_get_int8(&channel_entry->internal.refcnt),
+                   silc_atomic_get_int8(&channel_entry->internal.refcnt)
+                   - 1));
     silc_client_del_channel(client, conn, channel_entry);
+  }
 }
 
 /* Free channel entry list */
@@ -1787,9 +1791,7 @@ void silc_client_ref_server(SilcClient client, SilcClientConnection conn,
 void silc_client_unref_server(SilcClient client, SilcClientConnection conn,
                              SilcServerEntry server_entry)
 {
-  if (server_entry &&
-      silc_atomic_sub_int8(&server_entry->internal.refcnt, 1) == 0)
-    silc_client_del_server(client, conn, server_entry);
+  silc_client_del_server(client, conn, server_entry);
 }
 
 /* Free server entry list */
index 8f56f3571897708f628def8915cc39feddbb5025..0acee44df7bbbdfe4c7593bebee14bbc3b15cd06 100644 (file)
@@ -182,10 +182,12 @@ struct SilcClientConnectionInternalStruct {
   unsigned int connect            : 1;  /* Connect remote host */
   unsigned int disconnected       : 1;  /* Disconnected by remote host */
   unsigned int key_exchange       : 1;   /* Start key exchange */
+  unsigned int rekeying           : 1;   /* Start rekey */
 
   /* Flags */
   unsigned int verbose            : 1;   /* Notify application */
   unsigned int registering        : 1;  /* Set when registering to network */
+  unsigned int rekey_responder    : 1;   /* Set when rekeying as responder */
 
   SilcClientAway *away;
   SilcClientConnAuthRequest connauth;
@@ -219,6 +221,8 @@ SilcUInt16 silc_client_command_send_argv(SilcClient client,
                                         SilcUInt32 *argv_lens,
                                         SilcUInt32 *argv_types);
 void silc_client_command_free(SilcClientCommandContext cmd);
+void silc_client_fsm_destructor(SilcFSM fsm, void *fsm_context,
+                               void *destructor_context);
 
 void silc_client_ftp(SilcClient client, SilcClientConnection conn,
                     SilcPacket packet);
index fd8deeb074a571383960dd9470e7d83595ccb663..068b22d5926560c9dc9c9389a27f3e85eb96c8d1 100644 (file)
@@ -496,6 +496,7 @@ SILC_FSM_STATE(silc_client_notify_signoff)
   NOTIFY(client, conn, type, client_entry, tmp);
 
   /* Delete client */
+  silc_client_remove_from_channels(client, conn, client_entry);
   silc_client_del_client(client, conn, client_entry);
   silc_client_unref_client(client, conn, client_entry);
 
@@ -1136,7 +1137,6 @@ SILC_FSM_STATE(silc_client_notify_kicked)
   SilcArgumentPayload args = silc_notify_get_args(payload);
   SilcClientEntry client_entry, client_entry2;
   SilcChannelEntry channel = NULL;
-  SilcChannelUser chu;
   unsigned char *tmp;
   SilcUInt32 tmp_len;
   SilcID id;
@@ -1194,14 +1194,8 @@ SILC_FSM_STATE(silc_client_notify_kicked)
   tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
 
   /* Remove kicked client from channel */
-  if (client_entry != conn->local_entry) {
-    chu = silc_client_on_channel(channel, client_entry);
-    if (chu) {
-      silc_hash_table_del(client_entry->channels, channel);
-      silc_hash_table_del(channel->user_list, client_entry);
-      silc_free(chu);
-    }
-  }
+  if (client_entry != conn->local_entry)
+    silc_client_remove_from_channel(client, conn, channel, client_entry);
 
   /* Notify application. */
   NOTIFY(client, conn, type, client_entry, tmp, client_entry2, channel);
@@ -1210,6 +1204,7 @@ SILC_FSM_STATE(silc_client_notify_kicked)
   if (client_entry == conn->local_entry) {
     if (conn->current_channel == channel)
       conn->current_channel = NULL;
+    silc_client_empty_channel(client, conn, channel);
     silc_client_del_channel(client, conn, channel);
   }
 
@@ -1307,8 +1302,10 @@ SILC_FSM_STATE(silc_client_notify_killed)
   NOTIFY(client, conn, type, client_entry, comment, id.type, entry);
 
   /* Delete the killed client */
-  if (client_entry != conn->local_entry)
+  if (client_entry != conn->local_entry) {
+    silc_client_remove_from_channels(client, conn, client_entry);
     silc_client_del_client(client, conn, client_entry);
+  }
 
  out:
   silc_client_unref_client(client, conn, client_entry);
@@ -1341,7 +1338,7 @@ SILC_FSM_STATE(silc_client_notify_server_signoff)
   SilcID id;
   int i;
 
-  SILC_LOG_DEBUG(("Notify: SIGNOFF"));
+  SILC_LOG_DEBUG(("Notify: SERVER_SIGNOFF"));
 
   clients = silc_dlist_init();
   if (!clients)
@@ -1364,8 +1361,10 @@ SILC_FSM_STATE(silc_client_notify_server_signoff)
 
   /* Delete the clients */
   silc_dlist_start(clients);
-  while ((client_entry = silc_dlist_get(clients)))
+  while ((client_entry = silc_dlist_get(clients))) {
+    silc_client_remove_from_channels(client, conn, client_entry);
     silc_client_del_client(client, conn, client_entry);
+  }
 
  out:
   /** Notify processed */
@@ -1406,6 +1405,7 @@ SILC_FSM_STATE(silc_client_notify_error)
       goto out;
     client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
     if (client_entry) {
+      silc_client_remove_from_channels(client, conn, client_entry);
       silc_client_del_client(client, conn, client_entry);
       silc_client_unref_client(client, conn, client_entry);
     }
@@ -1516,8 +1516,10 @@ SILC_FSM_STATE(silc_client_notify_watch)
           ntype == SILC_NOTIFY_TYPE_KILLED)
     del_client = TRUE;
 
-  if (del_client)
+  if (del_client) {
+    silc_client_remove_from_channels(client, conn, client_entry);
     silc_client_del_client(client, conn, client_entry);
+  }
 
   if (public_key)
     silc_pkcs_public_key_free(public_key);
index 25ee56503e512de1383d4f2f3358000ec962c9b8..3b45718a669a922040d7de9bf94ee342ada0b2dd 100644 (file)
@@ -37,13 +37,13 @@ SilcBool silc_client_send_private_message(SilcClient client,
   SilcBuffer buffer;
   SilcBool ret;
 
-  SILC_LOG_DEBUG(("Sending private message"));
-
   if (!client || !conn || !client_entry)
     return FALSE;
   if (flags & SILC_MESSAGE_FLAG_SIGNED && !hash)
     return FALSE;
 
+  SILC_LOG_DEBUG(("Sending private message"));
+
   /* Encode private message payload */
   buffer =
     silc_message_payload_encode(flags, data, data_len,
index b0ddc907d61b0eab2ebf1c6a2cfbe1c872dafaea..977118032b854e7fdfb8d373b60a425acdafd948 100644 (file)
@@ -49,6 +49,26 @@ silc_client_register_command_called(SilcClient client,
                                    void *context,
                                    va_list ap)
 {
+  return FALSE;
+}
+
+/* Continues resuming after resolving.  Continue after last reply. */
+
+static SilcBool
+silc_client_resume_continue(SilcClient client,
+                           SilcClientConnection conn,
+                           SilcCommand command,
+                           SilcStatus status,
+                           SilcStatus error,
+                           void *context,
+                           va_list ap)
+{
+  if (status == SILC_STATUS_OK || status == SILC_STATUS_LIST_END ||
+      SILC_STATUS_IS_ERROR(status)) {
+    silc_fsm_continue(&conn->internal->event_thread);
+    return FALSE;
+  }
+
   return TRUE;
 }
 
@@ -179,7 +199,7 @@ SILC_FSM_STATE(silc_client_st_register_complete)
     /** Resend registering packet */
     silc_fsm_next(fsm, silc_client_st_register);
     conn->internal->retry_timer = ((conn->internal->retry_timer *
-                                  SILC_CLIENT_RETRY_MUL) +
+                                   SILC_CLIENT_RETRY_MUL) +
                                   (silc_rng_get_rn16(client->rng) %
                                    SILC_CLIENT_RETRY_RAND));
     return SILC_FSM_CONTINUE;
@@ -213,7 +233,8 @@ SILC_FSM_STATE(silc_client_st_register_complete)
                 conn->callback_context);
 
   conn->internal->registering = FALSE;
-  silc_schedule_task_del_by_context(conn->internal->schedule, conn);
+  silc_schedule_task_del_by_all(conn->internal->schedule, 0,
+                               silc_client_connect_timeout, conn);
 
   return SILC_FSM_FINISH;
 }
@@ -237,12 +258,12 @@ SILC_FSM_STATE(silc_client_st_register_error)
   conn->callback(client, conn, SILC_CLIENT_CONN_ERROR, 0, NULL,
                 conn->callback_context);
 
-  silc_schedule_task_del_by_context(conn->internal->schedule, conn);
+  silc_schedule_task_del_by_all(conn->internal->schedule, 0,
+                               silc_client_connect_timeout, conn);
 
   return SILC_FSM_FINISH;
 }
 
-
 /************************* Resume detached session **************************/
 
 /* Resume detached session */
@@ -310,9 +331,9 @@ SILC_FSM_STATE(silc_client_st_resume)
   /* Send RESUME_CLIENT packet to resume to network */
   if (!silc_packet_send_va(conn->stream, SILC_PACKET_RESUME_CLIENT, 0,
                           SILC_STR_UI_SHORT(id_len),
-                          SILC_STR_UI_XNSTRING(id, id_len),
-                          SILC_STR_UI_XNSTRING(silc_buffer_data(auth),
-                                               silc_buffer_len(auth)),
+                          SILC_STR_DATA(id, id_len),
+                          SILC_STR_DATA(silc_buffer_data(auth),
+                                        silc_buffer_len(auth)),
                           SILC_STR_END)) {
     /** Error sending packet */
     silc_fsm_next(fsm, silc_client_st_resume_error);
@@ -321,17 +342,20 @@ SILC_FSM_STATE(silc_client_st_resume)
 
   /** Wait for new ID */
   conn->internal->registering = TRUE;
-  silc_fsm_next_later(fsm, silc_client_st_resume_resolve, 15, 0);
+  silc_fsm_next_later(fsm, silc_client_st_resume_resolve_channels, 15, 0);
   return SILC_FSM_WAIT;
 }
 
-/* Resolve the old session information */
+/* Resolve the old session information, user mode and joined channels. */
 
-SILC_FSM_STATE(silc_client_st_resume_resolve)
+SILC_FSM_STATE(silc_client_st_resume_resolve_channels)
 {
-#if 0
   SilcClientConnection conn = fsm_context;
+  SilcClient client = conn->client;
   SilcClientResumeSession resume = state_context;
+  SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
+  unsigned char **res_argv = NULL;
+  int i;
 
   if (!conn->local_id) {
     /** Timeout, ID not received */
@@ -340,37 +364,77 @@ SILC_FSM_STATE(silc_client_st_resume_resolve)
     return SILC_FSM_CONTINUE;
   }
 
+  /* First, send UMODE command to get our own user mode in the network */
+  SILC_LOG_DEBUG(("Resolving user mode"));
+  silc_client_command_send(client, conn, SILC_COMMAND_UMODE,
+                          silc_client_register_command_called, NULL,
+                          1, 1, silc_buffer_data(conn->internal->local_idp),
+                          silc_buffer_len(conn->internal->local_idp));
 
-  for (i = 0; i < ch_count; i++) {
-    char *channel;
+  /* Second, send IDENTIFY command for all channels we know about.  These
+     are the channels we've joined to according our detachment data. */
+  for (i = 0; i < resume->channel_count; i++) {
+    SilcChannelID channel_id;
     unsigned char *chid;
     SilcUInt16 chid_len;
-    SilcUInt32 ch_mode;
-    SilcChannelID *channel_id;
-    SilcChannelEntry channel_entry;
-
-    len = silc_buffer_unformat(&detach,
-                              SILC_STR_UI16_NSTRING_ALLOC(&channel, NULL),
-                              SILC_STR_UI16_NSTRING(&chid, &chid_len),
-                              SILC_STR_UI_INT(&ch_mode),
-                              SILC_STR_END);
-    if (len == -1)
-      return FALSE;
-
-    /* Add new channel */
-    channel_id = silc_id_str2id(chid, chid_len, SILC_ID_CHANNEL);
-    channel_entry = silc_client_get_channel_by_id(client, conn, channel_id);
-    if (!channel_entry) {
-      channel_entry = silc_client_add_channel(client, conn, channel, ch_mode,
-                                             channel_id);
-    } else {
-      silc_free(channel);
-      silc_free(channel_id);
-    }
+    SilcBuffer idp;
 
-    silc_buffer_pull(&detach, len);
+    if (silc_buffer_unformat(&resume->detach,
+                            SILC_STR_ADVANCE,
+                            SILC_STR_UI16_NSTRING(NULL, NULL),
+                            SILC_STR_UI16_NSTRING(&chid, &chid_len),
+                            SILC_STR_UI_INT(NULL),
+                            SILC_STR_END) < 0)
+      continue;
+
+    idp = silc_id_payload_encode_data(chid, chid_len, SILC_ID_CHANNEL);
+    if (!idp)
+      continue;
+    res_argv = silc_realloc(res_argv, sizeof(*res_argv) * (res_argc + 1));
+    res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
+                                (res_argc + 1));
+    res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
+                                 (res_argc + 1));
+    res_argv[res_argc] = silc_buffer_steal(idp, &res_argv_lens[res_argc]);
+    res_argv_types[res_argc] = res_argc + 5;
+    res_argc++;
+    silc_buffer_free(idp);
   }
-#endif /* 0 */
+
+  /* Send IDENTIFY command */
+  SILC_LOG_DEBUG(("Resolving joined channels"));
+  silc_client_command_send_argv(client, conn, SILC_COMMAND_IDENTIFY,
+                               silc_client_resume_continue, conn,
+                               res_argc, res_argv, res_argv_lens,
+                               res_argv_types);
+
+  for (i = 0; i < resume->channel_count; i++)
+    silc_free(res_argv[i]);
+  silc_free(res_argv);
+  silc_free(res_argv_lens);
+  silc_free(res_argv_types);
+
+  /** Wait for channels */
+  silc_fsm_next(fsm, silc_client_st_resume_resolve_cmodes);
+  return SILC_FSM_WAIT;
+}
+
+/* Resolve joined channel modes. */
+
+SILC_FSM_STATE(silc_client_st_resume_resolve_cmodes)
+{
+  SilcClientConnection conn = fsm_context;
+  SilcClientResumeSession resume = state_context;
+  SilcHashTableList htl;
+  SilcChannelUser chu;
+
+  SILC_LOG_DEBUG(("Resolving joined channel modes"));
+
+  silc_hash_table_list(conn->local_entry->channels, &htl);
+  while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
+
+  }
+  silc_hash_table_list_reset(&htl);
 
   return SILC_FSM_FINISH;
 }
index 9343da97913ff159d429cfa1e09d762332782ff9..dca9ff9c81a0b4021576df3e96eb532aba97602f 100644 (file)
@@ -25,7 +25,8 @@ SILC_FSM_STATE(silc_client_st_register);
 SILC_FSM_STATE(silc_client_st_register_complete);
 SILC_FSM_STATE(silc_client_st_register_error);
 SILC_FSM_STATE(silc_client_st_resume);
-SILC_FSM_STATE(silc_client_st_resume_resolve);
+SILC_FSM_STATE(silc_client_st_resume_resolve_channels);
+SILC_FSM_STATE(silc_client_st_resume_resolve_cmodes);
 SILC_FSM_STATE(silc_client_st_resume_error);
 
 SilcBuffer silc_client_get_detach_data(SilcClient client,
index b1d233fc8c1a7f3f0ac6d4ec48104ed7366e8ae1..7ffa52fa36f471a90d84ecfcb6f5014447a41bfb 100644 (file)
@@ -352,6 +352,12 @@ void silc_client_command_free(SilcClientCommandContext cmd)
   SilcClientCommandReplyCallback cb;
   int i;
 
+  /* If command is running, finish it.  Destructor will free the context. */
+  if (silc_fsm_is_started(&cmd->thread)) {
+    silc_fsm_finish(&cmd->thread);
+    return;
+  }
+
   for (i = 0; i < cmd->argc; i++)
     silc_free(cmd->argv[i]);
   silc_free(cmd->argv);
index bbb4f2a29961d5c7e8c35267c8e3b5609bdc2605..ea1f74b0f2cd98e8da17d5759e04a0b2e046f366 100644 (file)
@@ -114,8 +114,9 @@ static void silc_client_command_process_error(SilcClientCommandContext cmd,
 
     client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
     if (client_entry) {
-      silc_client_unref_client(client, conn, client_entry);
+      silc_client_remove_from_channels(client, conn, client_entry);
       silc_client_del_client(client, conn, client_entry);
+      silc_client_unref_client(client, conn, client_entry);
     }
   }
 }
@@ -175,11 +176,14 @@ SILC_FSM_STATE(silc_client_command_reply)
 
 SILC_FSM_STATE(silc_client_command_reply_wait)
 {
+  SilcClientCommandContext cmd = fsm_context;
+
   SILC_LOG_DEBUG(("Wait for command reply"));
 
   /** Wait for command reply */
   silc_fsm_set_state_context(fsm, NULL);
-  silc_fsm_next_later(fsm, silc_client_command_reply_timeout, 20, 0);
+  silc_fsm_next_later(fsm, silc_client_command_reply_timeout,
+                     cmd->cmd != SILC_COMMAND_PING ? 25 : 60, 0);
   return SILC_FSM_WAIT;
 }
 
@@ -899,6 +903,7 @@ SILC_FSM_STATE(silc_client_command_reply_kill)
 
   /* Remove the client from all channels and free it */
   if (client_entry) {
+    silc_client_remove_from_channels(client, conn, client_entry);
     silc_client_del_client(client, conn, client_entry);
     silc_client_unref_client(client, conn, client_entry);
   }
@@ -1731,6 +1736,7 @@ SILC_FSM_STATE(silc_client_command_reply_leave)
   silc_client_command_callback(cmd, channel);
 
   /* Now delete the channel. */
+  silc_client_empty_channel(client, conn, channel);
   silc_client_del_channel(client, conn, channel);
 
  out:
index 2426cb57e5da8798e3c90f9c97c9d2bdeb296143..f6fdb7588efbcdec18861ac18b9d1385c162b978 100644 (file)
@@ -643,10 +643,6 @@ typedef struct {
      in the callbacks to protect application specific data. */
   SilcBool threads;
 
-  /* Rekey timeout in seconds. The client will perform rekey in this
-     time interval. If set to zero, the default value will be used. */
-  unsigned int rekey_secs;
-
   /* Connection authentication method request timeout. If server does not
      reply back the current authentication method when we've requested it
      in this time interval we'll assume the reply will not come at all.
@@ -926,6 +922,12 @@ typedef struct {
   /* Connection timeout.  If non-zero, the connection will timeout unless
      the SILC connection is completed in the specified amount of time. */
   SilcUInt32 timeout_secs;
+
+  /* Rekey timeout in seconds.  The client will perform rekey in this
+     time interval.  If set to zero, the default value will be used
+     (3600 seconds, 1 hour). */
+  unsigned int rekey_secs;
+
 } SilcClientConnectionParams;
 /***/