updates.
[silc.git] / apps / silcd / server.c
index 38f645e49338ac19068edc549ff44c093e289f82..5c93bed5ff664308ecffe150b7bc1ed49fdcecec 100644 (file)
@@ -84,6 +84,9 @@ void silc_server_free(SilcServer server)
     if (server->rng)
       silc_rng_free(server->rng);
 
+    if (server->pkcs)
+      silc_pkcs_free(server->pkcs);
+
 #ifdef SILC_SIM
     while ((sim = silc_dlist_get(server->sim)) != SILC_LIST_END) {
       silc_dlist_del(server->sim, sim);
@@ -115,6 +118,7 @@ int silc_server_init(SilcServer server)
   SilcServerID *id;
   SilcServerEntry id_entry;
   SilcIDListPurge purge;
+  SilcServerConfigSectionListenPort *listen;
 
   SILC_LOG_DEBUG(("Initializing server"));
   assert(server);
@@ -166,22 +170,27 @@ int silc_server_init(SilcServer server)
   /* Initialize none cipher */
   silc_cipher_alloc("none", &server->none_cipher);
 
-  /* Create a listening server. Note that our server can listen on
-     multiple ports. All listeners are created here and now. */
-  /* XXX Still check this whether to use server_info or listen_port. */
+  /* Allocate PKCS context for local public and private keys */
+  silc_pkcs_alloc(server->public_key->name, &server->pkcs);
+  silc_pkcs_public_key_set(server->pkcs, server->public_key);
+  silc_pkcs_private_key_set(server->pkcs, server->private_key);
+
+  /* Create a listening server. Note that our server can listen on multiple
+     ports. All listeners are created here and now. */
   sock_count = 0;
-  while(server->config->listen_port) {
+  listen = server->config->listen_port;
+  while(listen) {
     int tmp;
 
     tmp = silc_net_create_server(server->config->listen_port->port,
-                                server->config->listen_port->host);
+                                server->config->listen_port->listener_ip);
     if (tmp < 0)
       goto err0;
 
     sock = silc_realloc(sock, (sizeof(int *) * (sock_count + 1)));
     sock[sock_count] = tmp;
-    server->config->listen_port = server->config->listen_port->next;
     sock_count++;
+    listen = listen->next;
   }
 
   /* Initialize ID caches */
@@ -236,6 +245,7 @@ int silc_server_init(SilcServer server)
       SILC_LOG_ERROR(("Could not add ourselves to cache"));
       goto err0;
     }
+    id_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
     
     /* Add ourselves also to the socket table. The entry allocated above
        is sent as argument for fast referencing in the future. */
@@ -270,35 +280,29 @@ int silc_server_init(SilcServer server)
   /* Register protocols */
   silc_server_protocols_register();
 
-  /* Initialize the scheduler. This will register the task queues as well.
-     In SILC we have by default three task queues. One task queue for
-     non-timeout tasks which perform different kind of I/O on file
-     descriptors, timeout task queue for timeout tasks, and, generic
-     non-timeout task queue whose tasks apply to all connections. */
-  server->schedule = silc_schedule_init(&server->io_queue, 
-                                       &server->timeout_queue, 
-                                       &server->generic_queue, 
-                                       SILC_SERVER_MAX_CONNECTIONS);
+  /* Initialize the scheduler. */
+  server->schedule = silc_schedule_init(SILC_SERVER_MAX_CONNECTIONS);
   if (!server->schedule)
     goto err0;
   
-  /* Add the first task to the queue. This is task that is executed by
+  /* Add the first task to the scheduler. This is task that is executed by
      timeout. It expires as soon as the caller calls silc_server_run. This
      task performs authentication protocol and key exchange with our
      primary router. */
-  silc_task_register(server->timeout_queue, sock[0], 
-                    silc_server_connect_to_router,
-                    (void *)server, 0, 1,
-                    SILC_TASK_TIMEOUT,
-                    SILC_TASK_PRI_NORMAL);
+  silc_schedule_task_add(server->schedule, sock[0], 
+                        silc_server_connect_to_router,
+                        (void *)server, 0, 1,
+                        SILC_TASK_TIMEOUT,
+                        SILC_TASK_PRI_NORMAL);
 
-  /* Add listener task to the queue. This task receives new connections to the 
-     server. This task remains on the queue until the end of the program. */
-  silc_task_register(server->io_queue, sock[0],
-                    silc_server_accept_new_connection,
-                    (void *)server, 0, 0, 
-                    SILC_TASK_FD,
-                    SILC_TASK_PRI_NORMAL);
+  /* Add listener task to the scheduler. This task receives new connections
+     to the server. This task remains on the queue until the end of the 
+     program. */
+  silc_schedule_task_add(server->schedule, sock[0],
+                        silc_server_accept_new_connection,
+                        (void *)server, 0, 0, 
+                        SILC_TASK_FD,
+                        SILC_TASK_PRI_NORMAL);
   server->listenning = TRUE;
 
   /* If server connections has been configured then we must be router as
@@ -312,20 +316,20 @@ int silc_server_init(SilcServer server)
   /* Clients local list */
   purge = silc_calloc(1, sizeof(*purge));
   purge->cache = server->local_list->clients;
-  purge->timeout_queue = server->timeout_queue;
-  silc_task_register(purge->timeout_queue, 0, 
-                    silc_idlist_purge,
-                    (void *)purge, 600, 0,
-                    SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+  purge->schedule = server->schedule;
+  silc_schedule_task_add(purge->schedule, 0, 
+                        silc_idlist_purge,
+                        (void *)purge, 600, 0,
+                        SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
 
   /* Clients global list */
   purge = silc_calloc(1, sizeof(*purge));
   purge->cache = server->global_list->clients;
-  purge->timeout_queue = server->timeout_queue;
-  silc_task_register(purge->timeout_queue, 0, 
-                    silc_idlist_purge,
-                    (void *)purge, 300, 0,
-                    SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+  purge->schedule = server->schedule;
+  silc_schedule_task_add(purge->schedule, 0, 
+                        silc_idlist_purge,
+                        (void *)purge, 300, 0,
+                        SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
 
   SILC_LOG_DEBUG(("Server initialized"));
 
@@ -451,9 +455,6 @@ void silc_server_stop(SilcServer server)
 {
   SILC_LOG_DEBUG(("Stopping server"));
 
-  /* Stop the scheduler, although it might be already stopped. This
-     doesn't hurt anyone. This removes all the tasks and task queues,
-     as well. */
   silc_schedule_stop(server->schedule);
   silc_schedule_uninit(server->schedule);
 
@@ -509,10 +510,10 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_retry)
   }
 
   /* Wait one before retrying */
-  silc_task_register(server->timeout_queue, fd, silc_server_connect_router,
-                    context, sconn->retry_timeout, 
-                    server->params->retry_interval_min_usec,
-                    SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+  silc_schedule_task_add(server->schedule, fd, silc_server_connect_router,
+                        context, sconn->retry_timeout, 
+                        server->params->retry_interval_min_usec,
+                        SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
 }
 
 /* Generic routine to use connect to a router. */
@@ -530,14 +531,15 @@ SILC_TASK_CALLBACK(silc_server_connect_router)
                 sconn->remote_host, sconn->remote_port));
 
   /* Connect to remote host */
-  sock = silc_net_create_connection(sconn->remote_port, 
+  sock = silc_net_create_connection(server->config->listen_port->local_ip,
+                                   sconn->remote_port, 
                                    sconn->remote_host);
   if (sock < 0) {
     SILC_LOG_ERROR(("Could not connect to router"));
-    silc_task_register(server->timeout_queue, fd, 
-                      silc_server_connect_to_router_retry,
-                      context, 0, 1, SILC_TASK_TIMEOUT, 
-                      SILC_TASK_PRI_NORMAL);
+    silc_schedule_task_add(server->schedule, fd, 
+                          silc_server_connect_to_router_retry,
+                          context, 0, 1, SILC_TASK_TIMEOUT, 
+                          SILC_TASK_PRI_NORMAL);
     return;
   }
 
@@ -575,7 +577,7 @@ SILC_TASK_CALLBACK(silc_server_connect_router)
   /* Register a timeout task that will be executed if the protocol
      is not executed within set limit. */
   proto_ctx->timeout_task = 
-    silc_task_register(server->timeout_queue, sock, 
+    silc_schedule_task_add(server->schedule, sock, 
                       silc_server_timeout_remote,
                       server, server->params->protocol_timeout,
                       server->params->protocol_timeout_usec,
@@ -592,7 +594,7 @@ SILC_TASK_CALLBACK(silc_server_connect_router)
   SILC_REGISTER_CONNECTION_FOR_IO(sock);
   
   /* Run the protocol */
-  silc_protocol_execute(protocol, server->timeout_queue, 0, 0);
+  silc_protocol_execute(protocol, server->schedule, 0, 0);
 }
   
 /* This function connects to our primary router or if we are a router this
@@ -621,7 +623,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router)
       sconn->remote_host = strdup(server->config->routers->host);
       sconn->remote_port = server->config->routers->port;
 
-      silc_task_register(server->timeout_queue, fd, 
+      silc_schedule_task_add(server->schedule, fd, 
                         silc_server_connect_router,
                         (void *)sconn, 0, 1, SILC_TASK_TIMEOUT, 
                         SILC_TASK_PRI_NORMAL);
@@ -651,7 +653,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router)
        sconn->remote_host = strdup(ptr->host);
        sconn->remote_port = ptr->port;
 
-       silc_task_register(server->timeout_queue, fd, 
+       silc_schedule_task_add(server->schedule, fd, 
                           silc_server_connect_router,
                           (void *)sconn, 0, 1, SILC_TASK_TIMEOUT, 
                           SILC_TASK_PRI_NORMAL);
@@ -700,7 +702,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
     if (ctx->dest_id)
       silc_free(ctx->dest_id);
     silc_free(ctx);
-    silc_task_unregister_by_callback(server->timeout_queue,
+    silc_schedule_task_del_by_callback(server->schedule,
                                     silc_server_failure_callback);
     silc_server_disconnect_remote(server, sock, "Server closed connection: "
                                  "Key exchange failed");
@@ -727,7 +729,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
     if (ctx->dest_id)
       silc_free(ctx->dest_id);
     silc_free(ctx);
-    silc_task_unregister_by_callback(server->timeout_queue,
+    silc_schedule_task_del_by_callback(server->schedule,
                                     silc_server_failure_callback);
     silc_server_disconnect_remote(server, sock, "Server closed connection: "
                                  "Key exchange failed");
@@ -769,8 +771,8 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
     if (ctx->dest_id)
       silc_free(ctx->dest_id);
     silc_free(ctx);
-    silc_task_unregister_by_callback(server->timeout_queue,
-                                    silc_server_failure_callback);
+    silc_schedule_task_del_by_callback(server->schedule,
+                                      silc_server_failure_callback);
     silc_server_disconnect_remote(server, sock, "Server closed connection: "
                                  "Key exchange failed");
     return;
@@ -795,14 +797,14 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
      this timelimit the connection will be terminated. Currently
      this is 15 seconds and is hard coded limit (XXX). */
   proto_ctx->timeout_task = 
-    silc_task_register(server->timeout_queue, sock->sock, 
+    silc_schedule_task_add(server->schedule, sock->sock, 
                       silc_server_timeout_remote,
                       (void *)server, 15, 0,
                       SILC_TASK_TIMEOUT,
                       SILC_TASK_PRI_LOW);
 
   /* Run the protocol */
-  silc_protocol_execute(sock->protocol, server->timeout_queue, 0, 0);
+  silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
 }
 
 /* Finalizes the connection to router. Registers a server task to the
@@ -838,11 +840,11 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
   /* Add a task to the queue. This task receives new connections to the 
      server. This task remains on the queue until the end of the program. */
   if (!server->listenning) {
-    silc_task_register(server->io_queue, server->sock, 
-                      silc_server_accept_new_connection,
-                      (void *)server, 0, 0, 
-                      SILC_TASK_FD,
-                      SILC_TASK_PRI_NORMAL);
+    silc_schedule_task_add(server->schedule, server->sock, 
+                          silc_server_accept_new_connection,
+                          (void *)server, 0, 0, 
+                          SILC_TASK_FD,
+                          SILC_TASK_PRI_NORMAL);
     server->listenning = TRUE;
   }
 
@@ -866,7 +868,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
   silc_buffer_free(packet);
   silc_free(id_string);
 
-  SILC_LOG_DEBUG(("Connected to router %s", sock->hostname));
+  SILC_LOG_INFO(("Connected to router %s", sock->hostname));
 
   /* Add the connected router to local server list */
   server->standalone = FALSE;
@@ -887,7 +889,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
   server->id_entry->router = id_entry;
   server->router = id_entry;
   idata = (SilcIDListData)sock->user_data;
-  idata->registered = TRUE;
+  idata->status |= SILC_IDLIST_STATUS_REGISTERED;
 
   /* Perform keepalive. The `hb_context' will be freed automatically
      when finally calling the silc_socket_free function. XXX hardcoded 
@@ -896,12 +898,12 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
   hb_context->server = server;
   silc_socket_set_heartbeat(sock, 600, hb_context,
                            silc_server_perform_heartbeat,
-                           server->timeout_queue);
+                           server->schedule);
 
   /* Register re-key timeout */
   idata->rekey->timeout = 3600; /* XXX hardcoded */
   idata->rekey->context = (void *)server;
-  silc_task_register(server->timeout_queue, sock->sock, 
+  silc_schedule_task_add(server->schedule, sock->sock, 
                     silc_server_rekey_callback,
                     (void *)sock, idata->rekey->timeout, 0,
                     SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
@@ -1044,11 +1046,11 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
      now, this is a hard coded limit. After 60 secs the connection will
      be closed if the key exchange protocol has not been started. */
   proto_ctx->timeout_task = 
-    silc_task_register(server->timeout_queue, sock->sock, 
-                      silc_server_timeout_remote,
-                      context, 60, 0,
-                      SILC_TASK_TIMEOUT,
-                      SILC_TASK_PRI_LOW);
+    silc_schedule_task_add(server->schedule, sock->sock, 
+                          silc_server_timeout_remote,
+                          context, 60, 0,
+                          SILC_TASK_TIMEOUT,
+                          SILC_TASK_PRI_LOW);
 }
 
 /* Accepts new connections to the server. Accepting new connections are
@@ -1092,7 +1094,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection)
      is accepted further. */
   silc_socket_host_lookup(newsocket, TRUE, 
                          silc_server_accept_new_connection_lookup, context, 
-                         server->timeout_queue);
+                         server->schedule);
 }
 
 /* Second part of accepting new connection. Key exchange protocol has been
@@ -1125,7 +1127,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second)
     if (ctx->dest_id)
       silc_free(ctx->dest_id);
     silc_free(ctx);
-    silc_task_unregister_by_callback(server->timeout_queue,
+    silc_schedule_task_del_by_callback(server->schedule,
                                     silc_server_failure_callback);
     silc_server_disconnect_remote(server, sock, "Server closed connection: "
                                  "Key exchange failed");
@@ -1153,7 +1155,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second)
     if (ctx->dest_id)
       silc_free(ctx->dest_id);
     silc_free(ctx);
-    silc_task_unregister_by_callback(server->timeout_queue,
+    silc_schedule_task_del_by_callback(server->schedule,
                                     silc_server_failure_callback);
     silc_server_disconnect_remote(server, sock, "Server closed connection: "
                                  "Key exchange failed");
@@ -1194,11 +1196,11 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second)
      this timelimit the connection will be terminated. Currently
      this is 60 seconds and is hard coded limit (XXX). */
   proto_ctx->timeout_task = 
-    silc_task_register(server->timeout_queue, sock->sock, 
-                      silc_server_timeout_remote,
-                      (void *)server, 60, 0,
-                      SILC_TASK_TIMEOUT,
-                      SILC_TASK_PRI_LOW);
+    silc_schedule_task_add(server->schedule, sock->sock, 
+                          silc_server_timeout_remote,
+                          (void *)server, 60, 0,
+                          SILC_TASK_TIMEOUT,
+                          SILC_TASK_PRI_LOW);
 }
 
 /* Final part of accepting new connection. The connection has now
@@ -1213,6 +1215,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
   SilcServer server = (SilcServer)ctx->server;
   SilcSocketConnection sock = ctx->sock;
   SilcServerHBContext hb_context;
+  SilcUnknownEntry entry = (SilcUnknownEntry)sock->user_data;
   void *id_entry = NULL;
 
   SILC_LOG_DEBUG(("Start"));
@@ -1231,7 +1234,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
     silc_free(ctx);
     if (sock)
       sock->protocol = NULL;
-    silc_task_unregister_by_callback(server->timeout_queue,
+    silc_schedule_task_del_by_callback(server->schedule,
                                     silc_server_failure_callback);
     silc_server_disconnect_remote(server, sock, "Server closed connection: "
                                  "Authentication failed");
@@ -1239,7 +1242,9 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
     return;
   }
 
-  switch(ctx->conn_type) {
+  entry->data.last_receive = time(NULL);
+
+  switch (ctx->conn_type) {
   case SILC_SOCKET_TYPE_CLIENT:
     {
       SilcClientEntry client;
@@ -1357,11 +1362,11 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
   hb_context->server = server;
   silc_socket_set_heartbeat(sock, 600, hb_context,
                            silc_server_perform_heartbeat,
-                           server->timeout_queue);
+                           server->schedule);
 
  out:
-  silc_task_unregister_by_callback(server->timeout_queue,
-                                  silc_server_failure_callback);
+  silc_schedule_task_del_by_callback(server->schedule,
+                                    silc_server_failure_callback);
   silc_protocol_free(protocol);
   if (ctx->packet)
     silc_packet_context_free(ctx->packet);
@@ -1467,11 +1472,11 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
        start re-connecting phase. */
     if (!server->standalone && sock->type == SILC_SOCKET_TYPE_ROUTER && 
        sock == server->router->connection)
-      silc_task_register(server->timeout_queue, 0, 
-                        silc_server_connect_to_router,
-                        context, 1, 0,
-                        SILC_TASK_TIMEOUT,
-                        SILC_TASK_PRI_NORMAL);
+      silc_schedule_task_add(server->schedule, 0, 
+                            silc_server_connect_to_router,
+                            context, 1, 0,
+                            SILC_TASK_TIMEOUT,
+                            SILC_TASK_PRI_NORMAL);
 
     if (sock->user_data)
       silc_server_free_sock_user_data(server, sock);
@@ -1491,7 +1496,6 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
   /* Get keys and stuff from ID entry */
   idata = (SilcIDListData)sock->user_data;
   if (idata) {
-    idata->last_receive = time(NULL);
     cipher = idata->receive_key;
     hmac = idata->hmac_receive;
   }
@@ -1643,20 +1647,20 @@ void silc_server_packet_parse(SilcPacketParserContext *parser_context)
   case SILC_SOCKET_TYPE_UNKNOWN:
   case SILC_SOCKET_TYPE_CLIENT:
     /* Parse the packet with timeout */
-    silc_task_register(server->timeout_queue, sock->sock,
-                      silc_server_packet_parse_real,
-                      (void *)parser_context, 0, 100000,
-                      SILC_TASK_TIMEOUT,
-                      SILC_TASK_PRI_NORMAL);
+    silc_schedule_task_add(server->schedule, sock->sock,
+                          silc_server_packet_parse_real,
+                          (void *)parser_context, 0, 100000,
+                          SILC_TASK_TIMEOUT,
+                          SILC_TASK_PRI_NORMAL);
     break;
   case SILC_SOCKET_TYPE_SERVER:
   case SILC_SOCKET_TYPE_ROUTER:
     /* Packets from servers are parsed as soon as possible */
-    silc_task_register(server->timeout_queue, sock->sock,
-                      silc_server_packet_parse_real,
-                      (void *)parser_context, 0, 1,
-                      SILC_TASK_TIMEOUT,
-                      SILC_TASK_PRI_NORMAL);
+    silc_schedule_task_add(server->schedule, sock->sock,
+                          silc_server_packet_parse_real,
+                          (void *)parser_context, 0, 1,
+                          SILC_TASK_TIMEOUT,
+                          SILC_TASK_PRI_NORMAL);
     break;
   default:
     return;
@@ -1671,11 +1675,12 @@ void silc_server_packet_parse_type(SilcServer server,
                                   SilcPacketContext *packet)
 {
   SilcPacketType type = packet->type;
+  SilcIDListData idata = (SilcIDListData)sock->user_data;
 
   SILC_LOG_DEBUG(("Parsing packet type %d", type));
 
   /* Parse the packet type */
-  switch(type) {
+  switch (type) {
   case SILC_PACKET_DISCONNECT:
     SILC_LOG_DEBUG(("Disconnect packet"));
     if (packet->flags & SILC_PACKET_FLAG_LIST)
@@ -1692,7 +1697,7 @@ void silc_server_packet_parse_type(SilcServer server,
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       break;
     if (sock->protocol)
-      silc_protocol_execute(sock->protocol, server->timeout_queue, 0, 0);
+      silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
     break;
 
   case SILC_PACKET_FAILURE:
@@ -1711,7 +1716,7 @@ void silc_server_packet_parse_type(SilcServer server,
       f->sock = sock;
       
       /* We will wait 5 seconds to process this failure packet */
-      silc_task_register(server->timeout_queue, sock->sock,
+      silc_schedule_task_add(server->schedule, sock->sock,
                         silc_server_failure_callback, (void *)f, 5, 0,
                         SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
     }
@@ -1748,6 +1753,7 @@ void silc_server_packet_parse_type(SilcServer server,
     SILC_LOG_DEBUG(("Channel Message packet"));
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       break;
+    idata->last_receive = time(NULL);
     silc_server_channel_message(server, sock, packet);
     break;
 
@@ -1801,6 +1807,7 @@ void silc_server_packet_parse_type(SilcServer server,
     SILC_LOG_DEBUG(("Private Message packet"));
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       break;
+    idata->last_receive = time(NULL);
     silc_server_private_message(server, sock, packet);
     break;
 
@@ -1830,7 +1837,7 @@ void silc_server_packet_parse_type(SilcServer server,
       proto_ctx->packet = silc_packet_context_dup(packet);
 
       /* Let the protocol handle the packet */
-      silc_protocol_execute(sock->protocol, server->timeout_queue, 0, 100000);
+      silc_protocol_execute(sock->protocol, server->schedule, 0, 100000);
     } else {
       SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
                      "protocol active, packet dropped."));
@@ -1856,7 +1863,7 @@ void silc_server_packet_parse_type(SilcServer server,
        proto_ctx->packet = silc_packet_context_dup(packet);
 
        /* Let the protocol handle the packet */
-       silc_protocol_execute(sock->protocol, server->timeout_queue, 0, 0);
+       silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
       } else {
        SilcServerKEInternalContext *proto_ctx = 
          (SilcServerKEInternalContext *)sock->protocol->context;
@@ -1872,7 +1879,7 @@ void silc_server_packet_parse_type(SilcServer server,
          break;
 
        /* Let the protocol handle the packet */
-       silc_protocol_execute(sock->protocol, server->timeout_queue, 
+       silc_protocol_execute(sock->protocol, server->schedule, 
                              0, 100000);
       }
     } else {
@@ -1900,7 +1907,7 @@ void silc_server_packet_parse_type(SilcServer server,
        proto_ctx->packet = silc_packet_context_dup(packet);
 
        /* Let the protocol handle the packet */
-       silc_protocol_execute(sock->protocol, server->timeout_queue, 0, 0);
+       silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
       } else {
        SilcServerKEInternalContext *proto_ctx = 
          (SilcServerKEInternalContext *)sock->protocol->context;
@@ -1916,7 +1923,7 @@ void silc_server_packet_parse_type(SilcServer server,
          break;
 
        /* Let the protocol handle the packet */
-       silc_protocol_execute(sock->protocol, server->timeout_queue, 
+       silc_protocol_execute(sock->protocol, server->schedule, 
                              0, 100000);
       }
     } else {
@@ -1957,7 +1964,7 @@ void silc_server_packet_parse_type(SilcServer server,
       proto_ctx->packet = silc_packet_context_dup(packet);
 
       /* Let the protocol handle the packet */
-      silc_protocol_execute(sock->protocol, server->timeout_queue, 0, 0);
+      silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
     } else {
       SILC_LOG_ERROR(("Received Connection Auth packet but no authentication "
                      "protocol active, packet dropped."));
@@ -2064,7 +2071,7 @@ void silc_server_packet_parse_type(SilcServer server,
       proto_ctx->packet = silc_packet_context_dup(packet);
 
       /* Let the protocol handle the packet */
-      silc_protocol_execute(sock->protocol, server->timeout_queue, 0, 0);
+      silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
     } else {
       SILC_LOG_ERROR(("Received Re-key done packet but no re-key "
                      "protocol active, packet dropped."));
@@ -2091,10 +2098,10 @@ void silc_server_create_connection(SilcServer server,
   sconn->remote_host = strdup(remote_host);
   sconn->remote_port = port;
 
-  silc_task_register(server->timeout_queue, 0, 
-                    silc_server_connect_router,
-                    (void *)sconn, 0, 1, SILC_TASK_TIMEOUT, 
-                    SILC_TASK_PRI_NORMAL);
+  silc_schedule_task_add(server->schedule, 0, 
+                        silc_server_connect_router,
+                        (void *)sconn, 0, 1, SILC_TASK_TIMEOUT, 
+                        SILC_TASK_PRI_NORMAL);
 }
 
 SILC_TASK_CALLBACK(silc_server_close_connection_final)
@@ -2107,36 +2114,42 @@ SILC_TASK_CALLBACK(silc_server_close_connection_final)
 void silc_server_close_connection(SilcServer server,
                                  SilcSocketConnection sock)
 {
-  SILC_LOG_INFO(("Closing connection %s:%d [%s] (%d)", 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"), sock->sock));
-
-  /* If any protocol is active cancel its execution */
-  if (sock->protocol) {
-    silc_protocol_cancel(sock->protocol, server->timeout_queue);
-    sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
-    silc_protocol_execute_final(sock->protocol, server->timeout_queue);
-    sock->protocol = NULL;
-  }
+  SILC_LOG_INFO(("Closing connection %s:%d [%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")));
 
   /* We won't listen for this connection anymore */
   silc_schedule_unset_listen_fd(server->schedule, sock->sock);
 
   /* Unregister all tasks */
-  silc_task_unregister_by_fd(server->io_queue, sock->sock);
-  silc_task_unregister_by_fd(server->timeout_queue, sock->sock);
+  silc_schedule_task_del_by_fd(server->schedule, sock->sock);
 
   /* Close the actual connection */
   silc_net_close_connection(sock->sock);
   server->sockets[sock->sock] = NULL;
 
-  silc_task_register(server->timeout_queue, 0, 
-                    silc_server_close_connection_final,
-                    (void *)sock, 0, 1, SILC_TASK_TIMEOUT, 
-                    SILC_TASK_PRI_NORMAL);
+  /* If sock->user_data is NULL then we'll check for active protocols
+     here since the silc_server_free_sock_user_data has not been called
+     for this connection. */
+  if (!sock->user_data) {
+    /* If any protocol is active cancel its execution. It will call
+       the final callback which will finalize the disconnection. */
+    if (sock->protocol) {
+      silc_protocol_cancel(sock->protocol, server->schedule);
+      sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
+      silc_protocol_execute_final(sock->protocol, server->schedule);
+      sock->protocol = NULL;
+      return;
+    }
+  }
+
+  silc_schedule_task_add(server->schedule, 0, 
+                        silc_server_close_connection_final,
+                        (void *)sock, 0, 1, SILC_TASK_TIMEOUT, 
+                        SILC_TASK_PRI_NORMAL);
 }
 
 /* Sends disconnect message to remote connection and disconnects the 
@@ -2159,13 +2172,6 @@ void silc_server_disconnect_remote(SilcServer server,
 
   SILC_LOG_DEBUG(("Disconnecting remote host"));
 
-  SILC_LOG_INFO(("Disconnecting %s:%d [%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")));
-
   /* Notify remote end that the conversation is over. The notify message
      is tried to be sent immediately. */
   silc_server_packet_send(server, sock, SILC_PACKET_DISCONNECT, 0,  
@@ -2234,11 +2240,13 @@ void silc_server_free_client_data(SilcServer server,
      into history (for WHOWAS command) for 5 minutes */
   i->server = server;
   i->client = client;
-  silc_task_register(server->timeout_queue, 0, 
-                    silc_server_free_client_data_timeout,
-                    (void *)i, 300, 0,
-                    SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
-  client->data.registered = FALSE;
+  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->router = NULL;
+  client->connection = NULL;
 
   /* Free the client entry and everything in it */
   server->stat.my_clients--;
@@ -2256,7 +2264,7 @@ void silc_server_free_sock_user_data(SilcServer server,
 {
   SILC_LOG_DEBUG(("Start"));
 
-  switch(sock->type) {
+  switch (sock->type) {
   case SILC_SOCKET_TYPE_CLIENT:
     {
       SilcClientEntry user_data = (SilcClientEntry)sock->user_data;
@@ -2300,9 +2308,118 @@ void silc_server_free_sock_user_data(SilcServer server,
     }
   }
 
+  /* If any protocol is active cancel its execution */
+  if (sock->protocol) {
+    silc_protocol_cancel(sock->protocol, server->schedule);
+    sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
+    silc_protocol_execute_final(sock->protocol, server->schedule);
+    sock->protocol = NULL;
+  }
+
   sock->user_data = NULL;
 }
 
+/* Removes the client from channels and possibly removes the channels
+   as well.  After removing those channels that exist, their channel
+   keys are regnerated. This is called only by the function
+   silc_server_remove_clients_by_server. */
+
+static void silc_server_remove_clients_channels(SilcServer server, 
+                                               SilcSocketConnection sock,
+                                               SilcClientEntry client,
+                                               SilcHashTable channels)
+{
+  SilcChannelEntry channel;
+  SilcChannelClientEntry chl;
+  SilcHashTableList htl;
+  SilcBuffer clidp;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  if (!client || !client->id)
+    return;
+
+  clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+
+  /* Remove the client from all channels. The client is removed from
+     the channels' user list. */
+  silc_hash_table_list(client->channels, &htl);
+  while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
+    channel = chl->channel;
+
+    /* Remove channel from client's channel list */
+    silc_hash_table_del(client->channels, channel);
+
+    /* Remove channel if there is no users anymore */
+    if (server->server_type == SILC_ROUTER &&
+       silc_hash_table_count(channel->user_list) < 2) {
+
+      if (silc_hash_table_find(channels, channel, NULL, NULL))
+       silc_hash_table_del(channels, channel);
+
+      if (channel->rekey)
+       silc_schedule_task_del_by_context(server->schedule, channel->rekey);
+
+      if (!silc_idlist_del_channel(server->local_list, channel))
+       silc_idlist_del_channel(server->global_list, channel);
+      server->stat.my_channels--;
+      continue;
+    }
+
+    /* Remove client from channel's client list */
+    silc_hash_table_del(channel->user_list, chl->client);
+    silc_free(chl);
+    server->stat.my_chanclients--;
+
+    /* 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_SERVER && channel->global_users && 
+       chl->client->router && !silc_server_channel_has_global(channel))
+      channel->global_users = FALSE;
+
+    /* 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. */
+    if (server->server_type == SILC_SERVER &&
+       !silc_server_channel_has_local(channel)) {
+
+      if (silc_hash_table_find(channels, channel, NULL, NULL))
+       silc_hash_table_del(channels, channel);
+
+      if (channel->rekey)
+       silc_schedule_task_del_by_context(server->schedule, channel->rekey);
+
+      if (channel->founder_key) {
+       /* The founder auth data exists, do not remove the channel entry */
+       SilcChannelClientEntry chl2;
+       SilcHashTableList htl2;
+
+       channel->id = NULL;
+
+       silc_hash_table_list(channel->user_list, &htl2);
+       while (silc_hash_table_get(&htl2, NULL, (void *)&chl2)) {
+         silc_hash_table_del(chl2->client->channels, channel);
+         silc_hash_table_del(channel->user_list, chl2->client);
+         silc_free(chl2);
+       }
+       continue;
+      }
+
+      /* Remove the channel entry */
+      if (!silc_idlist_del_channel(server->local_list, channel))
+       silc_idlist_del_channel(server->global_list, channel);
+      server->stat.my_channels--;
+      continue;
+    }
+
+    /* Add the channel to the the channels list to regenerate the 
+       channel key */
+    if (!silc_hash_table_find(channels, channel, NULL, NULL))
+      silc_hash_table_add(channels, channel, channel);
+  }
+
+  silc_buffer_free(clidp);
+}
+
 /* This function is used to remove all client entries by the server `entry'.
    This is called when the connection is lost to the server. In this case
    we must invalidate all the client entries owned by the server `entry'. 
@@ -2321,10 +2438,9 @@ int silc_server_remove_clients_by_server(SilcServer server,
   uint32 clients_c = 0;
   unsigned char **argv = NULL;
   uint32 *argv_lens = NULL, *argv_types = NULL, argc = 0;
-  SilcHashTable channels;
-  SilcChannelClientEntry chl;
-  SilcChannelEntry channel;
   SilcHashTableList htl;
+  SilcChannelEntry channel;
+  SilcHashTable channels;
   int i;
 
   SILC_LOG_DEBUG(("Start"));
@@ -2353,7 +2469,7 @@ int silc_server_remove_clients_by_server(SilcServer server,
     if (silc_idcache_list_first(list, &id_cache)) {
       while (id_cache) {
        client = (SilcClientEntry)id_cache->context;
-       if (client->data.registered == FALSE) {
+       if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
          if (!silc_idcache_list_next(list, &id_cache))
            break;
          else
@@ -2389,16 +2505,8 @@ int silc_server_remove_clients_by_server(SilcServer server,
          silc_buffer_free(idp);
        }
 
-       silc_hash_table_list(client->channels, &htl);
-       while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
-         if (silc_hash_table_find(channels, chl->channel, NULL, NULL))
-           continue;
-         silc_hash_table_add(channels, chl->channel, chl->channel);
-       }
-
        /* Remove the client entry */
-       silc_server_remove_from_channels(server, NULL, client, FALSE, 
-                                        NULL, FALSE);
+       silc_server_remove_clients_channels(server, NULL, client, channels);
        silc_idlist_del_client(server->local_list, client);
 
        if (!silc_idcache_list_next(list, &id_cache))
@@ -2413,7 +2521,7 @@ int silc_server_remove_clients_by_server(SilcServer server,
     if (silc_idcache_list_first(list, &id_cache)) {
       while (id_cache) {
        client = (SilcClientEntry)id_cache->context;
-       if (client->data.registered == FALSE) {
+       if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
          if (!silc_idcache_list_next(list, &id_cache))
            break;
          else
@@ -2449,16 +2557,8 @@ int silc_server_remove_clients_by_server(SilcServer server,
          silc_buffer_free(idp);
        }
 
-       silc_hash_table_list(client->channels, &htl);
-       while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
-         if (silc_hash_table_find(channels, chl->channel, NULL, NULL))
-           continue;
-         silc_hash_table_add(channels, chl->channel, chl->channel);
-       }
-
        /* Remove the client entry */
-       silc_server_remove_from_channels(server, NULL, client, FALSE,
-                                        NULL, FALSE);
+       silc_server_remove_clients_channels(server, NULL, client, channels);
        silc_idlist_del_client(server->global_list, client);
 
        if (!silc_idcache_list_next(list, &id_cache))
@@ -2509,7 +2609,13 @@ int silc_server_remove_clients_by_server(SilcServer server,
      must re-generate the channel key. */
   silc_hash_table_list(channels, &htl);
   while (silc_hash_table_get(&htl, NULL, (void *)&channel)) {
-    silc_server_create_channel_key(server, channel, 0);
+    if (!silc_server_create_channel_key(server, channel, 0))
+      return FALSE;
+
+    /* Do not send the channel key if private channel key mode is set */
+    if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY)
+      continue;
+
     silc_server_send_channel_key(server, NULL, channel, 
                                 server->server_type == SILC_ROUTER ? 
                                 FALSE : !server->standalone);
@@ -2589,7 +2695,7 @@ void silc_server_remove_from_channels(SilcServer server,
     if (server->server_type == SILC_ROUTER &&
        silc_hash_table_count(channel->user_list) < 2) {
       if (channel->rekey)
-       silc_task_unregister_by_context(server->timeout_queue, channel->rekey);
+       silc_schedule_task_del_by_context(server->schedule, channel->rekey);
       if (!silc_idlist_del_channel(server->local_list, channel))
        silc_idlist_del_channel(server->global_list, channel);
       server->stat.my_channels--;
@@ -2621,7 +2727,7 @@ void silc_server_remove_from_channels(SilcServer server,
                                           strlen(signoff_message) : 0);
 
       if (channel->rekey)
-       silc_task_unregister_by_context(server->timeout_queue, channel->rekey);
+       silc_schedule_task_del_by_context(server->schedule, channel->rekey);
 
       if (channel->founder_key) {
        /* The founder auth data exists, do not remove the channel entry */
@@ -2658,7 +2764,8 @@ void silc_server_remove_from_channels(SilcServer server,
 
     if (keygen && !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
       /* Re-generate channel key */
-      silc_server_create_channel_key(server, channel, 0);
+      if (!silc_server_create_channel_key(server, channel, 0))
+       return;
       
       /* Send the channel key to the channel. The key of course is not sent
         to the client who was removed from the channel. */
@@ -2705,7 +2812,7 @@ int silc_server_remove_from_one_channel(SilcServer server,
   if (server->server_type == SILC_ROUTER &&
       silc_hash_table_count(channel->user_list) < 2) {
     if (channel->rekey)
-      silc_task_unregister_by_context(server->timeout_queue, channel->rekey);
+      silc_schedule_task_del_by_context(server->schedule, channel->rekey);
     if (!silc_idlist_del_channel(server->local_list, channel))
       silc_idlist_del_channel(server->global_list, channel);
     silc_buffer_free(clidp);
@@ -2737,7 +2844,7 @@ int silc_server_remove_from_one_channel(SilcServer server,
     silc_buffer_free(clidp);
     
     if (channel->rekey)
-      silc_task_unregister_by_context(server->timeout_queue, channel->rekey);
+      silc_schedule_task_del_by_context(server->schedule, channel->rekey);
 
     if (channel->founder_key) {
       /* The founder auth data exists, do not remove the channel entry */
@@ -2807,7 +2914,7 @@ SILC_TASK_CALLBACK(silc_server_timeout_remote)
      final callback so that all the memory is freed. */
   if (sock->protocol) {
     sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
-    silc_protocol_execute_final(sock->protocol, server->timeout_queue);
+    silc_protocol_execute_final(sock->protocol, server->schedule);
     return;
   }
 
@@ -2838,9 +2945,9 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server,
   SILC_LOG_DEBUG(("Creating new channel"));
 
   if (!cipher)
-    cipher = "aes-256-cbc";
+    cipher = SILC_DEFAULT_CIPHER;
   if (!hmac)
-    hmac = "hmac-sha1-96";
+    hmac = SILC_DEFAULT_HMAC;
 
   /* Allocate cipher */
   if (!silc_cipher_alloc(cipher, &key))
@@ -2855,7 +2962,13 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server,
   channel_name = strdup(channel_name);
 
   /* Create the channel */
-  silc_id_create_channel_id(router_id, server->rng, &channel_id);
+  if (!silc_id_create_channel_id(server, router_id, server->rng, 
+                                &channel_id)) {
+    silc_free(channel_name);
+    silc_cipher_free(key);
+    silc_hmac_free(newhmac);
+    return NULL;
+  }
   entry = silc_idlist_add_channel(server->local_list, channel_name, 
                                  SILC_CHANNEL_MODE_NONE, channel_id, 
                                  NULL, key, newhmac);
@@ -2870,8 +2983,15 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server,
   entry->hmac_name = strdup(hmac);
 
   /* Now create the actual key material */
-  silc_server_create_channel_key(server, entry, 
-                                silc_cipher_get_key_len(key) / 8);
+  if (!silc_server_create_channel_key(server, entry, 
+                                     silc_cipher_get_key_len(key) / 8)) {
+    silc_free(channel_name);
+    silc_cipher_free(key);
+    silc_hmac_free(newhmac);
+    silc_free(entry->cipher);
+    silc_free(entry->hmac_name);
+    return NULL;
+  }
 
   /* Notify other routers about the new channel. We send the packet
      to our primary route. */
@@ -2903,9 +3023,9 @@ silc_server_create_new_channel_with_id(SilcServer server,
   SILC_LOG_DEBUG(("Creating new channel"));
 
   if (!cipher)
-    cipher = "aes-256-cbc";
+    cipher = SILC_DEFAULT_CIPHER;
   if (!hmac)
-    hmac = "hmac-sha1-96";
+    hmac = SILC_DEFAULT_HMAC;
 
   /* Allocate cipher */
   if (!silc_cipher_alloc(cipher, &key))
@@ -2929,8 +3049,11 @@ silc_server_create_new_channel_with_id(SilcServer server,
   }
 
   /* Now create the actual key material */
-  silc_server_create_channel_key(server, entry, 
-                                silc_cipher_get_key_len(key) / 8);
+  if (!silc_server_create_channel_key(server, entry, 
+                                     silc_cipher_get_key_len(key) / 8)) {
+    silc_free(channel_name);
+    return NULL;
+  }
 
   /* Notify other routers about the new channel. We send the packet
      to our primary route. */
@@ -2952,21 +3075,19 @@ SILC_TASK_CALLBACK(silc_server_channel_key_rekey)
   SilcServerChannelRekey rekey = (SilcServerChannelRekey)context;
   SilcServer server = (SilcServer)rekey->context;
 
-  silc_server_create_channel_key(server, rekey->channel, rekey->key_len);
-  silc_server_send_channel_key(server, NULL, rekey->channel, FALSE);
+  rekey->task = NULL;
+
+  if (!silc_server_create_channel_key(server, rekey->channel, rekey->key_len))
+    return;
 
-  silc_task_register(server->timeout_queue, 0, 
-                    silc_server_channel_key_rekey,
-                    (void *)rekey, 3600, 0,
-                    SILC_TASK_TIMEOUT,
-                    SILC_TASK_PRI_NORMAL);
+  silc_server_send_channel_key(server, NULL, rekey->channel, FALSE);
 }
 
 /* Generates new channel key. This is used to create the initial channel key
    but also to re-generate new key for channel. If `key_len' is provided
    it is the bytes of the key length. */
 
-void silc_server_create_channel_key(SilcServer server, 
+bool silc_server_create_channel_key(SilcServer server, 
                                    SilcChannelEntry channel,
                                    uint32 key_len)
 {
@@ -2978,12 +3099,12 @@ void silc_server_create_channel_key(SilcServer server,
 
   if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
     SILC_LOG_DEBUG(("Channel has private keys, will not generate new key"));
-    return;
+    return TRUE;
   }
 
   if (!channel->channel_key)
-    if (!silc_cipher_alloc("aes-256-cbc", &channel->channel_key))
-      return;
+    if (!silc_cipher_alloc(SILC_DEFAULT_CIPHER, &channel->channel_key))
+      return FALSE;
 
   if (key_len)
     len = key_len;
@@ -3012,7 +3133,7 @@ void silc_server_create_channel_key(SilcServer server,
 
   /* Generate HMAC key from the channel key data and set it */
   if (!channel->hmac)
-    silc_hmac_alloc("hmac-sha1-96", NULL, &channel->hmac);
+    silc_hmac_alloc(SILC_DEFAULT_HMAC, NULL, &channel->hmac);
   silc_hash_make(channel->hmac->hash, channel->key, len, hash);
   silc_hmac_set_key(channel->hmac, hash, silc_hash_len(channel->hmac->hash));
   memset(hash, 0, sizeof(hash));
@@ -3023,15 +3144,18 @@ void silc_server_create_channel_key(SilcServer server,
     channel->rekey->context = (void *)server;
     channel->rekey->channel = channel;
     channel->rekey->key_len = key_len;
+    if (channel->rekey->task)
+      silc_schedule_task_del(server->schedule, channel->rekey->task);
 
-    silc_task_unregister_by_callback(server->timeout_queue,
-                                    silc_server_channel_key_rekey);
-    silc_task_register(server->timeout_queue, 0, 
-                      silc_server_channel_key_rekey,
-                      (void *)channel->rekey, 3600, 0,
-                      SILC_TASK_TIMEOUT,
-                      SILC_TASK_PRI_NORMAL);
+    channel->rekey->task = 
+      silc_schedule_task_add(server->schedule, 0, 
+                            silc_server_channel_key_rekey,
+                            (void *)channel->rekey, 3600, 0,
+                            SILC_TASK_TIMEOUT,
+                            SILC_TASK_PRI_NORMAL);
   }
+
+  return TRUE;
 }
 
 /* Saves the channel key found in the encoded `key_payload' buffer. This 
@@ -3116,7 +3240,7 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
 
   /* Generate HMAC key from the channel key data and set it */
   if (!channel->hmac)
-    silc_hmac_alloc("hmac-sha1-96", NULL, &channel->hmac);
+    silc_hmac_alloc(SILC_DEFAULT_HMAC, NULL, &channel->hmac);
   silc_hash_make(channel->hmac->hash, tmp, tmp_len, hash);
   silc_hmac_set_key(channel->hmac, hash, silc_hash_len(channel->hmac->hash));
 
@@ -3128,19 +3252,19 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
       channel->rekey = silc_calloc(1, sizeof(*channel->rekey));
     channel->rekey->context = (void *)server;
     channel->rekey->channel = channel;
+    if (channel->rekey->task)
+      silc_schedule_task_del(server->schedule, channel->rekey->task);
 
-    silc_task_unregister_by_callback(server->timeout_queue,
-                                    silc_server_channel_key_rekey);
-    silc_task_register(server->timeout_queue, 0, 
-                      silc_server_channel_key_rekey,
-                      (void *)channel->rekey, 3600, 0,
-                      SILC_TASK_TIMEOUT,
-                      SILC_TASK_PRI_NORMAL);
+    channel->rekey->task = 
+      silc_schedule_task_add(server->schedule, 0, 
+                            silc_server_channel_key_rekey,
+                            (void *)channel->rekey, 3600, 0,
+                            SILC_TASK_TIMEOUT,
+                            SILC_TASK_PRI_NORMAL);
   }
 
  out:
-  if (id)
-    silc_free(id);
+  silc_free(id);
   if (payload)
     silc_channel_key_payload_free(payload);
 
@@ -3167,6 +3291,7 @@ void silc_server_perform_heartbeat(SilcSocketConnection sock,
    form is dictated by the New ID payload. */
 
 static void silc_server_announce_get_servers(SilcServer server,
+                                            SilcServerEntry remote,
                                             SilcIDList id_list,
                                             SilcBuffer *servers)
 {
@@ -3181,6 +3306,14 @@ static void silc_server_announce_get_servers(SilcServer server,
       while (id_cache) {
        entry = (SilcServerEntry)id_cache->context;
 
+       /* Do not announce the one we've sending our announcements and
+          do not announce ourself. */
+       if (entry == remote || entry == server->id_entry) {
+         if (!silc_idcache_list_next(list, &id_cache))
+           break;
+         continue;
+       }
+
        idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
 
        *servers = silc_buffer_realloc(*servers, 
@@ -3211,10 +3344,12 @@ void silc_server_announce_servers(SilcServer server)
   SILC_LOG_DEBUG(("Announcing servers"));
 
   /* Get servers in local list */
-  silc_server_announce_get_servers(server, server->local_list, &servers);
+  silc_server_announce_get_servers(server, server->router,
+                                  server->local_list, &servers);
 
   /* Get servers in global list */
-  silc_server_announce_get_servers(server, server->global_list, &servers);
+  silc_server_announce_get_servers(server, server->router,
+                                  server->global_list, &servers);
 
   if (servers) {
     silc_buffer_push(servers, servers->data - servers->head);
@@ -3536,7 +3671,7 @@ SILC_TASK_CALLBACK(silc_server_failure_callback)
 
   if (f->sock->protocol) {
     f->sock->protocol->state = SILC_PROTOCOL_STATE_FAILURE;
-    silc_protocol_execute(f->sock->protocol, f->server->timeout_queue, 0, 0);
+    silc_protocol_execute(f->sock->protocol, f->server->schedule, 0, 0);
   }
 
   silc_free(f);
@@ -3603,9 +3738,6 @@ void silc_server_save_users_on_channel(SilcServer server,
 {
   int i;
 
-  /* Cache the received Client ID's and modes. This cache expires
-     whenever server sends notify message to channel. It means two things;
-     some user has joined or leaved the channel. XXX TODO! */
   for (i = 0; i < user_count; i++) {
     uint16 idp_len;
     uint32 mode;
@@ -3631,10 +3763,11 @@ void silc_server_save_users_on_channel(SilcServer server,
     
     /* Check if we have this client cached already. */
     client = silc_idlist_find_client_by_id(server->local_list, client_id,
-                                          NULL);
+                                          server->server_type, NULL);
     if (!client)
       client = silc_idlist_find_client_by_id(server->global_list, 
-                                            client_id, NULL);
+                                            client_id, server->server_type,
+                                            NULL);
     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. */
@@ -3650,11 +3783,12 @@ void silc_server_save_users_on_channel(SilcServer server,
                                      silc_id_dup(client_id, SILC_ID_CLIENT), 
                                      sock->user_data, NULL);
       if (!client) {
+       SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
        silc_free(client_id);
        continue;
       }
 
-      client->data.registered = TRUE;
+      client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
     }
 
     silc_free(client_id);
@@ -3700,13 +3834,10 @@ SilcSocketConnection silc_server_get_client_route(SilcServer server,
 
   /* If the destination belongs to our server we don't have to route
      the packet anywhere but to send it to the local destination. */
-  client = silc_idlist_find_client_by_id(server->local_list, id, NULL);
+  client = silc_idlist_find_client_by_id(server->local_list, id, TRUE, NULL);
   if (client) {
     silc_free(id);
 
-    if (client->data.registered == FALSE)
-      return NULL;
-
     /* If we are router and the client has router then the client is in
        our cell but not directly connected to us. */
     if (server->server_type == SILC_ROUTER && client->router) {
@@ -3737,7 +3868,8 @@ SilcSocketConnection silc_server_get_client_route(SilcServer server,
      and send the packet to fastest route. */
   if (server->server_type == SILC_ROUTER && !server->standalone) {
     /* Check first that the ID is valid */
-    client = silc_idlist_find_client_by_id(server->global_list, id, NULL);
+    client = silc_idlist_find_client_by_id(server->global_list, id, 
+                                          TRUE, NULL);
     if (client) {
       SilcSocketConnection dst_sock;
 
@@ -3810,10 +3942,11 @@ SilcClientEntry silc_server_get_client_resolve(SilcServer server,
 {
   SilcClientEntry client;
 
-  client = silc_idlist_find_client_by_id(server->local_list, client_id, NULL);
+  client = silc_idlist_find_client_by_id(server->local_list, client_id,
+                                        TRUE, NULL);
   if (!client) {
     client = silc_idlist_find_client_by_id(server->global_list, 
-                                          client_id, NULL);
+                                          client_id, TRUE, NULL);
     if (!client && server->server_type == SILC_ROUTER)
       return NULL;
   }
@@ -3824,9 +3957,13 @@ SilcClientEntry silc_server_get_client_resolve(SilcServer server,
   if (!client || !client->nickname || !client->username) {
     SilcBuffer buffer, idp;
 
+    client->data.status |= SILC_IDLIST_STATUS_RESOLVING;
+    client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
+    client->resolve_cmd_ident = ++server->cmd_ident;
+
     idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
     buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
-                                           ++server->cmd_ident, 1,
+                                           server->cmd_ident, 1,
                                            3, idp->data, idp->len);
     silc_server_packet_send(server, client ? client->router->connection :
                            server->router->connection,
@@ -3868,13 +4005,13 @@ SILC_TASK_CALLBACK(silc_server_rekey_callback)
   sock->protocol = protocol;
       
   /* Run the protocol */
-  silc_protocol_execute(protocol, server->timeout_queue, 0, 0);
+  silc_protocol_execute(protocol, server->schedule, 0, 0);
 
   /* Re-register re-key timeout */
-  silc_task_register(server->timeout_queue, sock->sock, 
-                    silc_server_rekey_callback,
-                    context, idata->rekey->timeout, 0,
-                    SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+  silc_schedule_task_add(server->schedule, sock->sock, 
+                        silc_server_rekey_callback,
+                        context, idata->rekey->timeout, 0,
+                        SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
 }
 
 /* The final callback for the REKEY protocol. This will actually take the
@@ -3893,7 +4030,7 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_final)
   if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
       protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
     /* Error occured during protocol */
-    silc_protocol_cancel(protocol, server->timeout_queue);
+    silc_protocol_cancel(protocol, server->schedule);
     silc_protocol_free(protocol);
     sock->protocol = NULL;
     if (ctx->packet)