* Added global variable silc_log_timestamp that tells silclog
[silc.git] / apps / silcd / server.c
index ebb3e811fc4b5f1184ed35882db0b7dd83a8127d..2d739f8a11e84870bed2edd40298efe1ec797a79 100644 (file)
@@ -1,6 +1,6 @@
 /*
 
-  server.c
+  server.c 
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
@@ -8,8 +8,7 @@
 
   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.
+  the Free Software Foundation; version 2 of the License.
 
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -78,6 +77,9 @@ int silc_server_alloc(SilcServer *new_server)
 
 void silc_server_free(SilcServer server)
 {
+  SilcIDCacheList list;
+  SilcIDCacheEntry cache;
+
   if (!server)
     return;
 
@@ -93,6 +95,7 @@ void silc_server_free(SilcServer server)
   }
 #endif
 
+  silc_server_backup_free(server);
   silc_server_config_unref(&server->config_ref);
   if (server->rng)
     silc_rng_free(server->rng);
@@ -107,6 +110,66 @@ void silc_server_free(SilcServer server)
   if (server->id_entry)
     silc_idlist_del_server(server->local_list, server->id_entry);
 
+  /* Delete all channels */
+  list = NULL;
+  if (silc_idcache_get_all(server->local_list->channels, &list) &&
+      silc_idcache_list_first(list, &cache)) {
+    silc_idlist_del_channel(server->local_list, cache->context);
+    while (silc_idcache_list_next(list, &cache))
+      silc_idlist_del_channel(server->local_list, cache->context);
+  }
+  if (list)
+    silc_idcache_list_free(list);
+  list = NULL;
+  if (silc_idcache_get_all(server->global_list->channels, &list) &&
+      silc_idcache_list_first(list, &cache)) {
+    silc_idlist_del_channel(server->global_list, cache->context);
+    while (silc_idcache_list_next(list, &cache))
+      silc_idlist_del_channel(server->global_list, cache->context);
+  }
+  if (list)
+    silc_idcache_list_free(list);
+
+  /* Delete all clients */
+  list = NULL;
+  if (silc_idcache_get_all(server->local_list->clients, &list) &&
+      silc_idcache_list_first(list, &cache)) {
+    silc_idlist_del_client(server->local_list, cache->context);
+    while (silc_idcache_list_next(list, &cache))
+      silc_idlist_del_client(server->local_list, cache->context);
+  }
+  if (list)
+    silc_idcache_list_free(list);
+  list = NULL;
+  if (silc_idcache_get_all(server->global_list->clients, &list) &&
+      silc_idcache_list_first(list, &cache)) {
+    silc_idlist_del_client(server->global_list, cache->context);
+    while (silc_idcache_list_next(list, &cache))
+      silc_idlist_del_client(server->global_list, cache->context);
+  }
+  if (list)
+    silc_idcache_list_free(list);
+
+  /* Delete all servers */
+  list = NULL;
+  if (silc_idcache_get_all(server->local_list->servers, &list) &&
+      silc_idcache_list_first(list, &cache)) {
+    silc_idlist_del_server(server->local_list, cache->context);
+    while (silc_idcache_list_next(list, &cache))
+      silc_idlist_del_server(server->local_list, cache->context);
+  }
+  if (list)
+    silc_idcache_list_free(list);
+  list = NULL;
+  if (silc_idcache_get_all(server->global_list->servers, &list) &&
+      silc_idcache_list_first(list, &cache)) {
+    silc_idlist_del_server(server->global_list, cache->context);
+    while (silc_idcache_list_next(list, &cache))
+      silc_idlist_del_server(server->global_list, cache->context);
+  }
+  if (list)
+    silc_idcache_list_free(list);
+
   silc_idcache_free(server->local_list->clients);
   silc_idcache_free(server->local_list->servers);
   silc_idcache_free(server->local_list->channels);
@@ -459,7 +522,7 @@ SILC_TASK_CALLBACK(silc_server_rehash_close_connection)
   if (!sock)
     return;
 
-  SILC_LOG_INFO(("Closing connection %s:%d [%s]: connection is unconfigured",
+  SILC_LOG_INFO(("Connection %s:%d [%s] is unconfigured",
                 sock->hostname, sock->port,
                 (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
                  sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
@@ -663,17 +726,20 @@ void silc_server_run(SilcServer server)
 
 void silc_server_stop(SilcServer server)
 {
-  SILC_LOG_DEBUG(("Stopping server"));
+  SILC_LOG_INFO(("SILC Server shutting down"));
 
   if (server->schedule) {
     int i;
 
+    server->server_shutdown = TRUE;
+
     /* Close all connections */
     for (i = 0; i < server->config->param.connections_max; i++) {
       if (!server->sockets[i])
        continue;
       if (!SILC_IS_LISTENER(server->sockets[i])) {
-       SilcIDListData idata = server->sockets[i]->user_data;
+       SilcSocketConnection sock = server->sockets[i];
+       SilcIDListData idata = sock->user_data;
 
        if (idata)
          idata->status &= ~SILC_IDLIST_STATUS_DISABLED;
@@ -683,6 +749,10 @@ void silc_server_stop(SilcServer server)
        silc_server_disconnect_remote(server, server->sockets[i], 
                                      SILC_STATUS_OK, 
                                      "Server is shutting down");
+       if (sock->user_data)
+         silc_server_free_sock_user_data(server, sock,
+                                         "Server is shutting down");
+       silc_socket_free(sock);
       } else {
        silc_socket_free(server->sockets[i]);
        server->sockets[i] = NULL;
@@ -796,6 +866,15 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_retry)
   SilcServerConfigConnParams *param =
                (conn->param ? conn->param : &server->config->param);
 
+  /* Don't retry if we are shutting down. */
+  if (server->server_shutdown) {
+    silc_server_config_unref(&sconn->conn);
+    silc_free(sconn->remote_host);
+    silc_free(sconn->backup_replace_ip);
+    silc_free(sconn);
+    return;
+  }
+
   SILC_LOG_INFO(("Retrying connecting to a router"));
 
   /* Calculate next timeout */
@@ -842,6 +921,14 @@ SILC_TASK_CALLBACK(silc_server_connect_router)
   SilcServerConfigRouter *rconn;
   int sock;
 
+  /* Don't connect if we are shutting down. */
+  if (server->server_shutdown) {
+    silc_free(sconn->remote_host);
+    silc_free(sconn->backup_replace_ip);
+    silc_free(sconn);
+    return;
+  }
+
   SILC_LOG_INFO(("Connecting to the %s %s on port %d",
                 (sconn->backup ? "backup router" : "router"),
                 sconn->remote_host, sconn->remote_port));
@@ -893,20 +980,19 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router)
   SilcServerConnection sconn;
   SilcServerConfigRouter *ptr;
 
-  SILC_LOG_DEBUG(("Connecting to router(s)"));
+  /* Don't connect if we are shutting down. */
+  if (server->server_shutdown)
+    return;
 
-  if (server->server_type == SILC_SERVER) {
-    SILC_LOG_DEBUG(("We are normal server"));
-  } else if (server->server_type == SILC_ROUTER) {
-    SILC_LOG_DEBUG(("We are router"));
-  } else {
-    SILC_LOG_DEBUG(("We are backup router/normal server"));
-  }
+  SILC_LOG_DEBUG(("We are %s",
+                 (server->server_type == SILC_SERVER ?
+                  "normal server" : server->server_type == SILC_ROUTER ?
+                  "router" : "backup router/normal server")));
 
   if (!server->config->routers) {
     /* There wasn't a configured router, we will continue but we don't
        have a connection to outside world.  We will be standalone server. */
-    SILC_LOG_DEBUG(("No router(s), server will be standalone"));
+    SILC_LOG_DEBUG(("No router(s), we are standalone"));
     server->standalone = TRUE;
     return;
   }
@@ -926,7 +1012,8 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router)
                    ptr->host, ptr->port));
 
     if (server->server_type == SILC_ROUTER && ptr->backup_router &&
-       ptr->initiator == FALSE && !server->backup_router)
+       ptr->initiator == FALSE && !server->backup_router &&
+       !silc_server_config_get_backup_router(server))
       server->wait_backup = TRUE;
 
     if (ptr->initiator) {
@@ -1237,7 +1324,8 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
   SILC_LOG_DEBUG(("New server id(%s)",
                  silc_id_render(ctx->dest_id, SILC_ID_SERVER)));
 
-  /* Add the connected router to global server list */
+  /* Add the connected router to global server list.  Router is sent
+     as NULL since it's local to us. */
   id_entry = silc_idlist_add_server(server->global_list,
                                    strdup(sock->hostname),
                                    SILC_ROUTER, ctx->dest_id, NULL, sock);
@@ -1285,10 +1373,12 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
       server->router = id_entry;
       server->standalone = FALSE;
 
-      /* If we are router then announce our possible servers. */
+      /* If we are router then announce our possible servers.  Backup
+        router announces also global servers. */
       if (server->server_type == SILC_ROUTER)
-       silc_server_announce_servers(server, FALSE, 0,
-                                    SILC_PRIMARY_ROUTE(server));
+       silc_server_announce_servers(server,
+                                    server->backup_router ? TRUE : FALSE,
+                                    0, SILC_PRIMARY_ROUTE(server));
 
       /* Announce our clients and channels to the router */
       silc_server_announce_clients(server, 0, SILC_PRIMARY_ROUTE(server));
@@ -1310,7 +1400,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
  out:
   /* Call the completion callback to indicate that we've connected to
      the router */
-  if (sconn->callback)
+  if (sconn && sconn->callback)
     (*sconn->callback)(server, id_entry, sconn->callback_context);
 
   /* Free the temporary connection data context */
@@ -1638,7 +1728,9 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second)
                           SILC_TASK_PRI_LOW);
 }
 
-/* After this is called, server don't wait for backup router anymore */
+/* After this is called, server don't wait for backup router anymore.  
+   This gets called automatically even after we have backup router
+   connection established. */
 
 SILC_TASK_CALLBACK(silc_server_backup_router_wait)
 {
@@ -1909,15 +2001,16 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
       /* If the incoming connection is router and marked as backup router
         then add it to be one of our backups */
       if (ctx->conn_type == SILC_SOCKET_TYPE_ROUTER && backup_router) {
-       silc_server_backup_add(server, new_server, backup_replace_ip,
-                              backup_replace_port, backup_local);
-
        /* Change it back to SERVER type since that's what it really is. */
        if (backup_local)
          ctx->conn_type = SILC_SOCKET_TYPE_SERVER;
-
        new_server->server_type = SILC_BACKUP_ROUTER;
-       server->wait_backup = FALSE;
+
+       /* Remove the backup waiting with timeout */
+       silc_schedule_task_add(server->schedule, 0,
+                              silc_server_backup_router_wait,
+                              (void *)server, 5, 0,
+                              SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
       }
 
       /* Statistics */
@@ -2151,8 +2244,9 @@ SILC_TASK_CALLBACK(silc_server_packet_parse_real)
     ret = silc_packet_parse_special(packet, idata ? idata->receive_key : NULL);
 
   /* If entry is disabled ignore what we got. */
-  if (ret != SILC_PACKET_RESUME_ROUTER &&
-      idata && idata->status & SILC_IDLIST_STATUS_DISABLED) {
+  if (idata && idata->status & SILC_IDLIST_STATUS_DISABLED && 
+      ret != SILC_PACKET_HEARTBEAT && ret != SILC_PACKET_RESUME_ROUTER &&
+      ret != SILC_PACKET_REKEY && ret != SILC_PACKET_REKEY_DONE) {
     SILC_LOG_DEBUG(("Connection is disabled"));
     goto out;
   }
@@ -2753,6 +2847,8 @@ SILC_TASK_CALLBACK(silc_server_close_connection_final)
 void silc_server_close_connection(SilcServer server,
                                  SilcSocketConnection sock)
 {
+  char tmp[128];
+
   if (!server->sockets[sock->sock] && SILC_IS_DISCONNECTED(sock)) {
     silc_schedule_task_add(server->schedule, 0,
                           silc_server_close_connection_final,
@@ -2761,12 +2857,14 @@ void silc_server_close_connection(SilcServer server,
     return;
   }
 
-  SILC_LOG_INFO(("Closing connection %s:%d [%s]", sock->hostname,
+  memset(tmp, 0, sizeof(tmp));
+  silc_socket_get_error(sock, tmp, sizeof(tmp));
+  SILC_LOG_INFO(("Closing connection %s:%d [%s] %s", sock->hostname,
                   sock->port,
                   (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
                    sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
                    sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
-                   "Router")));
+                   "Router"), tmp[0] ? tmp : ""));
 
   /* We won't listen for this connection anymore */
   silc_schedule_unset_listen_fd(server->schedule, sock->sock);
@@ -2863,6 +2961,8 @@ SILC_TASK_CALLBACK(silc_server_free_client_data_timeout)
 {
   FreeClientInternal i = (FreeClientInternal)context;
 
+  assert(!silc_hash_table_count(i->client->channels));
+
   silc_idlist_del_data(i->client);
   silc_idcache_purge_by_context(i->server->local_list->clients, i->client);
   silc_free(i);
@@ -2876,8 +2976,6 @@ void silc_server_free_client_data(SilcServer server,
                                  int notify,
                                  const char *signoff)
 {
-  FreeClientInternal i = silc_calloc(1, sizeof(*i));
-
   SILC_LOG_DEBUG(("Freeing client data"));
 
 #if 1
@@ -2928,17 +3026,26 @@ void silc_server_free_client_data(SilcServer server,
   silc_schedule_task_del_by_context(server->schedule, client);
 
   /* We will not delete the client entry right away. We will take it
-     into history (for WHOWAS command) for 5 minutes */
-  i->server = server;
-  i->client = client;
-  silc_schedule_task_add(server->schedule, 0,
-                        silc_server_free_client_data_timeout,
-                        (void *)i, 300, 0,
-                        SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
-  client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
-  client->mode = 0;
-  client->router = NULL;
-  client->connection = NULL;
+     into history (for WHOWAS command) for 5 minutes, unless we're
+     shutting down server. */
+  if (!server->server_shutdown) {
+    FreeClientInternal i = silc_calloc(1, sizeof(*i));
+    i->server = server;
+    i->client = client;
+    silc_schedule_task_add(server->schedule, 0,
+                          silc_server_free_client_data_timeout,
+                          (void *)i, 300, 0,
+                          SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+    client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
+    client->data.status &= ~SILC_IDLIST_STATUS_LOCAL;
+    client->mode = 0;
+    client->router = NULL;
+    client->connection = NULL;
+  } else {
+    /* Delete directly since we're shutting down server */
+    silc_idlist_del_data(client);
+    silc_idlist_del_client(server->local_list, client);
+  }
 }
 
 /* Frees user_data pointer from socket connection object. This also sends
@@ -2968,6 +3075,14 @@ void silc_server_free_sock_user_data(SilcServer server,
       if (user_data->id)
        backup_router = silc_server_backup_get(server, user_data->id);
 
+      if (!server->backup_router && server->server_type == SILC_ROUTER &&
+         backup_router == server->id_entry &&
+         sock->type != SILC_SOCKET_TYPE_ROUTER)
+       backup_router = NULL;
+
+      if (server->server_shutdown)
+       backup_router = NULL;
+
       /* If this was our primary router connection then we're lost to
         the outside world. */
       if (server->router == user_data) {
@@ -2996,6 +3111,9 @@ void silc_server_free_sock_user_data(SilcServer server,
            server->id_entry->router = NULL;
            server->router = NULL;
            server->standalone = TRUE;
+
+           /* We stop here to take a breath */
+           sleep(2);
          }
 
          if (server->server_type == SILC_BACKUP_ROUTER) {
@@ -3024,24 +3142,43 @@ void silc_server_free_sock_user_data(SilcServer server,
       }
 
       if (!backup_router) {
-       /* As router, remove clients and channels always.  As normal server
-          remove only if it is our primary router.  Other connections
-          may be backup routers and these normal server don't handle here. */
-       if (server->server_type != SILC_SERVER ||
-           server->standalone || sock == SILC_PRIMARY_ROUTE(server)) {
-         /* Free all client entries that this server owns as they will
-            become invalid now as well. */
-         silc_server_remove_clients_by_server(server, user_data, TRUE);
-         if (server->server_type == SILC_SERVER)
-           silc_server_remove_channels_by_server(server, user_data);
-       }
+       /* Remove all servers that are originated from this server, and
+          remove the clients of those servers too. */
+       silc_server_remove_servers_by_server(server, user_data, TRUE);
+
+       /* Remove the clients that this server owns as they will become
+          invalid now too. */
+       silc_server_remove_clients_by_server(server, user_data,
+                                            user_data, TRUE);
+
+       /* Remove channels owned by this server */
+       if (server->server_type == SILC_SERVER)
+         silc_server_remove_channels_by_server(server, user_data);
       } else {
-       /* Update the client entries of this server to the new backup
-          router. This also removes the clients that *really* was owned
-          by the primary router and went down with the router.  */
+       /* Enable local server connections that may be disabled */
        silc_server_local_servers_toggle_enabled(server, TRUE);
-       silc_server_update_clients_by_server(server, user_data, backup_router,
-                                            TRUE, TRUE);
+
+       /* Update the client entries of this server to the new backup
+          router.  If we are the backup router we also resolve the real
+          servers for the clients.  After updating is over this also
+          removes the clients that this server explicitly owns. */
+       silc_server_update_clients_by_server(server, user_data,
+                                            backup_router, TRUE);
+
+       /* If we are router and just lost our primary router (now standlaone)
+          we remove everything that was behind it, since we don't know
+          any better. */
+       if (server->server_type == SILC_ROUTER && server->standalone)
+         /* Remove all servers that are originated from this server, and
+            remove the clients of those servers too. */
+         silc_server_remove_servers_by_server(server, user_data, TRUE);
+
+       /* Finally remove the clients that are explicitly owned by this
+          server.  They go down with the server. */
+       silc_server_remove_clients_by_server(server, user_data,
+                                            user_data, TRUE);
+
+       /* Update our server cache to use the new backup router too. */
        silc_server_update_servers_by_server(server, user_data, backup_router);
        if (server->server_type == SILC_SERVER)
          silc_server_update_channels_by_server(server, user_data,
@@ -3054,7 +3191,7 @@ void silc_server_free_sock_user_data(SilcServer server,
                                 ("%s switched to backup router %s "
                                  "(we are primary router now)",
                                  server->server_name, server->server_name));
-       else
+       else if (server->router)
          SILC_SERVER_SEND_OPERS(server, FALSE, TRUE,
                                 SILC_NOTIFY_TYPE_NONE,
                                 ("%s switched to backup router %s",
@@ -3155,7 +3292,7 @@ void silc_server_remove_from_channels(SilcServer server,
 
     /* Remove channel if this is last client leaving the channel, unless
        the channel is permanent. */
-    if (server->server_type == SILC_ROUTER &&
+    if (server->server_type != SILC_SERVER &&
        silc_hash_table_count(channel->user_list) < 2) {
       silc_server_channel_delete(server, channel);
       continue;
@@ -3167,7 +3304,7 @@ void silc_server_remove_from_channels(SilcServer server,
 
     /* If there is no global users on the channel anymore mark the channel
        as local channel. Do not check if the removed client is local client. */
-    if (server->server_type != SILC_ROUTER && channel->global_users &&
+    if (server->server_type == SILC_SERVER && channel->global_users &&
        chl->client->router && !silc_server_channel_has_global(channel))
       channel->global_users = FALSE;
 
@@ -3184,7 +3321,7 @@ void silc_server_remove_from_channels(SilcServer server,
     /* If there is not at least one local user on the channel then we don't
        need the channel entry anymore, we can remove it safely, unless the
        channel is permanent channel */
-    if (server->server_type != SILC_ROUTER &&
+    if (server->server_type == SILC_SERVER &&
        !silc_server_channel_has_local(channel)) {
       /* Notify about leaving client if this channel has global users. */
       if (notify && channel->global_users)
@@ -3209,6 +3346,10 @@ void silc_server_remove_from_channels(SilcServer server,
                                         signoff_message, signoff_message ?
                                         strlen(signoff_message) : 0);
 
+    /* Don't create keys if we are shutting down */
+    if (server->server_shutdown)
+      continue;
+
     /* Re-generate channel key if needed */
     if (keygen && !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
       if (!silc_server_create_channel_key(server, channel, 0))
@@ -3253,7 +3394,7 @@ bool silc_server_remove_from_one_channel(SilcServer server,
 
   /* Remove channel if this is last client leaving the channel, unless
      the channel is permanent. */
-  if (server->server_type == SILC_ROUTER &&
+  if (server->server_type != SILC_SERVER &&
       silc_hash_table_count(channel->user_list) < 2) {
     silc_server_channel_delete(server, channel);
     return FALSE;
@@ -3265,7 +3406,7 @@ bool silc_server_remove_from_one_channel(SilcServer server,
 
   /* If there is no global users on the channel anymore mark the channel
      as local channel. Do not check if the client is local client. */
-  if (server->server_type != SILC_ROUTER && channel->global_users &&
+  if (server->server_type == SILC_SERVER && channel->global_users &&
       chl->client->router && !silc_server_channel_has_global(channel))
     channel->global_users = FALSE;
 
@@ -3286,7 +3427,7 @@ bool silc_server_remove_from_one_channel(SilcServer server,
   /* If there is not at least one local user on the channel then we don't
      need the channel entry anymore, we can remove it safely, unless the
      channel is permanent channel */
-  if (server->server_type != SILC_ROUTER &&
+  if (server->server_type == SILC_SERVER &&
       !silc_server_channel_has_local(channel)) {
     /* Notify about leaving client if this channel has global users. */
     if (notify && channel->global_users)
@@ -3545,6 +3686,10 @@ SILC_TASK_CALLBACK(silc_server_channel_key_rekey)
 
   rekey->task = NULL;
 
+  /* Return now if we are shutting down */
+  if (server->server_shutdown)
+    return;
+
   if (!silc_server_create_channel_key(server, rekey->channel, rekey->key_len))
     return;
 
@@ -3563,13 +3708,13 @@ bool silc_server_create_channel_key(SilcServer server,
   unsigned char channel_key[32], hash[32];
   SilcUInt32 len;
 
-  SILC_LOG_DEBUG(("Generating channel key"));
-
   if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
     SILC_LOG_DEBUG(("Channel has private keys, will not generate new key"));
     return TRUE;
   }
 
+  SILC_LOG_DEBUG(("Generating channel %s key", channel->channel_name));
+
   if (!channel->channel_key)
     if (!silc_cipher_alloc(SILC_DEFAULT_CIPHER, &channel->channel_key)) {
       channel->channel_key = NULL;
@@ -3643,8 +3788,6 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
   SilcUInt32 tmp_len;
   char *cipher;
 
-  SILC_LOG_DEBUG(("Saving new channel key"));
-
   /* Decode channel key payload */
   payload = silc_channel_key_payload_parse(key_payload->data,
                                           key_payload->len);
@@ -3676,6 +3819,8 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
     }
   }
 
+  SILC_LOG_DEBUG(("Saving new channel %s key", channel->channel_name));
+
   tmp = silc_channel_key_get_key(payload, &tmp_len);
   if (!tmp) {
     channel = NULL;
@@ -3755,7 +3900,8 @@ void silc_server_perform_heartbeat(SilcSocketConnection sock,
 {
   SilcServerHBContext hb = (SilcServerHBContext)hb_context;
 
-  SILC_LOG_DEBUG(("Sending heartbeat to %s (%s)", sock->hostname, sock->ip));
+  SILC_LOG_DEBUG(("Sending heartbeat to %s:%d (%s)", sock->hostname, 
+                sock->port, sock->ip));
 
   /* Send the heartbeat */
   silc_server_send_heartbeat(hb->server, sock);
@@ -3888,6 +4034,12 @@ static void silc_server_announce_get_clients(SilcServer server,
            break;
          continue;
        }
+       if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED) &&
+           !client->connection && !client->router && !SILC_IS_LOCAL(client)) {
+         if (!silc_idcache_list_next(list, &id_cache))
+           break;
+         continue;
+       }
 
        idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
 
@@ -4156,31 +4308,38 @@ void silc_server_announce_get_channels(SilcServer server,
          silc_buffer_pull(*channels, len);
        }
 
-       /* Channel user modes */
-       *channel_users_modes = silc_realloc(*channel_users_modes,
-                                           sizeof(**channel_users_modes) *
-                                           (i + 1));
-       (*channel_users_modes)[i] = NULL;
-       *channel_modes = silc_realloc(*channel_modes,
-                                     sizeof(**channel_modes) * (i + 1));
-       (*channel_modes)[i] = NULL;
-       *channel_ids = silc_realloc(*channel_ids,
-                                   sizeof(**channel_ids) * (i + 1));
-       (*channel_ids)[i] = NULL;
-       silc_server_announce_get_channel_users(server, channel,
-                                              &(*channel_modes)[i], 
-                                              channel_users,
-                                              &(*channel_users_modes)[i]);
-       (*channel_ids)[i] = channel->id;
-
-       /* Channel's topic */
-       *channel_topics = silc_realloc(*channel_topics,
-                                      sizeof(**channel_topics) * (i + 1));
-       (*channel_topics)[i] = NULL;
-       silc_server_announce_get_channel_topic(server, channel,
-                                              &(*channel_topics)[i]);
-       (*channel_users_modes_c)++;
-       i++;
+       if (creation_time && channel->updated < creation_time)
+         announce = FALSE;
+       else
+         announce = TRUE;
+
+       if (announce) {
+         /* Channel user modes */
+         *channel_users_modes = silc_realloc(*channel_users_modes,
+                                             sizeof(**channel_users_modes) *
+                                             (i + 1));
+         (*channel_users_modes)[i] = NULL;
+         *channel_modes = silc_realloc(*channel_modes,
+                                       sizeof(**channel_modes) * (i + 1));
+         (*channel_modes)[i] = NULL;
+         *channel_ids = silc_realloc(*channel_ids,
+                                     sizeof(**channel_ids) * (i + 1));
+         (*channel_ids)[i] = NULL;
+         silc_server_announce_get_channel_users(server, channel,
+                                                &(*channel_modes)[i], 
+                                                channel_users,
+                                                &(*channel_users_modes)[i]);
+         (*channel_ids)[i] = channel->id;
+
+         /* Channel's topic */
+         *channel_topics = silc_realloc(*channel_topics,
+                                        sizeof(**channel_topics) * (i + 1));
+         (*channel_topics)[i] = NULL;
+         silc_server_announce_get_channel_topic(server, channel,
+                                                &(*channel_topics)[i]);
+         (*channel_users_modes_c)++;
+         i++;
+       }
 
        if (!silc_idcache_list_next(list, &id_cache))
          break;
@@ -4417,9 +4576,9 @@ void silc_server_save_users_on_channel(SilcServer server,
   SilcClientEntry client;
   SilcIDCacheEntry cache;
   SilcChannelClientEntry chl;
-  bool global;
 
-  SILC_LOG_DEBUG(("Start"));
+  SILC_LOG_DEBUG(("Saving %d users on %s channel", user_count,
+                 channel->channel_name));
 
   for (i = 0; i < user_count; i++) {
     /* Client ID */
@@ -4439,21 +4598,19 @@ void silc_server_save_users_on_channel(SilcServer server,
       continue;
     }
 
-    global = FALSE;
+    cache = NULL;
 
     /* Check if we have this client cached already. */
     client = silc_idlist_find_client_by_id(server->local_list, client_id,
                                           server->server_type, &cache);
-    if (!client) {
+    if (!client)
       client = silc_idlist_find_client_by_id(server->global_list,
                                             client_id, server->server_type,
                                             &cache);
-      global = TRUE;
-    }
     if (!client) {
       /* If router did not find such Client ID in its lists then this must
         be bogus client or some router in the net is buggy. */
-      if (server->server_type == SILC_ROUTER) {
+      if (server->server_type != SILC_SERVER) {
        silc_free(client_id);
        continue;
       }
@@ -4471,15 +4628,18 @@ void silc_server_save_users_on_channel(SilcServer server,
       }
 
       client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
-    } else {
-      /* Found, if it is from global list we'll assure that we won't
-        expire it now that the entry is on channel. */
-      if (global)
-       cache->expire = 0;
     }
 
+    if (cache)
+      cache->expire = 0;
     silc_free(client_id);
 
+    if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
+      SILC_LOG_ERROR(("Attempting to add unregistered client to channel ",
+                     "%s", channel->channel_name));
+      continue;
+    }
+
     if (!silc_server_client_on_channel(client, channel, &chl)) {
       /* Client was not on the channel, add it. */
       chl = silc_calloc(1, sizeof(*chl));
@@ -4517,7 +4677,8 @@ void silc_server_save_user_channels(SilcServer server,
   char *name;
   int i = 0;
 
-  if (!channels ||!channels_user_modes)
+  if (!channels || !channels_user_modes ||
+      !(client->data.status & SILC_IDLIST_STATUS_REGISTERED))
     goto out;
   
   ch = silc_channel_payload_parse_list(channels->data, channels->len);
@@ -4828,8 +4989,6 @@ SILC_TASK_CALLBACK(silc_server_rekey_callback)
   SilcProtocol protocol;
   SilcServerRekeyInternalContext *proto_ctx;
 
-  SILC_LOG_DEBUG(("Start"));
-
   /* Allocate internal protocol context. This is sent as context
      to the protocol. */
   proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
@@ -4847,6 +5006,8 @@ SILC_TASK_CALLBACK(silc_server_rekey_callback)
   /* Run the protocol */
   silc_protocol_execute(protocol, server->schedule, 0, 0);
 
+  SILC_LOG_DEBUG(("Rekey protocol completed"));
+
   /* Re-register re-key timeout */
   silc_schedule_task_add(server->schedule, sock->sock,
                         silc_server_rekey_callback,