Added stacktrace support with --enable-stack-trace option.
[silc.git] / apps / silcd / server.c
index e8874aeca14a87cee0bc703ea1da3eafc6cb3eae..10530e00d7d4cacffbb5f65e07290a0eb3a5b6e9 100644 (file)
@@ -77,62 +77,138 @@ int silc_server_alloc(SilcServer *new_server)
 
 void silc_server_free(SilcServer server)
 {
-  if (server) {
+  int i;
+
+  if (!server)
+    return;
+
 #ifdef SILC_SIM
+  {
     SilcSim sim;
-
+    
     while ((sim = silc_dlist_get(server->sim)) != SILC_LIST_END) {
       silc_dlist_del(server->sim, sim);
       silc_sim_free(sim);
     }
     silc_dlist_uninit(server->sim);
+  }
 #endif
 
-    silc_server_config_unref(&server->config_ref);
-    if (server->rng)
-      silc_rng_free(server->rng);
-    if (server->pkcs)
-      silc_pkcs_free(server->pkcs);
-    if (server->public_key)
-      silc_pkcs_public_key_free(server->public_key);
-    if (server->private_key)
-      silc_pkcs_private_key_free(server->private_key);
-    if (server->pending_commands)
-      silc_dlist_uninit(server->pending_commands);
-    if (server->id_entry)
-      silc_idlist_del_server(server->local_list, server->id_entry);
-
-    silc_idcache_free(server->local_list->clients);
-    silc_idcache_free(server->local_list->servers);
-    silc_idcache_free(server->local_list->channels);
-    silc_idcache_free(server->global_list->clients);
-    silc_idcache_free(server->global_list->servers);
-    silc_idcache_free(server->global_list->channels);
-    silc_hash_table_free(server->watcher_list);
-
-    silc_free(server->sockets);
-    silc_free(server);
+  for (i = 0; i < server->config->param.connections_max; i++) {
+    if (!server->sockets[i])
+      continue;
+    silc_socket_free(server->sockets[i]);
   }
+  silc_free(server->sockets);
+
+  silc_server_config_unref(&server->config_ref);
+  if (server->rng)
+    silc_rng_free(server->rng);
+  if (server->pkcs)
+    silc_pkcs_free(server->pkcs);
+  if (server->public_key)
+    silc_pkcs_public_key_free(server->public_key);
+  if (server->private_key)
+    silc_pkcs_private_key_free(server->private_key);
+  if (server->pending_commands)
+    silc_dlist_uninit(server->pending_commands);
+  if (server->id_entry)
+    silc_idlist_del_server(server->local_list, server->id_entry);
+
+  silc_idcache_free(server->local_list->clients);
+  silc_idcache_free(server->local_list->servers);
+  silc_idcache_free(server->local_list->channels);
+  silc_idcache_free(server->global_list->clients);
+  silc_idcache_free(server->global_list->servers);
+  silc_idcache_free(server->global_list->channels);
+  silc_hash_table_free(server->watcher_list);
+
+  silc_hash_free(server->md5hash);
+  silc_hash_free(server->sha1hash);
+  silc_hmac_unregister_all();
+  silc_hash_unregister_all();
+  silc_cipher_unregister_all();
+  silc_pkcs_unregister_all();
+
+  silc_free(server->local_list);
+  silc_free(server->global_list);
+  silc_free(server->server_name);
+  silc_free(server->id_string);
+  silc_free(server->purge_i);
+  silc_free(server->purge_g);
+  silc_free(server);
 }
 
-/* Opens a listening port.
-   XXX This function will become more general and will support multiple
-   listening ports */
+/* Creates a new server listener. */
 
-static bool silc_server_listen(SilcServer server, int *sock)
+static bool silc_server_listen(SilcServer server, const char *server_ip,
+                              SilcUInt16 port, int *sock)
 {
-
-  *sock = silc_net_create_server(server->config->server_info->port,
-                               server->config->server_info->server_ip);
+  *sock = silc_net_create_server(port, server_ip);
   if (*sock < 0) {
     SILC_LOG_ERROR(("Could not create server listener: %s on %hu",
-                   server->config->server_info->server_ip,
-                   server->config->server_info->port));
+                       server_ip, port));
     return FALSE;
   }
   return TRUE;
 }
 
+/* Adds a secondary listener. */
+
+bool silc_server_init_secondary(SilcServer server)
+{
+  int sock = 0, sock_list[server->config->param.connections_max];
+  SilcSocketConnection newsocket = NULL;
+  SilcServerConfigServerInfoInterface *interface;
+
+  for (interface = server->config->server_info->secondary; interface; 
+       interface = interface->next, sock++) {
+
+    if (!silc_server_listen(server,
+       interface->server_ip, interface->port, &sock_list[sock]))
+      goto err;
+
+    /* Set socket to non-blocking mode */
+    silc_net_set_socket_nonblock(sock_list[sock]);
+
+    /* Add ourselves also to the socket table. The entry allocated above
+       is sent as argument for fast referencing in the future. */
+    silc_socket_alloc(sock_list[sock],
+                     SILC_SOCKET_TYPE_SERVER, NULL, &newsocket);
+    server->sockets[sock_list[sock]] = newsocket;
+
+    /* Perform name and address lookups to resolve the listenning address
+       and port. */
+    if (!silc_net_check_local_by_sock(sock_list[sock], &newsocket->hostname,
+                           &newsocket->ip)) {
+      if ((server->config->require_reverse_lookup && !newsocket->hostname) ||
+        !newsocket->ip) {
+        SILC_LOG_ERROR(("IP/DNS lookup failed for local host %s",
+                     newsocket->hostname ? newsocket->hostname :
+                     newsocket->ip ? newsocket->ip : ""));
+        server->stat.conn_failures++;
+        goto err;
+      }
+      if (!newsocket->hostname)
+        newsocket->hostname = strdup(newsocket->ip);
+    }
+    newsocket->port = silc_net_get_local_port(sock);
+
+    newsocket->user_data = (void *)server->id_entry;
+    silc_schedule_task_add(server->schedule, sock_list[sock],
+                        silc_server_accept_new_connection,
+                        (void *)server, 0, 0,
+                        SILC_TASK_FD,
+                        SILC_TASK_PRI_NORMAL);
+  }
+
+  return TRUE;
+
+ err:
+  do silc_net_close_server(sock_list[sock--]); while (sock >= 0);
+  return FALSE;
+}
+
 /* Initializes the entire SILC server. This is called always before running
    the server. This is called only once at the initialization of the program.
    This binds the server to its listenning port. After this function returns
@@ -218,7 +294,12 @@ bool silc_server_init(SilcServer server)
     goto err;
 
   /* Create a listening server */
-  if (!silc_server_listen(server, &sock))
+  if (!silc_server_listen(server,
+               server->config->server_info->primary == NULL ? NULL :
+                       server->config->server_info->primary->server_ip,
+               server->config->server_info->primary == NULL ? 0 :
+                       server->config->server_info->primary->port,
+               &sock))
     goto err;
 
   /* Set socket to non-blocking mode */
@@ -308,6 +389,10 @@ bool silc_server_init(SilcServer server)
                         (void *)server, 0, 0,
                         SILC_TASK_FD,
                         SILC_TASK_PRI_NORMAL);
+
+  if (silc_server_init_secondary(server) == FALSE)
+    goto err;
+  
   server->listenning = TRUE;
 
   /* If server connections has been configured then we must be router as
@@ -331,7 +416,7 @@ bool silc_server_init(SilcServer server)
      and removes the expired cache entries. */
 
   /* Clients local list */
-  purge = silc_calloc(1, sizeof(*purge));
+  server->purge_i = purge = silc_calloc(1, sizeof(*purge));
   purge->cache = server->local_list->clients;
   purge->schedule = server->schedule;
   purge->timeout = 600;
@@ -341,7 +426,7 @@ bool silc_server_init(SilcServer server)
                         SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
 
   /* Clients global list */
-  purge = silc_calloc(1, sizeof(*purge));
+  server->purge_g = purge = silc_calloc(1, sizeof(*purge));
   purge->cache = server->global_list->clients;
   purge->schedule = server->schedule;
   purge->timeout = 300;
@@ -357,6 +442,9 @@ bool silc_server_init(SilcServer server)
                           server, 10, 0, SILC_TASK_TIMEOUT,
                           SILC_TASK_PRI_LOW);
 
+  if (server->server_type == SILC_ROUTER)
+    server->stat.routers++;
+
   SILC_LOG_DEBUG(("Server initialized"));
 
   /* We are done here, return succesfully */
@@ -523,7 +611,7 @@ void silc_server_start_key_exchange(SilcServer server,
 
   /* Cancel any possible retry timeouts */
   silc_schedule_task_del_by_callback(server->schedule,
-                                    silc_server_connect_router);
+                                    silc_server_connect_to_router_retry);
 
   /* Set socket options */
   silc_net_set_socket_nonblock(sock);
@@ -659,9 +747,10 @@ SILC_TASK_CALLBACK(silc_server_connect_router)
   silc_server_config_ref(&sconn->conn, server->config, (void *)rconn);
 
   /* Connect to remote host */
-  sock = silc_net_create_connection(server->config->server_info->server_ip,
-                                   sconn->remote_port,
-                                   sconn->remote_host);
+  sock = silc_net_create_connection(
+                (!server->config->server_info->primary ? NULL :
+                 server->config->server_info->primary->server_ip),
+                sconn->remote_port, sconn->remote_host);
   if (sock < 0) {
     SILC_LOG_ERROR(("Could not connect to router %s:%d",
                    sconn->remote_host, sconn->remote_port));
@@ -1047,6 +1136,13 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
       /* Announce our clients and channels to the router */
       silc_server_announce_clients(server, 0, server->router->connection);
       silc_server_announce_channels(server, 0, server->router->connection);
+
+#ifdef BACKUP_SINGLE_ROUTER
+      /* If we are backup router then this primary router is whom we are
+        backing up. */
+      if (server->server_type == SILC_BACKUP_ROUTER)
+       silc_server_backup_add(server, server->id_entry, sock->ip, 0, TRUE);
+#endif /* BACKUP_SINGLE_ROUTER */
     }
   } else {
     /* Add this server to be our backup router */
@@ -1094,14 +1190,17 @@ static void
 silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
                                         void *context)
 {
-  SilcServer server = (SilcServer)context;
-  SilcServerKEInternalContext *proto_ctx;
+  SilcServerKEInternalContext *proto_ctx =
+    (SilcServerKEInternalContext *)context;
+  SilcServer server = (SilcServer)proto_ctx->server;
   SilcServerConfigClient *cconfig = NULL;
   SilcServerConfigServer *sconfig = NULL;
   SilcServerConfigRouter *rconfig = NULL;
   SilcServerConfigDeny *deny;
   int port;
 
+  context = (void *)server;
+
   SILC_LOG_DEBUG(("Start"));
 
   /* Check whether we could resolve both IP and FQDN. */
@@ -1114,6 +1213,7 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
     silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                  "Unknown host or IP");
+    silc_free(proto_ctx);
     return;
   }
 
@@ -1128,7 +1228,8 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
   SILC_LOG_INFO(("Incoming connection %s (%s)", sock->hostname,
                 sock->ip));
 
-  port = server->sockets[server->sock]->port; /* Listenning port */
+  /* Listenning port */
+  port = server->sockets[(SilcUInt32)proto_ctx->context]->port;
 
   /* Check whether this connection is denied to connect to us. */
   deny = silc_server_config_find_denied(server, sock->ip);
@@ -1138,10 +1239,11 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
     /* The connection is denied */
     SILC_LOG_INFO(("Connection %s (%s) is denied",
                   sock->hostname, sock->ip));
-    silc_server_disconnect_remote(server, sock, 
+    silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_BANNED_FROM_SERVER,
                                  deny->reason);
     server->stat.conn_failures++;
+    silc_free(proto_ctx);
     return;
   }
 
@@ -1154,7 +1256,7 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
     sconfig = silc_server_config_find_server_conn(server, sock->hostname);
   if (server->server_type == SILC_ROUTER) {
     if (!(rconfig = silc_server_config_find_router_conn(server,
-                                                       sock->ip, port)))
+                                                       sock->ip, sock->port)))
       rconfig = silc_server_config_find_router_conn(server, sock->hostname,
                                                    sock->port);
   }
@@ -1162,17 +1264,16 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
     SILC_LOG_INFO(("Connection %s (%s) is not allowed", sock->hostname,
                   sock->ip));
     silc_server_disconnect_remote(server, sock,
-                                 SILC_STATUS_ERR_BANNED_FROM_SERVER);
+                                 SILC_STATUS_ERR_BANNED_FROM_SERVER, NULL);
     server->stat.conn_failures++;
+    silc_free(proto_ctx);
     return;
   }
 
   /* The connection is allowed */
 
-  /* Allocate internal context for key exchange protocol. This is
+  /* Set internal context for key exchange protocol. This is
      sent as context for the protocol. */
-  proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
-  proto_ctx->server = context;
   proto_ctx->sock = sock;
   proto_ctx->rng = server->rng;
   proto_ctx->responder = TRUE;
@@ -1204,7 +1305,8 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
   proto_ctx->timeout_task =
     silc_schedule_task_add(server->schedule, sock->sock,
                           silc_server_timeout_remote,
-                          context, server->config->key_exchange_timeout, 0,
+                          (void *)server,
+                          server->config->key_exchange_timeout, 0,
                           SILC_TASK_TIMEOUT,
                           SILC_TASK_PRI_LOW);
 }
@@ -1216,13 +1318,14 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection)
 {
   SilcServer server = (SilcServer)context;
   SilcSocketConnection newsocket;
+  SilcServerKEInternalContext *proto_ctx;
   int sock;
 
   SILC_LOG_DEBUG(("Accepting new connection"));
 
   server->stat.conn_attempts++;
 
-  sock = silc_net_accept_connection(server->sock);
+  sock = silc_net_accept_connection(fd);
   if (sock < 0) {
     SILC_LOG_ERROR(("Could not accept new connection: %s", strerror(errno)));
     server->stat.conn_failures++;
@@ -1249,9 +1352,12 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection)
   /* Perform asynchronous host lookup. This will lookup the IP and the
      FQDN of the remote connection. After the lookup is done the connection
      is accepted further. */
+  proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+  proto_ctx->server = server;
+  proto_ctx->context = (void *)fd;
   silc_socket_host_lookup(newsocket, TRUE,
-                         silc_server_accept_new_connection_lookup, context,
-                         server->schedule);
+                         silc_server_accept_new_connection_lookup,
+                         (void *)proto_ctx, server->schedule);
 }
 
 /* Second part of accepting new connection. Key exchange protocol has been
@@ -1545,10 +1651,12 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
       }
 
       /* Statistics */
-      if (ctx->conn_type == SILC_SOCKET_TYPE_SERVER)
+      if (ctx->conn_type == SILC_SOCKET_TYPE_SERVER) {
        server->stat.my_servers++;
-      else
+      } else {
        server->stat.my_routers++;
+       server->stat.routers++;
+      }
       server->stat.servers++;
 
       id_entry = (void *)new_server;
@@ -1568,7 +1676,8 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
 
       /* Check whether this connection is to be our primary router connection
         if we do not already have the primary route. */
-      if (server->standalone && ctx->conn_type == SILC_SOCKET_TYPE_ROUTER) {
+      if (!backup_router &&
+         server->standalone && ctx->conn_type == SILC_SOCKET_TYPE_ROUTER) {
        if (silc_server_config_is_primary_route(server) && !initiator)
          break;
 
@@ -2533,6 +2642,11 @@ void silc_server_free_client_data(SilcServer server,
   silc_server_packet_queue_purge(server, sock);
 
   if (client->id) {
+    /* Check if anyone is watching this nickname */
+    if (server->server_type == SILC_ROUTER)
+      silc_server_check_watcher_list(server, client, NULL,
+                                    SILC_NOTIFY_TYPE_SIGNOFF);
+
     /* Send SIGNOFF notify to routers. */
     if (notify && !server->standalone && server->router)
       silc_server_send_notify_signoff(server, server->router->connection,
@@ -2547,11 +2661,6 @@ void silc_server_free_client_data(SilcServer server,
       silc_server_remove_from_channels(server, NULL, client,
                                       FALSE, NULL, FALSE);
 
-    /* Check if anyone is watching this nickname */
-    if (server->server_type == SILC_ROUTER)
-      silc_server_check_watcher_list(server, client, NULL,
-                                    SILC_NOTIFY_TYPE_SIGNOFF);
-
     /* Remove this client from watcher list if it is */
     silc_server_del_from_watcher_list(server, client);
   }
@@ -2626,10 +2735,21 @@ void silc_server_free_sock_user_data(SilcServer server,
                         backup_router->server_name));
          SILC_LOG_DEBUG(("New primary router is backup router %s",
                          backup_router->server_name));
-         server->id_entry->router = backup_router;
-         server->router = backup_router;
-         server->router_connect = time(0);
-         server->backup_primary = TRUE;
+#ifdef BACKUP_SINGLE_ROUTER
+         if (server->id_entry != backup_router) {
+#endif /* BACKUP_SINGLE_ROUTER */
+           server->id_entry->router = backup_router;
+           server->router = backup_router;
+           server->router_connect = time(0);
+           server->backup_primary = TRUE;
+#ifdef BACKUP_SINGLE_ROUTER
+         } else {
+           server->id_entry->router = NULL;
+           server->router = NULL;
+           server->standalone = TRUE;
+         }
+#endif /* BACKUP_SINGLE_ROUTER */
+
          if (server->server_type == SILC_BACKUP_ROUTER) {
            server->server_type = SILC_ROUTER;
 
@@ -2680,7 +2800,12 @@ void silc_server_free_sock_user_data(SilcServer server,
       silc_idlist_del_data(user_data);
       if (!silc_idlist_del_server(server->local_list, user_data))
        silc_idlist_del_server(server->global_list, user_data);
-      server->stat.my_servers--;
+      if (sock->type == SILC_SOCKET_TYPE_SERVER) {
+       server->stat.my_servers--;
+      } else {
+       server->stat.my_routers--;
+       server->stat.routers--;
+      }
       server->stat.servers--;
       if (server->server_type == SILC_ROUTER)
        server->stat.cell_servers--;
@@ -2771,7 +2896,14 @@ void silc_server_remove_from_channels(SilcServer server,
       channel->global_users = FALSE;
 
     silc_free(chl);
-    server->stat.my_chanclients--;
+
+    /* Update statistics */
+    if (client->connection)
+      server->stat.my_chanclients--;
+    if (server->server_type == SILC_ROUTER) {
+      server->stat.cell_chanclients--;
+      server->stat.chanclients--;
+    }
 
     /* 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
@@ -2861,7 +2993,14 @@ bool silc_server_remove_from_one_channel(SilcServer server,
     channel->global_users = FALSE;
 
   silc_free(chl);
-  server->stat.my_chanclients--;
+
+  /* Update statistics */
+  if (client->connection)
+    server->stat.my_chanclients--;
+  if (server->server_type == SILC_ROUTER) {
+    server->stat.cell_chanclients--;
+    server->stat.chanclients--;
+  }
 
   clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
   if (!clidp)
@@ -3009,10 +3148,28 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server,
                                 silc_id_get_len(entry->id, SILC_ID_CHANNEL),
                                 entry->mode);
 
-  server->stat.my_channels++;
+  /* Distribute to backup routers */
+  if (broadcast && server->server_type == SILC_ROUTER) {
+    SilcBuffer packet;
+    unsigned char *cid;
+    SilcUInt32 name_len = strlen(channel_name);
+    SilcUInt32 channel_id_len = silc_id_get_len(entry->id, SILC_ID_CHANNEL);
+    cid = silc_id_id2str(entry->id, SILC_ID_CHANNEL);
+
+    packet = silc_channel_payload_encode(channel_name, name_len,
+                                        cid, channel_id_len, entry->mode);
+    silc_server_backup_send(server, NULL, SILC_PACKET_NEW_CHANNEL, 0,
+                           packet->data, packet->len, FALSE, TRUE);
+    silc_free(cid);
+    silc_buffer_free(packet);
+  }
 
-  if (server->server_type == SILC_ROUTER)
+  server->stat.my_channels++;
+  if (server->server_type == SILC_ROUTER) {
+    server->stat.channels++;
+    server->stat.cell_channels++;
     entry->users_resolved = TRUE;
+  }
 
   return entry;
 }
@@ -3076,10 +3233,28 @@ silc_server_create_new_channel_with_id(SilcServer server,
                                 silc_id_get_len(entry->id, SILC_ID_CHANNEL),
                                 entry->mode);
 
-  server->stat.my_channels++;
+  /* Distribute to backup routers */
+  if (broadcast && server->server_type == SILC_ROUTER) {
+    SilcBuffer packet;
+    unsigned char *cid;
+    SilcUInt32 name_len = strlen(channel_name);
+    SilcUInt32 channel_id_len = silc_id_get_len(entry->id, SILC_ID_CHANNEL);
+    cid = silc_id_id2str(entry->id, SILC_ID_CHANNEL);
+
+    packet = silc_channel_payload_encode(channel_name, name_len,
+                                        cid, channel_id_len, entry->mode);
+    silc_server_backup_send(server, NULL, SILC_PACKET_NEW_CHANNEL, 0,
+                           packet->data, packet->len, FALSE, TRUE);
+    silc_free(cid);
+    silc_buffer_free(packet);
+  }
 
-  if (server->server_type == SILC_ROUTER)
+  server->stat.my_channels++;
+  if (server->server_type == SILC_ROUTER) {
+    server->stat.channels++;
+    server->stat.cell_channels++;
     entry->users_resolved = TRUE;
+  }
 
   return entry;
 }
@@ -3547,7 +3722,7 @@ void silc_server_announce_get_channel_users(SilcServer server,
 {
   SilcChannelClientEntry chl;
   SilcHashTableList htl;
-  SilcBuffer chidp, clidp;
+  SilcBuffer chidp, clidp, csidp;
   SilcBuffer tmp;
   int len;
   unsigned char mode[4], *fkey = NULL;
@@ -3557,16 +3732,16 @@ void silc_server_announce_get_channel_users(SilcServer server,
   SILC_LOG_DEBUG(("Start"));
 
   chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+  csidp = silc_id_payload_encode(server->id, SILC_ID_SERVER);
 
   /* CMODE notify */
-  clidp = silc_id_payload_encode(server->id, SILC_ID_SERVER);
   SILC_PUT32_MSB(channel->mode, mode);
   hmac = channel->hmac ? (char *)silc_hmac_get_name(channel->hmac) : NULL;
   if (channel->founder_key)
     fkey = silc_pkcs_public_key_encode(channel->founder_key, &fkey_len);
   tmp = 
     silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_CMODE_CHANGE,
-                                      6, clidp->data, clidp->len,
+                                      6, csidp->data, csidp->len,
                                       mode, sizeof(mode),
                                       NULL, 0,
                                       hmac, hmac ? strlen(hmac) : 0,
@@ -3585,8 +3760,9 @@ void silc_server_announce_get_channel_users(SilcServer server,
   silc_buffer_put(*channel_modes, tmp->data, tmp->len);
   silc_buffer_pull(*channel_modes, len);
   silc_buffer_free(tmp);
-  silc_buffer_free(clidp);
   silc_free(fkey);
+  fkey = NULL;
+  fkey_len = 0;
 
   /* Now find all users on the channel */
   silc_hash_table_list(channel->user_list, &htl);
@@ -3615,8 +3791,8 @@ void silc_server_announce_get_channel_users(SilcServer server,
     if (chl->mode & SILC_CHANNEL_UMODE_CHANFO && channel->founder_key)
       fkey = silc_pkcs_public_key_encode(channel->founder_key, &fkey_len);
     tmp = silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_CUMODE_CHANGE,
-                                            4, clidp->data, clidp->len,
-                                            mode, 4,
+                                            4, csidp->data, csidp->len,
+                                            mode, sizeof(mode),
                                             clidp->data, clidp->len,
                                             fkey, fkey_len);
     len = tmp->len;
@@ -3632,10 +3808,13 @@ void silc_server_announce_get_channel_users(SilcServer server,
     silc_buffer_pull(*channel_users_modes, len);
     silc_buffer_free(tmp);
     silc_free(fkey);
+    fkey = NULL;
+    fkey_len = 0;
     silc_buffer_free(clidp);
   }
   silc_hash_table_list_reset(&htl);
   silc_buffer_free(chidp);
+  silc_buffer_free(csidp);
 }
 
 /* Returns assembled packets for all channels and users on those channels
@@ -3891,7 +4070,7 @@ SILC_TASK_CALLBACK(silc_server_failure_callback)
 
 /* Assembles user list and users mode list from the `channel'. */
 
-void silc_server_get_users_on_channel(SilcServer server,
+bool silc_server_get_users_on_channel(SilcServer server,
                                      SilcChannelEntry channel,
                                      SilcBuffer *user_list,
                                      SilcBuffer *mode_list,
@@ -3904,6 +4083,9 @@ void silc_server_get_users_on_channel(SilcServer server,
   SilcBuffer idp;
   SilcUInt32 list_count = 0, len = 0;
 
+  if (!silc_hash_table_count(channel->user_list))
+    return FALSE;
+
   silc_hash_table_list(channel->user_list, &htl);
   while (silc_hash_table_get(&htl, NULL, (void *)&chl))
     len += (silc_id_get_len(chl->client->id, SILC_ID_CLIENT) + 4);
@@ -3938,6 +4120,7 @@ void silc_server_get_users_on_channel(SilcServer server,
   *user_list = client_id_list;
   *mode_list = client_mode_list;
   *user_count = list_count;
+  return TRUE;
 }
 
 /* Saves users and their modes to the `channel'. */